feat(workspace): per-session model picker for foreman chat #576
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!576
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "boss/569"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Adds a model dropdown in the foreman chat session header so each session can pin its own model, falling back to the worker's configured default when unset.
modelcolumn onforeman_sessions(forward-migrated viaALTER TABLEinensureSchema, mirroring the existingrepopattern)POST /foreman/chatreadssession.model ?? worker.config.modelso pinned sessions stay on their chosen model across turnsPATCH /foreman/sessions/:idendpoint accepts{ model: string | null }(null/empty string clears the pin)GET /agents/models(anthropic + deepseek catalogues) with a "Default (xxx)" sentinel and orphan handling for stale pinsCloses #569
Test plan
bun x turbo run typecheckcleanbun x @biomejs/biome@^2 check .clean (only pre-existing infos in unrelated files)bun x turbo run test— 2554 pass / 0 failsetSessionModelround-trip + 404, chat dispatching pinned model, chat fallback to worker default, GET exposes model, PATCH (pin / explicit null / empty-string unpin / 400 on empty body / 400 on bad type / 404 on unknown id)Adds a model dropdown in the foreman chat session header so each session can pin its own model, falling back to the worker's configured default when unset. Selection is persisted on the `foreman_sessions` row via a new nullable `model` column (forward-migrated through `ALTER TABLE` in `ensureSchema`, mirroring the existing `repo` pattern). `POST /foreman/chat` reads `session.model ?? worker.config.model` so pinned sessions stay on their chosen model across turns. New `PATCH /foreman/sessions/:id` endpoint accepts `{ model: string | null }` — null (or empty string) clears the pin. Web UI renders the picker beside the session title, sourcing options from `GET /agents/models` (anthropic + deepseek catalogues) and showing a "Default (xxx)" sentinel. Closes #569 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>0838a067c81276fafadfCI still pending at review time (run #1109, sha
1276fafa). Stepping off the review request — will be re-dispatched automatically when CI completes.CI still pending at review time (run #1109, sha
1276faf). Stepping off the review request — will be re-dispatched automatically when CI completes.CI still pending at review time (run #2595, sha
1276fafad). Stepping off the review request — will be re-dispatched automatically when CI completes.CI green (run #2595). Schema migration matches the
repopattern;setSessionModeluseschanges === 0for 404 without an extra round-trip;claude_session_idscrubbed from PATCH response; orphan-model guard prevents silent dropdown reset; all six PATCH edge cases + two chat-dispatch cases covered.Nit (non-blocking):
WorkspaceToolbarrenders{mode === "session" && modelPickerEnabled && <SessionModelPicker />}butmodelPickerEnabledalready encodesmode === "session", so the outer guard is redundant — harmless.