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