From 62095bb328d49644edc4228b3a0cf4541ff994d3 Mon Sep 17 00:00:00 2001 From: Roshan Bhatia Date: Thu, 14 Aug 2025 14:10:35 -0700 Subject: [PATCH 01/10] feat: adds cursor-agent as a cli provider Signed-off-by: Roshan Bhatia --- .../src/scenario_tests/provider_configs.rs | 1 + crates/goose/src/providers/cursor_agent.rs | 497 ++++++++++++++++++ crates/goose/src/providers/factory.rs | 3 + crates/goose/src/providers/mod.rs | 1 + .../docs/getting-started/providers.md | 10 +- documentation/docs/guides/cli-providers.md | 66 ++- 6 files changed, 566 insertions(+), 12 deletions(-) create mode 100644 crates/goose/src/providers/cursor_agent.rs diff --git a/crates/goose-cli/src/scenario_tests/provider_configs.rs b/crates/goose-cli/src/scenario_tests/provider_configs.rs index 1e8f8019070e..8bcbf2f1f9a3 100644 --- a/crates/goose-cli/src/scenario_tests/provider_configs.rs +++ b/crates/goose-cli/src/scenario_tests/provider_configs.rs @@ -75,6 +75,7 @@ static PROVIDER_CONFIGS: LazyLock> = LazyLock::new(|| { "claude-3-5-sonnet", Some("No keys available"), ), + ProviderConfig::simple_skip("cursor-agent", "gpt-5", Some("No keys available")), ProviderConfig::simple_skip( "databricks", "databricks-dbrx-instruct", diff --git a/crates/goose/src/providers/cursor_agent.rs b/crates/goose/src/providers/cursor_agent.rs new file mode 100644 index 000000000000..58072180d197 --- /dev/null +++ b/crates/goose/src/providers/cursor_agent.rs @@ -0,0 +1,497 @@ +use anyhow::Result; +use async_trait::async_trait; +use rmcp::model::Role; +use serde_json::{json, Value}; +use std::path::PathBuf; +use std::process::Stdio; +use tokio::io::{AsyncBufReadExt, BufReader}; +use tokio::process::Command; + +use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage}; +use super::errors::ProviderError; +use super::utils::emit_debug_trace; +use crate::impl_provider_default; +use crate::conversation::message::{Message, MessageContent}; +use crate::model::ModelConfig; +use rmcp::model::Tool; + +pub const CURSOR_AGENT_DEFAULT_MODEL: &str = "gpt-5"; +pub const CURSOR_AGENT_KNOWN_MODELS: &[&str] = &["gpt-5", "opus-4.1", "sonnet-4"]; + +pub const CURSOR_AGENT_DOC_URL: &str = "https://docs.cursor.com/en/cli/overview"; + +#[derive(Debug, serde::Serialize)] +pub struct CursorAgentProvider { + command: String, + model: ModelConfig, +} + +impl_provider_default!(CursorAgentProvider); + +impl CursorAgentProvider { + pub fn from_env(model: ModelConfig) -> Result { + let config = crate::config::Config::global(); + let command: String = config + .get_param("CURSOR_AGENT_COMMAND") + .unwrap_or_else(|_| "cursor-agent".to_string()); + + let resolved_command = if !command.contains('/') { + Self::find_cursor_agent_executable(&command).unwrap_or(command) + } else { + command + }; + + Ok(Self { + command: resolved_command, + model, + }) + } + + /// Search for cursor-agent executable in common installation locations + fn find_cursor_agent_executable(command_name: &str) -> Option { + let home = std::env::var("HOME").ok()?; + + let search_paths = vec![ + format!("/opt/homebrew/bin/{}", command_name), + format!("/usr/bin/{}", command_name), + format!("/usr/local/bin/{}", command_name), + format!("{}/.local/bin/{}", home, command_name), + format!("{}/bin/{}", home, command_name), + ]; + + for path in search_paths { + let path_buf = PathBuf::from(&path); + if path_buf.exists() && path_buf.is_file() { + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + if let Ok(metadata) = std::fs::metadata(&path_buf) { + let permissions = metadata.permissions(); + if permissions.mode() & 0o111 != 0 { + tracing::info!("Found cursor-agent executable at: {}", path); + return Some(path); + } + } + } + #[cfg(not(unix))] + { + tracing::info!("Found cursor-agent executable at: {}", path); + return Some(path); + } + } + } + + if let Ok(path_var) = std::env::var("PATH") { + #[cfg(unix)] + let path_separator = ':'; + #[cfg(windows)] + let path_separator = ';'; + + for dir in path_var.split(path_separator) { + let path_buf = PathBuf::from(dir).join(command_name); + if path_buf.exists() && path_buf.is_file() { + let full_path = path_buf.to_string_lossy().to_string(); + tracing::info!("Found cursor-agent executable in PATH at: {}", full_path); + return Some(full_path); + } + } + } + + tracing::warn!("Could not find cursor-agent executable in common locations"); + None + } + + /// Filter out the Extensions section from the system prompt + fn filter_extensions_from_system_prompt(&self, system: &str) -> String { + // Find the Extensions section and remove it + if let Some(extensions_start) = system.find("# Extensions") { + // Look for the next major section that starts with # + let after_extensions = &system[extensions_start..]; + if let Some(next_section_pos) = after_extensions[1..].find("\n# ") { + // Found next section, keep everything before Extensions and after the next section + let before_extensions = &system[..extensions_start]; + let next_section_start = extensions_start + next_section_pos + 1; + let after_next_section = &system[next_section_start..]; + format!("{}{}", before_extensions.trim_end(), after_next_section) + } else { + // No next section found, just remove everything from Extensions onward + system[..extensions_start].trim_end().to_string() + } + } else { + // No Extensions section found, return original + system.to_string() + } + } + + /// Convert goose messages to a simple prompt format for cursor-agent CLI + fn messages_to_cursor_agent_format(&self, system: &str, messages: &[Message]) -> String { + let mut full_prompt = String::new(); + + // Add system prompt + let filtered_system = self.filter_extensions_from_system_prompt(system); + full_prompt.push_str(&filtered_system); + full_prompt.push_str("\n\n"); + + // Add conversation history + for message in messages { + let role_prefix = match message.role { + Role::User => "Human: ", + Role::Assistant => "Assistant: ", + }; + full_prompt.push_str(role_prefix); + + for content in &message.content { + match content { + MessageContent::Text(text_content) => { + full_prompt.push_str(&text_content.text); + full_prompt.push('\n'); + } + MessageContent::ToolRequest(tool_request) => { + if let Ok(tool_call) = &tool_request.tool_call { + full_prompt.push_str(&format!( + "Tool Use: {} with args: {}\n", + tool_call.name, tool_call.arguments + )); + } + } + MessageContent::ToolResponse(tool_response) => { + if let Ok(tool_contents) = &tool_response.tool_result { + let content_text = tool_contents + .iter() + .filter_map(|content| match &content.raw { + rmcp::model::RawContent::Text(text_content) => { + Some(text_content.text.as_str()) + } + _ => None, + }) + .collect::>() + .join("\n"); + + full_prompt.push_str(&format!("Tool Result: {}\n", content_text)); + } + } + _ => { + // Skip other content types for now + } + } + } + full_prompt.push('\n'); + } + + full_prompt.push_str("Assistant: "); + full_prompt + } + + /// Parse the JSON response from cursor-agent CLI + fn parse_cursor_agent_response( + &self, + lines: &[String], + ) -> Result<(Message, Usage), ProviderError> { + // Try parsing each line as a JSON object and find the one with type="result" + for line in lines { + if let Ok(json_value) = serde_json::from_str::(line) { + if let Some(type_val) = json_value.get("type") { + if type_val == "result" { + let text_content = if let Some(result) = json_value.get("result") { + let result_str = result.as_str().unwrap_or("").to_string(); + + if result_str.is_empty() { + if json_value + .get("is_error") + .and_then(|v| v.as_bool()) + .unwrap_or(false) + { + "Error: cursor-agent returned an error response".to_string() + } else { + "cursor-agent completed successfully but returned no content" + .to_string() + } + } else { + result_str + } + } else { + format!("Raw cursor-agent response: {}", line) + }; + + let message_content = vec![MessageContent::text(text_content)]; + let response_message = Message { + id: None, + role: Role::Assistant, + created: chrono::Utc::now().timestamp(), + content: message_content, + }; + + let usage = Usage::default(); + + return Ok((response_message, usage)); + } + } + } + } + + // If no valid result line found, fallback to joining all lines + let response_text = lines.join("\n"); + + let message_content = vec![MessageContent::text(response_text)]; + let response_message = Message { + id: None, + role: Role::Assistant, + created: chrono::Utc::now().timestamp(), + content: message_content, + }; + let usage = Usage::default(); + + Ok((response_message, usage)) + } + + async fn execute_command( + &self, + system: &str, + messages: &[Message], + _tools: &[Tool], + ) -> Result, ProviderError> { + let prompt = self.messages_to_cursor_agent_format(system, messages); + + if std::env::var("GOOSE_CURSOR_AGENT_DEBUG").is_ok() { + println!("=== CURSOR AGENT PROVIDER DEBUG ==="); + println!("Command: {}", self.command); + println!("Original system prompt length: {} chars", system.len()); + println!( + "Filtered system prompt length: {} chars", + self.filter_extensions_from_system_prompt(system).len() + ); + println!("Full prompt: {}", prompt); + println!("Model: {}", self.model.model_name); + println!("================================"); + } + + let mut cmd = Command::new(&self.command); + + // Only pass model parameter if it's in the known models list + if CURSOR_AGENT_KNOWN_MODELS.contains(&self.model.model_name.as_str()) { + cmd.arg("-m").arg(&self.model.model_name); + } + + cmd.arg("-p") + .arg(&prompt) + .arg("--output-format") + .arg("json") + .arg("--force"); + + cmd.stdout(Stdio::piped()).stderr(Stdio::piped()); + + let mut child = cmd + .spawn() + .map_err(|e| ProviderError::RequestFailed(format!( + "Failed to spawn cursor-agent CLI command '{}': {}. \ + Make sure the cursor-agent CLI is installed and in your PATH, or set CURSOR_AGENT_COMMAND in your config to the correct path.", + self.command, e + )))?; + + let stdout = child + .stdout + .take() + .ok_or_else(|| ProviderError::RequestFailed("Failed to capture stdout".to_string()))?; + + let mut reader = BufReader::new(stdout); + let mut lines = Vec::new(); + let mut line = String::new(); + + loop { + line.clear(); + match reader.read_line(&mut line).await { + Ok(0) => break, // EOF + Ok(_) => { + let trimmed = line.trim(); + if !trimmed.is_empty() { + lines.push(trimmed.to_string()); + } + } + Err(e) => { + return Err(ProviderError::RequestFailed(format!( + "Failed to read output: {}", + e + ))); + } + } + } + + let exit_status = child.wait().await.map_err(|e| { + ProviderError::RequestFailed(format!("Failed to wait for command: {}", e)) + })?; + + if !exit_status.success() { + return Err(ProviderError::RequestFailed(format!( + "Command failed with exit code: {:?}", + exit_status.code() + ))); + } + + tracing::debug!("Command executed successfully, got {} lines", lines.len()); + for (i, line) in lines.iter().enumerate() { + tracing::debug!("Line {}: {}", i, line); + } + + Ok(lines) + } + + /// Generate a simple session description without calling subprocess + fn generate_simple_session_description( + &self, + messages: &[Message], + ) -> Result<(Message, ProviderUsage), ProviderError> { + // Extract the first user message text + let description = messages + .iter() + .find(|m| m.role == Role::User) + .and_then(|m| { + m.content.iter().find_map(|c| match c { + MessageContent::Text(text_content) => Some(&text_content.text), + _ => None, + }) + }) + .map(|text| { + // Take first few words, limit to 4 words + text.split_whitespace() + .take(4) + .collect::>() + .join(" ") + }) + .unwrap_or_else(|| "Simple task".to_string()); + + if std::env::var("GOOSE_CURSOR_AGENT_DEBUG").is_ok() { + println!("=== CURSOR AGENT PROVIDER DEBUG ==="); + println!("Generated simple session description: {}", description); + println!("Skipped subprocess call for session description"); + println!("================================"); + } + + let message = Message { + id: None, + role: Role::Assistant, + created: chrono::Utc::now().timestamp(), + content: vec![MessageContent::text(description.clone())], + }; + + let usage = Usage::default(); + + Ok(( + message, + ProviderUsage::new(self.model.model_name.clone(), usage), + )) + } +} + +#[async_trait] +impl Provider for CursorAgentProvider { + fn metadata() -> ProviderMetadata { + ProviderMetadata::new( + "cursor-agent", + "Cursor Agent", + "Execute AI models via cursor-agent CLI tool", + CURSOR_AGENT_DEFAULT_MODEL, + CURSOR_AGENT_KNOWN_MODELS.to_vec(), + CURSOR_AGENT_DOC_URL, + vec![ConfigKey::new( + "CURSOR_AGENT_COMMAND", + false, + false, + Some("cursor-agent"), + )], + ) + } + + fn get_model_config(&self) -> ModelConfig { + // Return the model config with appropriate context limit for Cursor models + self.model.clone() + } + + #[tracing::instrument( + skip(self, system, messages, tools), + fields(model_config, input, output, input_tokens, output_tokens, total_tokens) + )] + async fn complete( + &self, + system: &str, + messages: &[Message], + tools: &[Tool], + ) -> Result<(Message, ProviderUsage), ProviderError> { + // Check if this is a session description request (short system prompt asking for 4 words or less) + if system.contains("four words or less") || system.contains("4 words or less") { + return self.generate_simple_session_description(messages); + } + + let lines = self.execute_command(system, messages, tools).await?; + + let (message, usage) = self.parse_cursor_agent_response(&lines)?; + + // Create a dummy payload for debug tracing + let payload = json!({ + "command": self.command, + "model": self.model.model_name, + "system": system, + "messages": messages.len() + }); + + let response = json!({ + "lines": lines.len(), + "usage": usage + }); + + emit_debug_trace(&self.model, &payload, &response, &usage); + + Ok(( + message, + ProviderUsage::new(self.model.model_name.clone(), usage), + )) + } +} + +#[cfg(test)] +mod tests { + use super::ModelConfig; + use super::*; + + #[test] + fn test_cursor_agent_model_config() { + let provider = CursorAgentProvider::default(); + let config = provider.get_model_config(); + + assert_eq!(config.model_name, "gpt-5"); + // Context limit should be set by the ModelConfig + assert!(config.context_limit() > 0); + } + + #[test] + fn test_cursor_agent_invalid_model_no_fallback() { + // Test that an invalid model is kept as-is (no fallback) + let invalid_model = ModelConfig::new_or_fail("invalid-model"); + let provider = CursorAgentProvider::from_env(invalid_model).unwrap(); + let config = provider.get_model_config(); + + assert_eq!(config.model_name, "invalid-model"); + } + + #[test] + fn test_cursor_agent_valid_model() { + // Test that a valid model is preserved + let valid_model = ModelConfig::new_or_fail("gpt-5"); + let provider = CursorAgentProvider::from_env(valid_model).unwrap(); + let config = provider.get_model_config(); + + assert_eq!(config.model_name, "gpt-5"); + } + + #[test] + fn test_filter_extensions_from_system_prompt() { + let provider = CursorAgentProvider::default(); + + let system_with_extensions = "Some system prompt\n\n# Extensions\nSome extension info\n\n# Next Section\nMore content"; + let filtered = provider.filter_extensions_from_system_prompt(system_with_extensions); + assert_eq!(filtered, "Some system prompt\n# Next Section\nMore content"); + + let system_without_extensions = "Some system prompt\n\n# Other Section\nContent"; + let filtered = provider.filter_extensions_from_system_prompt(system_without_extensions); + assert_eq!(filtered, system_without_extensions); + } +} diff --git a/crates/goose/src/providers/factory.rs b/crates/goose/src/providers/factory.rs index 1ebf97344938..19101acb680c 100644 --- a/crates/goose/src/providers/factory.rs +++ b/crates/goose/src/providers/factory.rs @@ -6,6 +6,7 @@ use super::{ base::{Provider, ProviderMetadata}, bedrock::BedrockProvider, claude_code::ClaudeCodeProvider, + cursor_agent::CursorAgentProvider, databricks::DatabricksProvider, gcpvertexai::GcpVertexAIProvider, gemini_cli::GeminiCliProvider, @@ -45,6 +46,7 @@ pub fn providers() -> Vec { AzureProvider::metadata(), BedrockProvider::metadata(), ClaudeCodeProvider::metadata(), + CursorAgentProvider::metadata(), DatabricksProvider::metadata(), GcpVertexAIProvider::metadata(), GeminiCliProvider::metadata(), @@ -153,6 +155,7 @@ fn create_provider(name: &str, model: ModelConfig) -> Result> "aws_bedrock" => Ok(Arc::new(BedrockProvider::from_env(model)?)), "azure_openai" => Ok(Arc::new(AzureProvider::from_env(model)?)), "claude-code" => Ok(Arc::new(ClaudeCodeProvider::from_env(model)?)), + "cursor-agent" => Ok(Arc::new(CursorAgentProvider::from_env(model)?)), "databricks" => Ok(Arc::new(DatabricksProvider::from_env(model)?)), "gcp_vertex_ai" => Ok(Arc::new(GcpVertexAIProvider::from_env(model)?)), "gemini-cli" => Ok(Arc::new(GeminiCliProvider::from_env(model)?)), diff --git a/crates/goose/src/providers/mod.rs b/crates/goose/src/providers/mod.rs index 60386d2171ca..6ddec035b092 100644 --- a/crates/goose/src/providers/mod.rs +++ b/crates/goose/src/providers/mod.rs @@ -5,6 +5,7 @@ pub mod azureauth; pub mod base; pub mod bedrock; pub mod claude_code; +pub mod cursor_agent; pub mod databricks; pub mod embedding; pub mod errors; diff --git a/documentation/docs/getting-started/providers.md b/documentation/docs/getting-started/providers.md index 5f9173527989..8ab1cf9f60b2 100644 --- a/documentation/docs/getting-started/providers.md +++ b/documentation/docs/getting-started/providers.md @@ -45,6 +45,7 @@ Goose also supports special "pass-through" providers that work with existing CLI | Provider | Description | Requirements | |-----------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [Claude Code](https://www.anthropic.com/claude-code) (`claude-code`) | Uses Anthropic's Claude CLI tool with your Claude Code subscription. Provides access to Claude with 200K context limit. | Claude CLI installed and authenticated, active Claude Code subscription | +| [Cursor Agent](https://docs.cursor.com/en/cli/overview) (`cursor-agent`) | Uses Cursor's AI CLI tool with your Cursor subscription. Provides access to GPT-5, Claude 4, and other models through the cursor-agent command-line interface. | cursor-agent CLI installed and authenticated | | [Gemini CLI](https://ai.google.dev/gemini-api/docs) (`gemini-cli`) | Uses Google's Gemini CLI tool with your Google AI subscription. Provides access to Gemini with 1M context limit. | Gemini CLI installed and authenticated | :::tip CLI Providers @@ -144,14 +145,7 @@ To configure your chosen provider or see available options, run `goose configure │ ◓ Checking your configuration... └ Configuration saved successfully - ``` - Set the model for an individual session using the [`run` command](/docs/guides/goose-cli-commands.md#run-options): - - ```bash - goose run --model goose-claude-4-sonnet -t "initial prompt" - ``` - - +``` diff --git a/documentation/docs/guides/cli-providers.md b/documentation/docs/guides/cli-providers.md index 0432be1f189e..d92ef47ea9fb 100644 --- a/documentation/docs/guides/cli-providers.md +++ b/documentation/docs/guides/cli-providers.md @@ -2,18 +2,18 @@ sidebar_position: 8 title: CLI Providers sidebar_label: CLI Providers -description: Use Claude Code or Gemini CLI subscriptions in Goose +description: Use Claude Code, Cursor Agent, or Gemini CLI subscriptions in Goose --- # CLI Providers -Goose supports pass-through providers that integrate with existing CLI tools from Anthropic and Google. These providers allow you to use your existing Claude Code and Google Gemini CLI subscriptions through Goose's interface, adding session management, persistence, and workflow integration capabilities to these tools. +Goose supports pass-through providers that integrate with existing CLI tools from Anthropic, Cursor, and Google. These providers allow you to use your existing Claude Code, Cursor Agent, and Google Gemini CLI subscriptions through Goose's interface, adding session management, persistence, and workflow integration capabilities to these tools. ## Why Use CLI Providers? CLI providers are useful if you: -- already have a Claude Code or Google Gemini CLI subscription and want to use it through Goose instead of paying per token +- already have a Claude Code, Cursor, or Google Gemini CLI subscription and want to use it through Goose instead of paying per token - need session persistence to save, resume, and export conversation history - want to use Goose recipes and scheduled tasks to create repeatable workflows - prefer unified commands across different AI providers @@ -57,6 +57,20 @@ The Claude Code provider integrates with Anthropic's [Claude CLI tool](https://c - Active Claude Code subscription - CLI tool authenticated with your Anthropic account +### Cursor Agent + +The Cursor Agent provider integrates with Cursor's [cursor-agent CLI tool](https://docs.cursor.com/en/cli/installation), providing access to Cursor Agent through your existing subscription. + +**features:** + +- integrates with Cursor Agent CLI coding tasks. +- ideal for code-related workflows and file interactions. + +**requirements:** + +- cursor-agent tool installed and configured. +- CLI tool authenticated. + ### Gemini CLI The Gemini CLI provider integrates with Google's [Gemini CLI tool](https://ai.google.dev/gemini-api/docs), providing access to Gemini models through your Google AI subscription. @@ -103,6 +117,40 @@ The Gemini CLI provider integrates with Google's [Gemini CLI tool](https://ai.go ◇ Enter a model from that provider: │ default ``` +## Cursor Agent + +1. **Install Cursor agent Tool** + + Follow the [installation instructions for Cursor Agent](https://docs.cursor.com/en/cli/installation) to install and configure the cursor agent tool. + +2. **Authenticate with Cursor** + + Ensure your Cursor Agent is authenticated and working + +3. **Configure goose** + + set the provider environment variable: + + ```bash + export goose_provider=cursor-agent + ``` + + Or configure through the goose cli using `goose configure`: + + ```bash + ┌ goose-configure + │ + ◇ What would you like to configure? + │ configure providers + │ + ◇ Which model provider should we use? + │ Cursor Agent + │ + ◇ Model fetch complete + │ + ◇ Enter a model from that provider: + │ default + ``` ### Gemini CLI @@ -171,6 +219,14 @@ goose session | `GOOSE_PROVIDER` | Set to `claude-code` to use this provider | None | | `CLAUDE_CODE_COMMAND` | Path to the Claude CLI command | `claude` | + +### Cursor Agent Configuration + +| Environment Variable | Description | Default | +|---------------------|-------------|---------| +| `GOOSE_PROVIDER` | Set to `cursor-agent` to use this provider | None | +| `CURSOR_AGENT_COMMAND` | Path to the Cursor Agent command | `cursor-agent` | + ### Gemini CLI Configuration | Environment Variable | Description | Default | @@ -182,16 +238,18 @@ goose session ### System Prompt Filtering -Both CLI providers automatically filter out Goose's extension information from system prompts since these CLI tools have their own tool ecosystems. This prevents conflicts and ensures clean interaction with the underlying CLI tools. +The CLI providers automatically filter out Goose's extension information from system prompts since these CLI tools have their own tool ecosystems. This prevents conflicts and ensures clean interaction with the underlying CLI tools. ### Message Translation - **Claude Code**: Converts Goose messages to Claude's JSON message format, handling tool calls and responses appropriately +- **Cursor Agent**: Converts Goose messages to Cursor's JSON message format, handling tool calls and responses appropriately - **Gemini CLI**: Converts messages to simple text prompts with role prefixes (Human:/Assistant:) ### Response Processing - **Claude Code**: Parses JSON responses to extract text content and usage information +- **Cursor Agent**: Parses JSON responses to extract text content and usage information - **Gemini CLI**: Processes plain text responses from the CLI tool ## Error Handling From 635c513432bfc28b3c8de2859fbc819d658cde76 Mon Sep 17 00:00:00 2001 From: Roshan Bhatia Date: Fri, 15 Aug 2025 09:17:56 -0700 Subject: [PATCH 02/10] cargo fmt --- crates/goose/src/providers/cursor_agent.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/goose/src/providers/cursor_agent.rs b/crates/goose/src/providers/cursor_agent.rs index 58072180d197..432093df0b51 100644 --- a/crates/goose/src/providers/cursor_agent.rs +++ b/crates/goose/src/providers/cursor_agent.rs @@ -10,8 +10,8 @@ use tokio::process::Command; use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage}; use super::errors::ProviderError; use super::utils::emit_debug_trace; -use crate::impl_provider_default; use crate::conversation::message::{Message, MessageContent}; +use crate::impl_provider_default; use crate::model::ModelConfig; use rmcp::model::Tool; From d0e7181a771b6c9294d562a941e509d8b06c7d62 Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Mon, 18 Aug 2025 10:49:05 +1000 Subject: [PATCH 03/10] Update documentation/docs/guides/cli-providers.md --- documentation/docs/guides/cli-providers.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/documentation/docs/guides/cli-providers.md b/documentation/docs/guides/cli-providers.md index d92ef47ea9fb..2908797163f0 100644 --- a/documentation/docs/guides/cli-providers.md +++ b/documentation/docs/guides/cli-providers.md @@ -7,7 +7,9 @@ description: Use Claude Code, Cursor Agent, or Gemini CLI subscriptions in Goose # CLI Providers -Goose supports pass-through providers that integrate with existing CLI tools from Anthropic, Cursor, and Google. These providers allow you to use your existing Claude Code, Cursor Agent, and Google Gemini CLI subscriptions through Goose's interface, adding session management, persistence, and workflow integration capabilities to these tools. +Goose can make use of pass-through providers that integrate with existing CLI tools from Anthropic, Cursor, and Google. These providers allow you to use your existing Claude Code, Cursor Agent, and Google Gemini CLI subscriptions through Goose's interface, adding session management, persistence, and workflow integration capabilities to these tools. + +IMPORTANT: these providers have limited support for all the features of Goose, and may not work on all platforms or have limited capabilities, and can require some advanced debugging if you run in to issues, but they are provided as a convenience. ## Why Use CLI Providers? From 0ddf09ca2d6753a3071f4c10ffd636f3e6ba200c Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Mon, 18 Aug 2025 13:56:41 +1000 Subject: [PATCH 04/10] Update documentation/docs/guides/cli-providers.md Co-authored-by: Angie Jones --- documentation/docs/guides/cli-providers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/guides/cli-providers.md b/documentation/docs/guides/cli-providers.md index 2908797163f0..eb4b290b1b15 100644 --- a/documentation/docs/guides/cli-providers.md +++ b/documentation/docs/guides/cli-providers.md @@ -137,7 +137,7 @@ The Gemini CLI provider integrates with Google's [Gemini CLI tool](https://ai.go export goose_provider=cursor-agent ``` - Or configure through the goose cli using `goose configure`: + Or configure through the Goose CLI using `goose configure`: ```bash ┌ goose-configure From 591e83df5d5f4f392aa41e5cb1d447c26ee4a3d8 Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Mon, 18 Aug 2025 13:56:50 +1000 Subject: [PATCH 05/10] Update documentation/docs/guides/cli-providers.md Co-authored-by: Angie Jones --- documentation/docs/guides/cli-providers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/guides/cli-providers.md b/documentation/docs/guides/cli-providers.md index eb4b290b1b15..b3dc40ea6bc3 100644 --- a/documentation/docs/guides/cli-providers.md +++ b/documentation/docs/guides/cli-providers.md @@ -131,7 +131,7 @@ The Gemini CLI provider integrates with Google's [Gemini CLI tool](https://ai.go 3. **Configure goose** - set the provider environment variable: + Set the provider environment variable: ```bash export goose_provider=cursor-agent From f96b6518e64ed83ece288dad749246b7b209d864 Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Mon, 18 Aug 2025 13:56:56 +1000 Subject: [PATCH 06/10] Update documentation/docs/guides/cli-providers.md Co-authored-by: Angie Jones --- documentation/docs/guides/cli-providers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/guides/cli-providers.md b/documentation/docs/guides/cli-providers.md index b3dc40ea6bc3..6f16108d584e 100644 --- a/documentation/docs/guides/cli-providers.md +++ b/documentation/docs/guides/cli-providers.md @@ -68,7 +68,7 @@ The Cursor Agent provider integrates with Cursor's [cursor-agent CLI tool](https - integrates with Cursor Agent CLI coding tasks. - ideal for code-related workflows and file interactions. -**requirements:** +**Requirements:** - cursor-agent tool installed and configured. - CLI tool authenticated. From 74083d65071b2608f291a05add3d6e9b41003290 Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Mon, 18 Aug 2025 13:57:01 +1000 Subject: [PATCH 07/10] Update documentation/docs/guides/cli-providers.md Co-authored-by: Angie Jones --- documentation/docs/guides/cli-providers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/guides/cli-providers.md b/documentation/docs/guides/cli-providers.md index 6f16108d584e..da64bf43dd06 100644 --- a/documentation/docs/guides/cli-providers.md +++ b/documentation/docs/guides/cli-providers.md @@ -63,7 +63,7 @@ The Claude Code provider integrates with Anthropic's [Claude CLI tool](https://c The Cursor Agent provider integrates with Cursor's [cursor-agent CLI tool](https://docs.cursor.com/en/cli/installation), providing access to Cursor Agent through your existing subscription. -**features:** +**Features:** - integrates with Cursor Agent CLI coding tasks. - ideal for code-related workflows and file interactions. From 8fcb1b82166fad503ca89fa2a00f39842bcd583e Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Mon, 18 Aug 2025 13:57:13 +1000 Subject: [PATCH 08/10] Update documentation/docs/guides/cli-providers.md Co-authored-by: Angie Jones --- documentation/docs/guides/cli-providers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/guides/cli-providers.md b/documentation/docs/guides/cli-providers.md index da64bf43dd06..e58f5ad11f1b 100644 --- a/documentation/docs/guides/cli-providers.md +++ b/documentation/docs/guides/cli-providers.md @@ -61,7 +61,7 @@ The Claude Code provider integrates with Anthropic's [Claude CLI tool](https://c ### Cursor Agent -The Cursor Agent provider integrates with Cursor's [cursor-agent CLI tool](https://docs.cursor.com/en/cli/installation), providing access to Cursor Agent through your existing subscription. +The Cursor provider integrates with Cursor's [CLI agent](https://docs.cursor.com/en/cli/installation), providing access to through your existing subscription. **Features:** From d94f425df46ab53aaf00c6be05f2bc04a22894ef Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Mon, 18 Aug 2025 14:00:27 +1000 Subject: [PATCH 09/10] Update cli-providers.md --- documentation/docs/guides/cli-providers.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/documentation/docs/guides/cli-providers.md b/documentation/docs/guides/cli-providers.md index e58f5ad11f1b..4bac93e6846e 100644 --- a/documentation/docs/guides/cli-providers.md +++ b/documentation/docs/guides/cli-providers.md @@ -9,7 +9,8 @@ description: Use Claude Code, Cursor Agent, or Gemini CLI subscriptions in Goose Goose can make use of pass-through providers that integrate with existing CLI tools from Anthropic, Cursor, and Google. These providers allow you to use your existing Claude Code, Cursor Agent, and Google Gemini CLI subscriptions through Goose's interface, adding session management, persistence, and workflow integration capabilities to these tools. -IMPORTANT: these providers have limited support for all the features of Goose, and may not work on all platforms or have limited capabilities, and can require some advanced debugging if you run in to issues, but they are provided as a convenience. +> [!WARNING] +> These providers don’t fully support all Goose features, may have platform or capability limitations, and can sometimes require advanced debugging if issues arise. They’re included here purely as a convenience. ## Why Use CLI Providers? From 4a0156cb39c463b8290a0a0fbea78a0f27f3a97e Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Mon, 18 Aug 2025 14:06:26 +1000 Subject: [PATCH 10/10] use doc admonition style --- documentation/docs/guides/cli-providers.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/documentation/docs/guides/cli-providers.md b/documentation/docs/guides/cli-providers.md index 4bac93e6846e..a7d3ede5ca02 100644 --- a/documentation/docs/guides/cli-providers.md +++ b/documentation/docs/guides/cli-providers.md @@ -9,8 +9,9 @@ description: Use Claude Code, Cursor Agent, or Gemini CLI subscriptions in Goose Goose can make use of pass-through providers that integrate with existing CLI tools from Anthropic, Cursor, and Google. These providers allow you to use your existing Claude Code, Cursor Agent, and Google Gemini CLI subscriptions through Goose's interface, adding session management, persistence, and workflow integration capabilities to these tools. -> [!WARNING] -> These providers don’t fully support all Goose features, may have platform or capability limitations, and can sometimes require advanced debugging if issues arise. They’re included here purely as a convenience. +:::warning + +These providers don’t fully support all Goose features, may have platform or capability limitations, and can sometimes require advanced debugging if issues arise. They’re included here purely as a convenience. ## Why Use CLI Providers?