Download a model onto the machine that will serve it

The Models tab was about this backend's own disk, which is the wrong disk
for every session that runs anywhere else: llama.cpp reads the file where
it runs. So the models of a machine live under that machine's llama.cpp
provider now, beside the settings deciding how each is loaded, and the
download that produces one happens there.

A download is a detached `curl` on that machine, started by a script this
server writes and never spoken to again. Its state is a file beside the
partial, so nothing about it is held here: it survives the app closing,
this backend restarting and a second device watching, and the progress is
`wc -c` of the partial against the size HuggingFace published rather than
anything remembered. A run whose process is gone is reported failed, since
`kill -0` is asked at each listing, and there is no "finished" state -- a
download that finished is a model, in the list beside the ones still
going. Resuming is guarded by the published sha256, which is also checked
before the file takes its real name.

Two other things the same screens wanted:

A provider is drawn as a card rather than as a line of text, bordered
against the machine card it sits in -- the tint it had was one step along
the surface ladder and rendered as one flat block -- with room to tap and
no chevron.

Nothing in a raw block wraps any more; the block scrolls sideways
instead, one offset for all its lines, so a diff or a column-aligned test
run still reads as one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
iris-aiandClaude Opus 5 committed 2026-09-19 18:55:51 -04:00
1 parent 8c323fc7a9
commit 81c30dcda1
14 files changed
+1224 -1073

No files matched your search

+18 -4
View File
@@ -61,7 +61,8 @@ Module-by-module intent is in PLAN.md's "Backend layout".
because `llama-server` never reads the stdin whose closing ends a CLI and
the same kill left it loaded on the far machine; the model is looked for on
the machine that will serve it, so the spawn screen offers
`GET /machines/{id}/models` rather than the backend's own downloads; and the
`GET /machines/{id}/providers/{p}/models` rather than any list of this
backend's own; and the
readiness poll watches the process as well as the port, since a model that
will not load exits in a second and was being reported as "gave up after
300s". See PLAN.md's "Transport" and "llama-server management".
@@ -119,14 +120,27 @@ Module-by-module intent is in PLAN.md's "Backend layout".
for a provider's **models**, drawn in the machines tab's provider view —
the settings that decide how a model is loaded, which belong to the machine
because one loaded copy answers every session using it.
**A model is downloaded onto the machine that will serve it** (2026-09-19,
replacing the fetch this backend used to do onto its own disk, and the
Models tab that went with it). `models.rs` writes a script and a detached
`curl` runs it *there*; the state of a run is a file beside the partial
(`x.gguf.download`), so nothing about it is held in this process — it
survives the phone closing, this backend restarting and a second device
watching, and `kill -0` at each listing is what stops a machine that was
rebooted from leaving a download claiming to be running. The progress is
`wc -c` of the partial against the size HuggingFace published, the sha256
it publishes is what makes a resume safe, and a finished download is not a
state: it is a model, in the list beside the one still going.
Codex is one persistent `codex app-server --stdio` process per session; its
driver uses native turn steering and interruption, persists the protocol
state and thread id, and reads subscription limits through the same CLI
protocol.
- `app/` — the Compose app, package `com.example.aiapp`, label "AI Sessions".
`AppRoot.kt` is the navigation `when`; `MainScreen.kt` the root's four tabs
(sessions, import, models, machines); `Api.kt`/`EventStream.kt` the REST + SSE
clients; `Events.kt` the event model mirror; `ServerConfig.kt` settings and
`AppRoot.kt` is the navigation `when`; `MainScreen.kt` the root's three tabs
(sessions, import, machines); `MachineModels.kt` the models on one machine
and the downloads putting them there, drawn inside `ProviderScreen.kt` for a
provider that serves files off that machine's disk; `Api.kt`/`EventStream.kt`
the REST + SSE clients; `Events.kt` the event model mirror; `ServerConfig.kt` settings and
the Keystore-sealed token.
- `wg-app-link/` — a **git submodule** shared with dev-updater: the pinned CA
and leaf (`certs`), QR enrollment and the bearer token (`enroll`), wg0