deps: upgrade agent-client-protocol to 0.9.0 (#6109)

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Adrian Cole
2025-12-17 01:50:47 +01:00
committed by GitHub
parent 34b20ae0fe
commit 062fc07432
4 changed files with 186 additions and 183 deletions
Generated
+77 -4
View File
@@ -30,19 +30,33 @@ dependencies = [
[[package]] [[package]]
name = "agent-client-protocol" name = "agent-client-protocol"
version = "0.4.0" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2526e80463b9742afed4829aedd6ae5632d6db778c6cc1fecb80c960c3521b" checksum = "c2ffe7d502c1e451aafc5aff655000f84d09c9af681354ac0012527009b1af13"
dependencies = [ dependencies = [
"agent-client-protocol-schema",
"anyhow", "anyhow",
"async-broadcast", "async-broadcast",
"async-trait", "async-trait",
"derive_more",
"futures", "futures",
"log", "log",
"parking_lot", "serde",
"serde_json",
]
[[package]]
name = "agent-client-protocol-schema"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50cbb9a55080793c01e5e97c6fb0f1032d1f2460f7e3869225813cfa29001585"
dependencies = [
"anyhow",
"derive_more",
"schemars", "schemars",
"serde", "serde",
"serde_json", "serde_json",
"strum",
] ]
[[package]] [[package]]
@@ -1658,7 +1672,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf" checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"convert_case", "convert_case 0.6.0",
"json5", "json5",
"nom", "nom",
"pathdiff", "pathdiff",
@@ -1739,6 +1753,15 @@ dependencies = [
"unicode-segmentation", "unicode-segmentation",
] ]
[[package]]
name = "convert_case"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
dependencies = [
"unicode-segmentation",
]
[[package]] [[package]]
name = "cookie" name = "cookie"
version = "0.18.1" version = "0.18.1"
@@ -2176,6 +2199,29 @@ dependencies = [
"syn 2.0.111", "syn 2.0.111",
] ]
[[package]]
name = "derive_more"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b"
dependencies = [
"convert_case 0.10.0",
"proc-macro2",
"quote",
"rustc_version 0.4.1",
"syn 2.0.111",
"unicode-xid",
]
[[package]] [[package]]
name = "devgen-tree-sitter-swift" name = "devgen-tree-sitter-swift"
version = "0.21.0" version = "0.21.0"
@@ -7287,6 +7333,27 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "strum"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.111",
]
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.6.1" version = "2.6.1"
@@ -8347,6 +8414,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]] [[package]]
name = "unicode_categories" name = "unicode_categories"
version = "0.1.1" version = "0.1.1"
+1 -1
View File
@@ -19,7 +19,7 @@ goose = { path = "../goose" }
goose-bench = { path = "../goose-bench" } goose-bench = { path = "../goose-bench" }
goose-mcp = { path = "../goose-mcp" } goose-mcp = { path = "../goose-mcp" }
rmcp = { workspace = true } rmcp = { workspace = true }
agent-client-protocol = "0.4.0" agent-client-protocol = "0.9.0"
clap = { version = "4.4", features = ["derive"] } clap = { version = "4.4", features = ["derive"] }
cliclack = "0.3.5" cliclack = "0.3.5"
console = "0.15.8" console = "0.15.8"
+107 -177
View File
@@ -1,6 +1,6 @@
use agent_client_protocol::{ use agent_client_protocol::{
self as acp, Client, EmbeddedResource, ImageContent, SessionNotification, TextContent, self as acp, Client, Content, ContentChunk, EmbeddedResource, ExtResponse, ImageContent,
ToolCallContent, ProtocolVersion, SessionNotification, TextContent, ToolCallContent,
}; };
use anyhow::Result; use anyhow::Result;
use goose::agents::{Agent, SessionConfig}; use goose::agents::{Agent, SessionConfig};
@@ -37,11 +37,7 @@ struct GooseAcpAgent {
/// Create a ToolCallLocation with common defaults /// Create a ToolCallLocation with common defaults
fn create_tool_location(path: &str, line: Option<u32>) -> acp::ToolCallLocation { fn create_tool_location(path: &str, line: Option<u32>) -> acp::ToolCallLocation {
acp::ToolCallLocation { acp::ToolCallLocation::new(path).line(line)
path: path.into(),
line,
meta: None,
}
} }
/// Extract file locations from tool request and response /// Extract file locations from tool request and response
@@ -320,6 +316,7 @@ impl GooseAcpAgent {
} }
} }
acp::ContentBlock::Audio(..) => (), acp::ContentBlock::Audio(..) => (),
_ => (),
} }
} }
@@ -338,13 +335,12 @@ impl GooseAcpAgent {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.session_update_tx self.session_update_tx
.send(( .send((
SessionNotification { SessionNotification::new(
session_id: session_id.clone(), session_id.clone(),
update: acp::SessionUpdate::AgentMessageChunk { acp::SessionUpdate::AgentMessageChunk(ContentChunk::new(
content: text.text.clone().into(), acp::ContentBlock::Text(TextContent::new(text.text.clone())),
}, )),
meta: None, ),
},
tx, tx,
)) ))
.map_err(|_| acp::Error::internal_error())?; .map_err(|_| acp::Error::internal_error())?;
@@ -363,13 +359,14 @@ impl GooseAcpAgent {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.session_update_tx self.session_update_tx
.send(( .send((
SessionNotification { SessionNotification::new(
session_id: session_id.clone(), session_id.clone(),
update: acp::SessionUpdate::AgentThoughtChunk { acp::SessionUpdate::AgentThoughtChunk(ContentChunk::new(
content: thinking.thinking.clone().into(), acp::ContentBlock::Text(TextContent::new(
}, thinking.thinking.clone(),
meta: None, )),
}, )),
),
tx, tx,
)) ))
.map_err(|_| acp::Error::internal_error())?; .map_err(|_| acp::Error::internal_error())?;
@@ -410,21 +407,16 @@ impl GooseAcpAgent {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.session_update_tx self.session_update_tx
.send(( .send((
SessionNotification { SessionNotification::new(
session_id: session_id.clone(), session_id.clone(),
update: acp::SessionUpdate::ToolCall(acp::ToolCall { acp::SessionUpdate::ToolCall(
id: acp::ToolCallId(acp_tool_id.clone().into()), acp::ToolCall::new(
title: format_tool_name(&tool_name), acp::ToolCallId::new(acp_tool_id.clone()),
kind: acp::ToolKind::default(), format_tool_name(&tool_name),
status: acp::ToolCallStatus::Pending, )
content: Vec::new(), .status(acp::ToolCallStatus::Pending),
locations: Vec::new(), // Will be populated in handle_tool_response ),
raw_input: None, ),
raw_output: None,
meta: None,
}),
meta: None,
},
tx, tx,
)) ))
.map_err(|_| acp::Error::internal_error())?; .map_err(|_| acp::Error::internal_error())?;
@@ -462,24 +454,20 @@ impl GooseAcpAgent {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.session_update_tx self.session_update_tx
.send(( .send((
SessionNotification { SessionNotification::new(
session_id: session_id.clone(), session_id.clone(),
update: acp::SessionUpdate::ToolCallUpdate(acp::ToolCallUpdate { acp::SessionUpdate::ToolCallUpdate(acp::ToolCallUpdate::new(
id: acp::ToolCallId(acp_tool_id.clone().into()), acp::ToolCallId::new(acp_tool_id.clone()),
fields: acp::ToolCallUpdateFields { acp::ToolCallUpdateFields::new()
status: Some(status), .status(status)
content: Some(content), .content(content)
locations: if locations.is_empty() { .locations(if locations.is_empty() {
None None
} else { } else {
Some(locations) Some(locations)
}, }),
..Default::default() )),
}, ),
meta: None,
}),
meta: None,
},
tx, tx,
)) ))
.map_err(|_| acp::Error::internal_error())?; .map_err(|_| acp::Error::internal_error())?;
@@ -497,56 +485,37 @@ fn build_tool_call_content(tool_result: &ToolResult<CallToolResult>) -> Vec<Tool
.content .content
.iter() .iter()
.filter_map(|content| match &content.raw { .filter_map(|content| match &content.raw {
RawContent::Text(val) => Some(ToolCallContent::Content { RawContent::Text(val) => Some(ToolCallContent::Content(Content::new(
content: acp::ContentBlock::Text(TextContent { acp::ContentBlock::Text(TextContent::new(val.text.clone())),
annotations: None, ))),
text: val.text.clone(), RawContent::Image(val) => Some(ToolCallContent::Content(Content::new(
meta: None, acp::ContentBlock::Image(ImageContent::new(
}), val.data.clone(),
}), val.mime_type.clone(),
RawContent::Image(val) => Some(ToolCallContent::Content { )),
content: acp::ContentBlock::Image(ImageContent { ))),
annotations: None, RawContent::Resource(val) => Some(ToolCallContent::Content(Content::new(
data: val.data.clone(), acp::ContentBlock::Resource(EmbeddedResource::new(match &val.resource {
mime_type: val.mime_type.clone(), ResourceContents::TextResourceContents {
uri: None, mime_type,
meta: None, text,
}), uri,
}), ..
RawContent::Resource(val) => Some(ToolCallContent::Content { } => acp::EmbeddedResourceResource::TextResourceContents(
content: acp::ContentBlock::Resource(EmbeddedResource { acp::TextResourceContents::new(text.clone(), uri.clone())
annotations: None, .mime_type(mime_type.clone()),
resource: match &val.resource { ),
ResourceContents::TextResourceContents { ResourceContents::BlobResourceContents {
mime_type, mime_type,
text, blob,
uri, uri,
.. ..
} => acp::EmbeddedResourceResource::TextResourceContents( } => acp::EmbeddedResourceResource::BlobResourceContents(
acp::TextResourceContents { acp::BlobResourceContents::new(blob.clone(), uri.clone())
mime_type: mime_type.clone(), .mime_type(mime_type.clone()),
text: text.clone(), ),
uri: uri.clone(), })),
meta: None, ))),
},
),
ResourceContents::BlobResourceContents {
mime_type,
blob,
uri,
..
} => acp::EmbeddedResourceResource::BlobResourceContents(
acp::BlobResourceContents {
mime_type: mime_type.clone(),
blob: blob.clone(),
uri: uri.clone(),
meta: None,
},
),
},
meta: None,
}),
}),
RawContent::Audio(_) => { RawContent::Audio(_) => {
// Audio content is not supported in ACP ContentBlock, skip it // Audio content is not supported in ACP ContentBlock, skip it
None None
@@ -570,28 +539,17 @@ impl acp::Agent for GooseAcpAgent {
info!("ACP: Received initialize request {:?}", args); info!("ACP: Received initialize request {:?}", args);
// Advertise Goose's capabilities // Advertise Goose's capabilities
let agent_capabilities = acp::AgentCapabilities { let agent_capabilities = acp::AgentCapabilities::new()
load_session: true, .load_session(true)
prompt_capabilities: acp::PromptCapabilities { .prompt_capabilities(
image: true, // Goose supports image inputs via providers acp::PromptCapabilities::new()
audio: false, // TODO: Add audio support when providers support it .image(true)
embedded_context: true, // Goose can handle embedded context resources .embedded_context(true),
meta: None, );
}, Ok(
mcp_capabilities: acp::McpCapabilities { acp::InitializeResponse::new(ProtocolVersion::V1)
http: false, // TODO: Add MCP HTTP support if needed .agent_capabilities(agent_capabilities),
sse: false, // TODO: Add MCP SSE support if needed )
meta: None,
},
meta: None,
};
Ok(acp::InitializeResponse {
protocol_version: acp::V1,
agent_capabilities,
auth_methods: Vec::new(),
meta: None,
})
} }
async fn authenticate( async fn authenticate(
@@ -599,7 +557,7 @@ impl acp::Agent for GooseAcpAgent {
args: acp::AuthenticateRequest, args: acp::AuthenticateRequest,
) -> Result<acp::AuthenticateResponse, acp::Error> { ) -> Result<acp::AuthenticateResponse, acp::Error> {
info!("ACP: Received authenticate request {:?}", args); info!("ACP: Received authenticate request {:?}", args);
Ok(acp::AuthenticateResponse { meta: None }) Ok(acp::AuthenticateResponse::new())
} }
async fn new_session( async fn new_session(
@@ -627,11 +585,7 @@ impl acp::Agent for GooseAcpAgent {
info!("Created new ACP/goose session {}", goose_session.id); info!("Created new ACP/goose session {}", goose_session.id);
Ok(acp::NewSessionResponse { Ok(acp::NewSessionResponse::new(goose_session.id))
session_id: acp::SessionId(goose_session.id.into()),
modes: None,
meta: None,
})
} }
async fn load_session( async fn load_session(
@@ -681,21 +635,17 @@ impl acp::Agent for GooseAcpAgent {
match content_item { match content_item {
MessageContent::Text(text) => { MessageContent::Text(text) => {
let update = match message.role { let update = match message.role {
Role::User => acp::SessionUpdate::UserMessageChunk { Role::User => acp::SessionUpdate::UserMessageChunk(ContentChunk::new(
content: text.text.clone().into(), text.text.clone().into(),
}, )),
Role::Assistant => acp::SessionUpdate::AgentMessageChunk { Role::Assistant => acp::SessionUpdate::AgentMessageChunk(
content: text.text.clone().into(), ContentChunk::new(text.text.clone().into()),
}, ),
}; };
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.session_update_tx self.session_update_tx
.send(( .send((
SessionNotification { SessionNotification::new(args.session_id.clone(), update),
session_id: args.session_id.clone(),
update,
meta: None,
},
tx, tx,
)) ))
.map_err(|_| acp::Error::internal_error())?; .map_err(|_| acp::Error::internal_error())?;
@@ -713,13 +663,12 @@ impl acp::Agent for GooseAcpAgent {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.session_update_tx self.session_update_tx
.send(( .send((
SessionNotification { SessionNotification::new(
session_id: args.session_id.clone(), args.session_id.clone(),
update: acp::SessionUpdate::AgentThoughtChunk { acp::SessionUpdate::AgentThoughtChunk(ContentChunk::new(
content: thinking.thinking.clone().into(), thinking.thinking.clone().into(),
}, )),
meta: None, ),
},
tx, tx,
)) ))
.map_err(|_| acp::Error::internal_error())?; .map_err(|_| acp::Error::internal_error())?;
@@ -737,10 +686,7 @@ impl acp::Agent for GooseAcpAgent {
info!("Loaded ACP session {}", session_id); info!("Loaded ACP session {}", session_id);
Ok(acp::LoadSessionResponse { Ok(acp::LoadSessionResponse::new())
modes: None,
meta: None,
})
} }
async fn prompt(&self, args: acp::PromptRequest) -> Result<acp::PromptResponse, acp::Error> { async fn prompt(&self, args: acp::PromptRequest) -> Result<acp::PromptResponse, acp::Error> {
@@ -810,14 +756,11 @@ impl acp::Agent for GooseAcpAgent {
session.cancel_token = None; session.cancel_token = None;
} }
Ok(acp::PromptResponse { Ok(acp::PromptResponse::new(if was_cancelled {
stop_reason: if was_cancelled { acp::StopReason::Cancelled
acp::StopReason::Cancelled } else {
} else { acp::StopReason::EndTurn
acp::StopReason::EndTurn }))
},
meta: None,
})
} }
async fn cancel(&self, args: acp::CancelNotification) -> Result<(), acp::Error> { async fn cancel(&self, args: acp::CancelNotification) -> Result<(), acp::Error> {
@@ -842,20 +785,14 @@ impl acp::Agent for GooseAcpAgent {
&self, &self,
_args: acp::SetSessionModeRequest, _args: acp::SetSessionModeRequest,
) -> Result<acp::SetSessionModeResponse, acp::Error> { ) -> Result<acp::SetSessionModeResponse, acp::Error> {
// TODO: Implement session modes if needed
Err(acp::Error::method_not_found()) Err(acp::Error::method_not_found())
} }
async fn ext_method( async fn ext_method(&self, _args: acp::ExtRequest) -> Result<ExtResponse, acp::Error> {
&self,
_args: acp::ExtRequest,
) -> Result<std::sync::Arc<acp::RawValue>, acp::Error> {
// TODO: Implement extension methods if needed
Err(acp::Error::method_not_found()) Err(acp::Error::method_not_found())
} }
async fn ext_notification(&self, _args: acp::ExtNotification) -> Result<(), acp::Error> { async fn ext_notification(&self, _args: acp::ExtNotification) -> Result<(), acp::Error> {
// TODO: Implement extension notifications if needed
Ok(()) Ok(())
} }
} }
@@ -917,21 +854,14 @@ mod tests {
let mut file = NamedTempFile::new()?; let mut file = NamedTempFile::new()?;
file.write_all(content.as_bytes())?; file.write_all(content.as_bytes())?;
let link = ResourceLink { let link = ResourceLink::new(
annotations: None, file.path()
description: None,
mime_type: None,
name: file
.path()
.file_name() .file_name()
.unwrap() .unwrap()
.to_string_lossy() .to_string_lossy()
.to_string(), .to_string(),
size: None, format!("file://{}", file.path().to_str().unwrap()),
title: None, );
uri: format!("file://{}", file.path().to_str().unwrap()),
meta: None,
};
Ok((link, file)) Ok((link, file))
} }
@@ -1122,7 +1122,7 @@ impl ComputerControllerServer {
let json_params = params let json_params = params
.params .params
.as_ref() .as_ref()
.map(|p| serde_json::to_value(p).unwrap_or_else(|_| serde_json::Value::Null)); .map(|p| serde_json::to_value(p).unwrap_or(serde_json::Value::Null));
let result = crate::computercontroller::docx_tool::docx_tool( let result = crate::computercontroller::docx_tool::docx_tool(
path, path,