@@ -4,6 +4,7 @@ pub(crate) mod rpc_reply;
44pub ( crate ) mod session_update;
55pub ( crate ) mod terminal_create;
66pub ( crate ) mod terminal_kill;
7+ pub ( crate ) mod terminal_output;
78
89use crate :: agent:: Bridge ;
910use 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