code-yeongyu / code-yeongyu/senpi
session_start omits initialModelProvenance for --model and scoped runs (main.ts does not forward it to createAgentSessionFromServices)
- Dominant language
- TypeScript
- Stars
- 429
- Forks
- 98
- Avg merge
- 5h 3m
- Merged PRs (30d)
- 526
Description
## Summary
`session_start` reaches extensions **without** `initialModelProvenance` on exactly the runs where it matters most: `--model ` (provenance `cli`) and scoped-model runs (provenance `scoped`). Runs without an explicit model DO carry a provenance (e.g. `first-available`, `settings`).
## Reproduction
1. Extension that logs the `session_start` payload:
```ts
pi.on("session_start", (event) => console.error(JSON.stringify(event)))
```
2. `senpi -p --provider --model "hi"` -> `{"type":"session_start","reason":"startup"}` (no `initialModelProvenance`)
3. `senpi -p "hi"` (no `--model`) -> `{"type":"session_start","reason":"startup","initialModelProvenance":"first-available"}`
## Expected (ideal state)
Every `session_start` carries the provenance the CLI resolved: `cli` for `--model`, `scoped` for scoped models, and the existing values otherwise. Extensions can then distinguish "user pinned a model for this run" from "harness picked a default" without heuristics.
## Actual
`packages/coding-agent/src/main.ts` sets `options.initialModelProvenance = "cli"` (`:587`) and `"scoped"` (`:607`, `:615`), but the `createAgentSessionFromServices({ ... })` call (`:856`) never passes `initialModelProvenance`, so `packages/coding-agent/src/core/sdk.ts:516` (`const sessionStartEvent = initialModelProvenance ? {...} : options.sessionStartEvent`) falls through to a provenance-less event. The non-explicit path gets its provenance from model resolution (`sdk.ts:311`), which is why only the explicit-model runs lose it.
## Impact
The builtin `recommended-models` extension is safe because it allow-lists `provider-default`/`first-available` and treats `undefined` as "do not switch". Any extension that deny-lists `cli`/`scoped` (the natural reading of the contract) silently overrides a user's `--model`. Found while QA-ing an omo-senpi model-profile component: with `--model mock-1` and an active profile the session was switched to the profile's model; omo now treats a missing provenance as explicit user state as a workaround (code-yeongyu/oh-my-openagent#8084).
## Proposed fix
Forward the option: `initialModelProvenance: sessionOptions.initialModelProvenance` in the `createAgentSessionFromServices` call in `main.ts`, plus a test asserting the `session_start` payload carries `"cli"` for a `--model` run and `"scoped"` for a scoped run.
## Acceptance criteria
- `senpi -p --model ` -> extensions receive `session_start` with `initialModelProvenance: "cli"`.
- Scoped-model run -> `initialModelProvenance: "scoped"`.
- Existing provenances for the non-explicit path unchanged.
- Regression test in `packages/coding-agent` covering both explicit paths.
Evidence held locally (driver logs from the omo QA run).
Contributor guide
Research direction
Start in packages/coding-agent/src/main.ts at the createAgentSessionFromServices call around line 856, then read packages/coding-agent/src/core/sdk.ts around line 516 to follow session_start construction. Add regression coverage in packages/coding-agent for both --model and scoped-model runs. Done means extensions receive cli and scoped provenance while non-explicit provenance remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 86/100