Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Documentation

on:
push:
branches: [main, master]
paths:
- '*.md'
- 'docs/**'
- 'tests/backend/test_docs_*.py'
- '.github/workflows/docs.yml'
pull_request:
branches: [main, master]
paths:
- '*.md'
- 'docs/**'
- 'tests/backend/test_docs_*.py'
- '.github/workflows/docs.yml'

jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: pip
cache-dependency-path: requirements.txt
- run: pip install -r requirements.txt
- run: python -m unittest tests.backend.test_docs_links tests.backend.test_docs_sync -v
5 changes: 0 additions & 5 deletions backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -830,11 +830,6 @@ def dispatch_api_request(self, method, parsed, body=None):
else:
self.send_error(404)
return
if isinstance(match.handler, str):
handler = getattr(self, match.handler)
handler(parsed, body, dict(match.params))
return

request = Request(
method=method,
path=path,
Expand Down
16 changes: 5 additions & 11 deletions backend/routing.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
"""Small route registry used by the stdlib HTTP entrypoint."""

from dataclasses import dataclass
from typing import Any, Dict, Mapping, Optional, Tuple
from typing import Callable, Dict, Mapping, Optional, Tuple


@dataclass(frozen=True)
class RouteMatch:
handler: Any
handler: Callable
params: Mapping[str, str]

@property
def handler_name(self) -> str:
if isinstance(self.handler, str):
return self.handler
return getattr(self.handler, "__name__", str(self.handler))


@dataclass(frozen=True)
class _Route:
method: str
path: str
handler: Any
handler: Callable
param_name: Optional[str] = None
is_prefix: bool = False

Expand All @@ -37,15 +31,15 @@ def __init__(self) -> None:
self._exact: Dict[Tuple[str, str], RouteMatch] = {}
self._prefixes: list[_Route] = []

def add(self, method: str, path: str, handler: Any) -> "Router":
def add(self, method: str, path: str, handler: Callable) -> "Router":
self._exact[(method.upper(), path)] = RouteMatch(handler, {})
return self

def add_prefix(
self,
method: str,
prefix: str,
handler: Any,
handler: Callable,
param_name: Optional[str] = None,
) -> "Router":
self._prefixes.append(
Expand Down
39 changes: 8 additions & 31 deletions docs/chat-popout-capabilities.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# Chat pop-out Phase 1 capability findings

Date: 2026-09-11
Status: Phase 1 fixture evidence (2026-09-11). The production pop-out in `ui/js/chat-window/` is covered in [Chat in a separate window](chat-popout.md) and [Tests](tests.md); this fixture itself implements no production behavior.
Status: Historical Phase 1 evidence. The synthetic fixture was retired on 2026-09-23;
its recorded browser and native findings remain below. Current production behavior
and automated checks are documented in [Chat in a separate window](chat-popout.md)
and [Tests](tests.md).

The disposable check is run with:

```powershell
node tests/frontend/chat_popout_capabilities.cjs
```

The runner launches Playwright Chromium with fresh browser contexts and an ephemeral HTTP server. The server serves only the synthetic fixture page. It does not serve `ui/`, read or write `llama_gui_conversations`, accept chat requests, or expose any `/api/*` route. Each scenario uses a unique nonce and the only storage key it may create is `chat-popout-capability:<nonce>`. Closing the context removes that disposable state.
The retired probe used fresh Chromium contexts and an ephemeral server serving a
synthetic page, without application code, real chat history, or backend routes.
The following fixture findings describe that 2026-09-11 experiment, not a current
production regression suite.

## Evidence from the loopback fixture

Expand All @@ -36,29 +36,6 @@ Every fallback case uses a fresh browser context and keeps the source page recov

The blocked-popup, blocked-storage, missing-Web-Locks, and missing-opener conditions are controlled browser-context simulations. The normal popup, opener reference, same-context storage sharing, Web Locks contention, secure-context result, and close checks run against Chromium itself. Native window activation is not asserted by the headless fixture. A real embedded host that strips or changes these capabilities still needs a native check.

## Bootstrap and request-setting audit

The current frontend is a strict ordered global-script page. `app.js` is not a safe popup entry point to run wholesale:

- Before `DOMContentLoaded`, it selects `llama-server`, replaces `flagCore` values with defaults, creates the shared inference-stat engine, and configures API, sampler-preset, preset, tunnel, external-server, Hugging Face, Quick Launch, benchmark, Monitor, process-lifecycle, and Model Switcher modules. It also subscribes to lifecycle snapshots.
- Its `DOMContentLoaded` handler initializes the theme, tabs, tool and Configure controls, installation/API/preset/Quick Launch/Chat/benchmark/Monitor flows, model-directory controls, release fetching, command preview, endpoint rendering, launch/stop actions, polling visibility handlers, and the remaining page wiring.
- `chatUi.configure()` is a top-level dependency injection call near the end of `app.js`; `initChatTab()` only calls `chatUi.init()`. Loading the full application in a popup would therefore risk a second configuration authority, lifecycle controller, release fetch, and polling cycle.

The smallest popup bootstrap must retain the ordered dependencies required by the Chat package (`ui/js/chat/`) (`flagCore`, `chatTools`, `app-data`, `chat-rendering`, `chat-compaction`, and `character-cards`) and provide the existing Chat DOM/dependency boundary. It should inject a verified host adapter for settings, runtime identity/status, authorization behavior, and the existing baseline helper. The popup must not initialize its own lifecycle controller or external-server restore. This is an audit result for the next phase; it does not add a popup module or alter the application bootstrap.

`buildChatBody(history, draft, includeUsage)` currently consumes these request inputs:

- `#chat-system-prompt` and `chatTools.getInstructions()` for the system message.
- The complete history after `chatCompaction.workingMessages(...)`, passed through `chatTools.requestMessages(...)`, plus the trimmed draft as a final user message.
- The active model from the lifecycle snapshot first, then running status, then shared `flagCore` alias/selected model, with `local-model` as the last fallback.
- `stream: true` and, when requested, `stream_options.include_usage: true`.
- Shared `flagCore` sampler values: `temperature`, `top_p`, `top_k`, `min_p`, `repeat_penalty`, and `n_predict` mapped to `max_tokens` (with numeric normalization and the `-1` server-default sentinel omitted from `max_tokens`).
- `#chat-thinking-effort` (`auto`, `off`, `low`, `medium`, `high`, or `xhigh`). Non-auto values produce the top-level `reasoning_effort` and the compatibility `chat_template_kwargs`; `off` uses `none` and disables thinking.
- `#chat-web-search-toggle` and the clamped `#chat-web-search-max-results` value (1–10, default 5) when search is enabled.
- `chatTools.getDefinitions()` when the configured browser tools list is non-empty.

Context-preview and compaction keys also include the active runtime, external target, template capabilities, and the same request body. A popup host adapter therefore needs notifications that invalidate stale previews when the main window changes runtime or shared sampler state.

## Launch-environment limits

The Phase 1 fixture evidence is limited to a normal Chromium browser using loopback HTTP and isolated synthetic contexts. The following capabilities are not established by that fixture; later native observations are recorded separately below:
Expand Down
2 changes: 1 addition & 1 deletion docs/chat-popout.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ Only pages running this implementation in the same browser storage partition par

For a native launcher or browser check, use disposable test conversations and verify popup/opener retention, shared storage, focus, close/reload recovery, and Return/Send access with both panels and Context open. Check the launcher's embedded view separately from its external-browser link. Keep CI on Linux and Windows; native checks do not require adding macOS runners.

See [capability evidence](chat-popout-capabilities.md) and [test commands](tests.md).
See [historical capability evidence](chat-popout-capabilities.md) and [test commands](tests.md).
2 changes: 1 addition & 1 deletion docs/directory.md
Original file line number Diff line number Diff line change
Expand Up @@ -1364,7 +1364,7 @@ Prefer `rg` for local search. On Windows/PowerShell, use patterns like `rg -n "p
| `docs/security.md` | Security model, trust boundaries, and reporting guidance |
| `docs/troubleshooting.md` | Common installation, launch, model, GPU, and connectivity problems |
| `docs/chat-popout.md` | Chat pop-out user guide: transfer, recovery, and browser/launcher support |
| `docs/chat-popout-capabilities.md` | Phase 1 pop-out capability fixture evidence |
| `docs/chat-popout-capabilities.md` | Historical pop-out capability and native-browser evidence |
| `docs/upstream-changes.md` | llama.cpp upstream changes needing coordinated GUI updates |
| `docs/software-versioning-policy.md` | CalVer versioning and stable-release policy |
| `docs/images/` | Screenshots used by README.md |
27 changes: 9 additions & 18 deletions docs/tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ This repo has two main test groups:

The goal is not exhaustive coverage. Tests should make common regressions easier to diagnose, especially around shared launch state, command generation, route/service behavior, and UI helper logic.

The Documentation workflow runs the link and route-registry documentation checks on
Markdown and `docs/` changes, including docs-only pull requests. The full Tests
workflow retains its documentation exclusions and Linux/Windows matrix.

## Common Commands

`python -m unittest tests.backend.test_official_backends -v` (using the project
Expand All @@ -19,19 +23,13 @@ installation. These fixtures never download or launch real GPU binaries.
npm test
```

Runs the full frontend suite in three stages: `test:unit` (JavaScript syntax checks, fast Node unit tests, structural flag-definition validation, and module loading/contract checks), `test:flags` (flag compatibility against real binaries), and `test:frontend` (the Playwright browser suite).
Runs the full frontend suite in three stages: `test:unit` (fast Node unit tests, structural flag-definition validation, and module loading/contract checks), `test:flags` (flag compatibility against real binaries), and `test:frontend` (the Playwright browser suite).

```powershell
npm run test:unit
```

Runs the aggregate fast stage only — every Node unit suite plus `test:syntax`, `test:frontend:modules`, and `test:flag-definitions` — with no browser launch and no llama.cpp binary required. Use this as the inner loop; `test:flags` and `test:frontend` remain separate explicit stages, and `npm test` is the full gate.

```powershell
npm run test:syntax
```

Checks every frontend JavaScript file with `node --check`.
Runs the aggregate fast stage only — every Node unit suite plus `test:frontend:modules` and `test:flag-definitions` — with no browser launch and no llama.cpp binary required. Use this as the inner loop; `test:flags` and `test:frontend` remain separate explicit stages, and `npm test` is the full gate.

```powershell
npm run test:frontend:modules
Expand Down Expand Up @@ -68,23 +66,17 @@ npm run test:frontend

Runs the Playwright smoke test for browser-level shared-state sync. This is also the only suite that can cover the Configure sampler preset panel, because `renderFlags()` destroys and rebuilds it — the `<select>` an assertion reads is a different element than the one that was clicked, which a `node:vm` harness cannot reproduce.

The browser suite has named `node:test` scenarios with fresh browser contexts and API fixtures. A scenario failure does not prevent the remaining scenarios from running. To run one scenario:
The browser suite has named `node:test` scenarios with fresh browser contexts and API fixtures. Shared controls, authentication, inference, Chat streaming/recovery/compaction, samplers, external servers, custom launch arguments, backend activation, model switching, preset focus, model folders, and Monitor behavior run independently. A scenario failure does not prevent the remaining scenarios from running. To run one scenario:

```powershell
node --test --test-name-pattern="benchmark actions" tests/frontend/flag_sync_smoke.cjs
```

The smoke test also covers grouped sidebar navigation, current-page semantics, active-versus-pending runtime identity, external server details, duplicate Stop protection during transitions, mobile focus and dismissal, and maintenance access in short windows.

The Phase 1 chat pop-out capability check is intentionally separate from the application smoke test:

```powershell
node --test tests/frontend/chat_popout_capabilities.cjs
```

It uses a disposable ephemeral fixture server and fresh Playwright contexts to verify loopback secure-context support, same-origin popup/tab references, exact origin/source/version messaging, nonce-scoped storage partitioning, exclusive Web Locks, focus-message acknowledgments, close detection, and fallback handling for blocked popups, unavailable openers/Web Locks, and blocked storage. It never loads the real UI, writes real chat history, or calls backend lifecycle routes. Native window activation is not asserted by this fixture. Windows/Chrome and Pinokio manual results are recorded under [Native smoke checks](#native-smoke-checks); Public HTTPS tunnel/trusted-certificate, second-device LAN and native macOS checks remain pending; local transport results are recorded under [Local HTTPS and LAN-address follow-up](tests.md#local-https-and-lan-address-follow-up). See `docs/chat-popout-capabilities.md` for the fixture's evidence limits.
The retired synthetic pop-out capability probe is preserved as [historical evidence](chat-popout-capabilities.md). Current coverage loads the production Chat-window package and the real application.

`node tests/frontend/chat_window_unit.cjs` covers the host adapter's allowed settings and runtime projections, verified peer handshakes, exclusive ownership, repeated forward/reverse transfers, storage failures, durable deletion invalidations, third-page contention, and revocation during pending abort/restore. `chat_ui_unit.cjs` covers snapshot fidelity, transfer save hooks, mutation epochs, and interrupted response recovery; `chat_tools_unit.cjs` covers date/time preference ownership. These tests use synthetic storage and VM contexts. Both Chat-window and Chat UI
`node --test tests/frontend/chat_window_unit.cjs` covers the host adapter's allowed settings and runtime projections, verified peer handshakes, exclusive ownership, repeated forward/reverse transfers, storage failures, durable deletion invalidations, third-page contention, and revocation during pending abort/restore. `chat_ui_unit.cjs` covers snapshot fidelity, transfer save hooks, mutation epochs, and interrupted response recovery; `chat_tools_unit.cjs` covers date/time preference ownership. The Chat-window cases are named tests with synthetic storage and a fresh VM per scenario; coordinator/adapter cleanup runs after failures as well as successful assertions. Both Chat-window and Chat UI
VM harnesses discover the complete Chat-window package from `index.html` through
`getPackageScripts("js/chat-window")` in `script_order.cjs`; the pop-out integration fixture serves
that same real entrypoint.
Expand Down Expand Up @@ -199,7 +191,6 @@ Fast Node tests:
- `flag_definitions_unit.cjs`: structural validation of flag/category definitions and representative invalid cases, plus reference-identity checks for the shared chat-template, reasoning-format, and main/draft KV-cache option arrays.
- `llama_flags_runner_unit.cjs`: deterministic binary-selection fixtures, required-build failures, no fallback from explicit paths, custom-backend discovery, failed/timed-out help, negated flags, and fork-only exclusions.
- `llama_flags_supported_unit.cjs`: compares GUI flags against real `llama-server` / `llama-cli` help output. Flags marked `fork_only: true` are always exempt; flags marked `removed_in: "bNNNNN"` (upstream removals retained for older builds) are exempt when the probed binary reports a build at or above that tag, parsed from `--version`. CI requires the pinned CPU binaries; optional local discovery can skip with a message.
- `js_syntax_check.cjs`: syntax-only check for frontend JavaScript.

Browser smoke test:

Expand Down
Loading
Loading