systemprompt_api/services/gateway/protocol/inbound/openai_responses/
mod.rs1use 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;
18mod render_terminal;
19
20#[cfg(feature = "test-api")]
21pub mod test_api {
22 pub use super::parse::parse as parse_request;
23 pub use super::render::{render_event_frame, render_response_object};
24 pub use super::render_terminal::render_terminal_event_frame;
25}
26
27#[derive(Debug, Clone, Copy, Default)]
28pub struct OpenAiResponsesInbound;
29
30impl InboundAdapter for OpenAiResponsesInbound {
31 fn wire_name(&self) -> &'static str {
32 "openai.responses"
33 }
34
35 fn parse_request(&self, raw: &Bytes) -> Result<CanonicalRequest, InboundParseError> {
36 let value: Value = serde_json::from_slice(raw)
37 .map_err(|e| InboundParseError::InvalidJson(e.to_string()))?;
38 parse::parse(&value)
39 }
40
41 fn render_response(&self, response: &CanonicalResponse) -> Bytes {
42 let value = render::render_response_object(response);
43 Bytes::from(serde_json::to_vec(&value).unwrap_or_else(|_| b"{}".to_vec()))
44 }
45
46 fn render_event(&self, event: &CanonicalEvent, model: &str) -> Option<Bytes> {
47 render::render_event_frame(event, model)
48 }
49
50 fn render_terminal_event(
51 &self,
52 event: &CanonicalEvent,
53 snapshot: &CanonicalResponse,
54 _model: &str,
55 ) -> Option<Bytes> {
56 render_terminal::render_terminal_event_frame(event, snapshot)
57 }
58
59 fn render_error(&self, _status: StatusCode, message: &str) -> Bytes {
60 let escaped = message.replace('\\', "\\\\").replace('"', "\\\"");
61 let body = format!("{{\"error\":{{\"type\":\"api_error\",\"message\":\"{escaped}\"}}}}");
62 Bytes::from(body)
63 }
64}