Skip to content

Commit 7909440

Browse files
committed
feat(models): align provider save with allowlist and defaults
1 parent a8ac26b commit 7909440

File tree

6 files changed

+959
-135
lines changed

6 files changed

+959
-135
lines changed

.trellis/spec/backend/agents-persona-contract.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
```
1919
- `POST /api/agents/update`
2020
```json
21-
{ "agentId": "<string>", "name": "<optional>", "workspace": "<optional>", "avatar": "<optional>" }
21+
{ "agentId": "<string>", "name": "<optional>", "workspace": "<optional>", "model": "<optional>", "avatar": "<optional>" }
2222
```
2323
- `POST /api/agents/delete`
2424
```json
@@ -70,11 +70,12 @@
7070

7171
#### Create / update / delete rules
7272
- Create requires non-empty `name` and `workspace`.
73-
- Update requires non-empty `agentId` and at least one of `name | workspace | avatar`.
74-
- Provided `name` / `workspace` values must be strings and remain non-empty after trimming.
73+
- Update requires non-empty `agentId` and at least one of `name | workspace | model | avatar`.
74+
- Provided `name` / `workspace` / `model` values must be strings and remain non-empty after trimming.
7575
- Default agent cannot have its workspace changed. Backend returns `409` with a protection error.
7676
- Default agent cannot be deleted. Backend returns `409` with a protection error.
7777
- `deleteFiles` is optional input. Only `true` is forwarded downstream as “also remove files”; `false` / absence omits the field.
78+
- `model` is passed through to gateway `agents.update` as a plain `provider/model` string; the current Persona UI does not surface it yet, but the browser route contract supports it.
7879

7980
#### Persona file whitelist and missing-file behavior
8081
- `/api/agents/files` may also return a `workspace` field alongside `files[]`.
@@ -109,7 +110,7 @@
109110
| Create missing `name` or `workspace` | 400 | `{ "ok": false, "error": "name and workspace are required" }` |
110111
| Update missing `agentId` | 400 | `{ "ok": false, "error": "agentId is required" }` |
111112
| Update provides no mutable field | 400 | `{ "ok": false, "error": "at least one field to update is required" }` |
112-
| `emoji`, `avatar`, `name`, `workspace` provided with wrong type | 400 | `{ "ok": false, "error": "... must be a string ..." }` |
113+
| `emoji`, `avatar`, `name`, `workspace`, `model` provided with wrong type | 400 | `{ "ok": false, "error": "... must be a string ..." }` |
113114
| Update tries to change default-agent workspace | 409 | protection error |
114115
| Delete targets default agent | 409 | protection error |
115116
| File name not in whitelist | 400 | `{ "ok": false, "error": "unsupported agent file name" }` |
@@ -136,6 +137,9 @@
136137
- Protection rules
137138
- updating default-agent workspace returns 409
138139
- deleting default agent returns 409
140+
- Update contract
141+
- `model`-only updates are accepted and forwarded to gateway `agents.update`
142+
- omitted `model` preserves legacy `name/workspace/avatar` update behavior
139143
- File contract
140144
- whitelist allows only documented file names
141145
- missing file/list errors become HTTP 200 success payloads with `missing:true` / `files:[]`

.trellis/spec/backend/http-api-contracts.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
```json
2727
{
2828
"models": { "providers": { "<providerKey>": { "...": "..." } } },
29+
"agentsDefaultsModels": { "<provider/model>": { "...": "..." } },
30+
"agentsDefaultModel": { "primary": "<provider/model>", "fallbacks": ["<provider/model>"] },
2931
"baseHash": "<config hash>"
3032
}
3133
```
@@ -113,14 +115,22 @@
113115
{
114116
"modelList": "<gateway payload>",
115117
"configHash": "<hash>",
116-
"modelsConfig": { "providers": { "...": {} } }
118+
"modelsConfig": { "providers": { "...": {} } },
119+
"agentsDefaultsModels": { "<provider/model>": { "...": "..." } },
120+
"agentsDefaultModel": { "primary": "<provider/model>", "fallbacks": ["<provider/model>"] }
117121
}
118122
```
119-
- `/api/models/save` forwards to `config.patch({ raw, baseHash, note })` with note `"MVP dashboard updated model/provider config"`.
123+
- `/api/models/save` forwards one combined `config.patch({ raw, baseHash, note })` with note `"MVP dashboard updated model/provider config"`.
124+
- Browser currently uses that combined patch to update three config slices together:
125+
- `models.providers`
126+
- `agents.defaults.models`
127+
- `agents.defaults.model`
120128
- Browser editor depends on provider config round-tripping extra fields. Managed keys are `baseUrl|baseURL|url|apiKey|api|apiType|type|models`; everything else must survive save.
121129
- Browser provider save normalizes legacy adapter fields `apiType` / `type` into gateway-schema `api` before calling `/api/models/save`.
122130
- Browser provider delete / rename emits `models.providers.<key> = null` tombstones so `config.patch` actually removes old provider keys instead of merging them back.
123131
- Browser provider model rows always serialize as object entries; when `name` is omitted in the form, save falls back to `name = id` to satisfy gateway schema.
132+
- Browser model allowlist save emits `agents.defaults.models.<provider/model> = null` tombstones for refs that were unchecked or removed, so stale allowlist entries do not merge back.
133+
- Browser “设为默认” UI writes `agents.defaults.model.primary`; when the selected default is cleared by draft changes, save may send `agentsDefaultModel = null` to remove the config key.
124134
- `__OPENCLAW_REDACTED__` is a browser-only placeholder; save callers must remove it before sending.
125135

126136
#### Skills contract
@@ -185,11 +195,15 @@
185195
- 404 route => `{ ok:false, error }`
186196
- Models
187197
- `/api/models` returns `configHash` and `modelsConfig`
198+
- `/api/models` also returns `agentsDefaultsModels` and `agentsDefaultModel`
188199
- `/api/models/save` forwards `baseHash`
200+
- `/api/models/save` can patch `models.providers`, `agents.defaults.models`, and `agents.defaults.model` in one request
189201
- provider extra fields survive round-trip save
190202
- legacy provider `apiType` / `type` backfills and saves as `api`
191203
- deleting or renaming a provider removes the old provider key after reload
192204
- newly added provider models save as `{ id, name, ... }` objects instead of invalid string entries
205+
- unchecking a previously-allowlisted model removes the old `agents.defaults.models.<ref>` key after reload
206+
- selecting a default model persists `agents.defaults.model.primary`
193207
- Skills
194208
- `/api/skills/install` default `timeoutMs=120000`
195209
- `/api/skills/update` accepts enable-only and env/apiKey payloads

0 commit comments

Comments
 (0)