You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(builtin): ,model <id> command for per-session model switching (#244)
* feat(builtin): add `,model <id>` command for per-session model switching
Allow switching the model for the current session from chat via the
`,model <provider:model>` command, persisted across restarts.
- BuiltinImpl.run_model_stream now forwards state["model"] as the per-call
model override to Agent.run_stream (one-line pass-through).
- New builtin tool `model` (set_model) writes state["model"]; as a registered
tool it is directly invocable as the `,model <id>` chat command, and also
remains callable by the agent.
- A minimal SessionStateStore persists state["model"] per session under
bub.home/sessions/<id>.json via load_state/save_state (atomic write). Empty
values clear the override; nothing is written to the process environment.
- state["model"] is read once at turn start, so a mid-turn switch applies from
the next turn (documented in the run_model_stream hookspec).
Tests (LLM mocked) cover the pass-through, the tool/command, the end-to-end
per-call override, persistence round-trip, and concurrent-session isolation.
* Persist per-session model on the tape instead of a parallel store
Drops the SessionStateStore (a second JSON persistence module under
bub.home/sessions/) and reuses the existing per-session tape to carry
state["model"]:
- set_model now records each switch as a `model_switch` event on the
session tape (context.tape), which merges back to the persisted store
at end of turn — no new store.
- load_state recovers the latest `model_switch` event from the session
tape (reading the persisted store before the per-turn fork exists) and
injects state["model"]; nothing recorded -> no injection (fresh session
never inherits another's model).
- save_state reverts to lifespan-only; the tool owns persistence now.
Removes src/bub/builtin/session_state.py + tests/test_session_state.py;
rewrites the persistence tests against the tape. Reuses two existing
mechanisms (the in-memory state dict + the tape) rather than adding one.
`uv run pytest` (205 passed) and `uv run ruff check .` are green.
---------
Co-authored-by: yiling <yiling@ebay.com>
0 commit comments