Skip to main content

agentic_server/handler/http/
responses.rs

1use 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}