Changeset 0.22.0.1 (#94)

This commit is contained in:
2026-03-02 01:55:19 +00:00
parent 12e03cec8b
commit 06c4e2a5a1
33 changed files with 1929 additions and 418 deletions

View File

@@ -88,11 +88,20 @@ v0.21.1 Workspace ✅ v0.21.3 Surface Infra ✅
v0.21.2 Workspace ✅ v0.21.5 Editor Surface ✅
Indexing + Search (Development Mode)
│ │
v0.21.4 Git ✅ v0.21.6 Article Surface ✅
v0.21.4 Git ✅ v0.21.6 Editor Surface ✅
Integration + Document Output
└───────┬──────────────┘
v0.22.0 Smart Routing + Provider Extensions
v0.21.7 Bugfix: scanJSON driver buffer aliasing ✅
v0.22.0 Provider Health + Capability Overrides ✅
+ Workspace Pane Refactor (FE)
v0.22.1 Provider Extensions (declarative config)
v0.22.2 Routing Policies + Fallback Chains
v0.22.3 Provider Admin UI + Deferred Polish
v0.23.0 Multi-Participant Channels + Presence
@@ -832,14 +841,141 @@ Writing-focused surface. Document is artifact, conversation is secondary.
---
## v0.22.0 — Smart Routing + Provider Extensions
### v0.21.7 — Bugfix: scanJSON Driver Buffer Aliasing ✅
### Deferred from v0.21.x
Critical fix for intermittent 500 errors on paginated list endpoints.
Items moved from earlier sub-releases for proper scoping:
- [x] `scanJSON` []byte path: copy driver buffer instead of aliasing (`json.RawMessage(v)``make+copy`)
- [x] `CreateChannel` Postgres RETURNING path: use `scanJSON(&ch.Settings)` instead of bare `&ch.Settings`
- [x] `UpdateChannel` settings write: validate `json.Valid()` before JSONB merge, reject with 400
- [x] New tests: `TestScanJSON_ByteSliceNotAliased`, `TestScanJSON_ByteSliceIsolation_MultiRow`
**Root cause:** `json.RawMessage(v)` is a type conversion, not a copy — it aliases
the `[]byte` buffer owned by `database/sql`. Per the `Scanner` interface docs, `[]byte`
values are only valid until the next `rows.Scan()` call. In paginated list endpoints,
row N's Settings slice header pointed into memory that row N+1's scan overwrote,
producing corrupt JSON that passed `json.Valid()` at scan time but failed at marshal
time when `SafeJSON` serialized the full response.
---
## v0.22.0 — Provider Health + Capability Overrides ✅
Smallest shippable unit that unblocks routing. Track provider error rates
and latency, add admin override layer for model capabilities.
Depends on: usage tracking (v0.10.0), capabilities resolver (v0.9.1).
**Provider Health Tracking**
- [x] `provider_health` table: `provider_config_id` FK, `window_start` (hourly buckets), `request_count`, `error_count`, `timeout_count`, `total_latency_ms`, `max_latency_ms`, `last_error`, `last_error_at`
- [x] In-memory health accumulator: goroutine-safe counters per provider, flushed to DB on interval (60s)
- [x] `RecordSuccess`/`RecordError`/`RecordTimeout` called from completion handler after every provider call (sync + streaming)
- [x] Provider status derivation: `healthy` / `degraded` / `down` based on error rate thresholds (5% = degraded, 25% = down)
- [x] `GET /api/v1/admin/providers/:id/health` endpoint: current status + hourly windows (configurable hours param)
- [x] `GET /api/v1/admin/providers/health` endpoint: summary status for all providers
- [ ] _(deferred → v0.22.3)_ Health status included in `GET /api/v1/models/enabled` response (new `provider_status` field)
- [ ] _(deferred → v0.22.2)_ Auto-disable: optional policy to mark provider inactive when `down` for N consecutive windows
- [x] Background cleanup: prune health rows older than 7 days (6-hour cycle)
**Capability Admin Overrides**
- [x] `capability_overrides` table: `provider_config_id` (nullable for global), `model_id`, `field`, `value`, `set_by`, `created_at`
- [x] Three-tier resolution in `ResolveIntrinsic()`: catalog → heuristic → **admin override** (highest priority)
- [x] `PUT /api/v1/admin/models/:id/capabilities` endpoint: set individual capability overrides
- [x] `DELETE /api/v1/admin/models/:id/capabilities/:overrideId` endpoint: remove override
- [x] `GET /api/v1/admin/models/:id/capabilities` endpoint: show resolved caps with source annotation (catalog/heuristic/override)
- [x] `GET /api/v1/admin/capability-overrides` endpoint: list all overrides
- [x] Postgres + SQLite migrations (013_v0220_health.sql / sqlite 012_v0220_health.sql)
**Search Provider Health** _(deferred → v0.22.1)_
- [ ] `RecordOutcome` for web_search and url_fetch tool calls (search provider tracking)
- [ ] Rate limit tracking per provider config (requests/minute counter in health accumulator)
**Workspace Pane Refactor** (frontend)
- [x] `.workspace` flex container replaces `.chat-area` + `.side-panel` layout
- [x] `.workspace-primary` / `.workspace-secondary` independent pane model
- [x] `.workspace-handle` drag-resize between panes (replaces old side-panel-resize)
- [x] Surface layout declarations: `primary`, `secondary`, `secondaryOpts` per surface
- [x] Dual-view mode removed (was `_dualMode`, `_splitRatio`, `_secondary` in PanelRegistry)
- [x] Zoom selector updated for new class names
**Bugfix (v0.21.7)**
- [x] `scanJSON` driver buffer aliasing — copy `[]byte` from database driver instead of aliasing slice header
- [x] `CreateChannel` RETURNING path uses `scanJSON(&ch.Settings)` instead of bare scan
- [x] `UpdateChannel` validates `json.Valid()` on settings before JSONB merge
---
## v0.22.1 — Provider Extensions (Declarative Config)
Replace hardcoded provider-specific behavior with data-driven configuration.
Same model, different provider → different parameters.
Depends on: provider health (v0.22.0).
**Provider Profiles**
- [ ] `provider_profiles` JSONB column on `provider_configs` table (or separate table if schema cleaner)
- [ ] Profile schema per provider type: defines available settings, types, defaults, validation
- [ ] Built-in profile schemas for: openai, anthropic, venice, openrouter (others inherit openai-compatible)
- [ ] System prompt injection: provider-specific preambles (e.g. Venice character system prompt)
- [ ] Thinking mode toggle: per-provider `think` parameter mapping (Venice `venice_parameters.include_venice_system_prompt`, Anthropic `thinking.type=enabled`, etc.)
**Request/Response Transforms**
- [ ] `PreRequestHook(providerType string, profile JSONB, req *CompletionRequest)` — decorate request before dispatch
- [ ] `PostResponseHook(providerType string, profile JSONB, resp *StreamEvent)` — normalize provider-specific response fields
- [ ] Hook implementations: Venice thinking extraction, Anthropic extended thinking, OpenRouter model routing headers
- [ ] Preset-level overrides: Persona can override provider-specific settings ("always enable thinking for this Persona")
- [ ] `ProviderConfig.Settings` fully utilized: hooks read from config, not hardcoded switch statements
**Provider Type Registry** (prep for v0.22.2)
- [ ] `providers.Init()` reads provider type → adapter mapping from registry instead of hardcoded list
- [ ] New provider types registrable via config (openai-compatible endpoint + custom profile schema)
- [ ] `GET /api/v1/admin/provider-types` endpoint: list available provider types with their profile schemas
---
## v0.22.2 — Routing Policies + Fallback Chains
Rules-based routing engine — policy, not ML. Evaluated in `resolveConfig()`
between "what model was requested" and "which provider serves it."
Depends on: provider health (v0.22.0), provider extensions (v0.22.1).
**Routing Policies**
- [ ] `routing_policies` table: `id`, `name`, `scope` (global/team), `team_id`, `priority` (lower wins), `policy_type`, `config` (JSONB), `is_active`
- [ ] Policy types: `capability_match` ("cheapest model with tool_calling"), `provider_prefer` ("prefer provider X, fallback Y"), `team_route` ("team X uses provider Y"), `cost_limit` ("max $X/request")
- [ ] Policy evaluator: takes requested model + user context → returns ranked list of `(providerConfigID, modelID)` candidates
- [ ] Integration point: `resolveConfig()` calls evaluator after preset unwrap, before provider dispatch
**Fallback Chains**
- [ ] Fallback chain configuration: ordered list of providers for a given model or model family
- [ ] Health-aware: skip providers with status `down`, prefer `healthy` over `degraded`
- [ ] Automatic retry on provider error: next provider in chain, transparent to client (configurable max retries)
- [ ] Latency-aware preference: track response time percentiles, prefer faster providers (weight configurable)
- [ ] Cost-aware preference: factor pricing into routing decisions (cheapest-first, budget ceiling per request)
**Routing Metadata**
- [ ] `X-Switchboard-Provider` response header: which provider actually served the request (debug mode)
- [ ] `routing_decision` field in usage_log: selected provider, policy that matched, fallback depth
- [ ] `GET /api/v1/admin/routing/test` endpoint: dry-run policy evaluation for a given model + user
---
## v0.22.3 — Provider Admin UI + Deferred Polish
Admin interfaces for v0.22.0v0.22.2 features, plus deferred items from v0.21.x.
Depends on: routing policies (v0.22.2).
**Admin UI**
- [ ] Provider health dashboard: status badges, error rate sparklines, latency charts (last 24h)
- [ ] Capability override editor: per-model toggle grid with source indicators
- [ ] Provider profile editor: key-value config per provider type, preview of effective settings
- [ ] Routing policy builder: CRUD with priority ordering, dry-run test panel
- [ ] Fallback chain visualizer: drag-to-reorder provider priority per model family
**Deferred from v0.21.x**
- [ ] Mobile: mode selector collapses to hamburger/bottom nav
- [ ] Integration with extension loader (surfaces from manifest.json — requires extension loader update)
- [ ] Integration with extension loader (surfaces from manifest.json)
- [ ] Workspace settings UI: git config section in channel/project settings
- [ ] User Settings: git credentials management UI
- [ ] `.gitignore` respect in workspace indexing
@@ -849,31 +985,6 @@ Items moved from earlier sub-releases for proper scoping:
- [ ] PDF/DOCX export via pandoc in article mode
- [ ] Project-specific file uploads (full project-level upload architecture)
Depends on: model roles (v0.10.0), usage tracking (v0.10.0).
Rules-based routing engine — policy, not ML. Plus declarative provider
configuration to replace hardcoded provider-specific behavior.
_(Shifted from v0.19.0 — routing content unchanged, provider extensions added)_
**Routing**
- [ ] Admin routing policies: "cheapest model with required capabilities",
"prefer private providers, fallback to cloud", "for team X, use Y"
- [ ] Fallback chains: primary provider down → next with same model
- [ ] Cost-aware: factor pricing into routing decisions
- [ ] Latency-aware: track response times per provider, prefer faster
**Provider Extensions (declarative provider config)**
- [ ] `provider_profiles` table (or JSONB on `api_configs`): per-provider configuration schema
- [ ] System prompt injection: provider-specific preambles (e.g. Venice character system prompt)
- [ ] Thinking mode toggle: per-provider `think` parameter support (Venice `venice_parameters.include_venice_system_prompt`, Anthropic `thinking`, etc.)
- [ ] Request transform hooks: provider-specific parameter mapping before API call
- [ ] Response transform hooks: normalize provider-specific response fields
- [ ] Admin UI: provider profile editor (key-value config per provider type)
- [ ] Preset-level overrides: Persona can override provider-specific settings (e.g. "always enable thinking for this Persona")
- [ ] Provider health: track error rates, latency percentiles, auto-disable unhealthy providers
- [ ] Search/URL fetch rate limiting per provider
- [ ] Capability admin/user override: manual correction for model capabilities (`intrinsic.go` admin override layer)
---
## v0.23.0 — Multi-Participant Channels + Presence