1use crate::{ActorRef, Event, EventId, EventStore, RunId, StateError, YoAgentState};
2use async_trait::async_trait;
3use serde::{Deserialize, Serialize};
4use serde_json::{Value as JsonValue, json};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct YoAgentRunStarted {
8 pub run_id: RunId,
9 pub task: String,
10 pub metadata: JsonValue,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct YoAgentRunFinished {
15 pub run_id: RunId,
16 pub outcome: String,
17 pub metadata: JsonValue,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct YoAgentModelCalled {
22 pub run_id: RunId,
23 pub model: String,
24 pub prompt_summary: String,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct YoAgentModelFinished {
29 pub run_id: RunId,
30 pub model: String,
31 pub output_summary: String,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct YoAgentToolCalled {
36 pub run_id: RunId,
37 pub tool: String,
38 pub input_summary: String,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct YoAgentToolFinished {
43 pub run_id: RunId,
44 pub tool: String,
45 pub output_summary: String,
46 pub success: bool,
47}
48
49#[async_trait]
50pub trait YoAgentStateSink: Send + Sync {
51 async fn on_run_started(&self, event: YoAgentRunStarted) -> Result<EventId, StateError>;
52 async fn on_run_finished(&self, event: YoAgentRunFinished) -> Result<EventId, StateError>;
53 async fn on_model_called(&self, event: YoAgentModelCalled) -> Result<EventId, StateError>;
54 async fn on_model_finished(&self, event: YoAgentModelFinished) -> Result<EventId, StateError>;
55 async fn on_tool_called(&self, event: YoAgentToolCalled) -> Result<EventId, StateError>;
56 async fn on_tool_finished(&self, event: YoAgentToolFinished) -> Result<EventId, StateError>;
57}
58
59#[derive(Debug, Clone)]
60pub struct YoAgentStateAdapter<S: EventStore> {
61 state: YoAgentState<S>,
62 actor: ActorRef,
63}
64
65impl<S: EventStore> YoAgentStateAdapter<S> {
66 pub fn new(state: YoAgentState<S>, actor: ActorRef) -> Self {
67 Self { state, actor }
68 }
69
70 async fn record<T: Serialize + Send + Sync>(
71 &self,
72 kind: &'static str,
73 event: T,
74 ) -> Result<EventId, StateError> {
75 self.state
76 .record_event(Event::new(
77 self.actor.clone(),
78 kind,
79 serde_json::to_value(event)?,
80 ))
81 .await
82 }
83}
84
85#[async_trait]
86impl<S: EventStore> YoAgentStateSink for YoAgentStateAdapter<S> {
87 async fn on_run_started(&self, event: YoAgentRunStarted) -> Result<EventId, StateError> {
88 self.record("run.started", event).await
89 }
90
91 async fn on_run_finished(&self, event: YoAgentRunFinished) -> Result<EventId, StateError> {
92 self.record("run.finished", event).await
93 }
94
95 async fn on_model_called(&self, event: YoAgentModelCalled) -> Result<EventId, StateError> {
96 self.record("model.called", event).await
97 }
98
99 async fn on_model_finished(&self, event: YoAgentModelFinished) -> Result<EventId, StateError> {
100 self.record("model.finished", event).await
101 }
102
103 async fn on_tool_called(&self, event: YoAgentToolCalled) -> Result<EventId, StateError> {
104 self.record("tool.called", event).await
105 }
106
107 async fn on_tool_finished(&self, event: YoAgentToolFinished) -> Result<EventId, StateError> {
108 if !event.success {
109 self.state
110 .record_event(Event::new(
111 self.actor.clone(),
112 "failure.observed",
113 json!({
114 "run_id": event.run_id,
115 "tool": event.tool,
116 "output_summary": event.output_summary,
117 }),
118 ))
119 .await?;
120 return self.record("tool.finished", event).await;
121 }
122
123 self.record("tool.finished", event).await
124 }
125}