Skip to main content

atomr_agents_core/
event.rs

1use serde::{Deserialize, Serialize};
2
3use crate::ids::{AgentId, HarnessId, RunId, ToolId, WorkflowId};
4use crate::inference::FinishReason;
5
6/// Structured event emitted by every observable boundary in the
7/// framework. Fed to `atomr-telemetry`, used by traces, metrics, and
8/// the eval-suite replay path.
9#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(tag = "kind", rename_all = "snake_case")]
11pub enum Event {
12    StrategyResolved {
13        strategy: String,
14        agent_id: Option<AgentId>,
15        elapsed_ms: u64,
16        tokens_used: u32,
17    },
18    ToolInvoked {
19        tool_id: ToolId,
20        args_hash: u64,
21        elapsed_ms: u64,
22        ok: bool,
23    },
24    AgentTurn {
25        agent_id: AgentId,
26        input_tokens: u32,
27        output_tokens: u32,
28        finish_reason: Option<FinishReason>,
29        elapsed_ms: u64,
30    },
31    WorkflowStep {
32        workflow_id: WorkflowId,
33        step_id: String,
34        step_kind: String,
35        elapsed_ms: u64,
36        ok: bool,
37    },
38    HarnessIteration {
39        harness_id: HarnessId,
40        iteration: u64,
41        outcome: String,
42        budget_remaining_tokens: u32,
43    },
44    Backpressure {
45        actor_path: String,
46        queued: u32,
47        dropped: u32,
48    },
49}
50
51/// Tagged envelope around an event with timestamp + correlation id.
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct EventEnvelope {
54    pub timestamp_ms: i64,
55    pub correlation_id: Option<String>,
56    /// LangSmith-style run identification. Optional so existing call
57    /// sites still compile; tracers and the run-tree builder require
58    /// these to be populated.
59    #[serde(default, skip_serializing_if = "Option::is_none")]
60    pub run_id: Option<RunId>,
61    #[serde(default, skip_serializing_if = "Option::is_none")]
62    pub parent_run_id: Option<RunId>,
63    #[serde(default, skip_serializing_if = "Vec::is_empty")]
64    pub tags: Vec<String>,
65    pub event: Event,
66}
67
68impl EventEnvelope {
69    pub fn now(event: Event) -> Self {
70        Self {
71            timestamp_ms: chrono::Utc::now().timestamp_millis(),
72            correlation_id: None,
73            run_id: None,
74            parent_run_id: None,
75            tags: Vec::new(),
76            event,
77        }
78    }
79
80    pub fn with_run(mut self, run_id: RunId, parent: Option<RunId>) -> Self {
81        self.run_id = Some(run_id);
82        self.parent_run_id = parent;
83        self
84    }
85
86    pub fn with_tags(mut self, tags: Vec<String>) -> Self {
87        self.tags = tags;
88        self
89    }
90}