fix(webui): route Cursor ACP and gate reasoning effort by model#2792
Conversation
SummaryRead the diff at
The frontend session-creation honesty fix (visible picker selection actually carried into Code referenceCross-repo concern first: the WebUI side adds
The ACP routing hint at _ACP_SUBPROCESS_PROVIDERS = frozenset({"cursor-acp", "copilot-acp"})
def model_with_provider_context(model_id: str, model_provider: str | None = None) -> str:
...
# ACP subprocess providers always need the explicit hint — their slash IDs
# are not OpenRouter paths and must not inherit config_provider routing.
if provider in _ACP_SUBPROCESS_PROVIDERS:
return f"@{provider}:{model}"This is the right shape — The reasoning chip resolver at if provider in {"copilot", "github-copilot"}:
return github_model_reasoning_efforts(hinted_model)
if provider == "openai-codex":
bare = hinted_model.rsplit("/", 1)[-1]
return github_model_reasoning_efforts(bare)Reuses The new-chat picker fix at const modelSelForNew=$('modelSelect');
let newModelState=null;
if(modelSelForNew&&modelSelForNew.value&&typeof _modelStateForSelect==='function'){
newModelState=_modelStateForSelect(modelSelForNew,modelSelForNew.value);
}else if(typeof _readPersistedModelState==='function'){
newModelState=_readPersistedModelState();
}
if(newModelState&&newModelState.model){
reqBody.model=newModelState.model;
reqBody.model_provider=newModelState.model_provider||null;
}
The cached-agent eviction at from api.config import _evict_session_agent
_evict_session_agent(body["session_id"])
DiagnosisThe technical work is solid and the test surface is the right shape ( Two things to address before merge:
LGTM otherwise. Solid contributor PR with good test coverage on a non-trivial cross-cutting fix. |
|
Friendly bump @RobertoVillegas — wanted to make sure the comment 32h ago didn't get lost in your inbox. Three concrete next steps on this PR:
Will keep watching this thread. If you don't have bandwidth in the next few days, no worries — flag it and we'll plan the cherry-pick ourselves. |
785b34c to
d8e9e87
Compare
- Add cursor-acp to _PROVIDER_DISPLAY with label 'Cursor ACP' - Add cursor-acp static model list to _PROVIDER_MODELS - composer-2.5, composer-2, default, cursor-acp
Ensure cursor/composer IDs always resolve via @cursor-acp:, carry the visible picker selection into POST /api/session/new, persist model changes before a session exists, and evict cached agents on model switch. Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve supported reasoning efforts per active model/provider and pass that context through /api/reasoning so Composer and other non-configurable models no longer show a misleading effort picker. Co-authored-by: Cursor <cursoragent@cursor.com>
Model picker onchange now calls syncReasoningChip after session model/ provider updates, and dropdown selections pass providerId so duplicate bare model ids resolve to the correct backend capabilities. Co-authored-by: Cursor <cursoragent@cursor.com>
d8e9e87 to
4c4922a
Compare
|
Updated this PR after the review feedback:
Local validation: pytest tests/test_reasoning_effort_model_capabilities.py \
tests/test_issue1103_reasoning_chip_visibility.py \
tests/test_new_chat_default_model_frontend.py \
tests/test_provider_mismatch.py \
tests/test_reasoning_chip_btw_fixes.py \
tests/test_reasoning_chip_js_behaviour.py \
tests/test_mobile_layout.py::test_reasoning_chip_updates_desktop_and_mobile_controls \
tests/test_issue2545_xai_oauth_provider.py::test_xai_oauth_model_picker_group_uses_live_catalog \
tests/test_issue2569_model_provider_picker.py::test_temporary_configured_model_option_carries_provider_badge \
tests/test_ollama_model_chip_label_regression.py::test_select_model_custom_option_uses_friendly_label_helper -q
# 123 passed, 1 warningFull-suite note from local macOS: unrelated environment-sensitive tests still fail here ( Dependency note: Cursor ACP itself still depends on NousResearch/hermes-agent#30835 landing or a released Agent version containing |
08e9ce3
|
Merged in Release DM / v0.51.141 (stage-batch23 — 4-PR second hold-bucket pass with PRs #2506 #2792 #2888 #2958). Thanks @RobertoVillegas! 🚢 |
Complements NousResearch/hermes-agent#30835, which adds
cursor-acpas a Hermes provider. This PR is the WebUI-side wiring so users can select Cursor Composer in the browser, route new sessions to the selected provider, and only see the reasoning-effort chip when the active model actually supports configurable effort levels.Thinking Path
agent acp) with slash model IDs likecursor/composer-2.5.@provider:hints, but ACP subprocess IDs could be treated like ordinary slash paths and inherit the configured default provider.config.yamldefaults instead of the visible composer picker, so the chip could show Composer while the new session actually started on another provider/model.What Changed
Cursor ACP picker and routing
api/config.pycursor-acpto provider labels and the static model catalog (cursor/composer-2.5,cursor/composer-2,cursor/default)._ACP_SUBPROCESS_PROVIDERS.@cursor-acp:/@copilot-acp:routing hints inmodel_with_provider_context()so slash IDs do not inherit the configured default provider.static/sessions.jsnewSession()now sends the visible pickermodelandmodel_providerinPOST /api/session/new.static/boot.jsonchangepersists the selected model/provider and updates the chip even when there is no active session yet.api/routes.py_evict_session_agent()so subsequent turns use the selected backend.Model-aware reasoning effort chip
api/config.pyresolve_model_reasoning_efforts(model_id, provider_id, base_url)withhermes_cli.modelslookups and a heuristic fallback when CLI modules are unavailable.[]for ACP subprocess providers such ascursor-acpandcopilot-acp.@openai-codex:gpt-5.5before provider-specific reasoning capability lookup.get_reasoning_status()withsupported_effortsandsupports_reasoning_effort.api/routes.pyGET /api/reasoningaccepts optionalmodel,provider, andbase_urlquery params and passes them toget_reasoning_status().static/ui.js_reasoningEffortQuery()so/api/reasoningis queried with the active session model/provider.supported_effortsis empty.static/commands.js/reasoningstatus uses the active model/provider context.CHANGELOG.mdTests
tests/test_provider_mismatch.pytests/test_new_chat_default_model_frontend.pytests/test_reasoning_effort_model_capabilities.pytests/test_issue1103_reasoning_chip_visibility.pytests/test_reasoning_chip_btw_fixes.pyWhy It Matters
Without these fixes, Cursor Composer can appear selectable in the composer while requests silently route to a different provider. That breaks the mental model of the WebUI and makes model switching hard to trust.
The reasoning chip had a similar trust issue: showing effort-level controls for
cursor-acpimplied the user could configure thinking effort, but that provider does not expose those levels. Separating "display reasoning blocks" (display.show_reasoning) from "choose effort level" (model capability) keeps the composer footer aligned with actual backend capabilities.Verification
Automated:
pytest tests/test_provider_mismatch.py::test_cursor_acp_slash_model_always_gets_provider_hint \ tests/test_new_chat_default_model_frontend.py \ tests/test_provider_mismatch.py::TestFrontendModelProviderState \ tests/test_reasoning_effort_model_capabilities.py \ tests/test_issue1103_reasoning_chip_visibility.py \ tests/test_reasoning_chip_btw_fixes.py \ -qLatest focused local result:
Manual browser verification on WebUI running at port
8787:cursor/composer-2.5.model: cursor/composer-2.5andmodel_provider: cursor-acp.gpt-5.5.Responsive/UI notes:
UI Evidence
Before: reasoning effort shown for Cursor Composer even though it has no effect
The reasoning-effort chip was visible in the composer footer for
cursor/composer-2.5, implying configurable effort levels for a provider that does not expose them.After: reasoning effort hidden when the active model lacks effort levels
With the same Cursor Composer context, the chip is hidden because
/api/reasoningreports no supported effort levels forcursor-acp.Risks / Follow-ups
copilot-acpgets the same explicit-hint treatment; behavior should be unchanged but is worth a smoke test.hermes_cli.modelswhen available; the heuristic fallback may miss edge-case custom providers until catalog metadata improves.display.show_reasoningremains separate).Model Used
cursor-acp) and OpenAI Codex (openai-codex) during validation/debugging.cursor/composer-2.5,gpt-5.5.