docs(release): prepare 0.27.0 — curated changelog, rag/map sweep, concat rebuild script (#662)

This commit is contained in:
Renzo F
2026-07-23 11:33:02 +02:00
committed by GitHub
parent d8841279a8
commit dd4c3c3ed0
26 changed files with 501 additions and 81 deletions
+13 -4
View File
@@ -62,12 +62,19 @@ Cross-cutting support layer beneath the delivery services: the service-base/erro
| `get_decrypted_token` | method | `services/provider.py:211` | Decrypt provider token or None; raises `EncryptionError` on bad key |
| `ModelRoutingService` | class | `services/llm.py:119` | Per-agent route resolution + assignment CRUD + mode apply |
| `AgentRoute` | dataclass | `services/llm.py:95` | Frozen resolved route `(provider_id, type, base_url, auth_token, model_name)`; None base_url/token = Anthropic default |
| `resolve_for_agent` | method | `services/llm.py:124` | Precedence ladder agent>role>global; never raises — downgrades to legacy Anthropic path |
| `resolve_for_agent` | method | `services/llm.py:194` | Precedence ladder AGENT_SLUG > ROLE(:complexity) > ROLE > GLOBAL; optional `complexity` (a task's `estimated_complexity`, lowercased) enables the compound `ROLE:complexity` rung; never raises — downgrades to legacy Anthropic path |
| `_resolve_assignment` | method | `services/llm.py:248` | Tries AGENT_SLUG first, then (when `role` AND `complexity` both given) the compound `scope_value=f"{role}:{complexity}"` ROLE row, then the plain `role` ROLE row, then GLOBAL — the compound rung reuses the existing ROLE scope + `scope_value` column, no schema change |
| `probe_ollama_tags` | func | `services/llm.py:63` | `{base_url}/api/tags` probe; never raises, returns `([], error)` |
| `upsert_assignment` | method | `services/llm.py:241` | Insert-or-update by `(scope, scope_value)`; routes non-catalog names to LOCAL; auto-enables LOCAL provider |
| `apply_mode` | method | `services/llm.py:418` | Wipe role/global rows (AGENT_SLUG pins preserved) + set GLOBAL for anthropic/grok/ollama/self_hosted; per-agent map for mix |
| `derive_mode` | method | `services/llm.py:314` | Settings UI label from current assignments |
| `apply_mode` | method | `services/llm.py:567` | Wipe role/global rows (AGENT_SLUG pins preserved) + set GLOBAL for anthropic/grok/ollama/self_hosted/codex/gemini; per-agent map for mix. `apply_mode('cost_tiered')` is the one exception — it ADDITIVELY seeds a single day-1 `developer:low` → haiku override instead of wipe-then-seed, so it composes with whatever mode is already active. |
| `derive_mode` | method | `services/llm.py:443` | Settings UI label from current assignments |
| `set_ollama_api_key` / `set_grok_api_key` | methods | `services/llm.py:340,360` | Encrypt+enable / clear+disable on the seeded provider row |
| `_interactive_exempt` | func | `services/llm.py:176` | True when `agent_slug` is `intake-1`/`secretary-1` AND the resolved assignment routes to OPENAI/GEMINI — neither provider supports the interactive chat driver, so these two agents stay on Anthropic regardless of a fleet-wide mode switch; an explicit AGENT_SLUG pin onto either provider for these two slugs is refused loudly at the spawn/save boundary rather than silently producing a broken interactive session |
| `list_routing_presets` / `get_routing_preset` | methods | `services/llm.py:837,845` | List / fetch one saved `RoutingPresetTable` row |
| `save_routing_preset` | method | `services/llm.py:848` | Snapshot the FULL current routing state (mode + every assignment row, AGENT_SLUG pins included) into a named `RoutingPresetTable.payload` (JSONB) |
| `apply_routing_preset` | method | `services/llm.py:931` | Restore a saved preset wholesale — a full swap, validating every entry via `_validate_preset_entry` FIRST so an invalid payload never triggers the wipe (unlike a mode switch's pin-preserving behavior) |
| `_validate_preset_entry` | method | `services/llm.py:896` | Per-entry validation for `apply_routing_preset` (scope/provider/model shape) run before any row is touched |
| `delete_routing_preset` | method | `services/llm.py:886` | Delete a saved preset by id |
| `ProactiveKnowledgeService` | class | `services/proactive.py:90` | Builds `ContextPackage` from multiple RAG indexes on claim/session |
| `ContextPackage` | dataclass | `services/proactive.py:27` | Aggregates similar_tasks/learnings/code_patterns/standards/decisions/known_issues + summary |
| `on_task_claimed` / `on_session_started` | methods | `services/proactive.py:116,201` | Best-effort multi-index search; each source wrapped in try/except |
@@ -98,7 +105,9 @@ Cross-cutting support layer beneath the delivery services: the service-base/erro
## Data Flow
**Spawn routing.** The orchestrator (`runtime/orchestrator.py:3294`) opens a DB session, calls `get_model_routing_service(db).resolve_for_agent(agent_slug)`. `ModelRoutingService` walks `model_assignments` (AGENT_SLUG → ROLE → GLOBAL), joins the `provider_configs` row, decrypts any token via `ProviderService.get_decrypted_token` (Fernet from `utils/crypto`), probes LOCAL providers via `probe_ollama_tags`, and returns an `AgentRoute`. On any failure (decrypt, unreachable server, missing row) it falls back to `_legacy_route` (role → `MODEL_MAP` short name, Anthropic, mounted `~/.claude`). The orchestrator injects `ANTHROPIC_*`/base_url/auth env into the container only when the route is non-Anthropic.
**Spawn routing.** The orchestrator (`runtime/orchestrator.py:3294`) opens a DB session, calls `get_model_routing_service(db).resolve_for_agent(agent_slug, complexity=...)``complexity` threads through from the spawning task's `estimated_complexity` when one is bound, letting the compound `ROLE:complexity` rung (e.g. `developer:low`) pin a cheaper model at a given complexity without touching the plain ROLE row everything else still uses. `ModelRoutingService` walks `model_assignments` (AGENT_SLUG → ROLE:complexity → ROLE → GLOBAL via `_resolve_assignment`), joins the `provider_configs` row, decrypts any token via `ProviderService.get_decrypted_token` (Fernet from `utils/crypto`), probes LOCAL providers via `probe_ollama_tags`, and returns an `AgentRoute`. `_interactive_exempt` overrides the resolved route back to Anthropic for `intake-1`/`secretary-1` whenever it would otherwise land on OPENAI/GEMINI (neither provider supports the interactive chat driver). On any failure (decrypt, unreachable server, missing row) it falls back to `_legacy_route` (role → `MODEL_MAP` short name, Anthropic, mounted `~/.claude`). The orchestrator injects `ANTHROPIC_*`/base_url/auth env into the container only when the route is non-Anthropic.
**Routing presets.** On top of modes, an operator can `save_routing_preset(name)` to snapshot the FULL current routing state (mode + every assignment row, AGENT_SLUG pins included) into a `RoutingPresetTable` row, then `apply_routing_preset(preset_id)` later to restore it wholesale — a full swap that validates every entry via `_validate_preset_entry` BEFORE the wipe, unlike a mode switch's pin-preserving, validate-as-you-go behavior. Panel: the AI routing settings card (`ai-routing-card.tsx`) exposes preset save/apply/delete alongside the existing mode buttons and the complexity-override editor.
**Settings/flags.** At FastAPI lifespan (`api/app.py:117`), `apply_persisted_feature_flags(db)` reads each `FEATURE_FLAGS` key from `system_settings` and `setattr`s the live `roboco.config.settings` singleton so the rest of the app reads panel choices; an unset key keeps the env default. The Settings panel reads effective values via `feature_flag_effective_values` and writes via `SettingsService.set` (validates → upsert → flush; route commits).