@@ -34,6 +34,43 @@ pub async fn health() -> Json<serde_json::Value> {
3434 } ) )
3535}
3636
37+ /// POST endpoint for receiving messages via HTTP.
38+ ///
39+ /// Alternative to WebSocket for clients that prefer REST.
40+ /// Accepts RunAgentInput JSON body and routes to agent processor.
41+ pub async fn post_message (
42+ State ( state) : State < ServerState > ,
43+ Json ( input) : Json < RunAgentInput > ,
44+ ) -> Json < serde_json:: Value > {
45+ let thread_id = input. thread_id . to_string ( ) ;
46+ let run_id = input. run_id . to_string ( ) ;
47+
48+ debug ! (
49+ thread_id = %thread_id,
50+ run_id = %run_id,
51+ message_count = input. messages. len( ) ,
52+ "Received RunAgentInput via POST"
53+ ) ;
54+
55+ let message_tx = state. message_sender ( ) ;
56+ let agent_msg = AgentMessage :: new ( input) ;
57+
58+ match message_tx. send ( agent_msg) . await {
59+ Ok ( _) => Json ( json ! ( {
60+ "status" : "accepted" ,
61+ "thread_id" : thread_id,
62+ "run_id" : run_id
63+ } ) ) ,
64+ Err ( e) => {
65+ warn ! ( "Failed to route message to agent processor: {}" , e) ;
66+ Json ( json ! ( {
67+ "status" : "error" ,
68+ "message" : "Failed to route message to agent processor"
69+ } ) )
70+ }
71+ }
72+ }
73+
3774/// SSE endpoint for streaming AG-UI events.
3875pub async fn sse_handler (
3976 State ( state) : State < ServerState > ,
@@ -138,11 +175,40 @@ async fn handle_websocket(socket: WebSocket, state: ServerState) {
138175#[ cfg( test) ]
139176mod tests {
140177 use super :: * ;
178+ use ag_ui_core:: types:: Message as AgUiProtocolMessage ;
179+ use ag_ui_core:: { RunId , ThreadId } ;
180+ use axum:: extract:: State ;
141181
142182 #[ tokio:: test]
143183 async fn test_health_endpoint ( ) {
144184 let response = health ( ) . await ;
145185 assert_eq ! ( response. 0 [ "status" ] , "ok" ) ;
146186 assert_eq ! ( response. 0 [ "protocol" ] , "ag-ui" ) ;
147187 }
188+
189+ #[ tokio:: test]
190+ async fn test_post_message_accepted ( ) {
191+ use crate :: server:: ServerState ;
192+
193+ let state = ServerState :: new ( ) ;
194+ let mut msg_rx = state. take_message_receiver ( ) . await . expect ( "Should get receiver" ) ;
195+
196+ // Create RunAgentInput
197+ let thread_id = ThreadId :: random ( ) ;
198+ let run_id = RunId :: random ( ) ;
199+ let input = RunAgentInput :: new ( thread_id. clone ( ) , run_id. clone ( ) )
200+ . with_messages ( vec ! [ AgUiProtocolMessage :: new_user( "Hello from POST" ) ] ) ;
201+
202+ // Call post_message handler
203+ let response = post_message ( State ( state) , Json ( input) ) . await ;
204+
205+ // Verify response
206+ assert_eq ! ( response. 0 [ "status" ] , "accepted" ) ;
207+ assert_eq ! ( response. 0 [ "thread_id" ] , thread_id. to_string( ) ) ;
208+ assert_eq ! ( response. 0 [ "run_id" ] , run_id. to_string( ) ) ;
209+
210+ // Verify message was routed
211+ let received = msg_rx. recv ( ) . await . expect ( "Should receive message" ) ;
212+ assert_eq ! ( received. input. messages. len( ) , 1 ) ;
213+ }
148214}
0 commit comments