Repository navigation
Conversation
Copilot CLI 1.0.105 reports a model in session/new that the session does not run until a client sets one, and rejects reasoning_effort until then. T3 skipped setting a model whose reported value already matched, so a Copilot thread on the reported model ran Copilot's own default and lost its effort. The Copilot flavor now always sends the selected model. Co-Authored-By: Claude <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Copilot now explicitly receives the selected model even when it already reports that value, preventing its internal default from silently overriding the selection. The extra request is Copilot-specific and leaves other agents’ behavior unchanged. You can add or adjust custom eligibility rules. Learn more. |
Findings
|
| Layer / File(s) | Summary |
|---|---|
Runtime support for resending config values packages/provider-acp/src/server/AcpSessionRuntime.ts |
setConfigOption accepts resendCurrentValue. When enabled, a matching current value no longer skips the agent request. |
Copilot model selection and test coverage packages/provider-acp/src/server/adapter.ts, packages/provider-acp-registry/src/server/adapter.ts, apps/server/src/orchestration-v2/Adapters/AcpRegistryAdapterV2.test.ts |
The adapter passes the resend flag based on the flavor setting, and the Copilot flavor enables it. Tests cover stored model and reasoning-effort options. |
Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix
Suggested reviewers: stienswout, agadzik
Merge Risk: 
Moderate · up to 7a4dd
-
Copilot launched through npx can still run a different model than selected and reject reasoning-effort changes. Fix that launcher path before merging unless its limitation is explicitly accepted.
Pre-merge checks: 
4
-
Full details: Title check
-
Explanation
The title "fix(acp): Copilot runs the model it reports as selected" follows conventional commit form and names the main change: T3 now sends the model Copilot reports so Copilot runs that model. The changeset adds resendCurrentValue to setConfigOption and an alwaysSetModel flavor flag enabled for Copilot, which matches the title.
Full details: Description check
-
Explanation
The description follows the template's sections (Problem, Change, Scope and approval, Verification) and fills each one with specific content. The Problem section gives the Copilot CLI 1.0.105 behavior, reproduction context, and observed effects. The Change section maps each file to its modification and explains the Copilot-only flag. Scope and approval explains why no prior issue exists and why the fix qualifies as a very small, focused fix. Verification gives a live protocol check, a named replay test with its command and expected traffic, and a list of what was not checked. The template's header comment and the 'Scope and approval' guidance are addressed directly. The one soft point is that the author gives no linked issue or maintainer approval; the description explains the exemption reasoning instead, which the template allows for a very small, focused fix of an obvious bug.
-
Finishing Touches
-
Generate unit tests (beta)
-
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Problem
GitHub Copilot CLI 1.0.105 (ACP Registry agent
github-copilot-cli) returnsconfigOptionsfromsession/newwithmodel.currentValue: "claude-sonnet-5.5", but the session doesn't run that model until the client sets one withsession/set_config_option. Until then, settingreasoning_effortfails with-32603 "Request session.model.setReasoningEffort failed with message: This model does not support reasoning_effort configuration.". Oncemodelis set explicitly, even to the value already reported, effort changes work.T3 never sends that explicit set.
AcpSessionRuntime.setConfigOptionskips a write when the option already reports the value, and the ACP Registry driver marks Copilot's reported model as the default. So a new Copilot thread on the default model, or any thread where the user picks the model Copilot reports, never sendsmodel.What the user sees on
main:claude-sonnet-5.5and the effort they chose, and turns run and complete normally. No error appears.~/.copilot/session-state/<id>/events.jsonl) recordedsession.model_changewithnewModel: "gpt-6.1-sol"for threads T3 showed asclaude-sonnet-5.5.configureSessioncatches the-32603and logs only a server warning ("ACP session rejected a configuration option value",optionId: reasoning_effort). If the chosen effort equals the reportedmedium, nothing is sent and nothing is logged. Changing effort later in the thread hits the same rejection, because the model is still never set.Picking a model other than the reported one works, because that value differs and T3 sends it.
Change
packages/provider-acp/src/server/AcpSessionRuntime.ts:setConfigOptiontakes an optionalresendCurrentValue. When it is set, the runtime skips the "already current" short-circuit and writes the value. Every existing caller keeps its current behavior.packages/provider-acp/src/server/adapter.ts: a new optional flavor flag,alwaysSetModel. When it is set,configureSessionwrites the selected model through the model config option even if the option already reports it.configureSessionruns on session open, after asession/loadorsession/resumeactivation (including the Copilot restart path from fix(acp): a lost or locked Copilot session restarts on the next message instead of failing every time #26651), and when the selection changes at turn start, so all of those paths send the model before any effort or other option.packages/provider-acp-registry/src/server/adapter.ts: the existing Copilot-only flavor block setsalwaysSetModel: true.The cost is one extra
session/set_config_optionformodeleach time T3 configures a Copilot session.Why a Copilot flag and not a generic change
I also looked at the generic option: never trust a value
session/newreports until a set orconfig_option_updateconfirms it. I didn't use it for three reasons:session/newdescribing the session's real state is the ACP contract, and every other agent T3 supports follows it as far as I know. Distrusting it would add a write at session start for every agent and every matching option (model, mode, effort, and so on). Some agents do real work when the model changes.mcpOverHttp, andrestartRuntimeAfterPromptErrorfrom fix(acp): a lost or locked Copilot session restarts on the next message instead of failing every time #26651).The flag only affects the model config option path. In the
session/newresponses I observed, Copilot 1.0.105 sends amodelselect (and also legacymodels, which the adapter uses only when there is no select), so the legacysession/set_modelbranch is unchanged: it still skips a same-value write.Scope and approval
There is no prior issue or discussion. I think this qualifies as a very small, focused fix for an obvious bug: T3 shows one model and Copilot runs another, and the user's reasoning effort is silently rejected. The change is limited to Copilot: one optional runtime parameter, one flavor flag and one line enabling it for Copilot, plus a two-row test. There are no contract, setting or UI changes, and no other agent changes behavior. I'm also filing the underlying Copilot bug with github/copilot-cli. If Copilot fixes it, the extra write just becomes redundant.
Verification
Live protocol check, without prompts (free): a Node script speaks ACP to
copilot --acp1.0.105 with a freshCOPILOT_HOMEthat contains only a copiedconfig.json(nomodelsetting). It never sendssession/prompt.The same script showed that the full
configOptionsin the explicit-set response are identical to thesession/newones, so T3's view of the options doesn't change. Setting the same model again afterreasoning_effort: "high"still reportshigh, so the repeated write on a mid-thread selection change doesn't reset the reported effort.Test, at the lowest layer that fails on
main. A new two-row table inAcpRegistryAdapterV2.test.tssits next to the existing model-picker cases and reuses theiropenWithStoredPicksreplay helper (it gained an optionalagentId). It drives the real ACP Registry adapter against a replay-agent subprocess.session/newreportsmodel: "claude-sonnet-5.5"andreasoning_effort: "medium"; the stored selection isclaude-sonnet-5.5with effortlow. The replay requires the frames in order.session/newfixture-agentreasoning_effort: "low"only (the reported model is trusted)github-copilot-climodel: "claude-sonnet-5.5", thenreasoning_effort: "low"main(the three source files checked out frommain, new test kept): the Copilot row fails withUnexpected outbound ACP frame: the replay expected themodelwrite and T3 sentreasoning_effort: "low"first, the write Copilot rejects. The fixture row passes.session/prompton the wire. It isn't in the committed table because onmainthat variant hangs on the turn after the rejected effort write instead of failing at the mismatch.AcpAdapterV2.test.ts(118 tests across the two files).vp run check:changed upstream/main: format, lint, knip, graphql, typecheck (13 packages) and tests all pass.Not checked:
session/set_config_optionright aftersession/newwas followed in Copilot's session events bysession.model_changetoclaude-sonnet-5.5. That is my workaround, not this patch.session/loadresponse has the same problem. A session that never received a prompt isn't saved, sosession/loadreturns-32002 not found. The fix also sends the model after load and resume activations when that response lists a model config option. If it lists only legacymodels, the adapter falls back tosession/set_model, which still skips a same-value write, as onmain.Written by Opus 5.5 with Claude Code. Reviewed by GPT 6.1 Sol: 2 rounds, verdict approved.