swarm-ui: set the review classifier's keys from the classifier settings
The classifier's Anthropic and ACP provider keys were written by hand in the
secret store's UI. The controller now stores them: GET
/api/review-classifier/keys says whether each is set and when it changed, and
PUT /api/review-classifier/keys/{runtime} writes one. No route answers a key.
The controller's store policy gains create and update on the two leaves with
no read of their values, and a metadata read for the set state. The swarm UI's
classifier settings card gets a key form beside the settings, saved apart
because it goes to the secret store.
This commit is contained in:
parent
c5d601e3a2
commit
6875a4f0f8
3 changed files with 628 additions and 20 deletions
|
|
@ -233,7 +233,8 @@ leaves under `secret/data/swarm/services/attic/` (`push-token`, `pull-token`,
|
|||
`url`, `cache` and `public-key`). That shows the key tree and each key's
|
||||
versions and timestamps, and no value: the store refuses every `secret/data/`
|
||||
read. The writes are the leaves the operator fills in by hand: the review
|
||||
classifier's keys, and the cache's tokens and facts, which configure an external
|
||||
classifier's keys (which `swarm-controller` also writes for the swarm UI, with
|
||||
`create` and `update` and no `read` of the value), and the cache's tokens and facts, which configure an external
|
||||
cache or replace the in-swarm cache's own. The cache's host units create those
|
||||
leaves only while the store holds none, so a saved value survives their next run
|
||||
and every deploy. The cache's signing key, `attic/jwt-secret`, isn't writable here.
|
||||
|
|
|
|||
|
|
@ -284,8 +284,33 @@ does. Every error is problem+json with the reason in `detail`:
|
|||
- **500** when the controller can't read or write the settings
|
||||
|
||||
When the controller can't read the settings, a try-out answers the same 503
|
||||
or 500, and a review posts a no-verdict comment. The operator writes each
|
||||
runtime's key by hand in the secret store
|
||||
or 500, and a review posts a no-verdict comment. The keys aren't in this
|
||||
document; see [The keys](#the-keys).
|
||||
|
||||
### The keys
|
||||
|
||||
`GET /api/review-classifier/keys` answers whether each runtime has a key:
|
||||
|
||||
```json
|
||||
{
|
||||
"api_key": { "set": true, "updated": "2026-11-11T10:00:00Z" },
|
||||
"acp": { "set": false, "updated": null }
|
||||
}
|
||||
```
|
||||
|
||||
`PUT /api/review-classifier/keys/{runtime}` (`api-key` or `acp`) takes
|
||||
`{"api_key": "…"}`, stores it at that runtime's leaf and answers the same
|
||||
document. No route answers a key. The controller's store policy holds `create`
|
||||
and `update` on the two leaves with no `read` of their values, and `read` on
|
||||
their metadata, which is where `set` and `updated` come from. The route trims a
|
||||
key and refuses one that's empty, over 4096 bytes or holds whitespace. The
|
||||
PUT needs the `Remote-User` header, and logs the operator and the runtime, never
|
||||
the key. Every error is problem+json: **400** for a body that isn't this shape,
|
||||
a runtime that isn't one of the two or a refused key, **401** for no
|
||||
`Remote-User`, **503** when the store is unreachable or refuses.
|
||||
|
||||
The classifier reads the leaf on every run, so a new key applies from the next
|
||||
run. The operator can still write the leaves in the secret store's UI
|
||||
([`services.md`](../../2-handbook/swarm/services.md#review-classifier)).
|
||||
|
||||
The per-agent equivalent is [`inference.md`](inference.md), where the
|
||||
|
|
@ -479,7 +504,8 @@ ACP provider, so each runtime has a model field of its own.
|
|||
|
||||
To switch to ACP, an admin:
|
||||
|
||||
1. writes the provider key in the secret store's UI under the OIDC login, at
|
||||
1. stores the provider key, in the swarm UI's classifier settings or in the
|
||||
secret store's UI under the OIDC login, at
|
||||
`secret/swarm/services/review-classifier/acp-provider`, field `api_key`
|
||||
2. PUTs the runtime and the provider:
|
||||
|
||||
|
|
|
|||
|
|
@ -327,8 +327,15 @@ limit gets a no-verdict review, and a try-out with more gets a 400.
|
|||
the runtime, model, effort and limits, and the provider too while the runtime is
|
||||
ACP, so switching back to API key keeps the stored provider for next time. If
|
||||
the controller refuses it, the page shows the reason and leaves the form as you
|
||||
typed it. A change takes effect from the next run, with no restart. The page
|
||||
has no API key field: admins set each runtime's key in the bao UI.
|
||||
typed it. A change takes effect from the next run, with no restart.
|
||||
|
||||
Under the settings form sits a **key** form for the runtime the form chooses.
|
||||
Its label says whether that runtime has a key and when it last changed
|
||||
(`GET /api/review-classifier/keys`, which never answers a key). The field is a
|
||||
password input; **save key** sends it alone with `PUT
|
||||
/api/review-classifier/keys/{runtime}`, apart from the settings, and clears the
|
||||
field once the controller has stored it. Switching the runtime drops a key you
|
||||
typed for the other one.
|
||||
|
||||
### Scheduled prompts
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue