1use crate::{InvocationContext, Result, event::Event};
2use async_trait::async_trait;
3use futures::stream::Stream;
4use std::pin::Pin;
5use std::sync::Arc;
6
7pub type EventStream = Pin<Box<dyn Stream<Item = Result<Event>> + Send>>;
9
10#[async_trait]
17pub trait Agent: Send + Sync {
18 fn name(&self) -> &str;
20 fn description(&self) -> &str;
22 fn sub_agents(&self) -> &[Arc<dyn Agent>];
24
25 fn supports_agent_transfer(&self) -> bool {
39 true
40 }
41
42 async fn run(&self, ctx: Arc<dyn InvocationContext>) -> Result<EventStream>;
44}
45
46#[derive(Clone)]
57pub struct ResolvedContext {
58 pub system_instruction: String,
60 pub active_tools: Vec<Arc<dyn crate::Tool>>,
62}
63
64impl std::fmt::Debug for ResolvedContext {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 f.debug_struct("ResolvedContext")
67 .field("system_instruction_len", &self.system_instruction.len())
68 .field("active_tools_count", &self.active_tools.len())
69 .finish()
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use crate::{Content, ReadonlyContext, RunConfig};
77 use async_stream::stream;
78
79 struct TestAgent {
80 name: String,
81 }
82
83 use crate::{CallbackContext, Session, State};
84 use std::collections::HashMap;
85
86 struct MockState;
87 impl State for MockState {
88 fn get(&self, _key: &str) -> Option<serde_json::Value> {
89 None
90 }
91 fn set(&mut self, _key: String, _value: serde_json::Value) {}
92 fn all(&self) -> HashMap<String, serde_json::Value> {
93 HashMap::new()
94 }
95 }
96
97 struct MockSession;
98 impl Session for MockSession {
99 fn id(&self) -> &str {
100 "session"
101 }
102 fn app_name(&self) -> &str {
103 "app"
104 }
105 fn user_id(&self) -> &str {
106 "user"
107 }
108 fn state(&self) -> &dyn State {
109 &MockState
110 }
111 fn conversation_history(&self) -> Vec<Content> {
112 Vec::new()
113 }
114 }
115
116 #[allow(dead_code)]
117 struct TestContext {
118 content: Content,
119 config: RunConfig,
120 session: MockSession,
121 }
122
123 #[allow(dead_code)]
124 impl TestContext {
125 fn new() -> Self {
126 Self {
127 content: Content::new("user"),
128 config: RunConfig::default(),
129 session: MockSession,
130 }
131 }
132 }
133
134 #[async_trait]
135 impl ReadonlyContext for TestContext {
136 fn invocation_id(&self) -> &str {
137 "test"
138 }
139 fn agent_name(&self) -> &str {
140 "test"
141 }
142 fn user_id(&self) -> &str {
143 "user"
144 }
145 fn app_name(&self) -> &str {
146 "app"
147 }
148 fn session_id(&self) -> &str {
149 "session"
150 }
151 fn branch(&self) -> &str {
152 ""
153 }
154 fn user_content(&self) -> &Content {
155 &self.content
156 }
157 }
158
159 #[async_trait]
160 impl CallbackContext for TestContext {
161 fn artifacts(&self) -> Option<Arc<dyn crate::Artifacts>> {
162 None
163 }
164 }
165
166 #[async_trait]
167 impl InvocationContext for TestContext {
168 fn agent(&self) -> Arc<dyn Agent> {
169 unimplemented!()
170 }
171 fn memory(&self) -> Option<Arc<dyn crate::Memory>> {
172 None
173 }
174 fn session(&self) -> &dyn Session {
175 &self.session
176 }
177 fn run_config(&self) -> &RunConfig {
178 &self.config
179 }
180 fn end_invocation(&self) {}
181 fn ended(&self) -> bool {
182 false
183 }
184 }
185
186 #[async_trait]
187 impl Agent for TestAgent {
188 fn name(&self) -> &str {
189 &self.name
190 }
191
192 fn description(&self) -> &str {
193 "test agent"
194 }
195
196 fn sub_agents(&self) -> &[Arc<dyn Agent>] {
197 &[]
198 }
199
200 async fn run(&self, _ctx: Arc<dyn InvocationContext>) -> Result<EventStream> {
201 let s = stream! {
202 yield Ok(Event::new("test"));
203 };
204 Ok(Box::pin(s))
205 }
206 }
207
208 #[test]
209 fn test_agent_trait() {
210 let agent = TestAgent { name: "test".to_string() };
211 assert_eq!(agent.name(), "test");
212 assert_eq!(agent.description(), "test agent");
213 }
214}