[BUG] SessionStart hook cannot tell which model the session runs after /clear (`model` missing from hook input)
I use a SessionStart hook to inject different context depending on which model the session runs. On a fresh startup this works. After /clear it silently loads the wrong context: the hook input's model field is simply not there for source=clear, even though the schema documents it and other sources (compact) do include it.
There is also no workaround from inside the hook. The two obvious fallbacks both fail exactly in the /clear case:
transcript_pathpoints at the brand-new empty transcript, so there is no previous assistant message to read the model from.- settings.json only has the configured default model, which is wrong precisely when the user picked a different model with
/model- the case where knowing the model matters.
So the hook is left guessing at the one moment it needs the answer. Meanwhile the statusline command, fed from the same app state, shows the correct model the whole time, so the information clearly exists in the process.
Repro (v2.1.233, Linux, standalone Homebrew binary):
- Register a SessionStart hook that logs its stdin:
jq -r '[.hook_event_name, .source, .model // "MISSING"] | @tsv' >> /tmp/ss.log - Start an interactive session and switch to a model different from the settings.json default via
/model. - Run
/clear. - The clear event logs
MISSINGfor.model.
I looked at the 2.1.233 bundle to see why (minified names as found in this build). The SessionStart payload builder always includes the field (hook_event_name:"SessionStart",source:t,agent_type:o,model:i,...); whether it is set depends on what each call site passes to the runner (G7e(session, source, {model, ...})):
- compact: passes
model:t.options.mainLoopModel - resume/fork, interactive path: passes
model:Sp??fr - clear: passes only
{storageV5:f}- no model - resume/fork, second path: also omits it
Based on that, /compact should log the real model id in step 4's log (I observed the missing field live on /clear; the compact behavior is read from the call sites, not observed).
Related: the SessionEnd payload (which fires with reason "clear" on the outgoing session) carries no model field either, so a hook pair that wants to hand the model across a /clear has to parse the outgoing transcript instead of reading it from either event.
Expected: every SessionStart source passes the current mainLoopModel, like the compact call site already does.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗