From e1150144e82ce56ee5da6dbbaafeca767347b9b5 Mon Sep 17 00:00:00 2001 From: Adam Dalloul <47503782+Adam-Dalloul@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:12:19 -0700 Subject: [PATCH] feat(cursor): advertise the native parameterized model picker Without this flag Cursor ACP publishes one exploded model list, so the chat picker only shows base names. Advertising parameterizedModelPicker lets Cursor send the base model plus separate reasoning, context, and fast options. The composer already renders those, so future Cursor variants show up without another host change. --- src-tauri/src/acp/connection.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src-tauri/src/acp/connection.rs b/src-tauri/src/acp/connection.rs index d3c8fa1e8..e9d39e4a3 100644 --- a/src-tauri/src/acp/connection.rs +++ b/src-tauri/src/acp/connection.rs @@ -3067,6 +3067,13 @@ fn claude_raw_sdk_session_meta( /// Codex to keep the blast radius off other agents (e.g. Claude's native /// AskUserQuestion, which would otherwise un-gate and duplicate the /// codeg-mcp ask tool). +/// - Cursor only: `_meta["parameterizedModelPicker"] = true` — Cursor +/// ACP then publishes the base model plus separate session config +/// options for reasoning / effort / thinking / context / fast, instead +/// of one exploded `model` list whose values look like +/// `claude-opus-4-6[thinking=true,context=200k,effort=high]`. The chat +/// composer already renders each advertised option. Cursor staff +/// documented this `_meta` flag as the client opt-in (2026-05-22). /// - Claude Code only: `_meta["subagent-transcript"] = true` — opt into /// claude-agent-acp ≥0.63's subagent transcript forwarding (#881, SDK /// `forwardSubagentText`). Subagent text/thought chunks then stream with @@ -3113,6 +3120,14 @@ fn build_client_capabilities( if agent_type == AgentType::ClaudeCode { meta.insert("subagent-transcript".to_string(), serde_json::Value::Bool(true)); } + if agent_type == AgentType::Cursor { + // Cursor checks strictly for boolean true. Unknown agents ignore + // the key, so this stays Cursor-scoped on purpose. + meta.insert( + "parameterizedModelPicker".to_string(), + serde_json::Value::Bool(true), + ); + } // The capabilities array is deliberately "sessionFailure" ONLY. // claude-agent-acp 0.69.0 and codex-acp 1.4.0 added a second AIR // capability, "agentFileChangeReport": advertise it and every prompt may @@ -12975,6 +12990,15 @@ mod tests { assert!(deepseek.get("elicitation").is_some()); assert!(deepseek.get("_meta").is_none()); + // Cursor: native model + effort/context/fast options, no elicitation. + let cursor = caps_of(AgentType::Cursor); + assert_eq!( + cursor["_meta"]["parameterizedModelPicker"], + serde_json::Value::Bool(true) + ); + assert!(cursor["_meta"].get("subagent-transcript").is_none()); + assert!(cursor.get("elicitation").is_none()); + // Everyone else: neither gate; fs + terminal always advertised. let other = caps_of(AgentType::Gemini); assert!(other.get("_meta").is_none());