Skip to main content

systemprompt_api/services/gateway/protocol/inbound/openai_responses/
mod.rs

1//! Inbound adapter for the `OpenAI` Responses wire protocol.
2//!
3//! [`OpenAiResponsesInbound`] parses Responses-format request bodies into the
4//! canonical request model and renders canonical responses, streaming events,
5//! and errors back in Responses format.
6
7use bytes::Bytes;
8use http::StatusCode;
9use serde_json::Value;
10
11use super::super::canonical::CanonicalRequest;
12use super::super::canonical_response::{CanonicalEvent, CanonicalResponse};
13use super::{InboundAdapter, InboundParseError};
14
15mod input;
16mod parse;
17mod render;
18
19#[cfg(feature = "test-api")]
20pub mod test_api {
21    pub use super::parse::parse as parse_request;
22    pub use super::render::{render_event_frame, render_response_object};
23}
24
25#[derive(Debug, Clone, Copy, Default)]
26pub struct OpenAiResponsesInbound;
27
28impl InboundAdapter for OpenAiResponsesInbound {
29    fn wire_name(&self) -> &'static str {
30        "openai.responses"
31    }
32
33    fn parse_request(&self, raw: &Bytes) -> Result<CanonicalRequest, InboundParseError> {
34        let value: Value = serde_json::from_slice(raw)
35            .map_err(|e| InboundParseError::InvalidJson(e.to_string()))?;
36        parse::parse(&value)
37    }
38
39    fn render_response(&self, response: &CanonicalResponse) -> Bytes {
40        let value = render::render_response_object(response);
41        Bytes::from(serde_json::to_vec(&value).unwrap_or_else(|_| b"{}".to_vec()))
42    }
43
44    fn render_event(&self, event: &CanonicalEvent, model: &str) -> Option<Bytes> {
45        render::render_event_frame(event, model)
46    }
47
48    fn render_error(&self, _status: StatusCode, message: &str) -> Bytes {
49        let escaped = message.replace('\\', "\\\\").replace('"', "\\\"");
50        let body = format!("{{\"error\":{{\"type\":\"api_error\",\"message\":\"{escaped}\"}}}}");
51        Bytes::from(body)
52    }
53}