agentic_server/handler/http/
responses.rs1use axum::extract::{Request, State};
2use axum::http::request::Parts;
3use axum::response::{IntoResponse, Response};
4use bytes::Bytes;
5use either::Either;
6use tracing::debug;
7
8use std::sync::Arc;
9
10use agentic_core::executor::ExecuteRequest;
11use agentic_core::proxy::{ProxyRequest, proxy_request};
12use agentic_core::types::request_response::RequestPayload;
13use agentic_core::types::tools::ResponsesTool;
14
15use super::super::common::{convert_response, executor_error_response, extract_bearer, read_and_parse, sse_response};
16use crate::app::AppState;
17
18async fn proxy_responses(state: &AppState, parts: Parts, body: Bytes) -> Response {
19 let proxy_req = ProxyRequest {
20 headers: parts.headers,
21 body,
22 query: parts.uri.query().map(str::to_string),
23 };
24 convert_response(proxy_request(proxy_req, &state.proxy_state).await)
25}
26
27async fn execute_responses(state: &AppState, parts: Parts, payload: RequestPayload) -> Response {
28 let auth = extract_bearer(&parts.headers, state.openai_api_key.as_deref());
29 match ExecuteRequest::new(payload, Arc::clone(&state.exec_ctx))
30 .with_auth(auth)
31 .run()
32 .await
33 {
34 Ok(Either::Left(response_payload)) => axum::Json(response_payload).into_response(),
35 Ok(Either::Right(stream)) => sse_response(stream),
36 Err(e) => executor_error_response(e),
37 }
38}
39
40fn has_gateway_tools(payload: &RequestPayload) -> bool {
41 payload
42 .tools
43 .as_ref()
44 .is_some_and(|tools| tools.iter().any(|tool| !matches!(tool, ResponsesTool::Function(_))))
45}
46
47pub async fn responses(State(state): State<AppState>, req: Request) -> Response {
48 let (parts, body) = req.into_parts();
49 let (bytes, payload) = match read_and_parse(body).await {
50 Ok(v) => v,
51 Err(e) => return e,
52 };
53
54 let should_execute = payload.store
55 || payload.previous_response_id.is_some()
56 || payload.conversation_id.is_some()
57 || has_gateway_tools(&payload);
58 debug!(
59 route = if should_execute { "executor" } else { "proxy" },
60 store = payload.store,
61 stream = payload.stream,
62 has_previous_response_id = payload.previous_response_id.is_some(),
63 has_conversation_id = payload.conversation_id.is_some(),
64 tools = payload.tools.as_ref().map_or(0, Vec::len),
65 "routing HTTP responses request"
66 );
67
68 if should_execute {
69 execute_responses(&state, parts, payload).await
70 } else {
71 proxy_responses(&state, parts, bytes).await
72 }
73}