switchyard_translation/codecs/responses/
mod.rs1mod buffered;
7mod stream;
8
9pub use buffered::OpenAiResponsesCodec;
10pub use stream::OpenAiResponsesStreamCodec;
11
12pub(crate) fn is_native_output(kind: &str) -> bool {
13 matches!(
14 kind,
15 "apply_patch_call" | "shell_call" | "computer_call" | "image_generation_call"
16 )
17}
18
19pub(crate) fn validate_response_output(
20 response: &crate::AggLlmResponse,
21 target: crate::WireFormat,
22) -> crate::Result<()> {
23 for block in response.outputs.iter().flat_map(|output| &output.content) {
24 if let crate::ContentBlock::Unknown { provider, raw } = block
25 && provider.as_str() == crate::WireFormat::OpenAiResponses.as_str()
26 && raw["type"].as_str().is_some_and(is_native_output)
27 {
28 return Err(crate::TranslationError::UnsupportedTranslation {
29 from: provider.clone(),
30 to: target.into(),
31 });
32 }
33 }
34 Ok(())
35}
36
37pub(crate) fn validate_stream_output(
39 source: &crate::FormatId,
40 target: &crate::FormatId,
41 event: &serde_json::Value,
42) -> crate::Result<()> {
43 if source.as_str() == crate::WireFormat::OpenAiResponses.as_str() && source != target {
44 let mut items = event
45 .get("item")
46 .into_iter()
47 .chain(event["response"]["output"].as_array().into_iter().flatten());
48 if items.any(|item| item["type"].as_str().is_some_and(is_native_output)) {
49 return Err(crate::TranslationError::UnsupportedTranslation {
50 from: source.clone(),
51 to: target.clone(),
52 });
53 }
54 }
55 Ok(())
56}
57
58const ANTHROPIC_THINKING_PREFIX: &str = "switchyard:anthropic-thinking:v1:";
61
62fn encode_anthropic_thinking(text: &str, signature: &str) -> String {
63 format!(
64 "{ANTHROPIC_THINKING_PREFIX}{}",
65 serde_json::json!([text, signature])
66 )
67}
68
69fn decode_anthropic_thinking(payload: &str) -> Option<(String, String)> {
70 serde_json::from_str(payload.strip_prefix(ANTHROPIC_THINKING_PREFIX)?).ok()
71}
72
73pub fn is_anthropic_thinking_envelope(encrypted_content: &str) -> bool {
77 encrypted_content.starts_with(ANTHROPIC_THINKING_PREFIX)
78}