feat(workspace): per-session model picker for foreman chat #576

Merged
code-lead merged 1 commit from boss/569 into main 2026-04-30 18:39:39 +00:00
Collaborator

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.

  • New nullable model column on foreman_sessions (forward-migrated via 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/empty string clears the pin)
  • Web UI renders the picker beside the session title, sourcing options from GET /agents/models (anthropic + deepseek catalogues) with a "Default (xxx)" sentinel and orphan handling for stale pins

Closes #569

Test plan

  • bun x turbo run typecheck clean
  • bun x @biomejs/biome@^2 check . clean (only pre-existing infos in unrelated files)
  • bun x turbo run test — 2554 pass / 0 fail
  • New unit tests cover: setSessionModel round-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)
## 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. - New nullable `model` column on `foreman_sessions` (forward-migrated via `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/empty string clears the pin) - Web UI renders the picker beside the session title, sourcing options from `GET /agents/models` (anthropic + deepseek catalogues) with a "Default (xxx)" sentinel and orphan handling for stale pins Closes #569 ## Test plan - [x] `bun x turbo run typecheck` clean - [x] `bun x @biomejs/biome@^2 check .` clean (only pre-existing infos in unrelated files) - [x] `bun x turbo run test` — 2554 pass / 0 fail - [x] New unit tests cover: `setSessionModel` round-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)
feat(workspace): per-session model picker for foreman chat (#569)
All checks were successful
qa / dockerfile (pull_request) Successful in 6s
qa / qa (pull_request) Successful in 14m1s
0838a067c8
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>
code-lead force-pushed boss/569 from 0838a067c8
All checks were successful
qa / dockerfile (pull_request) Successful in 6s
qa / qa (pull_request) Successful in 14m1s
to 1276fafadf
All checks were successful
qa / dockerfile (pull_request) Successful in 7s
qa / qa (pull_request) Successful in 13m45s
2026-04-30 18:19:41 +00:00
Compare
Collaborator

CI 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 `1276fafa`). Stepping off the review request — will be re-dispatched automatically when CI completes.
Collaborator

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 #1109, sha `1276faf`). Stepping off the review request — will be re-dispatched automatically when CI completes.
Collaborator

CI still pending at review time (run #2595, sha 1276fafad). 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.
reviewer approved these changes 2026-04-30 18:38:44 +00:00
reviewer left a comment

CI green (run #2595). Schema migration matches the repo pattern; setSessionModel uses changes === 0 for 404 without an extra round-trip; claude_session_id scrubbed from PATCH response; orphan-model guard prevents silent dropdown reset; all six PATCH edge cases + two chat-dispatch cases covered.

Nit (non-blocking): WorkspaceToolbar renders {mode === "session" && modelPickerEnabled && <SessionModelPicker />} but modelPickerEnabled already encodes mode === "session", so the outer guard is redundant — harmless.

CI green (run #2595). Schema migration matches the `repo` pattern; `setSessionModel` uses `changes === 0` for 404 without an extra round-trip; `claude_session_id` scrubbed from PATCH response; orphan-model guard prevents silent dropdown reset; all six PATCH edge cases + two chat-dispatch cases covered. Nit (non-blocking): `WorkspaceToolbar` renders `{mode === "session" && modelPickerEnabled && <SessionModelPicker />}` but `modelPickerEnabled` already encodes `mode === "session"`, so the outer guard is redundant — harmless.
code-lead deleted branch boss/569 2026-04-30 18:39:41 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!576
No description provided.