1use crate::{Agent, AgentThread, AgentThreadEntry, AgentThreadSummary, ResponseEvent, ThreadId};
2use agentic_coding_protocol as acp;
3use anyhow::{Context as _, Result};
4use async_trait::async_trait;
5use futures::channel::mpsc::UnboundedReceiver;
6use gpui::{AppContext, AsyncApp, Entity, Task};
7use project::Project;
8use smol::process::Child;
9use util::ResultExt;
10
11pub struct AcpAgent {
12 connection: acp::Connection,
13 _handler_task: Task<()>,
14 _io_task: Task<()>,
15}
16
17struct AcpClientDelegate {
18 project: Entity<Project>,
19 cx: AsyncApp,
20 // sent_buffer_versions: HashMap<Entity<Buffer>, HashMap<u64, BufferSnapshot>>,
21}
22
23#[async_trait]
24impl acp::Client for AcpClientDelegate {
25 async fn read_file(&self, request: acp::ReadFileParams) -> Result<acp::ReadFileResponse> {
26 let cx = &mut self.cx.clone();
27 let buffer = self
28 .project
29 .update(cx, |project, cx| {
30 let path = project
31 .project_path_for_absolute_path(request.path, cx)
32 .context("Failed to get project path")?;
33 project.open_buffer(path, cx)
34 })?
35 .await?;
36
37 anyhow::Ok(buffer.update(cx, |buffer, cx| acp::ReadFileResponse {
38 content: buffer.text(),
39 // todo!
40 version: 0,
41 }))
42 }
43}
44
45impl AcpAgent {
46 pub fn stdio(process: Child, project: Entity<Project>, cx: AsyncApp) -> Self {
47 let stdin = process.stdin.expect("process didn't have stdin");
48 let stdout = process.stdout.expect("process didn't have stdout");
49
50 let (connection, handler_fut, io_fut) =
51 acp::Connection::client_to_agent(AcpClientDelegate { project, cx }, stdin, stdout);
52
53 let io_task = cx.background_spawn(async move {
54 io_fut.await.log_err();
55 });
56
57 Self {
58 connection,
59 _handler_task: cx.foreground_executor().spawn(handler_fut),
60 _io_task: io_task,
61 }
62 }
63}
64
65impl Agent for AcpAgent {
66 type Thread = AcpAgentThread;
67
68 async fn threads(&self) -> Result<Vec<AgentThreadSummary>> {
69 let threads = self.connection.request(acp::ListThreadsParams).await?;
70 threads
71 .threads
72 .into_iter()
73 .map(|thread| {
74 Ok(AgentThreadSummary {
75 id: ThreadId(thread.id.0),
76 title: thread.title,
77 created_at: thread.created_at,
78 })
79 })
80 .collect()
81 }
82
83 async fn create_thread(&self) -> Result<Self::Thread> {
84 todo!()
85 }
86
87 async fn open_thread(&self, id: crate::ThreadId) -> Result<Self::Thread> {
88 todo!()
89 }
90}
91
92struct AcpAgentThread {}
93
94impl AgentThread for AcpAgentThread {
95 async fn entries(&self) -> Result<Vec<AgentThreadEntry>> {
96 todo!()
97 }
98
99 async fn send(
100 &self,
101 message: crate::Message,
102 ) -> Result<UnboundedReceiver<Result<ResponseEvent>>> {
103 todo!()
104 }
105}