systemprompt_models/wire/canonical/
response.rs1use super::request::{CanonicalContent, flatten_part};
12use super::usage::{CanonicalUsage, CanonicalUsageUpdate};
13use crate::wire::inspect::ForwardedSurface;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum CanonicalStopReason {
25 EndTurn,
26 MaxTokens,
27 StopSequence,
28 ToolUse,
29 Refusal,
30 Other,
31}
32
33impl CanonicalStopReason {
34 pub const fn anthropic_str(self) -> &'static str {
35 match self {
36 Self::MaxTokens => "max_tokens",
37 Self::StopSequence => "stop_sequence",
38 Self::ToolUse => "tool_use",
39 Self::Refusal => "refusal",
40 Self::EndTurn | Self::Other => "end_turn",
41 }
42 }
43
44 pub const fn openai_str(self) -> &'static str {
45 match self {
46 Self::MaxTokens => "length",
47 Self::ToolUse => "tool_calls",
48 Self::Refusal => "content_filter",
49 Self::EndTurn | Self::StopSequence | Self::Other => "stop",
50 }
51 }
52
53 #[must_use]
57 pub const fn empty_terminal_is_error(self) -> bool {
58 matches!(self, Self::Refusal | Self::Other)
59 }
60
61 pub fn from_anthropic(s: &str) -> Self {
62 match s {
63 "end_turn" => Self::EndTurn,
64 "max_tokens" => Self::MaxTokens,
65 "stop_sequence" => Self::StopSequence,
66 "tool_use" => Self::ToolUse,
67 "refusal" => Self::Refusal,
68 _ => Self::Other,
69 }
70 }
71
72 #[must_use]
75 pub const fn with_tool_use(self, has_tool_use: bool) -> Self {
76 match self {
77 Self::EndTurn | Self::Other if has_tool_use => Self::ToolUse,
78 other => other,
79 }
80 }
81
82 pub fn from_openai(s: &str) -> Self {
83 match s {
84 "stop" => Self::EndTurn,
85 "length" => Self::MaxTokens,
86 "tool_calls" | "function_call" => Self::ToolUse,
87 "content_filter" => Self::Refusal,
88 _ => Self::Other,
89 }
90 }
91}
92
93#[derive(Debug, Clone, Default)]
94pub struct GroundedSource {
95 pub uri: String,
96 pub title: Option<String>,
97 pub snippet: Option<String>,
98 pub relevance: Option<f32>,
99}
100
101#[derive(Debug, Clone, Default)]
102pub struct Grounding {
103 pub sources: Vec<GroundedSource>,
104 pub queries: Vec<String>,
105}
106
107#[derive(Debug, Clone, Default)]
108pub struct CodeExecutionOutput {
109 pub language: Option<String>,
110 pub code: String,
111 pub result: Option<String>,
112 pub outcome: Option<String>,
113}
114
115#[derive(Debug, Clone, Default)]
116pub struct CanonicalResponse {
117 pub id: String,
118 pub model: String,
119 pub content: Vec<CanonicalContent>,
120 pub stop_reason: Option<CanonicalStopReason>,
121 pub usage: CanonicalUsage,
122 pub grounding: Option<Grounding>,
123 pub code_execution: Option<CodeExecutionOutput>,
124 pub raw_finish_reason: Option<String>,
125 pub received_surface: ForwardedSurface,
126}
127
128impl CanonicalResponse {
129 pub fn content_units(&self) -> Vec<String> {
130 let mut units = Vec::with_capacity(self.content.len() + self.received_surface.len());
131 for part in &self.content {
132 let mut out = String::new();
133 flatten_part(&mut out, part);
134 if !out.is_empty() {
135 units.push(out);
136 }
137 }
138 for leaf in self.received_surface.leaves() {
139 units.push(leaf.value.clone());
140 }
141 units
142 }
143}
144
145#[derive(Debug, Clone)]
146pub enum CanonicalEvent {
147 MessageStart {
148 id: String,
149 model: String,
150 usage: CanonicalUsage,
151 },
152 ContentBlockStart {
153 index: u32,
154 block: ContentBlockKind,
155 },
156 TextDelta {
157 index: u32,
158 text: String,
159 },
160 ThinkingDelta {
161 index: u32,
162 text: String,
163 },
164 SignatureDelta {
165 index: u32,
166 signature: String,
167 },
168 EncryptedContentDelta {
169 index: u32,
170 data: String,
171 },
172 ToolUseDelta {
173 index: u32,
174 partial_json: String,
175 },
176 ContentBlockStop {
177 index: u32,
178 },
179 UsageDelta(CanonicalUsageUpdate),
180 MessageStop {
181 id: String,
182 stop_reason: Option<CanonicalStopReason>,
183 raw_finish_reason: Option<String>,
184 },
185 Error(String),
186}
187
188#[derive(Debug, Clone)]
189pub enum ContentBlockKind {
190 Text,
191 Thinking {
192 id: Option<String>,
193 signature: Option<String>,
194 },
195 ToolUse {
196 id: String,
197 name: String,
198 signature: Option<String>,
199 },
200}