Skip to main content

artifactize_core/agent/session/
events.rs

1//! Known JSONL event shapes parsed once when a conversation is opened.
2
3use crate::{
4    config::Backend,
5    llm::Attempt,
6    types::{RequestId, RunId, SessionId},
7};
8use rig_core::{completion::ToolDefinition, message::Message};
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11use std::collections::BTreeMap;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Event {
15    #[serde(default, skip_serializing_if = "Option::is_none")]
16    pub at: Option<crate::types::Timestamp>,
17    #[serde(default, skip_serializing_if = "Option::is_none")]
18    pub send: Option<usize>,
19    #[serde(flatten)]
20    pub kind: Kind,
21}
22impl Event {
23    /// The shared typed JSONL boundary. Unknown kinds and malformed known records are errors;
24    /// unknown header metadata remains compatible through Header::extra.
25    pub fn parse(bytes: &[u8]) -> Result<Self, serde_json::Error> {
26        serde_json::from_slice(bytes)
27    }
28}
29#[derive(Debug, Clone, Serialize, Deserialize)]
30#[serde(tag = "kind", rename_all = "lowercase")]
31pub enum Kind {
32    Review(Box<Header>),
33    Message(MessageEvent),
34    Attempt(Attempt),
35    End(End),
36    Send(Send),
37    Answer(Answer),
38    /// Display-only provider delivery; never part of replay history or usage calculations.
39    Delivery(Delivery),
40}
41#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
42#[serde(rename_all = "camelCase")]
43pub enum DeliveryKind {
44    Text,
45    Summary,
46}
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
48#[serde(rename_all = "camelCase")]
49pub enum DeliveryState {
50    Delta,
51    Complete,
52    Interrupted,
53}
54#[derive(Debug, Clone, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct Delivery {
57    pub turn: usize,
58    pub attempt: usize,
59    pub block: crate::types::DeliveryBlock,
60    #[serde(rename = "contentKind")]
61    pub kind: DeliveryKind,
62    pub text: String,
63    pub state: DeliveryState,
64}
65
66#[derive(Debug, Clone, Default, Serialize, Deserialize)]
67#[serde(rename_all = "camelCase")]
68pub struct Header {
69    #[serde(default, skip_serializing_if = "Option::is_none")]
70    pub version: Option<u32>,
71    #[serde(default, skip_serializing_if = "Option::is_none")]
72    pub session_id: Option<SessionId>,
73    #[serde(default, skip_serializing_if = "Option::is_none")]
74    pub run_id: Option<RunId>,
75    #[serde(default, skip_serializing_if = "Option::is_none")]
76    pub request_id: Option<RequestId>,
77    #[serde(default, skip_serializing_if = "Option::is_none")]
78    pub backend: Option<Backend>,
79    #[serde(default, skip_serializing_if = "Option::is_none")]
80    pub model: Option<crate::config::ModelId>,
81    #[serde(default)]
82    pub reasoning: Option<crate::config::Reasoning>,
83    #[serde(default, skip_serializing_if = "Option::is_none")]
84    pub budgets: Option<Budgets>,
85    #[serde(default, skip_serializing_if = "Option::is_none")]
86    pub tools: Option<Vec<ToolDefinition>>,
87    #[serde(default, skip_serializing_if = "Option::is_none")]
88    pub producer: Option<crate::types::ProducerId>,
89    #[serde(default, skip_serializing_if = "Option::is_none")]
90    pub state: Option<crate::types::StateId>,
91    #[serde(default, skip_serializing_if = "Option::is_none")]
92    pub eval_id: Option<crate::types::EvalId>,
93    #[serde(default, skip_serializing_if = "Option::is_none")]
94    pub target: Option<crate::types::ArtifactName>,
95    /// Provider-specific parameters remain dynamic.
96    #[serde(default)]
97    pub parameters: Value,
98    // Unknown saved display metadata is retained for compatibility.
99    #[serde(flatten)]
100    pub extra: BTreeMap<String, Value>,
101}
102#[derive(Debug, Clone, Default, Serialize, Deserialize)]
103#[serde(rename_all = "camelCase")]
104pub struct Budgets {
105    #[serde(default, with = "crate::config::validation::milliseconds")]
106    pub timeout_ms: Option<std::time::Duration>,
107    #[serde(default)]
108    pub max_tool_calls: Option<u64>,
109    #[serde(default)]
110    pub max_tokens: Option<u64>,
111}
112#[derive(Debug, Clone, Serialize, Deserialize)]
113#[serde(rename_all = "camelCase")]
114pub struct MessageEvent {
115    #[serde(default)]
116    pub turn: usize,
117    pub message: Message,
118    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
119    pub repair: bool,
120    #[serde(default, skip_serializing_if = "Vec::is_empty")]
121    pub is_error: Vec<bool>,
122    #[serde(default, skip_serializing_if = "Option::is_none")]
123    pub question: Option<String>,
124}
125#[derive(Debug, Clone, Default, Serialize, Deserialize)]
126#[serde(rename_all = "camelCase")]
127pub struct Send {
128    #[serde(default, skip_serializing_if = "Option::is_none")]
129    pub text: Option<String>,
130    #[serde(default, skip_serializing_if = "Option::is_none")]
131    pub framing: Option<String>,
132    #[serde(default, skip_serializing_if = "Option::is_none")]
133    pub files_changed: Option<bool>,
134    #[serde(default, skip_serializing_if = "Option::is_none")]
135    pub tools: Option<Vec<crate::types::ToolName>>,
136}
137pub use super::outcome::{Answer, End};