claude: Respect always allow setting (#36450)
Claude will now respect the `agent.always_allow_tool_actions` setting and will set it when "Always Allow" is clicked. Release Notes: - N/A
This commit is contained in:
parent
33fbe53d48
commit
b578031120
4 changed files with 64 additions and 11 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -258,6 +258,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"acp_thread",
|
||||
"agent-client-protocol",
|
||||
"agent_settings",
|
||||
"agentic-coding-protocol",
|
||||
"anyhow",
|
||||
"collections",
|
||||
|
|
|
@ -19,6 +19,7 @@ doctest = false
|
|||
[dependencies]
|
||||
acp_thread.workspace = true
|
||||
agent-client-protocol.workspace = true
|
||||
agent_settings.workspace = true
|
||||
agentic-coding-protocol.workspace = true
|
||||
anyhow.workspace = true
|
||||
collections.workspace = true
|
||||
|
|
|
@ -111,7 +111,8 @@ impl AgentConnection for ClaudeAgentConnection {
|
|||
})?;
|
||||
|
||||
let (mut thread_tx, thread_rx) = watch::channel(WeakEntity::new_invalid());
|
||||
let permission_mcp_server = ClaudeZedMcpServer::new(thread_rx.clone(), cx).await?;
|
||||
let fs = project.read_with(cx, |project, _cx| project.fs().clone())?;
|
||||
let permission_mcp_server = ClaudeZedMcpServer::new(thread_rx.clone(), fs, cx).await?;
|
||||
|
||||
let mut mcp_servers = HashMap::default();
|
||||
mcp_servers.insert(
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::claude::tools::{ClaudeTool, EditToolParams, ReadToolParams};
|
||||
use acp_thread::AcpThread;
|
||||
use agent_client_protocol as acp;
|
||||
use agent_settings::AgentSettings;
|
||||
use anyhow::{Context, Result};
|
||||
use collections::HashMap;
|
||||
use context_server::listener::{McpServerTool, ToolResponse};
|
||||
|
@ -11,8 +13,11 @@ use context_server::types::{
|
|||
ToolAnnotations, ToolResponseContent, ToolsCapabilities, requests,
|
||||
};
|
||||
use gpui::{App, AsyncApp, Task, WeakEntity};
|
||||
use project::Fs;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings as _, update_settings_file};
|
||||
use util::debug_panic;
|
||||
|
||||
pub struct ClaudeZedMcpServer {
|
||||
server: context_server::listener::McpServer,
|
||||
|
@ -23,6 +28,7 @@ pub const SERVER_NAME: &str = "zed";
|
|||
impl ClaudeZedMcpServer {
|
||||
pub async fn new(
|
||||
thread_rx: watch::Receiver<WeakEntity<AcpThread>>,
|
||||
fs: Arc<dyn Fs>,
|
||||
cx: &AsyncApp,
|
||||
) -> Result<Self> {
|
||||
let mut mcp_server = context_server::listener::McpServer::new(cx).await?;
|
||||
|
@ -30,6 +36,7 @@ impl ClaudeZedMcpServer {
|
|||
|
||||
mcp_server.add_tool(PermissionTool {
|
||||
thread_rx: thread_rx.clone(),
|
||||
fs: fs.clone(),
|
||||
});
|
||||
mcp_server.add_tool(ReadTool {
|
||||
thread_rx: thread_rx.clone(),
|
||||
|
@ -102,6 +109,7 @@ pub struct McpServerConfig {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct PermissionTool {
|
||||
fs: Arc<dyn Fs>,
|
||||
thread_rx: watch::Receiver<WeakEntity<AcpThread>>,
|
||||
}
|
||||
|
||||
|
@ -141,6 +149,24 @@ impl McpServerTool for PermissionTool {
|
|||
input: Self::Input,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<ToolResponse<Self::Output>> {
|
||||
if agent_settings::AgentSettings::try_read_global(cx, |settings| {
|
||||
settings.always_allow_tool_actions
|
||||
})
|
||||
.unwrap_or(false)
|
||||
{
|
||||
let response = PermissionToolResponse {
|
||||
behavior: PermissionToolBehavior::Allow,
|
||||
updated_input: input.input,
|
||||
};
|
||||
|
||||
return Ok(ToolResponse {
|
||||
content: vec![ToolResponseContent::Text {
|
||||
text: serde_json::to_string(&response)?,
|
||||
}],
|
||||
structured_content: (),
|
||||
});
|
||||
}
|
||||
|
||||
let mut thread_rx = self.thread_rx.clone();
|
||||
let Some(thread) = thread_rx.recv().await?.upgrade() else {
|
||||
anyhow::bail!("Thread closed");
|
||||
|
@ -148,8 +174,10 @@ impl McpServerTool for PermissionTool {
|
|||
|
||||
let claude_tool = ClaudeTool::infer(&input.tool_name, input.input.clone());
|
||||
let tool_call_id = acp::ToolCallId(input.tool_use_id.context("Tool ID required")?.into());
|
||||
let allow_option_id = acp::PermissionOptionId("allow".into());
|
||||
let reject_option_id = acp::PermissionOptionId("reject".into());
|
||||
|
||||
const ALWAYS_ALLOW: &'static str = "always_allow";
|
||||
const ALLOW: &'static str = "allow";
|
||||
const REJECT: &'static str = "reject";
|
||||
|
||||
let chosen_option = thread
|
||||
.update(cx, |thread, cx| {
|
||||
|
@ -157,12 +185,17 @@ impl McpServerTool for PermissionTool {
|
|||
claude_tool.as_acp(tool_call_id).into(),
|
||||
vec![
|
||||
acp::PermissionOption {
|
||||
id: allow_option_id.clone(),
|
||||
id: acp::PermissionOptionId(ALWAYS_ALLOW.into()),
|
||||
name: "Always Allow".into(),
|
||||
kind: acp::PermissionOptionKind::AllowAlways,
|
||||
},
|
||||
acp::PermissionOption {
|
||||
id: acp::PermissionOptionId(ALLOW.into()),
|
||||
name: "Allow".into(),
|
||||
kind: acp::PermissionOptionKind::AllowOnce,
|
||||
},
|
||||
acp::PermissionOption {
|
||||
id: reject_option_id.clone(),
|
||||
id: acp::PermissionOptionId(REJECT.into()),
|
||||
name: "Reject".into(),
|
||||
kind: acp::PermissionOptionKind::RejectOnce,
|
||||
},
|
||||
|
@ -172,16 +205,33 @@ impl McpServerTool for PermissionTool {
|
|||
})??
|
||||
.await?;
|
||||
|
||||
let response = if chosen_option == allow_option_id {
|
||||
PermissionToolResponse {
|
||||
let response = match chosen_option.0.as_ref() {
|
||||
ALWAYS_ALLOW => {
|
||||
cx.update(|cx| {
|
||||
update_settings_file::<AgentSettings>(self.fs.clone(), cx, |settings, _| {
|
||||
settings.set_always_allow_tool_actions(true);
|
||||
});
|
||||
})?;
|
||||
|
||||
PermissionToolResponse {
|
||||
behavior: PermissionToolBehavior::Allow,
|
||||
updated_input: input.input,
|
||||
}
|
||||
}
|
||||
ALLOW => PermissionToolResponse {
|
||||
behavior: PermissionToolBehavior::Allow,
|
||||
updated_input: input.input,
|
||||
}
|
||||
} else {
|
||||
debug_assert_eq!(chosen_option, reject_option_id);
|
||||
PermissionToolResponse {
|
||||
},
|
||||
REJECT => PermissionToolResponse {
|
||||
behavior: PermissionToolBehavior::Deny,
|
||||
updated_input: input.input,
|
||||
},
|
||||
opt => {
|
||||
debug_panic!("Unexpected option: {}", opt);
|
||||
PermissionToolResponse {
|
||||
behavior: PermissionToolBehavior::Deny,
|
||||
updated_input: input.input,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue