1use async_trait::async_trait;
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::fmt;
9
10pub mod error;
12pub mod event;
13pub mod global;
14
15pub use error::{ErrorCategory, ErrorContext, GlobalError, GlobalResult};
16pub use event::{EventBuilder, GlobalEvent};
17pub use event::{execution, lifecycle, message, plugin, state};
18pub use global::{GlobalMessage, MessageContent, MessageMetadata};
20
21#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
27pub enum AgentState {
28 #[default]
30 Created,
31 Initializing,
33 Ready,
35 Running,
37 Executing,
39 Paused,
41 Interrupted,
43 ShuttingDown,
45 Shutdown,
47 Failed,
49 Destroyed,
51 Error(String),
53}
54
55impl fmt::Display for AgentState {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 match self {
58 AgentState::Created => write!(f, "Created"),
59 AgentState::Initializing => write!(f, "Initializing"),
60 AgentState::Ready => write!(f, "Ready"),
61 AgentState::Executing => write!(f, "Executing"),
62 AgentState::Paused => write!(f, "Paused"),
63 AgentState::Interrupted => write!(f, "Interrupted"),
64 AgentState::ShuttingDown => write!(f, "ShuttingDown"),
65 AgentState::Shutdown => write!(f, "Shutdown"),
66 AgentState::Failed => write!(f, "Failed"),
67 AgentState::Error(msg) => write!(f, "Error({})", msg),
68 AgentState::Running => {
69 write!(f, "Running")
70 }
71 AgentState::Destroyed => {
72 write!(f, "Destroyed")
73 }
74 }
75 }
76}
77
78impl AgentState {
79 pub fn transition_to(
81 &self,
82 target: AgentState,
83 ) -> Result<AgentState, super::error::AgentError> {
84 if self.can_transition_to(&target) {
85 Ok(target)
86 } else {
87 Err(super::error::AgentError::invalid_state_transition(
88 self, &target,
89 ))
90 }
91 }
92
93 pub fn can_transition_to(&self, target: &AgentState) -> bool {
95 use AgentState::*;
96 matches!(
97 (self, target),
98 (Created, Initializing)
99 | (Initializing, Ready)
100 | (Initializing, Error(_))
101 | (Initializing, Failed)
102 | (Ready, Executing)
103 | (Ready, ShuttingDown)
104 | (Executing, Ready)
105 | (Executing, Paused)
106 | (Executing, Interrupted)
107 | (Executing, Error(_))
108 | (Executing, Failed)
109 | (Paused, Ready)
110 | (Paused, Executing)
111 | (Paused, ShuttingDown)
112 | (Interrupted, Ready)
113 | (Interrupted, ShuttingDown)
114 | (ShuttingDown, Shutdown)
115 | (Error(_), ShuttingDown)
116 | (Error(_), Shutdown)
117 | (Failed, ShuttingDown)
118 | (Failed, Shutdown)
119 )
120 }
121
122 pub fn is_active(&self) -> bool {
124 matches!(self, AgentState::Ready | AgentState::Executing)
125 }
126
127 pub fn is_terminal(&self) -> bool {
129 matches!(
130 self,
131 AgentState::Shutdown | AgentState::Failed | AgentState::Error(_)
132 )
133 }
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize, Default)]
142pub enum AgentInput {
143 Text(String),
145 Texts(Vec<String>),
147 Json(serde_json::Value),
149 Map(HashMap<String, serde_json::Value>),
151 Binary(Vec<u8>),
153 #[default]
155 Empty,
156}
157
158impl AgentInput {
159 pub fn text(s: impl Into<String>) -> Self {
161 Self::Text(s.into())
162 }
163
164 pub fn json(value: serde_json::Value) -> Self {
166 Self::Json(value)
167 }
168
169 pub fn map(map: HashMap<String, serde_json::Value>) -> Self {
171 Self::Map(map)
172 }
173
174 pub fn as_text(&self) -> Option<&str> {
176 match self {
177 Self::Text(s) => Some(s),
178 _ => None,
179 }
180 }
181
182 pub fn to_text(&self) -> String {
184 match self {
185 Self::Text(s) => s.clone(),
186 Self::Texts(v) => v.join("\n"),
187 Self::Json(v) => v.to_string(),
188 Self::Map(m) => serde_json::to_string(m).unwrap_or_default(),
189 Self::Binary(b) => String::from_utf8_lossy(b).to_string(),
190 Self::Empty => String::new(),
191 }
192 }
193
194 pub fn as_json(&self) -> Option<&serde_json::Value> {
196 match self {
197 Self::Json(v) => Some(v),
198 _ => None,
199 }
200 }
201
202 pub fn to_json(&self) -> serde_json::Value {
204 match self {
205 Self::Text(s) => serde_json::Value::String(s.clone()),
206 Self::Texts(v) => serde_json::json!(v),
207 Self::Json(v) => v.clone(),
208 Self::Map(m) => serde_json::to_value(m).unwrap_or_default(),
209 Self::Binary(b) => serde_json::json!({ "binary": base64_encode(b) }),
210 Self::Empty => serde_json::Value::Null,
211 }
212 }
213
214 pub fn is_empty(&self) -> bool {
216 matches!(self, Self::Empty)
217 }
218}
219
220impl From<String> for AgentInput {
221 fn from(s: String) -> Self {
222 Self::Text(s)
223 }
224}
225
226impl From<&str> for AgentInput {
227 fn from(s: &str) -> Self {
228 Self::Text(s.to_string())
229 }
230}
231
232impl From<serde_json::Value> for AgentInput {
233 fn from(v: serde_json::Value) -> Self {
234 Self::Json(v)
235 }
236}
237
238#[derive(Debug, Clone, Serialize, Deserialize)]
244pub struct AgentOutput {
245 pub content: OutputContent,
247 pub metadata: HashMap<String, serde_json::Value>,
249 pub tools_used: Vec<ToolUsage>,
251 pub reasoning_steps: Vec<ReasoningStep>,
253 pub duration_ms: u64,
255 pub token_usage: Option<TokenUsage>,
257}
258
259impl Default for AgentOutput {
260 fn default() -> Self {
261 Self {
262 content: OutputContent::Empty,
263 metadata: HashMap::new(),
264 tools_used: Vec::new(),
265 reasoning_steps: Vec::new(),
266 duration_ms: 0,
267 token_usage: None,
268 }
269 }
270}
271
272impl AgentOutput {
273 pub fn text(s: impl Into<String>) -> Self {
275 Self {
276 content: OutputContent::Text(s.into()),
277 ..Default::default()
278 }
279 }
280
281 pub fn json(value: serde_json::Value) -> Self {
283 Self {
284 content: OutputContent::Json(value),
285 ..Default::default()
286 }
287 }
288
289 pub fn error(message: impl Into<String>) -> Self {
291 Self {
292 content: OutputContent::Error(message.into()),
293 ..Default::default()
294 }
295 }
296
297 pub fn as_text(&self) -> Option<&str> {
299 match &self.content {
300 OutputContent::Text(s) => Some(s),
301 _ => None,
302 }
303 }
304
305 pub fn to_text(&self) -> String {
307 self.content.to_text()
308 }
309
310 pub fn with_duration(mut self, duration_ms: u64) -> Self {
312 self.duration_ms = duration_ms;
313 self
314 }
315
316 pub fn with_metadata(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
318 self.metadata.insert(key.into(), value);
319 self
320 }
321
322 pub fn with_tool_usage(mut self, usage: ToolUsage) -> Self {
324 self.tools_used.push(usage);
325 self
326 }
327
328 pub fn with_tools_used(mut self, usages: Vec<ToolUsage>) -> Self {
330 self.tools_used = usages;
331 self
332 }
333
334 pub fn with_reasoning_step(mut self, step: ReasoningStep) -> Self {
336 self.reasoning_steps.push(step);
337 self
338 }
339
340 pub fn with_reasoning_steps(mut self, steps: Vec<ReasoningStep>) -> Self {
342 self.reasoning_steps = steps;
343 self
344 }
345
346 pub fn with_token_usage(mut self, usage: TokenUsage) -> Self {
348 self.token_usage = Some(usage);
349 self
350 }
351
352 pub fn is_error(&self) -> bool {
354 matches!(self.content, OutputContent::Error(_))
355 }
356}
357
358#[derive(Debug, Clone, Serialize, Deserialize)]
360pub enum OutputContent {
361 Text(String),
363 Texts(Vec<String>),
365 Json(serde_json::Value),
367 Binary(Vec<u8>),
369 Stream,
371 Error(String),
373 Empty,
375}
376
377impl OutputContent {
378 pub fn to_text(&self) -> String {
380 match self {
381 Self::Text(s) => s.clone(),
382 Self::Texts(v) => v.join("\n"),
383 Self::Json(v) => v.to_string(),
384 Self::Binary(b) => String::from_utf8_lossy(b).to_string(),
385 Self::Stream => "[STREAM]".to_string(),
386 Self::Error(e) => format!("Error: {}", e),
387 Self::Empty => String::new(),
388 }
389 }
390}
391
392#[derive(Debug, Clone, Serialize, Deserialize)]
398pub struct ToolUsage {
399 pub name: String,
401 pub input: serde_json::Value,
403 pub output: Option<serde_json::Value>,
405 pub success: bool,
407 pub error: Option<String>,
409 pub duration_ms: u64,
411}
412
413impl ToolUsage {
414 pub fn success(
416 name: impl Into<String>,
417 input: serde_json::Value,
418 output: serde_json::Value,
419 duration_ms: u64,
420 ) -> Self {
421 Self {
422 name: name.into(),
423 input,
424 output: Some(output),
425 success: true,
426 error: None,
427 duration_ms,
428 }
429 }
430
431 pub fn failure(
433 name: impl Into<String>,
434 input: serde_json::Value,
435 error: impl Into<String>,
436 duration_ms: u64,
437 ) -> Self {
438 Self {
439 name: name.into(),
440 input,
441 output: None,
442 success: false,
443 error: Some(error.into()),
444 duration_ms,
445 }
446 }
447}
448
449#[derive(Debug, Clone, Serialize, Deserialize)]
451pub struct ReasoningStep {
452 pub step_type: ReasoningStepType,
454 pub content: String,
456 pub step_number: usize,
458 pub timestamp_ms: u64,
460}
461
462impl ReasoningStep {
463 pub fn new(
465 step_type: ReasoningStepType,
466 content: impl Into<String>,
467 step_number: usize,
468 ) -> Self {
469 let now = std::time::SystemTime::now()
470 .duration_since(std::time::UNIX_EPOCH)
471 .unwrap_or_default()
472 .as_millis() as u64;
473
474 Self {
475 step_type,
476 content: content.into(),
477 step_number,
478 timestamp_ms: now,
479 }
480 }
481}
482
483#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
485pub enum ReasoningStepType {
486 Thought,
488 Action,
490 Observation,
492 Reflection,
494 Decision,
496 FinalAnswer,
498 Custom(String),
500}
501
502#[derive(Debug, Clone, Default, Serialize, Deserialize)]
504pub struct TokenUsage {
505 pub prompt_tokens: u32,
507 pub completion_tokens: u32,
509 pub total_tokens: u32,
511}
512
513impl TokenUsage {
514 pub fn new(prompt_tokens: u32, completion_tokens: u32) -> Self {
515 let total_tokens = prompt_tokens + completion_tokens;
516 Self {
517 prompt_tokens,
518 completion_tokens,
519 total_tokens,
520 }
521 }
522}
523
524#[derive(Debug, Clone)]
530pub struct ChatCompletionRequest {
531 pub messages: Vec<ChatMessage>,
533 pub model: Option<String>,
535 pub tools: Option<Vec<ToolDefinition>>,
537 pub temperature: Option<f32>,
539 pub max_tokens: Option<u32>,
541}
542
543#[derive(Debug, Clone, Serialize, Deserialize)]
545pub struct ChatMessage {
546 pub role: String,
548 pub content: Option<String>,
550 pub tool_call_id: Option<String>,
552 pub tool_calls: Option<Vec<ToolCall>>,
554}
555
556#[derive(Debug, Clone, Serialize, Deserialize)]
558pub struct ToolCall {
559 pub id: String,
561 pub name: String,
563 pub arguments: serde_json::Value,
565}
566
567#[derive(Debug, Clone, Serialize, Deserialize)]
569pub struct ToolDefinition {
570 pub name: String,
572 pub description: String,
574 pub parameters: serde_json::Value,
576}
577
578#[derive(Debug, Clone)]
580pub struct ChatCompletionResponse {
581 pub content: Option<String>,
583 pub tool_calls: Option<Vec<ToolCall>>,
585 pub usage: Option<TokenUsage>,
587}
588
589#[async_trait]
610pub trait LLMProvider: Send + Sync {
611 fn name(&self) -> &str;
613
614 async fn chat(
616 &self,
617 request: ChatCompletionRequest,
618 ) -> super::error::AgentResult<ChatCompletionResponse>;
619}
620
621#[derive(Debug, Clone, Serialize, Deserialize)]
627pub enum InterruptResult {
628 Acknowledged,
630 Paused,
632 Interrupted {
634 partial_result: Option<String>,
636 },
637 TaskTerminated {
639 partial_result: Option<AgentOutput>,
641 },
642 Ignored,
644}
645
646#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
652pub enum InputType {
653 Text,
654 Image,
655 Audio,
656 Video,
657 Structured(String),
658 Binary,
659}
660
661#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
663pub enum OutputType {
664 Text,
665 Json,
666 StructuredJson,
667 Stream,
668 Binary,
669 Multimodal,
670}
671
672fn base64_encode(data: &[u8]) -> String {
677 const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
678 let mut result = Vec::new();
679
680 for chunk in data.chunks(3) {
681 let (n, _pad) = match chunk.len() {
682 1 => (((chunk[0] as u32) << 16), 2),
683 2 => (((chunk[0] as u32) << 16) | ((chunk[1] as u32) << 8), 1),
684 _ => (
685 ((chunk[0] as u32) << 16) | ((chunk[1] as u32) << 8) | (chunk[2] as u32),
686 0,
687 ),
688 };
689
690 result.push(CHARS[((n >> 18) & 0x3F) as usize]);
691 result.push(CHARS[((n >> 12) & 0x3F) as usize]);
692
693 if chunk.len() > 1 {
694 result.push(CHARS[((n >> 6) & 0x3F) as usize]);
695 } else {
696 result.push(b'=');
697 }
698
699 if chunk.len() > 2 {
700 result.push(CHARS[(n & 0x3F) as usize]);
701 } else {
702 result.push(b'=');
703 }
704 }
705
706 String::from_utf8(result).unwrap_or_default()
707}
708
709#[cfg(test)]
710mod tests {
711 use super::*;
712
713 #[test]
714 fn test_agent_state_transitions() {
715 let state = AgentState::Created;
716 assert!(state.can_transition_to(&AgentState::Initializing));
717 assert!(!state.can_transition_to(&AgentState::Executing));
718 }
719
720 #[test]
721 fn test_agent_input_text() {
722 let input = AgentInput::text("Hello");
723 assert_eq!(input.as_text(), Some("Hello"));
724 assert_eq!(input.to_text(), "Hello");
725 }
726
727 #[test]
728 fn test_agent_output_text() {
729 let output = AgentOutput::text("World")
730 .with_duration(100)
731 .with_metadata("key", serde_json::json!("value"));
732
733 assert_eq!(output.as_text(), Some("World"));
734 assert_eq!(output.duration_ms, 100);
735 assert!(output.metadata.contains_key("key"));
736 }
737
738 #[test]
739 fn test_tool_usage() {
740 let usage = ToolUsage::success(
741 "calculator",
742 serde_json::json!({"a": 1, "b": 2}),
743 serde_json::json!(3),
744 50,
745 );
746 assert!(usage.success);
747 assert_eq!(usage.name, "calculator");
748 }
749}