Skip to content

fix(step): fall back to the session's model when a step's start was missed - #139

Open
spoler wants to merge 1 commit into
DEVtheOPS:mainfrom
spoler:fix/step-model-fallback
Open

spoler wants to merge 1 commit into
DEVtheOPS:mainfrom
spoler:fix/step-model-fallback

Conversation

@spoler

@spoler spoler commented Oct 23, 2026

Copy link
Copy Markdown

Problem

session.step.ended and session.step.failed carry no model, so handleStepEnded / handleStepFailed take it from the stepMeta entry that session.step.started writes. When that entry is missing, every signal of the step reports model and provider unknown: the api_request / api_error log, token.usage, cost.usage, message.count and model.usage.

We see this in practice: api_request records with model="unknown" and real token counts, which a backend reading these logs can't price or attribute to a model. The entry goes missing when:

  • the plugin subscribes after the step started (durable events are not replayed, the same case ensureSession handles for sessions), or
  • the execution ends before the step does: sweepExecution deletes the session's stepMeta entries, so a session.step.ended / failed arriving after it finds nothing.

Change

stepModel resolves the model in this order:

  1. the step's own stepMeta (unchanged),
  2. the session's in-flight model request (activeLlm, written by model.request and session.step.started),
  3. the session's last known model, now kept on SessionIdentity.model: written on every step start, and from session.get when contextForSession looks a session up (a resumed session),
  4. unknown, only when none of them names one.

finalizeSession keeps the identity, so 3 also covers a step that ends after its execution was swept. A model switched mid-run could in theory be attributed to the previous model for such a step; that is still closer than unknown.

Tests

tests/handlers/step.test.ts (step model fallback): missed start, a step ending after its execution was interrupted and finalized, an in-flight model request on a failed step, and unknown when nothing names the model. tests/state.test.ts: contextForSession keeps a looked-up session's model.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LjxP4wYYiGM6J8Bazqkuc5

…issed

`session.step.ended` and `session.step.failed` carry no model, so the model
comes from the `stepMeta` entry `session.step.started` writes. When that entry
is missing (the plugin subscribed after the step started, or the execution
ended and its sweep cleared the entry before the step ended), `api_request`,
`api_error`, the token, cost and message metrics all report model and provider
`unknown`.

The model now falls back to the in-flight model request of the session
(`activeLlm`), then to the session's last known model, kept on the session
identity from each step start and from `session.get` for a session the plugin
looks up, and only then to `unknown`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant