Skip to main content

agent_sessions/
event.rs

1use crate::{Endpoint, Origin, Role, TokenCounts, TokenSemantics, UsageBasis};
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub struct Location {
8    pub record_index: u64,
9    pub line_no: u64,
10    pub byte_start: u64,
11    pub byte_end: u64,
12    pub event_index: usize,
13}
14
15#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16pub struct Located<T> {
17    pub location: Location,
18    pub at: Option<DateTime<Utc>>,
19    pub timestamp_text: Option<String>,
20    pub record_id: Option<String>,
21    pub record_type: Option<String>,
22    pub session_id: Option<String>,
23    pub message_id: Option<String>,
24    pub value: T,
25}
26
27#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
28#[non_exhaustive]
29pub enum Event {
30    Meta(MetaUpdate),
31    Message(Message),
32    ToolCall(ToolCall),
33    ToolResult(ToolResult),
34    Usage(Usage),
35}
36
37#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
38pub struct MetaUpdate {
39    pub session_id: Option<String>,
40    pub cwd: Option<String>,
41    pub git_branch: Option<String>,
42    pub model: Option<String>,
43    pub origin: Option<Origin>,
44    pub agent_version: Option<String>,
45    /// Native provenance fields; classification never replaces this evidence.
46    pub source: Option<Value>,
47    pub originator: Option<String>,
48    pub thread_source: Option<String>,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
52pub struct Message {
53    pub role: Role,
54    pub text: String,
55    pub text_segments: Vec<std::ops::Range<usize>>,
56    pub is_meta: bool,
57    pub is_sidechain: bool,
58    pub parent_id: Option<String>,
59}
60impl Message {
61    /// Original first text block, including an empty first block.
62    pub fn first_text(&self) -> Option<&str> {
63        self.text.get(self.text_segments.first()?.clone())
64    }
65}
66
67#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
68pub struct ToolCall {
69    pub kind: crate::ToolCallKind,
70    pub id: Option<String>,
71    pub name: String,
72    pub arguments: ToolArgs,
73}
74
75#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
76#[non_exhaustive]
77pub enum ToolArgs {
78    Json(Value),
79    RawString(String),
80    Missing,
81}
82
83#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
84pub struct ToolResult {
85    pub call_id: Option<String>,
86    pub is_error: Option<bool>,
87    pub text: String,
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
91pub struct Usage {
92    pub adjustments: Vec<crate::UsageAdjustment>,
93    /// Source identity only. Scope with host/session when deduplicating.
94    /// None requires the consumer to use physical occurrence identity.
95    pub dedup_key: Option<String>,
96    pub model: Option<String>,
97    pub counts: TokenCounts,
98    pub cumulative: Option<TokenCounts>,
99    pub semantics: TokenSemantics,
100    pub basis: UsageBasis,
101    pub stop_reason: Option<String>,
102    pub endpoint: Endpoint,
103    /// Undocumented Claude field; endpoint classification is only a heuristic.
104    pub inference_geo: Option<String>,
105}
106
107/// Select projections. Relevant metadata continuity is always maintained;
108/// excluded payloads are not validated or materialized.
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110pub struct EventKinds(u8);
111impl Default for EventKinds {
112    fn default() -> Self {
113        Self::ALL
114    }
115}
116impl EventKinds {
117    pub const META: Self = Self(1);
118    pub const MESSAGE: Self = Self(2);
119    pub const TOOL_CALL: Self = Self(4);
120    pub const TOOL_RESULT: Self = Self(8);
121    pub const USAGE: Self = Self(16);
122    pub const ALL: Self = Self(31);
123    pub fn contains(self, other: Self) -> bool {
124        self.0 & other.0 == other.0
125    }
126    pub fn union(self, other: Self) -> Self {
127        Self(self.0 | other.0)
128    }
129    pub(crate) fn includes(self, event: &Event) -> bool {
130        let bit = match event {
131            Event::Meta(_) => 1,
132            Event::Message(_) => 2,
133            Event::ToolCall(_) => 4,
134            Event::ToolResult(_) => 8,
135            Event::Usage(_) => 16,
136        };
137        self.0 & bit != 0
138    }
139}