Changeset 0.10.0 (#56)

This commit is contained in:
2026-02-24 14:50:53 +00:00
parent cdfd69bad3
commit ea03f956ca
31 changed files with 3303 additions and 167 deletions

View File

@@ -346,7 +346,7 @@ func (s *Store) DecryptAPIKey(config ApiConfig, uekCache *sync.Map) (string, err
**Admin tooling**
- [ ] `switchboard vault rekey` CLI command _(deferred)_
- [ ] Admin UI: encryption status indicator _(deferred)_
- [ ] Admin UI: password reset warning _(deferred)_
- [x] Admin UI: password reset warning (v0.10.0 — vault destruction dialog)
**CI/CD**
- [x] `ENCRYPTION_KEY` Gitea secret → k8s `switchboard-encryption` secret sync
@@ -360,26 +360,47 @@ func (s *Store) DecryptAPIKey(config ApiConfig, uekCache *sync.Map) (string, err
---
Two pieces of infrastructure that everything downstream depends on.
## ✅ v0.10.0 — Model Roles + Usage Tracking + Vault Debt
Three tracks of infrastructure that everything downstream depends on.
**Vault Debt (Security Fixes)**
- [x] UEK re-wrap on user password change (prevents permanent key loss)
- [x] UEK destruction on admin password reset (vault + personal BYOK keys deleted)
- [x] Admin UI: password reset confirmation with vault destruction warning
- [x] Audit logging for vault destruction events
**Model Roles** (see [EXTENSIONS.md Appendix B](EXTENSIONS.md#appendix-b-model-roles))
- [ ] `model_roles` in global_settings: named slots (utility, embedding, generation)
- [ ] Each role: primary provider+model, optional fallback provider+model
- [ ] Team-level role overrides (team.settings JSONB)
- [ ] Backend API: `roles.Complete(ctx, "utility", messages)` with automatic fallback
- [ ] Backend API: `roles.Embed(ctx, "embedding", text)` with automatic fallback
- [ ] Admin UI: role configuration (select provider + model per role)
- [x] `model_roles` in global_settings: named slots (utility, embedding, generation)
- [x] Each role: primary provider+model, optional fallback provider+model
- [x] Team-level role overrides (team.settings JSONB)
- [x] `Provider.Embed()` interface — OpenAI/Venice/OpenRouter implement, Anthropic returns `ErrNotSupported`
- [x] `roles.Resolver` package: `Complete()` + `Embed()` with automatic fallback
- [x] Admin API: `GET/PUT /admin/roles/:role`, `POST /admin/roles/:role/test`
- [x] Team API: `GET/PUT/DELETE /teams/:id/roles/:role`
- [x] Admin UI: role configuration tab (select provider + model per role, test fire)
**Usage Tracking**
- [ ] Capture from provider responses: prompt_tokens, completion_tokens,
cache_creation_tokens, cache_read_tokens
- [ ] `usage_log` table: channel_id, user_id, model_id, provider_id,
role (nullable — "utility", "embedding", or NULL for user chat),
token counts, timestamp
- [ ] Model pricing from catalog sync (Venice/OpenAI report pricing)
- [ ] Admin override pricing (per M tokens, decimal)
- [ ] Cost calculated at query time (join usage × pricing)
- [ ] Per-user and per-team usage dashboard in admin panel
- [x] Streaming token capture fix — OpenAI: `stream_options.include_usage` + parse usage chunk;
Anthropic: parse `message_start`/`message_delta` usage events
- [x] Cache token fields across all types (`CompletionResponse`, `StreamEvent`, `streamResult`)
- [x] `usage_log` table: channel_id, user_id, model_id, provider_config_id,
role, token counts (prompt, completion, cache_creation, cache_read), cost, timestamp
- [x] `model_pricing` table: provider+model, input/output/cache per-M, source (catalog/manual)
- [x] Cost calculated at insert time (baked, not query-time)
- [x] BYOK exclusion: admin views filter `provider_scope != 'personal'`, BYOK gets separate endpoint
- [x] Model pricing from catalog sync (won't overwrite manual overrides)
- [x] Admin API: `GET /admin/usage`, `GET /admin/usage/users/:id`, `GET /admin/usage/teams/:id`
- [x] Admin API: `GET/PUT/DELETE /admin/pricing`
- [x] User API: `GET /usage` (personal usage summary)
- [x] Admin UI: usage dashboard (period selector, group-by, totals cards, breakdown table, pricing table)
- [x] Team admin UI: usage dashboard for team-owned providers (`GET /teams/:teamId/usage`)
- [x] Token accumulation across multi-tool-call iterations in `stream_loop.go`
**Schema (migration 004)**
- [x] `usage_log` with indexes on user, created_at, provider, model, scope
- [x] `model_pricing` with unique constraint on (provider_config_id, model_id)
- [x] `model_roles` seed in global_settings
---