use crate::id::{ConnectionId, ExternalSessionId};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct InterpretationId(String);
impl InterpretationId {
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
pub fn generate() -> Self {
Self(uuid::Uuid::new_v4().to_string())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct UnitId(String);
impl UnitId {
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct FlowId(String);
impl FlowId {
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
pub fn main() -> Self {
Self("main".into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct LaneId(String);
impl LaneId {
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
pub fn response() -> Self {
Self("response".into())
}
pub fn tool() -> Self {
Self("tool".into())
}
pub fn reasoning() -> Self {
Self("reasoning".into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ToolActionId(String);
impl ToolActionId {
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum TextChannel {
PublicResponse,
PublicReasoningSummary,
StatusNarration,
QuotedExternalContent,
}
impl TextChannel {
pub fn label(self) -> &'static str {
match self {
Self::PublicResponse => "assistant",
Self::PublicReasoningSummary => "reasoning",
Self::StatusNarration => "status",
Self::QuotedExternalContent => "quoted",
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum UnitState {
Complete,
Waiting,
Incomplete,
Malformed,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum CanonicalUnit {
Text(TextSentence),
Structure(StructuralAtom),
Paragraph(ParagraphBoundary),
Tool(ToolActionEvent),
Usage(UsageObservation),
Diagnostic(ModelDiagnostic),
Boundary(SemanticBoundary),
}
impl CanonicalUnit {
pub fn kind_label(&self) -> &'static str {
match self {
Self::Text(_) => "text",
Self::Structure(_) => "structure",
Self::Paragraph(_) => "paragraph",
Self::Tool(_) => "tool",
Self::Usage(_) => "usage",
Self::Diagnostic(_) => "diagnostic",
Self::Boundary(_) => "boundary",
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct TextSentence {
pub sentence_id: UnitId,
pub channel: TextChannel,
pub paragraph_id: Option<UnitId>,
pub sentence_ordinal: u64,
pub content: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct StructuralAtom {
pub structure_id: UnitId,
pub kind: StructureKind,
pub content: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum StructureKind {
Heading,
ListItem,
CodeBlock,
TableRow,
BlockQuote,
ThematicBreak,
RawBlock,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ParagraphBoundary {
pub paragraph_id: UnitId,
pub kind: ParagraphKind,
pub channel: TextChannel,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ParagraphKind {
Opened,
Closed,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ToolActionEvent {
pub tool_action_id: ToolActionId,
pub tool_name: Option<String>,
pub request_state: ToolRequestState,
pub execution_state: ToolExecutionState,
pub result_state: ToolResultState,
pub request_payload: Option<String>,
pub result_payload: Option<String>,
pub terminal_outcome: Option<ToolTerminalOutcome>,
pub waiting_for: Option<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ToolRequestState {
Assembling,
Ready,
Malformed,
Incomplete,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ToolExecutionState {
NotObserved,
Waiting,
Running,
Terminal,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ToolResultState {
Absent,
Assembling,
Complete,
Malformed,
Incomplete,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ToolTerminalOutcome {
Success,
Failure,
Cancelled,
Lost,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct UsageObservation {
pub input_tokens: TokenCount,
pub output_tokens: TokenCount,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum TokenCount {
Measured(u64),
Unavailable,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ModelDiagnostic {
pub kind: DiagnosticKind,
pub message: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum DiagnosticKind {
DialectWarning,
ModelReportedError,
UnsupportedEvent,
MalformedFrame,
MalformedSemanticPayload,
IncompleteText,
IncompleteStructure,
IncompleteToolAction,
LimitExceeded,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct SemanticBoundary {
pub kind: BoundaryKind,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum BoundaryKind {
ResponseStarted,
ChannelStarted,
ChannelFinished,
ResponseFinished,
UsageFinalized,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct SourceTimeObservation {
pub first_ms: u64,
pub last_ms: u64,
}
impl SourceTimeObservation {
pub fn point(ms: u64) -> Self {
Self {
first_ms: ms,
last_ms: ms,
}
}
pub fn merge(self, other: Self) -> Self {
Self {
first_ms: self.first_ms.min(other.first_ms),
last_ms: self.last_ms.max(other.last_ms),
}
}
pub fn include(self, ms: Option<u64>) -> Self {
match ms {
Some(t) => self.merge(Self::point(t)),
None => self,
}
}
pub fn from_bounds(first: Option<u64>, last: Option<u64>) -> Option<Self> {
match (first, last) {
(Some(f), Some(l)) => Some(Self {
first_ms: f.min(l),
last_ms: f.max(l),
}),
(Some(t), None) | (None, Some(t)) => Some(Self::point(t)),
(None, None) => None,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CanonicalUnitSnapshot {
pub unit_id: UnitId,
pub unit_generation: u64,
pub unit_state: UnitState,
pub interpretation_id: InterpretationId,
pub connection_id: ConnectionId,
pub external_session_id: Option<ExternalSessionId>,
pub flow_id: FlowId,
pub lane_id: LaneId,
pub lane_ordinal: u64,
pub causal_parent_id: Option<UnitId>,
pub source_time: Option<SourceTimeObservation>,
pub source_step: Option<u64>,
pub unit: CanonicalUnit,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum CanonicalUnitEvent {
Created(CanonicalUnitSnapshot),
Advanced(CanonicalUnitSnapshot),
Completed(CanonicalUnitSnapshot),
Incomplete(CanonicalUnitSnapshot),
}
impl CanonicalUnitEvent {
pub fn snapshot(&self) -> &CanonicalUnitSnapshot {
match self {
Self::Created(s) | Self::Advanced(s) | Self::Completed(s) | Self::Incomplete(s) => s,
}
}
pub fn lifecycle_label(&self) -> &'static str {
match self {
Self::Created(_) => "created",
Self::Advanced(_) => "advanced",
Self::Completed(_) => "completed",
Self::Incomplete(_) => "incomplete",
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct InterpretationEnd {
pub interpretation_id: InterpretationId,
pub connection_id: ConnectionId,
pub external_session_id: Option<ExternalSessionId>,
pub kind: InterpretationEndKind,
pub canonical_event_count: u64,
pub completed_sentence_count: u64,
pub completed_structure_count: u64,
pub unresolved_text_bytes: u64,
pub source_bytes_consumed: u64,
pub safe_diagnostics: Vec<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum InterpretationEndKind {
Complete,
Cancelled,
Terminated,
TransportFailed,
DialectFailed,
LimitExceeded,
InvariantFailed,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum InterpreterOutputEvent {
Unit(Box<CanonicalUnitEvent>),
Ended(InterpretationEnd),
}
impl InterpreterOutputEvent {
pub fn unit(event: CanonicalUnitEvent) -> Self {
Self::Unit(Box::new(event))
}
}