1use async_trait::async_trait;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct AgentRequest {
6 pub prompt: String,
7 pub profile_names: Vec<String>,
8 pub model: String,
9 #[serde(default, skip_serializing_if = "Option::is_none")]
11 pub system_prompt: Option<String>,
12 #[serde(default)]
13 pub history: Vec<ChatMessage>,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
17pub struct ChatMessage {
18 pub role: String,
19 pub content: String,
20 #[serde(default, skip_serializing_if = "Vec::is_empty")]
21 pub tool_calls: Vec<ToolCall>,
22 #[serde(default, skip_serializing_if = "Option::is_none")]
23 pub tool_call_id: Option<String>,
24}
25
26impl ChatMessage {
27 pub fn text(role: &str, content: impl Into<String>) -> Self {
28 Self {
29 role: role.into(),
30 content: content.into(),
31 tool_calls: Vec::new(),
32 tool_call_id: None,
33 }
34 }
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
38pub struct ToolCall {
39 pub id: String,
40 pub name: String,
41 pub arguments: serde_json::Value,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
45pub struct ToolMetadata {
46 pub name: String,
47 pub status: String,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct ChatRequest {
52 pub model: String,
53 pub messages: Vec<ChatMessage>,
54 pub tools: Vec<ToolDefinition>,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct ChatResponse {
59 pub message: ChatMessage,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
65#[serde(tag = "type", rename_all = "snake_case")]
66pub enum AgentEvent {
67 AssistantText {
68 text: String,
69 },
70 ToolRequested {
73 name: String,
74 #[serde(default, skip_serializing_if = "serde_json::Value::is_null")]
75 arguments: serde_json::Value,
76 },
77 ToolCompleted {
78 name: String,
79 summary: String,
80 },
81 ToolDenied {
82 name: String,
83 reason: String,
84 },
85 Complete,
86}
87
88#[async_trait]
89pub trait ApprovalDecider: Send + Sync {
90 async fn approve(&self, tool: &ToolDefinition, arguments: &serde_json::Value) -> bool;
93}
94
95pub struct AllowReadOnlyApproval;
96
97#[async_trait]
98impl ApprovalDecider for AllowReadOnlyApproval {
99 async fn approve(&self, _: &ToolDefinition, _: &serde_json::Value) -> bool {
100 true
101 }
102}
103
104#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
105pub enum ProviderError {
106 #[error("provider request failed: {0}")]
107 Request(String),
108 #[error("provider returned an invalid response")]
109 InvalidResponse,
110 #[error("provider is not configured: {0}")]
111 Configuration(String),
112 #[error("provider stream was cancelled")]
113 Cancelled,
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct ToolDefinition {
118 pub name: String,
119 pub description: String,
120 pub read_only: bool,
121 pub parameters: serde_json::Value,
122 pub requires_approval: bool,
123}
124
125#[async_trait]
126pub trait ToolExecutor: Send + Sync {
127 async fn execute(
128 &self,
129 name: &str,
130 arguments: serde_json::Value,
131 ) -> Result<serde_json::Value, String>;
132}