Detailed changes
@@ -196,9 +196,9 @@ dependencies = [
[[package]]
name = "agent-client-protocol"
-version = "0.2.0-alpha.8"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08539e8d6b2ccca6cd00afdd42211698f7677adef09108a09414c11f1f45fdaf"
+checksum = "003fb91bf1b8d6e15f72c45fb9171839af8241e81e3839fbb73536af113b7a79"
dependencies = [
"anyhow",
"async-broadcast",
@@ -434,7 +434,7 @@ zlog_settings = { path = "crates/zlog_settings" }
# External crates
#
-agent-client-protocol = { version = "0.2.0-alpha.8", features = ["unstable"] }
+agent-client-protocol = { version = "0.2.1", features = ["unstable"] }
aho-corasick = "1.1"
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty.git", branch = "add-hush-login-flag" }
any_vec = "0.14"
@@ -862,7 +862,7 @@ impl AcpThread {
mut prompt_capabilities_rx: watch::Receiver<acp::PromptCapabilities>,
cx: &mut Context<Self>,
) -> Self {
- let prompt_capabilities = *prompt_capabilities_rx.borrow();
+ let prompt_capabilities = prompt_capabilities_rx.borrow().clone();
let task = cx.spawn::<_, anyhow::Result<()>>(async move |this, cx| {
loop {
let caps = prompt_capabilities_rx.recv().await?;
@@ -906,7 +906,7 @@ impl AcpThread {
}
pub fn prompt_capabilities(&self) -> acp::PromptCapabilities {
- self.prompt_capabilities
+ self.prompt_capabilities.clone()
}
pub fn connection(&self) -> &Rc<dyn AgentConnection> {
@@ -1446,6 +1446,7 @@ impl AcpThread {
vec![acp::ContentBlock::Text(acp::TextContent {
text: message.to_string(),
annotations: None,
+ meta: None,
})],
cx,
)
@@ -1464,6 +1465,7 @@ impl AcpThread {
let request = acp::PromptRequest {
prompt: message.clone(),
session_id: self.session_id.clone(),
+ meta: None,
};
let git_store = self.project.read(cx).git_store().clone();
@@ -1555,7 +1557,8 @@ impl AcpThread {
let canceled = matches!(
result,
Ok(Ok(acp::PromptResponse {
- stop_reason: acp::StopReason::Cancelled
+ stop_reason: acp::StopReason::Cancelled,
+ meta: None,
}))
);
@@ -1571,6 +1574,7 @@ impl AcpThread {
// Handle refusal - distinguish between user prompt and tool call refusals
if let Ok(Ok(acp::PromptResponse {
stop_reason: acp::StopReason::Refusal,
+ meta: _,
})) = result
{
if let Some((user_msg_ix, _)) = this.last_user_message() {
@@ -2163,6 +2167,7 @@ mod tests {
acp::ContentBlock::Text(acp::TextContent {
annotations: None,
text: "Hello, ".to_string(),
+ meta: None,
}),
cx,
);
@@ -2186,6 +2191,7 @@ mod tests {
acp::ContentBlock::Text(acp::TextContent {
annotations: None,
text: "world!".to_string(),
+ meta: None,
}),
cx,
);
@@ -2207,6 +2213,7 @@ mod tests {
acp::ContentBlock::Text(acp::TextContent {
annotations: None,
text: "Assistant response".to_string(),
+ meta: None,
}),
false,
cx,
@@ -2220,6 +2227,7 @@ mod tests {
acp::ContentBlock::Text(acp::TextContent {
annotations: None,
text: "New user message".to_string(),
+ meta: None,
}),
cx,
);
@@ -2265,6 +2273,7 @@ mod tests {
})?;
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
+ meta: None,
})
}
.boxed_local()
@@ -2335,6 +2344,7 @@ mod tests {
.unwrap();
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
+ meta: None,
})
}
.boxed_local()
@@ -2403,6 +2413,7 @@ mod tests {
locations: vec![],
raw_input: None,
raw_output: None,
+ meta: None,
}),
cx,
)
@@ -2411,6 +2422,7 @@ mod tests {
.unwrap();
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
+ meta: None,
})
}
.boxed_local()
@@ -2459,6 +2471,7 @@ mod tests {
status: Some(acp::ToolCallStatus::Completed),
..Default::default()
},
+ meta: None,
}),
cx,
)
@@ -2501,11 +2514,13 @@ mod tests {
path: "/test/test.txt".into(),
old_text: None,
new_text: "foo".into(),
+ meta: None,
},
}],
locations: vec![],
raw_input: None,
raw_output: None,
+ meta: None,
}),
cx,
)
@@ -2514,6 +2529,7 @@ mod tests {
.unwrap();
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
+ meta: None,
})
}
.boxed_local()
@@ -2576,6 +2592,7 @@ mod tests {
})?;
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
+ meta: None,
})
}
.boxed_local()
@@ -2743,6 +2760,7 @@ mod tests {
raw_output: Some(
serde_json::json!({"result": "inappropriate content"}),
),
+ meta: None,
}),
cx,
)
@@ -2752,10 +2770,12 @@ mod tests {
// Now return refusal because of the tool result
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::Refusal,
+ meta: None,
})
} else {
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
+ meta: None,
})
}
}
@@ -2789,6 +2809,7 @@ mod tests {
vec![acp::ContentBlock::Text(acp::TextContent {
text: "Hello".into(),
annotations: None,
+ meta: None,
})],
cx,
)
@@ -2841,6 +2862,7 @@ mod tests {
async move {
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::Refusal,
+ meta: None,
})
}
.boxed_local()
@@ -2848,6 +2870,7 @@ mod tests {
async move {
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
+ meta: None,
})
}
.boxed_local()
@@ -2909,6 +2932,7 @@ mod tests {
if refuse_next.load(SeqCst) {
return Ok(acp::PromptResponse {
stop_reason: acp::StopReason::Refusal,
+ meta: None,
});
}
@@ -2927,6 +2951,7 @@ mod tests {
})?;
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
+ meta: None,
})
}
.boxed_local()
@@ -3082,6 +3107,7 @@ mod tests {
image: true,
audio: true,
embedded_context: true,
+ meta: None,
}),
cx,
)
@@ -3113,6 +3139,7 @@ mod tests {
} else {
Task::ready(Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
+ meta: None,
}))
}
}
@@ -354,6 +354,7 @@ mod test_support {
image: true,
audio: true,
embedded_context: true,
+ meta: None,
}),
cx,
)
@@ -393,7 +394,10 @@ mod test_support {
response_tx.replace(tx);
cx.spawn(async move |_| {
let stop_reason = rx.await?;
- Ok(acp::PromptResponse { stop_reason })
+ Ok(acp::PromptResponse {
+ stop_reason,
+ meta: None,
+ })
})
} else {
for update in self.next_prompt_updates.lock().drain(..) {
@@ -432,6 +436,7 @@ mod test_support {
try_join_all(tasks).await?;
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
+ meta: None,
})
})
}
@@ -75,6 +75,7 @@ impl Terminal {
acp::TerminalExitStatus {
exit_code: exit_status.as_ref().map(|e| e.exit_code()),
signal: exit_status.and_then(|e| e.signal().map(Into::into)),
+ meta: None,
}
})
.shared(),
@@ -105,7 +106,9 @@ impl Terminal {
exit_status: Some(acp::TerminalExitStatus {
exit_code: exit_status.as_ref().map(|e| e.exit_code()),
signal: exit_status.and_then(|e| e.signal().map(Into::into)),
+ meta: None,
}),
+ meta: None,
}
} else {
let (current_content, original_len) = self.truncated_output(cx);
@@ -114,6 +117,7 @@ impl Terminal {
truncated: current_content.len() < original_len,
output: current_content,
exit_status: None,
+ meta: None,
}
}
}
@@ -747,6 +747,7 @@ impl NativeAgentConnection {
acp::ContentBlock::Text(acp::TextContent {
text,
annotations: None,
+ meta: None,
}),
false,
cx,
@@ -759,6 +760,7 @@ impl NativeAgentConnection {
acp::ContentBlock::Text(acp::TextContent {
text,
annotations: None,
+ meta: None,
}),
true,
cx,
@@ -804,7 +806,10 @@ impl NativeAgentConnection {
}
ThreadEvent::Stop(stop_reason) => {
log::debug!("Assistant message complete: {:?}", stop_reason);
- return Ok(acp::PromptResponse { stop_reason });
+ return Ok(acp::PromptResponse {
+ stop_reason,
+ meta: None,
+ });
}
}
}
@@ -818,6 +823,7 @@ impl NativeAgentConnection {
log::debug!("Response stream completed");
anyhow::Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
+ meta: None,
})
})
}
@@ -1441,6 +1447,7 @@ mod tests {
mime_type: None,
size: None,
title: None,
+ meta: None,
}),
" mean?".into(),
],
@@ -1299,6 +1299,7 @@ async fn test_cancellation(cx: &mut TestAppContext) {
status: Some(acp::ToolCallStatus::Completed),
..
},
+ meta: None,
},
)) if Some(&id) == echo_id.as_ref() => {
echo_completed = true;
@@ -1926,6 +1927,7 @@ async fn test_agent_connection(cx: &mut TestAppContext) {
acp::PromptRequest {
session_id: session_id.clone(),
prompt: vec!["ghi".into()],
+ meta: None,
},
cx,
)
@@ -1990,6 +1992,7 @@ async fn test_tool_updates_to_completion(cx: &mut TestAppContext) {
locations: vec![],
raw_input: Some(json!({})),
raw_output: None,
+ meta: None,
}
);
let update = expect_tool_call_update_fields(&mut events).await;
@@ -2003,6 +2006,7 @@ async fn test_tool_updates_to_completion(cx: &mut TestAppContext) {
raw_input: Some(json!({ "content": "Thinking hard!" })),
..Default::default()
},
+ meta: None,
}
);
let update = expect_tool_call_update_fields(&mut events).await;
@@ -2014,6 +2018,7 @@ async fn test_tool_updates_to_completion(cx: &mut TestAppContext) {
status: Some(acp::ToolCallStatus::InProgress),
..Default::default()
},
+ meta: None,
}
);
let update = expect_tool_call_update_fields(&mut events).await;
@@ -2025,6 +2030,7 @@ async fn test_tool_updates_to_completion(cx: &mut TestAppContext) {
content: Some(vec!["Thinking hard!".into()]),
..Default::default()
},
+ meta: None,
}
);
let update = expect_tool_call_update_fields(&mut events).await;
@@ -2037,6 +2043,7 @@ async fn test_tool_updates_to_completion(cx: &mut TestAppContext) {
raw_output: Some("Finished thinking.".into()),
..Default::default()
},
+ meta: None,
}
);
}
@@ -614,6 +614,7 @@ impl Thread {
fn prompt_capabilities(model: Option<&dyn LanguageModel>) -> acp::PromptCapabilities {
let image = model.map_or(true, |model| model.supports_images());
acp::PromptCapabilities {
+ meta: None,
image,
audio: false,
embedded_context: true,
@@ -728,6 +729,7 @@ impl Thread {
stream
.0
.unbounded_send(Ok(ThreadEvent::ToolCall(acp::ToolCall {
+ meta: None,
id: acp::ToolCallId(tool_use.id.to_string().into()),
title: tool_use.name.to_string(),
kind: acp::ToolKind::Other,
@@ -2333,6 +2335,7 @@ impl ThreadEventStream {
input: serde_json::Value,
) -> acp::ToolCall {
acp::ToolCall {
+ meta: None,
id: acp::ToolCallId(id.to_string().into()),
title,
kind,
@@ -2352,6 +2355,7 @@ impl ThreadEventStream {
self.0
.unbounded_send(Ok(ThreadEvent::ToolCallUpdate(
acp::ToolCallUpdate {
+ meta: None,
id: acp::ToolCallId(tool_use_id.to_string().into()),
fields,
}
@@ -2437,6 +2441,7 @@ impl ToolCallEventStream {
.unbounded_send(Ok(ThreadEvent::ToolCallAuthorization(
ToolCallAuthorization {
tool_call: acp::ToolCallUpdate {
+ meta: None,
id: acp::ToolCallId(self.tool_use_id.to_string().into()),
fields: acp::ToolCallUpdateFields {
title: Some(title.into()),
@@ -2448,16 +2453,19 @@ impl ToolCallEventStream {
id: acp::PermissionOptionId("always_allow".into()),
name: "Always Allow".into(),
kind: acp::PermissionOptionKind::AllowAlways,
+ meta: None,
},
acp::PermissionOption {
id: acp::PermissionOptionId("allow".into()),
name: "Allow".into(),
kind: acp::PermissionOptionKind::AllowOnce,
+ meta: None,
},
acp::PermissionOption {
id: acp::PermissionOptionId("deny".into()),
name: "Deny".into(),
kind: acp::PermissionOptionKind::RejectOnce,
+ meta: None,
},
],
response: response_tx,
@@ -2611,17 +2619,21 @@ impl From<UserMessageContent> for acp::ContentBlock {
UserMessageContent::Text(text) => acp::ContentBlock::Text(acp::TextContent {
text,
annotations: None,
+ meta: None,
}),
UserMessageContent::Image(image) => acp::ContentBlock::Image(acp::ImageContent {
data: image.source.to_string(),
mime_type: "image/png".to_string(),
+ meta: None,
annotations: None,
uri: None,
}),
UserMessageContent::Mention { uri, content } => {
acp::ContentBlock::Resource(acp::EmbeddedResource {
+ meta: None,
resource: acp::EmbeddedResourceResource::TextResourceContents(
acp::TextResourceContents {
+ meta: None,
mime_type: None,
text: content,
uri: uri.to_uri().to_string(),
@@ -274,6 +274,7 @@ impl AgentTool for EditFileTool {
locations: Some(vec![acp::ToolCallLocation {
path: abs_path,
line: None,
+ meta: None,
}]),
..Default::default()
});
@@ -353,7 +354,7 @@ impl AgentTool for EditFileTool {
}).ok();
if let Some(abs_path) = abs_path.clone() {
event_stream.update_fields(ToolCallUpdateFields {
- locations: Some(vec![ToolCallLocation { path: abs_path, line }]),
+ locations: Some(vec![ToolCallLocation { path: abs_path, line, meta: None }]),
..Default::default()
});
}
@@ -138,6 +138,7 @@ impl AgentTool for FindPathTool {
mime_type: None,
size: None,
title: None,
+ meta: None,
}),
})
.collect(),
@@ -149,6 +149,7 @@ impl AgentTool for ReadFileTool {
locations: Some(vec![acp::ToolCallLocation {
path: abs_path.clone(),
line: input.start_line.map(|line| line.saturating_sub(1)),
+ meta: None,
}]),
..Default::default()
});
@@ -122,6 +122,7 @@ fn emit_update(response: &WebSearchResponse, event_stream: &ToolCallEventStream)
mime_type: None,
annotations: None,
size: None,
+ meta: None,
}),
})
.collect(),
@@ -13,7 +13,7 @@ use util::ResultExt as _;
use std::path::PathBuf;
use std::{any::Any, cell::RefCell};
-use std::{path::Path, rc::Rc};
+use std::{path::Path, rc::Rc, sync::Arc};
use thiserror::Error;
use anyhow::{Context as _, Result};
@@ -156,9 +156,12 @@ impl AcpConnection {
fs: acp::FileSystemCapability {
read_text_file: true,
write_text_file: true,
+ meta: None,
},
terminal: true,
+ meta: None,
},
+ meta: None,
})
.await?;
@@ -226,6 +229,7 @@ impl AgentConnection for AcpConnection {
.map(|(name, value)| acp::EnvVariable {
name: name.clone(),
value: value.clone(),
+ meta: None,
})
.collect()
} else {
@@ -243,7 +247,7 @@ impl AgentConnection for AcpConnection {
cx.spawn(async move |cx| {
let response = conn
- .new_session(acp::NewSessionRequest { mcp_servers, cwd })
+ .new_session(acp::NewSessionRequest { mcp_servers, cwd, meta: None })
.await
.map_err(|err| {
if err.code == acp::ErrorCode::AUTH_REQUIRED.code {
@@ -277,6 +281,7 @@ impl AgentConnection for AcpConnection {
let result = conn.set_session_mode(acp::SetSessionModeRequest {
session_id,
mode_id: default_mode,
+ meta: None,
})
.await.log_err();
@@ -316,7 +321,7 @@ impl AgentConnection for AcpConnection {
action_log,
session_id.clone(),
// ACP doesn't currently support per-session prompt capabilities or changing capabilities dynamically.
- watch::Receiver::constant(self.agent_capabilities.prompt_capabilities),
+ watch::Receiver::constant(self.agent_capabilities.prompt_capabilities.clone()),
cx,
)
})?;
@@ -339,13 +344,13 @@ impl AgentConnection for AcpConnection {
fn authenticate(&self, method_id: acp::AuthMethodId, cx: &mut App) -> Task<Result<()>> {
let conn = self.connection.clone();
cx.foreground_executor().spawn(async move {
- let result = conn
- .authenticate(acp::AuthenticateRequest {
- method_id: method_id.clone(),
- })
- .await?;
+ conn.authenticate(acp::AuthenticateRequest {
+ method_id: method_id.clone(),
+ meta: None,
+ })
+ .await?;
- Ok(result)
+ Ok(())
})
}
@@ -396,6 +401,7 @@ impl AgentConnection for AcpConnection {
{
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::Cancelled,
+ meta: None,
})
} else {
Err(anyhow!(details))
@@ -415,6 +421,7 @@ impl AgentConnection for AcpConnection {
let conn = self.connection.clone();
let params = acp::CancelNotification {
session_id: session_id.clone(),
+ meta: None,
};
cx.foreground_executor()
.spawn(async move { conn.cancel(params).await })
@@ -478,6 +485,7 @@ impl acp_thread::AgentSessionModes for AcpSessionModes {
.set_session_mode(acp::SetSessionModeRequest {
session_id,
mode_id,
+ meta: None,
})
.await;
@@ -526,13 +534,16 @@ impl acp::Client for ClientDelegate {
let outcome = task.await;
- Ok(acp::RequestPermissionResponse { outcome })
+ Ok(acp::RequestPermissionResponse {
+ outcome,
+ meta: None,
+ })
}
async fn write_text_file(
&self,
arguments: acp::WriteTextFileRequest,
- ) -> Result<(), acp::Error> {
+ ) -> Result<acp::WriteTextFileResponse, acp::Error> {
let cx = &mut self.cx.clone();
let task = self
.session_thread(&arguments.session_id)?
@@ -542,7 +553,7 @@ impl acp::Client for ClientDelegate {
task.await?;
- Ok(())
+ Ok(Default::default())
}
async fn read_text_file(
@@ -558,7 +569,10 @@ impl acp::Client for ClientDelegate {
let content = task.await?;
- Ok(acp::ReadTextFileResponse { content })
+ Ok(acp::ReadTextFileResponse {
+ content,
+ meta: None,
+ })
}
async fn session_notification(
@@ -607,26 +621,49 @@ impl acp::Client for ClientDelegate {
Ok(
terminal.read_with(&self.cx, |terminal, _| acp::CreateTerminalResponse {
terminal_id: terminal.id().clone(),
+ meta: None,
})?,
)
}
- async fn kill_terminal(&self, args: acp::KillTerminalRequest) -> Result<(), acp::Error> {
+ async fn kill_terminal_command(
+ &self,
+ args: acp::KillTerminalCommandRequest,
+ ) -> Result<acp::KillTerminalCommandResponse, acp::Error> {
self.session_thread(&args.session_id)?
.update(&mut self.cx.clone(), |thread, cx| {
thread.kill_terminal(args.terminal_id, cx)
})??;
- Ok(())
+ Ok(Default::default())
}
- async fn release_terminal(&self, args: acp::ReleaseTerminalRequest) -> Result<(), acp::Error> {
+ async fn ext_method(
+ &self,
+ _name: Arc<str>,
+ _params: Arc<serde_json::value::RawValue>,
+ ) -> Result<Arc<serde_json::value::RawValue>, acp::Error> {
+ Err(acp::Error::method_not_found())
+ }
+
+ async fn ext_notification(
+ &self,
+ _name: Arc<str>,
+ _params: Arc<serde_json::value::RawValue>,
+ ) -> Result<(), acp::Error> {
+ Err(acp::Error::method_not_found())
+ }
+
+ async fn release_terminal(
+ &self,
+ args: acp::ReleaseTerminalRequest,
+ ) -> Result<acp::ReleaseTerminalResponse, acp::Error> {
self.session_thread(&args.session_id)?
.update(&mut self.cx.clone(), |thread, cx| {
thread.release_terminal(args.terminal_id, cx)
})??;
- Ok(())
+ Ok(Default::default())
}
async fn terminal_output(
@@ -655,7 +692,10 @@ impl acp::Client for ClientDelegate {
})??
.await;
- Ok(acp::WaitForTerminalExitResponse { exit_status })
+ Ok(acp::WaitForTerminalExitResponse {
+ exit_status,
+ meta: None,
+ })
}
}
@@ -83,6 +83,7 @@ where
acp::ContentBlock::Text(acp::TextContent {
text: "Read the file ".into(),
annotations: None,
+ meta: None,
}),
acp::ContentBlock::ResourceLink(acp::ResourceLink {
uri: "foo.rs".into(),
@@ -92,10 +93,12 @@ where
mime_type: None,
size: None,
title: None,
+ meta: None,
}),
acp::ContentBlock::Text(acp::TextContent {
text: " and tell me what the content of the println! is".into(),
annotations: None,
+ meta: None,
}),
],
cx,
@@ -1,4 +1,4 @@
-use std::cell::{Cell, RefCell};
+use std::cell::RefCell;
use std::ops::Range;
use std::rc::Rc;
use std::sync::Arc;
@@ -68,7 +68,7 @@ pub struct ContextPickerCompletionProvider {
workspace: WeakEntity<Workspace>,
history_store: Entity<HistoryStore>,
prompt_store: Option<Entity<PromptStore>>,
- prompt_capabilities: Rc<Cell<acp::PromptCapabilities>>,
+ prompt_capabilities: Rc<RefCell<acp::PromptCapabilities>>,
available_commands: Rc<RefCell<Vec<acp::AvailableCommand>>>,
}
@@ -78,7 +78,7 @@ impl ContextPickerCompletionProvider {
workspace: WeakEntity<Workspace>,
history_store: Entity<HistoryStore>,
prompt_store: Option<Entity<PromptStore>>,
- prompt_capabilities: Rc<Cell<acp::PromptCapabilities>>,
+ prompt_capabilities: Rc<RefCell<acp::PromptCapabilities>>,
available_commands: Rc<RefCell<Vec<acp::AvailableCommand>>>,
) -> Self {
Self {
@@ -600,7 +600,7 @@ impl ContextPickerCompletionProvider {
}),
);
- if self.prompt_capabilities.get().embedded_context {
+ if self.prompt_capabilities.borrow().embedded_context {
const RECENT_COUNT: usize = 2;
let threads = self
.history_store
@@ -622,7 +622,7 @@ impl ContextPickerCompletionProvider {
workspace: &Entity<Workspace>,
cx: &mut App,
) -> Vec<ContextPickerEntry> {
- let embedded_context = self.prompt_capabilities.get().embedded_context;
+ let embedded_context = self.prompt_capabilities.borrow().embedded_context;
let mut entries = if embedded_context {
vec![
ContextPickerEntry::Mode(ContextPickerMode::File),
@@ -694,7 +694,7 @@ impl CompletionProvider for ContextPickerCompletionProvider {
ContextCompletion::try_parse(
line,
offset_to_line,
- self.prompt_capabilities.get().embedded_context,
+ self.prompt_capabilities.borrow().embedded_context,
)
});
let Some(state) = state else {
@@ -896,7 +896,7 @@ impl CompletionProvider for ContextPickerCompletionProvider {
ContextCompletion::try_parse(
line,
offset_to_line,
- self.prompt_capabilities.get().embedded_context,
+ self.prompt_capabilities.borrow().embedded_context,
)
.map(|completion| {
completion.source_range().start <= offset_to_line + position.column as usize
@@ -1,8 +1,4 @@
-use std::{
- cell::{Cell, RefCell},
- ops::Range,
- rc::Rc,
-};
+use std::{cell::RefCell, ops::Range, rc::Rc};
use acp_thread::{AcpThread, AgentThreadEntry};
use agent_client_protocol::{self as acp, ToolCallId};
@@ -30,7 +26,7 @@ pub struct EntryViewState {
history_store: Entity<HistoryStore>,
prompt_store: Option<Entity<PromptStore>>,
entries: Vec<Entry>,
- prompt_capabilities: Rc<Cell<acp::PromptCapabilities>>,
+ prompt_capabilities: Rc<RefCell<acp::PromptCapabilities>>,
available_commands: Rc<RefCell<Vec<acp::AvailableCommand>>>,
agent_name: SharedString,
}
@@ -41,7 +37,7 @@ impl EntryViewState {
project: Entity<Project>,
history_store: Entity<HistoryStore>,
prompt_store: Option<Entity<PromptStore>>,
- prompt_capabilities: Rc<Cell<acp::PromptCapabilities>>,
+ prompt_capabilities: Rc<RefCell<acp::PromptCapabilities>>,
available_commands: Rc<RefCell<Vec<acp::AvailableCommand>>>,
agent_name: SharedString,
) -> Self {
@@ -448,11 +444,13 @@ mod tests {
path: "/project/hello.txt".into(),
old_text: Some("hi world".into()),
new_text: "hello world".into(),
+ meta: None,
},
}],
locations: vec![],
raw_input: None,
raw_output: None,
+ meta: None,
};
let connection = Rc::new(StubAgentConnection::new());
let thread = cx
@@ -36,7 +36,7 @@ use prompt_store::{PromptId, PromptStore};
use rope::Point;
use settings::Settings;
use std::{
- cell::{Cell, RefCell},
+ cell::RefCell,
ffi::OsStr,
fmt::Write,
ops::{Range, RangeInclusive},
@@ -64,7 +64,7 @@ pub struct MessageEditor {
workspace: WeakEntity<Workspace>,
history_store: Entity<HistoryStore>,
prompt_store: Option<Entity<PromptStore>>,
- prompt_capabilities: Rc<Cell<acp::PromptCapabilities>>,
+ prompt_capabilities: Rc<RefCell<acp::PromptCapabilities>>,
available_commands: Rc<RefCell<Vec<acp::AvailableCommand>>>,
agent_name: SharedString,
_subscriptions: Vec<Subscription>,
@@ -89,7 +89,7 @@ impl MessageEditor {
project: Entity<Project>,
history_store: Entity<HistoryStore>,
prompt_store: Option<Entity<PromptStore>>,
- prompt_capabilities: Rc<Cell<acp::PromptCapabilities>>,
+ prompt_capabilities: Rc<RefCell<acp::PromptCapabilities>>,
available_commands: Rc<RefCell<Vec<acp::AvailableCommand>>>,
agent_name: SharedString,
placeholder: &str,
@@ -428,7 +428,7 @@ impl MessageEditor {
.unwrap_or_default();
if Img::extensions().contains(&extension) && !extension.contains("svg") {
- if !self.prompt_capabilities.get().image {
+ if !self.prompt_capabilities.borrow().image {
return Task::ready(Err(anyhow!("This model does not support images yet")));
}
let task = self
@@ -789,7 +789,7 @@ impl MessageEditor {
let contents = self
.mention_set
- .contents(&self.prompt_capabilities.get(), cx);
+ .contents(&self.prompt_capabilities.borrow(), cx);
let editor = self.editor.clone();
cx.spawn(async move |_, cx| {
@@ -834,8 +834,10 @@ impl MessageEditor {
mime_type: None,
text: content.clone(),
uri: uri.to_uri().to_string(),
+ meta: None,
},
),
+ meta: None,
})
}
Mention::Image(mention_image) => {
@@ -855,6 +857,7 @@ impl MessageEditor {
data: mention_image.data.to_string(),
mime_type: mention_image.format.mime_type().into(),
uri,
+ meta: None,
})
}
Mention::UriOnly => {
@@ -866,6 +869,7 @@ impl MessageEditor {
mime_type: None,
size: None,
title: None,
+ meta: None,
})
}
};
@@ -920,7 +924,7 @@ impl MessageEditor {
}
fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
- if !self.prompt_capabilities.get().image {
+ if !self.prompt_capabilities.borrow().image {
return;
}
@@ -1188,6 +1192,7 @@ impl MessageEditor {
data,
mime_type,
annotations: _,
+ meta: _,
}) => {
let mention_uri = if let Some(uri) = uri {
MentionUri::parse(&uri)
@@ -1571,13 +1576,7 @@ impl Addon for MessageEditorAddon {
#[cfg(test)]
mod tests {
- use std::{
- cell::{Cell, RefCell},
- ops::Range,
- path::Path,
- rc::Rc,
- sync::Arc,
- };
+ use std::{cell::RefCell, ops::Range, path::Path, rc::Rc, sync::Arc};
use acp_thread::MentionUri;
use agent_client_protocol as acp;
@@ -1724,7 +1723,7 @@ mod tests {
let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await;
let context_store = cx.new(|cx| ContextStore::fake(project.clone(), cx));
let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
- let prompt_capabilities = Rc::new(Cell::new(acp::PromptCapabilities::default()));
+ let prompt_capabilities = Rc::new(RefCell::new(acp::PromptCapabilities::default()));
// Start with no available commands - simulating Claude which doesn't support slash commands
let available_commands = Rc::new(RefCell::new(vec![]));
@@ -1773,6 +1772,7 @@ mod tests {
name: "help".to_string(),
description: "Get help".to_string(),
input: None,
+ meta: None,
}]);
// Test that unsupported slash commands trigger an error when we have a list of available commands
@@ -1887,12 +1887,13 @@ mod tests {
let context_store = cx.new(|cx| ContextStore::fake(project.clone(), cx));
let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
- let prompt_capabilities = Rc::new(Cell::new(acp::PromptCapabilities::default()));
+ let prompt_capabilities = Rc::new(RefCell::new(acp::PromptCapabilities::default()));
let available_commands = Rc::new(RefCell::new(vec![
acp::AvailableCommand {
name: "quick-math".to_string(),
description: "2 + 2 = 4 - 1 = 3".to_string(),
input: None,
+ meta: None,
},
acp::AvailableCommand {
name: "say-hello".to_string(),
@@ -1900,6 +1901,7 @@ mod tests {
input: Some(acp::AvailableCommandInput::Unstructured {
hint: "<name>".to_string(),
}),
+ meta: None,
},
]));
@@ -2134,7 +2136,7 @@ mod tests {
let context_store = cx.new(|cx| ContextStore::fake(project.clone(), cx));
let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
- let prompt_capabilities = Rc::new(Cell::new(acp::PromptCapabilities::default()));
+ let prompt_capabilities = Rc::new(RefCell::new(acp::PromptCapabilities::default()));
let (message_editor, editor) = workspace.update_in(&mut cx, |workspace, window, cx| {
let workspace_handle = cx.weak_entity();
@@ -2189,10 +2191,11 @@ mod tests {
editor.set_text("", window, cx);
});
- prompt_capabilities.set(acp::PromptCapabilities {
+ prompt_capabilities.replace(acp::PromptCapabilities {
image: true,
audio: true,
embedded_context: true,
+ meta: None,
});
cx.simulate_input("Lorem ");
@@ -2264,6 +2267,7 @@ mod tests {
image: true,
audio: true,
embedded_context: true,
+ meta: None,
};
let contents = message_editor
@@ -2640,8 +2644,9 @@ mod tests {
cx,
);
// Enable embedded context so files are actually included
- editor.prompt_capabilities.set(acp::PromptCapabilities {
+ editor.prompt_capabilities.replace(acp::PromptCapabilities {
embedded_context: true,
+ meta: None,
..Default::default()
});
editor
@@ -37,7 +37,7 @@ use project::{Project, ProjectEntryId};
use prompt_store::{PromptId, PromptStore};
use rope::Point;
use settings::{Settings as _, SettingsStore};
-use std::cell::{Cell, RefCell};
+use std::cell::RefCell;
use std::path::Path;
use std::sync::Arc;
use std::time::Instant;
@@ -290,7 +290,7 @@ pub struct AcpThreadView {
editor_expanded: bool,
should_be_following: bool,
editing_message: Option<usize>,
- prompt_capabilities: Rc<Cell<PromptCapabilities>>,
+ prompt_capabilities: Rc<RefCell<PromptCapabilities>>,
available_commands: Rc<RefCell<Vec<acp::AvailableCommand>>>,
is_loading_contents: bool,
new_server_version_available: Option<SharedString>,
@@ -334,7 +334,7 @@ impl AcpThreadView {
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
- let prompt_capabilities = Rc::new(Cell::new(acp::PromptCapabilities::default()));
+ let prompt_capabilities = Rc::new(RefCell::new(acp::PromptCapabilities::default()));
let available_commands = Rc::new(RefCell::new(vec![]));
let placeholder = if agent.name() == "Zed Agent" {
@@ -559,7 +559,7 @@ impl AcpThreadView {
let action_log = thread.read(cx).action_log().clone();
this.prompt_capabilities
- .set(thread.read(cx).prompt_capabilities());
+ .replace(thread.read(cx).prompt_capabilities());
let count = thread.read(cx).entries().len();
this.entry_view_state.update(cx, |view_state, cx| {
@@ -1373,7 +1373,7 @@ impl AcpThreadView {
}
AcpThreadEvent::PromptCapabilitiesUpdated => {
self.prompt_capabilities
- .set(thread.read(cx).prompt_capabilities());
+ .replace(thread.read(cx).prompt_capabilities());
}
AcpThreadEvent::TokenUsageUpdated => {}
AcpThreadEvent::AvailableCommandsUpdated(available_commands) => {
@@ -1390,11 +1390,13 @@ impl AcpThreadView {
name: "login".to_owned(),
description: "Authenticate".to_owned(),
input: None,
+ meta: None,
});
available_commands.push(acp::AvailableCommand {
name: "logout".to_owned(),
description: "Authenticate".to_owned(),
input: None,
+ meta: None,
});
}
@@ -5722,6 +5724,7 @@ pub(crate) mod tests {
locations: vec![],
raw_input: None,
raw_output: None,
+ meta: None,
};
let connection =
StubAgentConnection::new().with_permission_requests(HashMap::from_iter([(
@@ -5730,6 +5733,7 @@ pub(crate) mod tests {
id: acp::PermissionOptionId("1".into()),
name: "Allow".into(),
kind: acp::PermissionOptionKind::AllowOnce,
+ meta: None,
}],
)]));
@@ -5906,6 +5910,7 @@ pub(crate) mod tests {
image: true,
audio: true,
embedded_context: true,
+ meta: None,
}),
cx,
)
@@ -5965,6 +5970,7 @@ pub(crate) mod tests {
image: true,
audio: true,
embedded_context: true,
+ meta: None,
}),
cx,
)
@@ -5991,6 +5997,7 @@ pub(crate) mod tests {
) -> Task<gpui::Result<acp::PromptResponse>> {
Task::ready(Ok(acp::PromptResponse {
stop_reason: acp::StopReason::Refusal,
+ meta: None,
}))
}
@@ -6074,11 +6081,13 @@ pub(crate) mod tests {
path: "/project/test1.txt".into(),
old_text: Some("old content 1".into()),
new_text: "new content 1".into(),
+ meta: None,
},
}],
locations: vec![],
raw_input: None,
raw_output: None,
+ meta: None,
})]);
thread
@@ -6115,11 +6124,13 @@ pub(crate) mod tests {
path: "/project/test2.txt".into(),
old_text: Some("old content 2".into()),
new_text: "new content 2".into(),
+ meta: None,
},
}],
locations: vec![],
raw_input: None,
raw_output: None,
+ meta: None,
})]);
thread
@@ -6197,6 +6208,7 @@ pub(crate) mod tests {
content: acp::ContentBlock::Text(acp::TextContent {
text: "Response".into(),
annotations: None,
+ meta: None,
}),
}]);
@@ -6286,6 +6298,7 @@ pub(crate) mod tests {
content: acp::ContentBlock::Text(acp::TextContent {
text: "Response".into(),
annotations: None,
+ meta: None,
}),
}]);
@@ -6329,6 +6342,7 @@ pub(crate) mod tests {
content: acp::ContentBlock::Text(acp::TextContent {
text: "New Response".into(),
annotations: None,
+ meta: None,
}),
}]);
@@ -6421,6 +6435,7 @@ pub(crate) mod tests {
content: acp::ContentBlock::Text(acp::TextContent {
text: "Response".into(),
annotations: None,
+ meta: None,
}),
},
cx,