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