The local model window could hold one model. A second install was refused
(409 already-installed), and a model a Remove kept could never be freed
from the window again. The store can now hold several models, and exactly
one of them is the model in use: the one the endpoint record lists, the
runtime is started for and a session may be launched on.
Server
- LocalModelStateFile.library lists every model that passed the check
(id, label, context, digest, size, coding agent). The service writes
the entry when verify passes; the reducer carries it and remove drops
it. An installed file of an earlier build counts its one model.
- POST /api/local-model/install is allowed from installed: it adds a
model, and the earlier one stays. A replaced job no longer deletes a
model of the library, only an unchecked or partial download.
- POST /api/local-model/use switches to a checked model: a job of the
two steps verify and connect. The stored digest is compared before
anything is loaded (model-changed otherwise). Nothing is downloaded.
- DELETE /api/local-model/models deletes one model by its name, through
the runtime's own delete, never by a path, never the model in use.
- Adding and switching answer 409 sessions-open while a live session
uses the endpoint. Until such a job ends installed, a session start is
refused with the new code job-unfinished.
- The view carries library (the state's entries joined with what the
running runtime lists: ready, changed, missing, unverified) and store
(the size of the blob folder). Both are cached and refreshed in the
background, never read on the one-second poll.
- With nothing installed, remove is offered while the store still holds
models an earlier Remove kept.
Window
- The installed screen lists the models on this Mac with the context
each was checked with, its state and its size on disk, with Use and
Delete per row (Delete asks once, in the row) and Add a model.
- In the chooser a model that is on this Mac already says so and is
switched to without a download or a confirm screen.
- A paused or failed job that has a checked model beside it shows the
way back to that model.
Every route is admin only in multi-user mode, like the existing ones.
Not run on a Mac: the tests use fakes and the fake runtime, and the
listing, store size and delete were checked against a real Ollama 0.13.0
on Linux, not the pinned 0.40.15 build for macOS.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
The connect step records the connection in the state file BEFORE it writes
the endpoint record and the settings flag (the flag's earlier value read by
inspectLocalEndpoint()), so a state write that fails or a server killed
between the two never leaves a record of ours that the state file does not
know; a record under the reserved id that says exactly what ours would say
is ours. changePort() writes the state first and puts the old port back when
the endpoint move is refused.
A job whose end could not be written (a full disk) is kept in memory: the
view shows it, Resume and a new install start from it, the next verb writes
it, and Cancel never answers a 500. A first install on a full disk is a 507
with the sentence. "installing" in the file while this process runs no job
always reads as paused or that failure.
An installed model whose runtime does not start says so (runtime-start-failed
with Start as the next step, and the launch check says it too); the stored
runtime version is started while its folder is unpacked. Stop, Remove and
the boot of anything that is not a running installation end a runtime an
earlier server left behind before any file is deleted. Stop and "Use another
port" answer 409 sessions-open while a live session uses the model. A pull
that failed because the runtime is gone is runtime-stopped, not a network
problem. After "does not fit" only a model that needs less memory is offered.
A replaced job's partial blobs are deleted. Every 400 carries its sentence as
data.message, and the six inline sentences are labels with zh-CN entries.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The real routes, service, recommendation, runtime download and unpack,
supervisor, pull, checks, connection and state file, joined together. Only
the runtime (a fake HTTP server the injected spawn "starts"), the hardware,
the coding agent's installer and the waits between retries are stand-ins.
Walks: the whole install and its removal (the folder is gone, the settings
flag is restored); a runtime download that arrives damaged; a model download
that fails twice and then succeeds; one that keeps failing; a model that
calls no tool; Cancel during the model download; a server restart during the
model download, which comes back paused and waits for a click.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>