1use std::path::PathBuf;
8
9use crate::inference::TokenUsage;
10use crate::policy_mode::PolicyMode;
11use async_trait::async_trait;
12
13#[derive(Debug, Clone)]
14pub struct BackendStart {
15 pub cwd: PathBuf,
16 pub model: Option<String>,
17 pub resume_thread: Option<String>,
18 pub policy_mode: PolicyMode,
19}
20
21#[derive(Debug, Clone, PartialEq)]
22pub enum BackendEvent {
23 TurnStarted {
24 turn_id: String,
25 },
26 Text(String),
27 Usage(TokenUsage),
28 ProviderMetadata(serde_json::Value),
29 ToolStarted {
30 id: String,
31 label: String,
32 },
33 ToolOutput {
34 id: String,
35 text: String,
36 },
37 ToolFinished {
38 id: String,
39 label: String,
40 summary: String,
41 },
42 FileChanged {
43 path: String,
44 change_type: String,
45 },
46 Approval {
47 request_id: String,
48 description: String,
49 },
50 Question {
51 request_id: String,
52 questions: Vec<BackendQuestion>,
53 },
54 TurnFinished {
55 turn_id: String,
56 status: String,
57 },
58 Notice(String),
59}
60
61#[derive(Debug, Clone, PartialEq, Eq)]
62pub struct BackendQuestion {
63 pub id: String,
64 pub text: String,
65 pub options: Vec<String>,
66}
67
68#[derive(Debug, Clone, Default)]
69pub struct BackendThreadSnapshot {
70 pub preview: String,
71 pub cwd: String,
72 pub created_at: i64,
73 pub updated_at: i64,
74 pub turns: Vec<BackendHistoryTurn>,
75}
76
77#[derive(Debug, Clone)]
78pub struct BackendThreadSummary {
79 pub id: String,
80 pub model: String,
81 pub snapshot: BackendThreadSnapshot,
82}
83
84#[derive(Debug, Clone)]
85pub struct BackendModel {
86 pub id: String,
87 pub name: String,
88 pub is_default: bool,
89 pub default_reasoning: String,
90 pub reasoning_efforts: Vec<String>,
91}
92
93#[derive(Debug, Clone)]
94pub struct BackendHistoryTurn {
95 pub id: String,
96 pub status: String,
97 pub started_at: Option<i64>,
98 pub completed_at: Option<i64>,
99 pub items: Vec<BackendHistoryItem>,
100}
101
102#[derive(Debug, Clone)]
103pub enum BackendHistoryItem {
104 User {
105 id: String,
106 text: String,
107 },
108 Agent {
109 id: String,
110 text: String,
111 },
112 Tool {
113 id: String,
114 name: String,
115 output: Option<String>,
116 status: String,
117 },
118 Other {
119 id: String,
120 payload: serde_json::Value,
121 },
122}
123
124#[async_trait]
125pub trait AgentBackend: Send + Sync {
126 fn id(&self) -> &'static str;
127
128 async fn connect(&self, start: BackendStart) -> anyhow::Result<Box<dyn AgentBackendSession>>;
129 async fn list_threads(
130 &self,
131 cwd: PathBuf,
132 limit: Option<usize>,
133 ) -> anyhow::Result<Vec<BackendThreadSummary>>;
134 async fn list_models(&self, cwd: PathBuf) -> anyhow::Result<Vec<BackendModel>>;
135}
136
137#[async_trait]
138pub trait AgentBackendSession: Send {
139 fn thread_id(&self) -> &str;
140 fn model(&self) -> &str;
141 fn reasoning(&self) -> &str;
142 fn snapshot(&self) -> BackendThreadSnapshot;
143 async fn send(
144 &mut self,
145 text: String,
146 policy_mode: Option<PolicyMode>,
147 model: Option<String>,
148 reasoning: Option<String>,
149 ) -> anyhow::Result<String>;
150 async fn interrupt(&mut self) -> anyhow::Result<()>;
151 async fn archive(&mut self) -> anyhow::Result<()>;
152 async fn approve(&mut self, request_id: &str, approved: bool) -> anyhow::Result<()>;
153 async fn answer(
154 &mut self,
155 request_id: &str,
156 answers: Vec<(String, String)>,
157 ) -> anyhow::Result<()>;
158 async fn next_event(&mut self) -> anyhow::Result<BackendEvent>;
159}