mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
feat(acp): Read files (#4531)
This commit is contained in:
Generated
+9
-8
@@ -2376,9 +2376,9 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
@@ -2746,6 +2746,7 @@ dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
"tracing-subscriber",
|
||||
"url",
|
||||
"uuid",
|
||||
"webbrowser 1.0.4",
|
||||
"winapi",
|
||||
@@ -3346,9 +3347,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.0.3"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
|
||||
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
|
||||
dependencies = [
|
||||
"idna_adapter",
|
||||
"smallvec",
|
||||
@@ -4694,9 +4695,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
@@ -7035,9 +7036,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
version = "2.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
|
||||
checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
|
||||
@@ -60,6 +60,7 @@ indicatif = "0.17.11"
|
||||
tokio-util = { version = "0.7.15", features = ["compat"] }
|
||||
is-terminal = "0.4.16"
|
||||
anstream = "0.6.18"
|
||||
url = "2.5.7"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3", features = ["wincred"] }
|
||||
|
||||
@@ -6,12 +6,14 @@ use goose::conversation::message::{Message, MessageContent};
|
||||
use goose::conversation::Conversation;
|
||||
use goose::providers::create;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{mpsc, oneshot, Mutex};
|
||||
use tokio::task::JoinSet;
|
||||
use tokio_util::compat::{TokioAsyncReadCompatExt as _, TokioAsyncWriteCompatExt as _};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{error, info, warn};
|
||||
use url::Url;
|
||||
|
||||
/// Represents a single Goose session for ACP
|
||||
struct GooseSession {
|
||||
@@ -28,6 +30,22 @@ struct GooseAcpAgent {
|
||||
provider: Arc<dyn goose::providers::base::Provider>,
|
||||
}
|
||||
|
||||
fn read_resource_link(link: acp::ResourceLink) -> Option<String> {
|
||||
let url = Url::parse(&link.uri).ok()?;
|
||||
if url.scheme() == "file" {
|
||||
let path = url.to_file_path().ok()?;
|
||||
let contents = fs::read_to_string(&path).ok()?;
|
||||
|
||||
Some(format!(
|
||||
"\n\n# {}\n```\n{}\n```",
|
||||
path.to_string_lossy(),
|
||||
contents
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl GooseAcpAgent {
|
||||
async fn new(
|
||||
session_update_tx: mpsc::UnboundedSender<(acp::SessionNotification, oneshot::Sender<()>)>,
|
||||
@@ -234,9 +252,12 @@ impl acp::Agent for GooseAcpAgent {
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Ignore unsupported content types for now
|
||||
acp::ContentBlock::ResourceLink(link) => {
|
||||
if let Some(text) = read_resource_link(link) {
|
||||
user_message = user_message.with_text(text)
|
||||
}
|
||||
}
|
||||
acp::ContentBlock::Audio(..) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,3 +514,51 @@ pub async fn run_acp_agent() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use agent_client_protocol::ResourceLink;
|
||||
use std::io::Write;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
use crate::commands::acp::read_resource_link;
|
||||
|
||||
fn new_resource_link(content: &str) -> anyhow::Result<(ResourceLink, NamedTempFile)> {
|
||||
let mut file = NamedTempFile::new()?;
|
||||
file.write_all(content.as_bytes())?;
|
||||
|
||||
let link = ResourceLink {
|
||||
annotations: None,
|
||||
description: None,
|
||||
mime_type: None,
|
||||
name: file
|
||||
.path()
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
size: None,
|
||||
title: None,
|
||||
uri: format!("file://{}", file.path().to_str().unwrap()),
|
||||
};
|
||||
Ok((link, file))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_resource_link_non_file_scheme() {
|
||||
let (link, file) = new_resource_link("print(\"hello, world\")").unwrap();
|
||||
|
||||
let result = read_resource_link(link).unwrap();
|
||||
let expected = format!(
|
||||
"
|
||||
|
||||
# {}
|
||||
```
|
||||
print(\"hello, world\")
|
||||
```",
|
||||
file.path().to_str().unwrap(),
|
||||
);
|
||||
|
||||
assert_eq!(result, expected,)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user