feat(acp): derive and forward thinking effort from the ACP harness - #10949
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 88454b0058
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
e5f991b to
3fd3daf
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3fd3dafc7d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…er hooks Groundwork for deriving the ACP thinking_effort menu from harness capability instead of model-name sniffing (which the ACP "current" sentinel always fails), and for forwarding effort picks to the harness: - thinking.rs: add ThinkingEffortOption, ThinkingEffortCapability, and ThinkingEffortSupport (Unspecified / Unsupported / Options) so ACP providers can report a harness-advertised effort option verbatim. - base.rs: add defaulted Provider trait methods thinking_effort_support() (Unspecified), set_thinking_effort() (Ok(false) = not handled), and apply_model_selection() (no-op), leaving all existing providers unaffected. - model.rs: fix with_default_thinking_effort to guard on raw-param presence rather than enum parseability, so a persisted harness value like "default" is not silently overwritten by GOOSE_THINKING_EFFORT; add unit tests for both branches. Verified with cargo fmt, cargo test -p goose-provider-types (460 passed), and cargo clippy --all-targets -- -D warnings. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
Second step of the ACP thinking-effort fix: AcpProvider now mirrors the harness's own effort config option and forwards picks back to it, so the knob stops being dead. Menu construction and the agent/server forward path follow in later commits. - Mirror the harness's effort selector into effort_state, detected by category `thought_level` with the well-known id "effort" as fallback, so any ACP agent advertising it works without per-provider config. - Keep it fresh from all three harness sources: the session/new response, session/set_config_option responses (previously discarded, and the freshest source after a goose-initiated model switch), and config_option_update notifications. Payloads carry the full option set, so an absent selector clears the mirrored capability. - Map goose effort values onto the harness vocabulary (exact match, off -> default, max <-> xhigh) and never forward an unmapped value, so the harness keeps its own default instead of rejecting the request. - Implement thinking_effort_support(), set_thinking_effort() (live-apply via the harness option id, no provider respawn) and apply_model_selection(), plus apply_effort_if_changed() in stream() so the persisted value survives provider recreation. - Reuse the new select-value flattening helper in the model-option extraction path. Adds 23 unit tests covering capability extraction (category, id fallback, grouped values, labels, absent), state refresh from a config_option_update, the value-mapping table, both trait entry points, and every apply_effort_if_changed skip path. Verified with cargo fmt, cargo test -p goose --lib acp:: (238 passed), and cargo clippy --all-targets -- -D warnings. The 10 remaining failures in the full `cargo test -p goose --lib` run (prompt-manager snapshot, plugin discovery, gcpauth/JWT) are pre-existing on this branch. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
…ating it Third step of the ACP thinking-effort fix: wire the forward path so a user's pick actually reaches the harness instead of respawning it. - Agent::update_thinking_effort now takes the raw option value and asks the provider first. A provider that applied the value live (ACP) gets the raw string persisted into the session's ModelConfig with no provider recreation, which would otherwise discard the harness session state just configured. Providers that decline keep the existing ThinkingEffort parse plus recreate_provider_for_session path. - The raw value matters: harness vocabularies include values like "xhigh" and "default" that are not ThinkingEffort member spellings, so on_set_thinking_effort stops parsing the enum eagerly and passes the option id through. Value rejections now surface from the agent, so the ACP error stays invalid_params. - Agent::update_provider calls the new apply_model_selection hook after installing the provider, so a provider that manages its own model is synced to the session's selection before the next config snapshot is built rather than at the next prompt. Failures are logged, not fatal: stream() re-applies. Adds four unit tests around a mock provider covering the provider-applied persist path (no respawn), the legacy parse rejection, a provider rejection, and the model-selection hook firing from update_provider. Verified with cargo fmt, cargo test -p goose --lib acp:: (238 passed) and agents:: excluding the prompt-manager snapshot (326 passed), and cargo clippy --all-targets -- -D warnings. The prompt-manager snapshot failure was confirmed pre-existing on a clean HEAD. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
Final step of the ACP thinking-effort fix, and the one that actually cures the missing menu: the effort options now come from what the connected provider advertises instead of sniffing the model name, which the ACP "current" sentinel could never satisfy. - response_builder: build_config_options/build_session_setup_config take a ThinkingEffortSupport and branch on it. Options mirrors the agent's selector verbatim (values and labels), with current resolved as session pick -> GOOSE_THINKING_EFFORT -> the agent's own current -> first value, both goose-side values mapped into the agent's vocabulary so the selection is always an offered option. Unsupported offers only off, and Unspecified keeps the existing model-name path for API providers. - Thread the capability to every menu build site: build_config_update (already holds the provider), handle_load_session, finish_new_session_setup via build_new_session_response, and fork_session. A session without a live provider resolves to Unspecified, so an unconfigured provider still loads. - Export map_effort_value and THINKING_EFFORT_PARAM from acp::provider so the menu and the forward path share one mapping table. Adds 8 response_builder tests: the sentinel-model regression test (a "current" session gets the full agent menu, and asserts the sentinel really does fail is_reasoning_model), the current-value precedence table including off -> default and max -> xhigh, the global-default fallback, and the Unsupported collapse. Adds a live-gated claude-acp effort test to the provider suite asserting Options with non-empty values, a successful set_thinking_effort, and a following complete() round-trip. Verified with cargo fmt, cargo clippy --all-targets -- -D warnings, and cargo test -p goose --lib acp:: (246 passed). Against the installed claude-agent-acp the new integration test passes: the harness advertises default/low/medium/high/xhigh/max with its own labels, and setting max is accepted. Reaching it required locally bypassing test_model_listing's assert_ne!(resolved, ACP_CURRENT_MODEL), which fails identically on a clean HEAD (sentinel resolution is a deliberate non-goal here). The 10 remaining failures in a full cargo test -p goose --lib run are pre-existing and outside acp:: (prompt-manager snapshot, plugin discovery, gcpauth/JWT, oauth/logging caches); a clean-HEAD run fails the same families. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
Code review on dcfc29e flagged that the applied_effort write-through cache was never reconciled when effort_state was refreshed: if the agent reset its own effort (e.g. a model switch rebuilding per-model levels), apply_effort_if_changed still skipped the re-send because the cache said the persisted value was applied, leaving goose and the harness silently divergent. Drop the cache and compare against the mirrored capability's `current` instead, which every refresh site keeps fresh — including the agent's own SetConfigOption response, which handle_requests folds into effort_state before set_effort_option returns, so the very send being guarded also updates the guard. Rename the skip test to reflect the new semantics (already-applied is now expressed as the capability's current) and add a regression test: after a refresh reverts the agent's current back to "default", a persisted "high" is re-sent rather than skipped. Verified with cargo fmt, cargo test -p goose --lib acp:: (247 passed), and cargo clippy --all-targets -- -D warnings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
Code review on dcfc29e flagged that when the agent advertises no effort selector, the menu offers only "off" (the Unsupported branch), yet picking that sole entry returned Ok(false) from set_thinking_effort, sending Agent::update_thinking_effort down the legacy path — which parses "off" and calls recreate_provider_for_session, respawning the ACP harness subprocess for what should be a no-op. Return Ok(true) instead: AcpProvider manages reasoning itself, so with no capability the pick is applied by doing nothing. Persisting the raw value is harmless — apply_effort_if_changed already returns early when no capability is mirrored, so nothing is sent on later streams either. Update the no-capability unit test to assert the pick is reported as applied ("off", matching what the menu can actually offer) with nothing sent to the agent. Verified with cargo fmt, cargo test -p goose --lib acp:: (247 passed), and cargo clippy --all-targets -- -D warnings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
…onses Code review on 2bd8883 flagged that session bootstrap discarded its session/set_config_option responses. That loop is how copilot_acp and pi_acp pin the model, and a model switch is exactly when the agent rebuilds its per-model effort levels — so the mirrored capability kept reflecting pre-switch state. Since the mirrored `current` is now the redundant-send guard, a stale `current` that happened to equal the persisted goose value suppressed a needed re-send until the next config_option_update arrived. Thread effort_state into apply_session_config_options and fold each response into the mirror, matching the goose-initiated path: the response carries the agent's full option set, so it replaces the mirror (including clearing it when the selector is gone), and the last response wins. The session/new refresh stays — for agents with an empty bootstrap list it is the only source. claude_acp, amp_acp and codex_acp pass an empty list, so their behavior is unchanged. Adds an integration test that drives connect_with_transport against a scripted in-process agent over duplex byte streams: session/new advertises low/medium/high with current "medium", the bootstrap model pin responds with a rebuilt minimal/high selector at "high", and the test asserts the provider reports the rebuilt options. Without the fix it sees "medium" and low/medium/high, encoding the reviewer's scenario. Verified with cargo fmt, cargo test -p goose --lib acp:: (247 passed), cargo test -p goose --test acp_bootstrap_effort_test (passes, and fails as expected with the provider change stashed), and cargo clippy --all-targets -- -D warnings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
…rnal_error Code review on 2bd8883 flagged that on_set_thinking_effort mapped every failure from Agent::update_thinking_effort to invalid_params. A value rejection genuinely is bad params — the client should learn a different value might work — but a dying harness subprocess is an I/O problem that says nothing about the client's input, and it previously surfaced as internal_error. The conflation came from flattening every failure class into the same stringly types on the way up, so classify at the source instead: - goose-provider-types: add ProviderError::InvalidValue for bad input, with an "invalid_value" telemetry arm. The retry catch-all makes it non-retryable, which is right for a value that will never be accepted. - AcpProvider::set_thinking_effort: an unmapped value is InvalidValue outright, and a send failure is classified by the wire error code. Only an agent that actually evaluated our params can answer with the JSON-RPC invalid_params code; the ACP client library synthesizes internal_error locally for a failed send or dropped connection, and goose's own send failures carry no ACP error at all. Conservative by design: a nonstandard rejection code maps to the operational side. - Agent::update_thinking_effort: use .context() instead of anyhow!(), which preserves the ProviderError as a downcastable source, and give the legacy-path parse failure the same InvalidValue vocabulary so the server has exactly one discriminator. - on_set_thinking_effort: map by variant via a free thinking_effort_error function (unit-testable without a live session agent). The error data uses {e:#} so context layering doesn't hide the cause chain. The other failures in that path — session persist, provider respawn, provider lookup — now correctly reach the client as internal_error, restoring the pre-branch semantics for API providers too. Adds three provider tests (agent replies invalid_params -> InvalidValue; replies internal_error, and drops the response, -> RequestFailed), the downcast assertions the agent tests now depend on, and three thinking_effort_error mapping tests. Verified with cargo fmt, cargo clippy --all-targets -- -D warnings, cargo test -p goose-provider-types (460 passed), cargo test -p goose --lib acp:: (253 passed), the agents:: effort tests (4 passed), and cargo test -p goose --test acp_bootstrap_effort_test. The new value-rejection test was confirmed to fail with the downcast branch disabled. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
… chain A Codex review on dcfc29e flagged that the effort menu's current value and the value goose actually sends the agent were resolved independently. The menu walked session pick -> global default -> agent current -> first offered; apply_effort_if_changed only honored the first link, logging and sending nothing when the persisted pick did not map into the agent's vocabulary. That diverges after a model switch rebuilds the agent's selector: a session persisted `medium` against a rebuilt `default/high` selector with GOOSE_THINKING_EFFORT=high advertises `high` as selected while the agent keeps running at its own default. The state is sticky, since with_default_thinking_effort guards on raw-param presence, so the stale `medium` also blocks reply_parts from folding the global in. Extract resolve_effort_value next to map_effort_value (persisted pick, then global, each mapped) and drive both sites from it, so the two can't drift again. The unmappable pick stays persisted rather than being overwritten by the fallback: it becomes honorable again if the user switches back to a model that offers it, and since both sides share the resolver the unpersisted-but-applied fallback is consistent either way. The redundant-send guard is untouched, so a resolved global already equal to the agent's mirrored current still sends nothing. Adds a regression test for the reviewer's scenario, and pins GOOSE_THINKING_EFFORT in the two skip tests so they assert deterministically rather than depending on the developer machine's configured default. Verified with cargo fmt, cargo test -p goose --lib acp:: (254 passed), cargo test -p goose --test acp_bootstrap_effort_test, and cargo clippy --all-targets -- -D warnings. The regression test was confirmed to fail with only the apply_effort_if_changed change reverted, so the menu-side refactor does not mask it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
3fd3daf to
bebd866
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bebd8660f1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6fe7c6ee42
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3482eb4eca
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 891830bb19
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6a5f97c3c6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3235faa8d2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 36e60ebd96
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f1a1179c80
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…bined * origin/main: (85 commits) feat(desktop): sort configured providers to the top of the provider list (#11409) fix(cli): refuse symlink diagnostics outputs (#11398) test(plugins): isolate GOOSE_PATH_ROOT in discovery tests (#11407) fix(config): serialize secret mutations (#11388) fix: decouple source file and tool response limits (#11391) chore(deps): bump pctx_code_mode from 0.4.1 to 0.5.0 (#11245) fix(security): suppress sensitive OTLP traces (#11381) feat(openrouter): forward session_id and add app category header (#10868) feat(acp): derive and forward thinking effort from the ACP harness (#10949) fix(aws_bedrock): replace flat model list with routing table, add Gemma 4 Mantle support (#10297) Add GPT-5.6 follow-up support for Codex and Responses API (#10460) fix(update): fetch attestation bundles from bundle_url (#10557) fix(security): fail closed on invalid default GCP credentials (#11363) fix(codex): reject socket-backed MCP extensions (#11304) fix: pass complete response to stop hooks (#11366) fix: contain and bound skill supporting file reads (#11342) chore(deps): bump the ui-minor-and-patch group across 1 directory with 53 updates (#11386) fix(security): bound call graph traversal (#11193) fix: pin arrayref to known-good commit (#11389) feat(providers): add SayGM as declarative OpenAI-compatible provider (#11267) ... # Conflicts: # crates/goose/src/agents/agent.rs
* main: (70 commits) cli: remove recipe secret discovery (#11435) fix(openrouter): escape Gemini tool response ref keys (#11276) fix(security): honor MCP tool model visibility in Code Mode (#11425) fix(providers): estimate cost for Azure Foundry models via inferred catalog pricing (#11264) feat(providers): add Gondola as declarative OpenAI-compatible provider (#11421) feat(otel): add request params, response metadata, tool call parity, and agent identification (#11261) fix(providers): coalesce consecutive Thinking blocks in collect_stream (#11317) feat(hooks): add PreToolUseResult event and stable tool_call_id across tool lifecycle (#11120) add MCP conformance tests to goose CI (combines #10800 + #10801) (#10940) feat(desktop): sort configured providers to the top of the provider list (#11409) fix(cli): refuse symlink diagnostics outputs (#11398) test(plugins): isolate GOOSE_PATH_ROOT in discovery tests (#11407) fix(config): serialize secret mutations (#11388) fix: decouple source file and tool response limits (#11391) chore(deps): bump pctx_code_mode from 0.4.1 to 0.5.0 (#11245) fix(security): suppress sensitive OTLP traces (#11381) feat(openrouter): forward session_id and add app category header (#10868) feat(acp): derive and forward thinking effort from the ACP harness (#10949) fix(aws_bedrock): replace flat model list with routing table, add Gemma 4 Mantle support (#10297) Add GPT-5.6 follow-up support for Codex and Responses API (#10460) ...
Problem
On ACP-backed providers (e.g.
claude-agent-acp), the thinking-effort selector was effectively dead:ACP_CURRENT_MODELsentinel, which never matches — so no effort options were offered at all.ThinkingEffortand routed throughrecreate_provider_for_session, respawning the harness subprocess (and discarding its session state) instead of telling the harness about the change.Approach
Derive the menu from what the connected provider actually advertises, and forward picks to it.
goose-provider-typesthinking.rs:ThinkingEffortOption/ThinkingEffortCapability/ThinkingEffortSupport(Unspecified|Unsupported|Options) so a provider can report a harness-advertised effort option verbatim.base.rs: defaultedProviderhooksthinking_effort_support(),set_thinking_effort()(Ok(false)= not handled) andapply_model_selection(). Existing providers are unaffected.model.rs:with_default_thinking_effortnow guards on raw-param presence rather than enum parseability, so a persisted harness value like"default"isn't overwritten byGOOSE_THINKING_EFFORT.errors.rs: newProviderError::InvalidValuefor bad input (non-retryable, distinct from operational failure).AcpProviderthought_level, with the well-known ideffortas fallback) — no per-provider config needed.session/newresponse,session/set_config_optionresponses (including the ones issued during session bootstrap to pin a model, which were previously discarded), andconfig_option_updatenotifications. Each payload carries the full option set, so an absent selector clears the capability.off→default,max↔xhigh) and never forwards an unmapped value.currentand the value actually sent to the harness are resolved from one shared chain (resolve_effort_value: session pick →GOOSE_THINKING_EFFORT, each mapped into the agent's vocabulary), so the two can't drift. Previously, a persisted pick that a rebuilt selector no longer offered (e.g.mediumafter a model switch to adefault/highagent) was advertised as selected while nothing was ever sent; now both sides fall back to the global default together. The unmappable pick stays persisted, so it becomes honorable again if the user switches back to a model that offers it.set_thinking_effort()applies live via the harness option id — no respawn — andapply_effort_if_changed()instream()re-applies the persisted value after provider recreation, guarded against the mirroredcurrent(not a local write-through cache) so an agent-side reset is re-sent rather than skipped.Unsupportedmenu only offersoff, and routing it through the legacy path would respawn the subprocess for a no-op.Agent/ ACP serverupdate_thinking_efforttakes the raw option value and asks the provider first. A provider that applied it live gets the raw string persisted with no recreation; providers that decline keep the existing parse +recreate_provider_for_sessionpath. The raw value matters because harness vocabularies include values (xhigh,default) that aren'tThinkingEffortspellings.update_providercallsapply_model_selectionafter installing the provider, so a self-managing provider is synced before the next config snapshot. Failures are logged, not fatal —stream()re-applies.response_builder:build_config_options/build_session_setup_configbranch on the capability.Optionsmirrors the agent's selector verbatim, withcurrentresolved via the shared chain and then the agent's own current → first value;Unsupportedoffers onlyoff;Unspecifiedkeeps the model-name path for API providers. Threaded throughbuild_config_update,handle_load_session,finish_new_session_setupandfork_session; a session without a live provider resolves toUnspecifiedso unconfigured providers still load.invalid_params, while a dead subprocess, failed persist or failed respawn surfaces asinternal_error(restoring pre-branch semantics for API providers).Verification
cargo fmt,cargo clippy --all-targets -- -D warningscargo test -p goose-provider-types(460 passed),cargo test -p goose --lib acp::(254 passed), theagents::effort tests, andcargo test -p goose --test acp_bootstrap_effort_testapply_effort_if_changedskip/re-send path, the sentinel-model menu regression,current-value precedence, error-classification mapping, the advertised-vs-applied divergence regression (persisted pick outside a rebuilt selector's vocabulary with a mappable global set), and an integration test drivingconnect_with_transportagainst a scripted in-process agent whose bootstrap model pin rebuilds the effort selector. Each regression test was confirmed to fail with its fix removed.claude-agent-acp, which advertisesdefault/low/medium/high/xhigh/max: the menu shows the harness's own labels and settingmaxis accepted.Pre-existing
cargo test -p goose --libfailures outsideacp::(prompt-manager snapshot, plugin discovery, gcpauth/JWT, oauth/logging caches) reproduce identically on a cleanmain.No tracking issue exists for this on the Goose Issues board — filing as maintainer-directed work.
🤖 Generated with Claude Code