Skip to main content

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

1//! Inbound protocol adapters: caller wire format to canonical model.
2//!
3//! The [`InboundAdapter`] trait parses a request body into a
4//! [`CanonicalRequest`] and renders canonical responses, streaming events, and
5//! errors back in the caller's protocol. Implementations cover the Anthropic
6//! Messages and `OpenAI` Responses surfaces; [`InboundParseError`] reports
7//! malformed or unsupported inputs.
8
9pub mod anthropic_messages;
10pub mod openai_responses;
11
12use bytes::Bytes;
13use http::StatusCode;
14
15use super::canonical::CanonicalRequest;
16use super::canonical_response::{CanonicalEvent, CanonicalResponse};
17
18#[derive(Debug, thiserror::Error)]
19pub enum InboundParseError {
20    #[error("invalid request body: {0}")]
21    InvalidJson(String),
22    #[error("missing required field: {0}")]
23    MissingField(&'static str),
24    #[error("unsupported value for {field}: {detail}")]
25    Unsupported { field: &'static str, detail: String },
26}
27
28pub trait InboundAdapter: Send + Sync + std::fmt::Debug {
29    fn wire_name(&self) -> &'static str;
30    fn parse_request(&self, raw: &Bytes) -> Result<CanonicalRequest, InboundParseError>;
31    fn render_response(&self, response: &CanonicalResponse) -> Bytes;
32    fn render_event(&self, event: &CanonicalEvent, model: &str) -> Option<Bytes>;
33
34    /// Render a terminal streaming event whose wire form must embed
35    /// fully-accumulated item content — the complete tool-call arguments and
36    /// the output list — which the per-event [`CanonicalEvent`] alone does
37    /// not carry. Returns `None` for wires that finalize correctly from
38    /// per-event deltas (the caller then falls back to
39    /// [`InboundAdapter::render_event`]).
40    fn render_terminal_event(
41        &self,
42        event: &CanonicalEvent,
43        snapshot: &CanonicalResponse,
44        model: &str,
45    ) -> Option<Bytes> {
46        // Why: default impl ignores args; wires that need terminal finalization
47        // override this.
48        let _ = (event, snapshot, model);
49        None
50    }
51
52    fn render_error(&self, status: StatusCode, message: &str) -> Bytes;
53    fn streaming_content_type(&self) -> &'static str {
54        "text/event-stream"
55    }
56}