1use crate::id::{ConnectionId, ExternalSessionId};
6use serde::{Deserialize, Serialize};
7
8#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub struct InterpretationId(String);
11
12impl InterpretationId {
13 pub fn new(value: impl Into<String>) -> Self {
15 Self(value.into())
16 }
17
18 pub fn generate() -> Self {
20 Self(uuid::Uuid::new_v4().to_string())
21 }
22
23 pub fn as_str(&self) -> &str {
25 &self.0
26 }
27}
28
29#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
31pub struct UnitId(String);
32
33impl UnitId {
34 pub fn new(value: impl Into<String>) -> Self {
36 Self(value.into())
37 }
38
39 pub fn as_str(&self) -> &str {
41 &self.0
42 }
43}
44
45#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
47pub struct FlowId(String);
48
49impl FlowId {
50 pub fn new(value: impl Into<String>) -> Self {
52 Self(value.into())
53 }
54
55 pub fn main() -> Self {
57 Self("main".into())
58 }
59
60 pub fn as_str(&self) -> &str {
62 &self.0
63 }
64}
65
66#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
68pub struct LaneId(String);
69
70impl LaneId {
71 pub fn new(value: impl Into<String>) -> Self {
73 Self(value.into())
74 }
75
76 pub fn response() -> Self {
78 Self("response".into())
79 }
80
81 pub fn tool() -> Self {
83 Self("tool".into())
84 }
85
86 pub fn reasoning() -> Self {
88 Self("reasoning".into())
89 }
90
91 pub fn as_str(&self) -> &str {
93 &self.0
94 }
95}
96
97#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
99pub struct ToolActionId(String);
100
101impl ToolActionId {
102 pub fn new(value: impl Into<String>) -> Self {
104 Self(value.into())
105 }
106
107 pub fn as_str(&self) -> &str {
109 &self.0
110 }
111}
112
113#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
115pub enum TextChannel {
116 PublicResponse,
118 PublicReasoningSummary,
120 StatusNarration,
122 QuotedExternalContent,
124}
125
126impl TextChannel {
127 pub fn label(self) -> &'static str {
129 match self {
130 Self::PublicResponse => "assistant",
131 Self::PublicReasoningSummary => "reasoning",
132 Self::StatusNarration => "status",
133 Self::QuotedExternalContent => "quoted",
134 }
135 }
136}
137
138#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
140pub enum UnitState {
141 Complete,
143 Waiting,
145 Incomplete,
147 Malformed,
149}
150
151#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
153pub enum CanonicalUnit {
154 Text(TextSentence),
156 Structure(StructuralAtom),
158 Paragraph(ParagraphBoundary),
160 Tool(ToolActionEvent),
162 Usage(UsageObservation),
164 Diagnostic(ModelDiagnostic),
166 Boundary(SemanticBoundary),
168}
169
170impl CanonicalUnit {
171 pub fn kind_label(&self) -> &'static str {
173 match self {
174 Self::Text(_) => "text",
175 Self::Structure(_) => "structure",
176 Self::Paragraph(_) => "paragraph",
177 Self::Tool(_) => "tool",
178 Self::Usage(_) => "usage",
179 Self::Diagnostic(_) => "diagnostic",
180 Self::Boundary(_) => "boundary",
181 }
182 }
183}
184
185#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
187pub struct TextSentence {
188 pub sentence_id: UnitId,
190 pub channel: TextChannel,
192 pub paragraph_id: Option<UnitId>,
194 pub sentence_ordinal: u64,
196 pub content: String,
198}
199
200#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
202pub struct StructuralAtom {
203 pub structure_id: UnitId,
205 pub kind: StructureKind,
207 pub content: String,
209}
210
211#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
213pub enum StructureKind {
214 Heading,
216 ListItem,
218 CodeBlock,
220 TableRow,
222 BlockQuote,
224 ThematicBreak,
226 RawBlock,
228}
229
230#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
232pub struct ParagraphBoundary {
233 pub paragraph_id: UnitId,
235 pub kind: ParagraphKind,
237 pub channel: TextChannel,
239}
240
241#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
243pub enum ParagraphKind {
244 Opened,
246 Closed,
248}
249
250#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
252pub struct ToolActionEvent {
253 pub tool_action_id: ToolActionId,
255 pub tool_name: Option<String>,
257 pub request_state: ToolRequestState,
259 pub execution_state: ToolExecutionState,
261 pub result_state: ToolResultState,
263 pub request_payload: Option<String>,
265 pub result_payload: Option<String>,
267 pub terminal_outcome: Option<ToolTerminalOutcome>,
269 pub waiting_for: Option<String>,
271}
272
273#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
275pub enum ToolRequestState {
276 Assembling,
278 Ready,
280 Malformed,
282 Incomplete,
284}
285
286#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
288pub enum ToolExecutionState {
289 NotObserved,
291 Waiting,
293 Running,
295 Terminal,
297}
298
299#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
301pub enum ToolResultState {
302 Absent,
304 Assembling,
306 Complete,
308 Malformed,
310 Incomplete,
312}
313
314#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
316pub enum ToolTerminalOutcome {
317 Success,
319 Failure,
321 Cancelled,
323 Lost,
325}
326
327#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
329pub struct UsageObservation {
330 pub input_tokens: TokenCount,
332 pub output_tokens: TokenCount,
334}
335
336#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
338pub enum TokenCount {
339 Measured(u64),
341 Unavailable,
343}
344
345#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
347pub struct ModelDiagnostic {
348 pub kind: DiagnosticKind,
350 pub message: String,
352}
353
354#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
356pub enum DiagnosticKind {
357 DialectWarning,
359 ModelReportedError,
361 UnsupportedEvent,
363 MalformedFrame,
365 MalformedSemanticPayload,
367 IncompleteText,
369 IncompleteStructure,
371 IncompleteToolAction,
373 LimitExceeded,
375}
376
377#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
379pub struct SemanticBoundary {
380 pub kind: BoundaryKind,
382}
383
384#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
386pub enum BoundaryKind {
387 ResponseStarted,
389 ChannelStarted,
391 ChannelFinished,
393 ResponseFinished,
395 UsageFinalized,
397}
398
399#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
406pub struct SourceTimeObservation {
407 pub first_ms: u64,
409 pub last_ms: u64,
411}
412
413impl SourceTimeObservation {
414 pub fn point(ms: u64) -> Self {
416 Self {
417 first_ms: ms,
418 last_ms: ms,
419 }
420 }
421
422 pub fn merge(self, other: Self) -> Self {
424 Self {
425 first_ms: self.first_ms.min(other.first_ms),
426 last_ms: self.last_ms.max(other.last_ms),
427 }
428 }
429
430 pub fn include(self, ms: Option<u64>) -> Self {
432 match ms {
433 Some(t) => self.merge(Self::point(t)),
434 None => self,
435 }
436 }
437
438 pub fn from_bounds(first: Option<u64>, last: Option<u64>) -> Option<Self> {
440 match (first, last) {
441 (Some(f), Some(l)) => Some(Self {
442 first_ms: f.min(l),
443 last_ms: f.max(l),
444 }),
445 (Some(t), None) | (None, Some(t)) => Some(Self::point(t)),
446 (None, None) => None,
447 }
448 }
449}
450
451#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
453pub struct CanonicalUnitSnapshot {
454 pub unit_id: UnitId,
456 pub unit_generation: u64,
458 pub unit_state: UnitState,
460 pub interpretation_id: InterpretationId,
462 pub connection_id: ConnectionId,
464 pub external_session_id: Option<ExternalSessionId>,
466 pub flow_id: FlowId,
468 pub lane_id: LaneId,
470 pub lane_ordinal: u64,
472 pub causal_parent_id: Option<UnitId>,
474 pub source_time: Option<SourceTimeObservation>,
476 pub source_step: Option<u64>,
481 pub unit: CanonicalUnit,
483}
484
485#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
487pub enum CanonicalUnitEvent {
488 Created(CanonicalUnitSnapshot),
490 Advanced(CanonicalUnitSnapshot),
492 Completed(CanonicalUnitSnapshot),
494 Incomplete(CanonicalUnitSnapshot),
496}
497
498impl CanonicalUnitEvent {
499 pub fn snapshot(&self) -> &CanonicalUnitSnapshot {
501 match self {
502 Self::Created(s) | Self::Advanced(s) | Self::Completed(s) | Self::Incomplete(s) => s,
503 }
504 }
505
506 pub fn lifecycle_label(&self) -> &'static str {
508 match self {
509 Self::Created(_) => "created",
510 Self::Advanced(_) => "advanced",
511 Self::Completed(_) => "completed",
512 Self::Incomplete(_) => "incomplete",
513 }
514 }
515}
516
517#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
519pub struct InterpretationEnd {
520 pub interpretation_id: InterpretationId,
522 pub connection_id: ConnectionId,
524 pub external_session_id: Option<ExternalSessionId>,
526 pub kind: InterpretationEndKind,
528 pub canonical_event_count: u64,
530 pub completed_sentence_count: u64,
532 pub completed_structure_count: u64,
534 pub unresolved_text_bytes: u64,
536 pub source_bytes_consumed: u64,
538 pub safe_diagnostics: Vec<String>,
540}
541
542#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
544pub enum InterpretationEndKind {
545 Complete,
547 Cancelled,
549 Terminated,
551 TransportFailed,
553 DialectFailed,
555 LimitExceeded,
557 InvariantFailed,
559}
560
561#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
565pub enum InterpreterOutputEvent {
566 Unit(Box<CanonicalUnitEvent>),
568 Ended(InterpretationEnd),
570}
571
572impl InterpreterOutputEvent {
573 pub fn unit(event: CanonicalUnitEvent) -> Self {
575 Self::Unit(Box::new(event))
576 }
577}