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