Skip to main content

agent_runtime/
types.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[cfg(test)]
5#[path = "types_test.rs"]
6mod types_test;
7
8/// Unique identifier for workflows
9pub type WorkflowId = String;
10
11/// Unique identifier for events
12pub type EventId = String;
13
14/// Sequential offset for event ordering
15pub type EventOffset = u64;
16
17/// Generic JSON value for flexible data passing
18pub type JsonValue = serde_json::Value;
19
20/// Input data passed to an agent
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct AgentInput {
23    pub data: JsonValue,
24    pub metadata: AgentInputMetadata,
25
26    /// Optional pre-built chat history. If provided, this is used directly
27    /// instead of building messages from data. Allows outer layer to manage
28    /// conversation context across multiple agent calls.
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub chat_history: Option<Vec<crate::llm::types::ChatMessage>>,
31}
32
33impl AgentInput {
34    /// Create a new AgentInput from a text string
35    pub fn from_text(text: impl Into<String>) -> Self {
36        Self {
37            data: serde_json::json!(text.into()),
38            metadata: AgentInputMetadata {
39                step_index: 0,
40                previous_agent: None,
41            },
42            chat_history: None,
43        }
44    }
45
46    /// Create a new AgentInput from any JSON-serializable value
47    pub fn from_value(value: JsonValue) -> Self {
48        Self {
49            data: value,
50            metadata: AgentInputMetadata {
51                step_index: 0,
52                previous_agent: None,
53            },
54            chat_history: None,
55        }
56    }
57
58    /// Create a new AgentInput with metadata
59    pub fn with_metadata(data: JsonValue, metadata: AgentInputMetadata) -> Self {
60        Self {
61            data,
62            metadata,
63            chat_history: None,
64        }
65    }
66
67    /// Create a new AgentInput from existing chat messages
68    /// This allows the outer layer to manage conversation history and context.
69    ///
70    /// # Example
71    /// ```
72    /// use agent_runtime::{AgentInput, ChatMessage};
73    ///
74    /// let mut history = vec![
75    ///     ChatMessage::system("You are a helpful assistant"),
76    ///     ChatMessage::user("What's 2+2?"),
77    ///     ChatMessage::assistant("4"),
78    ///     ChatMessage::user("What about 3+3?"),
79    /// ];
80    ///
81    /// let input = AgentInput::from_messages(history);
82    /// // Agent will continue this conversation
83    /// ```
84    pub fn from_messages(messages: Vec<crate::llm::types::ChatMessage>) -> Self {
85        Self {
86            data: serde_json::Value::Null, // Not used when messages provided
87            metadata: AgentInputMetadata {
88                step_index: 0,
89                previous_agent: None,
90            },
91            chat_history: Some(messages),
92        }
93    }
94
95    /// Create a new AgentInput from chat messages with custom metadata
96    pub fn from_messages_with_metadata(
97        messages: Vec<crate::llm::types::ChatMessage>,
98        metadata: AgentInputMetadata,
99    ) -> Self {
100        Self {
101            data: serde_json::Value::Null,
102            metadata,
103            chat_history: Some(messages),
104        }
105    }
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct AgentInputMetadata {
110    pub step_index: usize,
111    pub previous_agent: Option<String>,
112}
113
114/// Output data produced by an agent
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct AgentOutput {
117    pub data: JsonValue,
118    pub metadata: AgentOutputMetadata,
119
120    /// The complete chat history after agent execution.
121    /// This includes all messages (system, user, assistant, tool) that were
122    /// part of the conversation. Useful for:
123    /// - Continuing multi-turn conversations
124    /// - Saving and resuming agent state
125    /// - Debugging agent behavior
126    #[serde(skip_serializing_if = "Option::is_none")]
127    pub chat_history: Option<Vec<crate::llm::types::ChatMessage>>,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct AgentOutputMetadata {
132    pub agent_name: String,
133    pub execution_time_ms: u64,
134    pub tool_calls_count: usize,
135}
136
137/// Result type for agent execution
138pub type AgentResult = Result<AgentOutput, AgentError>;
139
140/// Errors that can occur during agent execution
141#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
142pub enum AgentError {
143    #[error("Tool execution failed: {0}")]
144    ToolError(String),
145
146    #[error("Invalid input: {0}")]
147    InvalidInput(String),
148
149    #[error("Execution failed: {0}")]
150    ExecutionError(String),
151}
152
153/// Tool invocation parameters
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct ToolCall {
156    pub tool_name: String,
157    pub parameters: HashMap<String, JsonValue>,
158}
159
160/// Status of a tool execution
161#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
162#[serde(rename_all = "snake_case")]
163pub enum ToolStatus {
164    /// Tool executed successfully and returned data
165    #[default]
166    Success,
167
168    /// Tool executed successfully but found no data/results
169    /// This signals to the LLM: "Don't retry, this is a valid empty result"
170    SuccessNoData,
171
172    /// Tool execution failed
173    Error,
174}
175
176/// Tool execution result
177#[derive(Debug, Clone, Serialize, Deserialize)]
178pub struct ToolResult {
179    pub output: JsonValue,
180    /// Duration in milliseconds with microsecond precision (e.g., 0.123 ms)
181    pub duration_ms: f64,
182    /// Status of the execution
183    #[serde(default)]
184    pub status: ToolStatus,
185    /// Optional message explaining the result
186    pub message: Option<String>,
187}
188
189impl ToolResult {
190    /// Create a successful result with data
191    pub fn success(output: JsonValue, duration_ms: f64) -> Self {
192        Self {
193            output,
194            duration_ms,
195            status: ToolStatus::Success,
196            message: None,
197        }
198    }
199
200    /// Create a successful result with no data
201    pub fn success_no_data(message: impl Into<String>, duration_ms: f64) -> Self {
202        Self {
203            output: JsonValue::Null,
204            duration_ms,
205            status: ToolStatus::SuccessNoData,
206            message: Some(message.into()),
207        }
208    }
209
210    /// Create an error result
211    pub fn error(message: impl Into<String>, duration_ms: f64) -> Self {
212        Self {
213            output: JsonValue::Null,
214            duration_ms,
215            status: ToolStatus::Error,
216            message: Some(message.into()),
217        }
218    }
219
220    /// Add a message to this result
221    pub fn with_message(mut self, message: impl Into<String>) -> Self {
222        self.message = Some(message.into());
223        self
224    }
225}
226
227/// Result type for tool execution
228pub type ToolExecutionResult = Result<ToolResult, ToolError>;
229
230/// Errors that can occur during tool execution
231#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
232pub enum ToolError {
233    #[error("Invalid parameters: {0}")]
234    InvalidParameters(String),
235
236    #[error("Execution failed: {0}")]
237    ExecutionFailed(String),
238}