Skip to content

Commit 2e0c0ee

Browse files
committed
feat(acp-nats): add terminal_output client handler
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
1 parent 81ba171 commit 2e0c0ee

5 files changed

Lines changed: 457 additions & 1 deletion

File tree

rsworkspace/crates/acp-nats/src/client/mod.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub(crate) mod rpc_reply;
44
pub(crate) mod session_update;
55
pub(crate) mod terminal_create;
66
pub(crate) mod terminal_kill;
7+
pub(crate) mod terminal_output;
78

89
use crate::agent::Bridge;
910
use crate::error::AGENT_UNAVAILABLE;
@@ -225,6 +226,17 @@ async fn dispatch_client_method<
225226
)
226227
.await;
227228
}
229+
ClientMethod::TerminalOutput => {
230+
terminal_output::handle(
231+
&payload,
232+
ctx.client,
233+
reply.as_deref(),
234+
ctx.nats,
235+
parsed.session_id.as_str(),
236+
ctx.serializer,
237+
)
238+
.await;
239+
}
228240
}
229241
}
230242

@@ -237,7 +249,7 @@ mod tests {
237249
KillTerminalCommandRequest, KillTerminalCommandResponse, ReadTextFileRequest,
238250
ReadTextFileResponse, Request, RequestId, RequestPermissionOutcome,
239251
RequestPermissionRequest, RequestPermissionResponse, SessionNotification, SessionUpdate,
240-
ToolCallUpdate, ToolCallUpdateFields,
252+
TerminalOutputRequest, TerminalOutputResponse, ToolCallUpdate, ToolCallUpdateFields,
241253
};
242254
use async_trait::async_trait;
243255
use std::cell::RefCell;
@@ -304,6 +316,16 @@ mod tests {
304316
*self.kill_terminal_calls.borrow_mut() += 1;
305317
Ok(KillTerminalCommandResponse::new())
306318
}
319+
320+
async fn terminal_output(
321+
&self,
322+
_: TerminalOutputRequest,
323+
) -> agent_client_protocol::Result<TerminalOutputResponse> {
324+
Ok(TerminalOutputResponse::new(
325+
"mock output".to_string(),
326+
false,
327+
))
328+
}
307329
}
308330

309331
fn make_msg(subject: &str, payload: &[u8], reply: Option<&str>) -> async_nats::Message {
@@ -577,6 +599,47 @@ mod tests {
577599
assert!(response.get("error").is_none());
578600
}
579601

602+
#[tokio::test]
603+
async fn dispatch_client_method_dispatches_terminal_output() {
604+
let nats = MockNatsClient::new();
605+
let client = MockClient::new();
606+
let session_id = AcpSessionId::new("sess-1").unwrap();
607+
608+
let envelope = Request {
609+
id: RequestId::Number(1),
610+
method: std::sync::Arc::from("terminal/output"),
611+
params: Some(TerminalOutputRequest::new("sess-1", "term-001")),
612+
};
613+
let payload = bytes::Bytes::from(serde_json::to_vec(&envelope).unwrap());
614+
615+
let parsed = crate::nats::ParsedClientSubject {
616+
session_id,
617+
method: ClientMethod::TerminalOutput,
618+
};
619+
620+
let ctx = DispatchContext {
621+
nats: &nats,
622+
client: &client,
623+
serializer: &StdJsonSerialize,
624+
};
625+
dispatch_client_method(
626+
"acp.sess-1.client.terminal.output",
627+
parsed,
628+
payload,
629+
Some("_INBOX.reply".to_string()),
630+
&ctx,
631+
)
632+
.await;
633+
634+
assert_eq!(nats.published_messages(), vec!["_INBOX.reply"]);
635+
let payloads = nats.published_payloads();
636+
assert_eq!(payloads.len(), 1);
637+
let response: serde_json::Value = serde_json::from_slice(payloads[0].as_ref()).unwrap();
638+
assert_eq!(response.get("id"), Some(&serde_json::Value::from(1)));
639+
assert!(response.get("result").is_some());
640+
assert!(response.get("error").is_none());
641+
}
642+
580643
#[tokio::test]
581644
async fn dispatch_client_method_terminal_kill_no_reply_does_not_call_client_or_publish() {
582645
let nats = MockNatsClient::new();

0 commit comments

Comments
 (0)