Repository navigation
fix(chat): send pi and acp messages after a model-only change - #32004
Conversation
Admission now reads the value Orca last applied per key. A model write's effort marker and the agent's reported effort no longer refuse a send.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to
|
What the user saw
In a Pi or ACP chat (OpenCode 2, OMP, Grok, Antigravity), picking a different model in the picker and sending showed "OpenCode 2 didn't accept this message." (or the OMP / Grok / Pi equivalent). The message never reached the agent. Every later send on that model was refused the same way.
Root cause
Orca decided whether to admit a message by looking at the wrong facts. It should have used the choice Orca last applied.
optionProof.writes, which exists to cancel an in-flight effort write. Dispatch read that same token as "Orca set an effort". So a message with a model and no effort was refused right after its own model switch (rpc-message-dispatch.ts).acp-message-execution-options.ts). OMP always reports one. OpenCode 2 starts on a model with no effort option, then reportsthought_level: "default"after a switch to a model that has one, such asopencode/deepseek-v4.1-flash-free. So the first send after that switch is refused, though the model switch itself already went through.Both have been there since #28046.
The fix
This follows the contract #30982 set for Claude: record the last successfully applied choice after a successful control, and never treat a settings readback as admission authority.
A message that leaves a key unspecified is now refused only when Orca's last successful write for that key set a value other than the one the session opened with.
session.selected, which was already set only after a successful write. The model write's effort token still supersedes in-flight writes.AcpStructuredOptions.applied, set where a write is confirmed.Restoring the opening effort when returning to the opening model doesn't count as an override. So switching away, back, and away again keeps working. An explicit earlier effort the new model has no known default for is still refused, as #28046 intended.
Codex is separate (STA-11443).
Linked Issue
Linear STA-11450 (no GitHub issue). #31998 is a community PR for the ACP half of the same refusal.
Visual Proof
OpenCode 2
Real OpenCode 2.1.3 with isolated config and data, in a hidden dev build. Steps: open an OpenCode 2 chat (it starts on Big Pickle), pick DeepSeek V4.1 Flash Free, send twice. The saved chat options were
{"model":"opencode/deepseek-v4.1-flash-free"}in both runs. On the branch, OpenCode's own store records both turns ondeepseek-v4.1-flash-freewithvariant: "default".Before (main):
After (this branch):
OMP
Real OMP 18.12.2 in an isolated config with two models (Alpha, Beta) served by a local fake OpenAI endpoint, in a hidden dev build. Steps: send a first message on Alpha, pick only Beta in the picker, send again. The saved chat options were
{"model":"scratch/beta"}in both runs.Before (main):
After (this branch):
Testing
src/main/pi,src/main/acpand the Pi startup / effort-at-rest runtime tests.