1use super::*;
2
3#[derive(Clone)]
4pub struct RunOptions {
5 pub worker_exe: PathBuf,
6}
7
8#[derive(Debug, Clone, serde::Serialize)]
9pub(crate) struct ZellijAdoptCandidate {
10 pub(crate) zellij_session: String,
11 pub(crate) zellij_pane_id: String,
12 pub(crate) title: String,
13 pub(crate) cwd: String,
14 pub(crate) cli_id: String,
15 pub(crate) cli_pid: Option<i32>,
16 pub(crate) pane_cols: Option<u16>,
17 pub(crate) pane_rows: Option<u16>,
18}
19
20#[derive(Debug, Clone, serde::Deserialize)]
21pub(crate) struct AdoptZellijSessionRequest {
22 pub(crate) zellij_session: String,
23 pub(crate) zellij_pane_id: String,
24 pub(crate) cli_id: String,
25 pub(crate) cli_bin: String,
26 pub(crate) title: Option<String>,
27 pub(crate) cwd: String,
28 pub(crate) pane_cols: Option<u16>,
29 pub(crate) pane_rows: Option<u16>,
30 #[serde(default)]
31 pub(crate) lark_app_id: Option<String>,
32 #[serde(default)]
33 pub(crate) chat_id: Option<String>,
34 #[serde(default)]
35 pub(crate) chat_type: Option<String>,
36 #[serde(default)]
37 pub(crate) root_message_id: Option<String>,
38 #[serde(default)]
39 pub(crate) scope: Option<SessionScope>,
40 #[serde(default)]
41 pub(crate) thread_id: Option<String>,
42 #[serde(default)]
43 pub(crate) owner_open_id: Option<String>,
44}
45
46#[derive(Clone)]
47pub(crate) struct AppState {
48 pub(crate) paths: BeamPaths,
49 pub(crate) started_at: chrono::DateTime<Utc>,
50 pub(crate) sessions: Arc<Mutex<HashMap<String, Session>>>,
51 pub(crate) workers: Arc<Mutex<HashMap<String, WorkerHandle>>>,
52 pub(crate) attempt_resumes: Arc<Mutex<HashMap<String, AttemptResumeEntry>>>,
53 pub(crate) shutdown: Arc<Mutex<Option<tokio::sync::oneshot::Sender<()>>>>,
54 pub(crate) options: RunOptions,
55 pub(crate) http: Client,
56 pub(crate) config: Config,
57 pub(crate) bots: Arc<HashMap<String, BotConfig>>,
58 pub(crate) lark_tokens: Arc<Mutex<HashMap<String, CachedLarkToken>>>,
59 pub(crate) chat_mode_cache: Arc<Mutex<HashMap<String, CachedChatMode>>>,
60 pub(crate) recent_lark_events: Arc<Mutex<HashMap<String, Instant>>>,
61 pub(crate) inflight_final_output_turns: Arc<Mutex<HashSet<String>>>,
62 pub(crate) workflow_progress_cards: Arc<Mutex<HashMap<String, String>>>,
63 pub(crate) ask_pending: Arc<Mutex<HashMap<String, ask::AskPendingEntry>>>,
64 pub(crate) grant_pending: Arc<Mutex<HashMap<String, grant::GrantPendingEntry>>>,
65 pub(crate) pending_creates: Arc<Mutex<HashMap<String, dir_select::PendingCreateSession>>>,
66 pub(crate) dashboard_token: Arc<Mutex<Option<DashboardAuthToken>>>,
67 pub(crate) external_host: String,
68}
69
70pub(crate) struct WorkerHandle {
71 pub(crate) child: Child,
72 pub(crate) stdin: Arc<Mutex<ChildStdin>>,
73}
74
75#[derive(Debug, Clone)]
76pub(crate) struct CachedLarkToken {
77 pub(crate) token: String,
78 pub(crate) expires_at: Instant,
79}
80
81#[derive(Debug, Clone)]
82pub(crate) struct CachedChatMode {
83 pub(crate) mode: ChatMode,
84 pub(crate) cached_at: Instant,
85}
86
87#[derive(Debug, Clone)]
88pub(crate) struct DashboardAuthToken {
89 pub(crate) token: String,
90 pub(crate) expires_at: Instant,
91}
92
93#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
94pub(crate) struct AttemptResumeSidecar {
95 pub(crate) schema_version: u64,
96 pub(crate) resume_id: String,
97 pub(crate) run_id: String,
98 pub(crate) activity_id: String,
99 pub(crate) attempt_id: String,
100 pub(crate) session_id: String,
101 pub(crate) original_session_id: String,
102 pub(crate) cli_session_id: Option<String>,
103 pub(crate) web_port: Option<u16>,
104 pub(crate) write_token: Option<String>,
105 pub(crate) status: String,
106 pub(crate) lark_app_id: String,
107 pub(crate) bot_name: Option<String>,
108 pub(crate) cli_id: String,
109 pub(crate) working_dir: String,
110 pub(crate) log_path: String,
111 pub(crate) started_at: u64,
112 pub(crate) updated_at: u64,
113 pub(crate) closed_at: Option<u64>,
114 pub(crate) close_reason: Option<String>,
115}
116
117#[derive(Debug, Clone)]
118pub(crate) struct AttemptResumeEntry {
119 pub(crate) resume_id: String,
120 pub(crate) run_id: String,
121 pub(crate) activity_id: String,
122 pub(crate) attempt_id: String,
123 pub(crate) session_id: String,
124 pub(crate) original_session_id: String,
125 pub(crate) cli_session_id: Option<String>,
126 pub(crate) lark_app_id: String,
127 pub(crate) bot_name: Option<String>,
128 pub(crate) cli_id: String,
129 pub(crate) working_dir: String,
130 pub(crate) log_path: String,
131 pub(crate) sidecar_path: String,
132 pub(crate) started_at: u64,
133 pub(crate) updated_at: u64,
134 pub(crate) web_port: Option<u16>,
135 pub(crate) write_token: Option<String>,
136 pub(crate) close_reason: Option<String>,
137}
138
139#[derive(Debug)]
140pub(crate) enum AttemptResumeWaitOutcome {
141 Ready(AttemptResumeEntry),
142 Failed {
143 error: String,
144 message: Option<String>,
145 },
146}
147
148#[derive(Debug, serde::Deserialize)]
149pub(crate) struct LarkTokenResponse {
150 pub(crate) code: i32,
151 pub(crate) msg: Option<String>,
152 pub(crate) tenant_access_token: Option<String>,
153 pub(crate) expire: Option<u64>,
154}
155
156#[derive(Debug, serde::Deserialize)]
157pub(crate) struct LarkMessageResponse {
158 pub(crate) code: Option<i32>,
159 pub(crate) msg: Option<String>,
160 pub(crate) data: Option<LarkMessageResponseData>,
161}
162
163#[derive(Debug, serde::Deserialize)]
164pub(crate) struct LarkMessageResponseData {
165 pub(crate) message_id: Option<String>,
166}
167
168#[derive(Debug, Clone, serde::Deserialize)]
169pub(crate) struct WorkflowRunRequest {
170 #[serde(default, rename = "rawParams")]
171 pub(crate) raw_params: BTreeMap<String, String>,
172 #[serde(default)]
173 pub(crate) initiator: Option<String>,
174 #[serde(default, rename = "chatBinding")]
175 pub(crate) chat_binding: Option<RunChatBinding>,
176}
177
178#[derive(Debug, Clone, serde::Deserialize, Default)]
179pub(crate) struct WorkflowWindowQuery {
180 #[serde(default)]
181 pub(crate) tail: Option<usize>,
182 #[serde(default, rename = "beforeSeq")]
183 pub(crate) before_seq: Option<u64>,
184 #[serde(default, rename = "afterSeq")]
185 pub(crate) after_seq: Option<u64>,
186 #[serde(default)]
187 pub(crate) limit: Option<usize>,
188}
189
190#[derive(Debug, Clone, serde::Deserialize, Default)]
191pub(crate) struct WorkflowRunsQuery {
192 #[serde(default)]
193 pub(crate) all: Option<String>,
194 #[serde(default)]
195 pub(crate) status: Option<String>,
196}
197
198#[derive(Debug, Clone, serde::Deserialize)]
199pub(crate) struct WorkflowCancelRequest {
200 #[serde(default)]
201 pub(crate) reason: Option<String>,
202}
203
204#[derive(Debug, Clone, serde::Deserialize)]
205pub(crate) struct WorkflowWaitActionRequest {
206 #[serde(default)]
207 pub(crate) comment: Option<String>,
208}
209
210#[derive(Debug, Clone, serde::Deserialize)]
211pub(crate) struct WorkflowResumeRequest {
212 #[serde(default)]
213 pub(crate) reason: Option<String>,
214}
215
216#[derive(Debug, Clone, serde::Deserialize)]
217pub(crate) struct WorkflowRunTriggerBody {
218 #[serde(default, rename = "params")]
219 pub(crate) params: BTreeMap<String, Value>,
220 #[serde(default, rename = "chatBinding")]
221 pub(crate) chat_binding: Option<RunChatBinding>,
222}
223
224#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
225#[serde(rename_all = "camelCase")]
226pub(crate) struct ApiTriggerSource {
227 #[serde(rename = "type")]
228 pub(crate) source_type: String,
229 #[serde(default)]
230 pub(crate) connector_id: Option<String>,
231 #[serde(default)]
232 pub(crate) request_id: Option<String>,
233 #[serde(default)]
234 pub(crate) received_at: Option<String>,
235}
236
237#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
238#[serde(rename_all = "camelCase")]
239pub(crate) struct ApiTriggerTarget {
240 pub(crate) kind: String,
241 #[serde(default)]
242 pub(crate) bot_id: Option<String>,
243 #[serde(default)]
244 pub(crate) chat_id: Option<String>,
245 #[serde(default)]
246 pub(crate) session_id: Option<String>,
247 #[serde(default)]
248 pub(crate) workflow_id: Option<String>,
249}
250
251#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
252#[serde(rename_all = "camelCase")]
253pub(crate) struct ApiTriggerEnvelope {
254 pub(crate) format: String,
255 pub(crate) source_name: String,
256 pub(crate) trusted: bool,
257 #[serde(default)]
258 pub(crate) headers: Option<Value>,
259 #[serde(default)]
260 pub(crate) payload: Option<Value>,
261 #[serde(default)]
262 pub(crate) raw_text: Option<String>,
263}
264
265#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, Default)]
266#[serde(rename_all = "camelCase")]
267pub(crate) struct ApiTriggerOptions {
268 #[serde(default)]
269 pub(crate) dry_run: Option<bool>,
270 #[serde(default)]
271 pub(crate) dedup_key: Option<String>,
272 #[serde(default)]
273 pub(crate) status: Option<String>,
274}
275
276#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
277#[serde(rename_all = "camelCase")]
278pub(crate) struct ApiTriggerRequest {
279 pub(crate) source: ApiTriggerSource,
280 pub(crate) target: ApiTriggerTarget,
281 pub(crate) envelope: ApiTriggerEnvelope,
282 #[serde(default)]
283 pub(crate) options: ApiTriggerOptions,
284}
285
286#[derive(Debug, Clone, serde::Deserialize)]
287pub(crate) struct FeishuResumeInput {
288 #[serde(rename = "larkAppId")]
289 pub(crate) lark_app_id: String,
290 #[serde(rename = "chatId", default)]
291 pub(crate) chat_id: Option<String>,
292 #[serde(rename = "rootMessageId", default)]
293 pub(crate) root_message_id: Option<String>,
294 pub(crate) content: String,
295}
296
297#[derive(Debug, Clone, PartialEq, Eq)]
298pub(crate) struct FeishuResumeOutcome {
299 pub(crate) activity_id: String,
300 pub(crate) attempt_id: String,
301 pub(crate) decision: String,
302}
303
304#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
305#[serde(rename_all = "camelCase")]
306pub(crate) struct FeishuTransientFailure {
307 pub(crate) activity_id: String,
308 pub(crate) attempt_id: String,
309 pub(crate) provider: String,
310 pub(crate) idempotency_key: String,
311 pub(crate) error_code: String,
312 pub(crate) error_class: String,
313 pub(crate) error_message: String,
314}
315
316#[derive(Debug, Clone, PartialEq, Eq, Default)]
317pub(crate) struct FeishuResumeResult {
318 pub(crate) reconciled: Vec<FeishuResumeOutcome>,
319 pub(crate) fresh_retry: Vec<FeishuResumeOutcome>,
320 pub(crate) transient_failures: Vec<FeishuTransientFailure>,
321 pub(crate) skipped: Vec<String>,
322}
323
324#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
325pub(crate) struct WorkflowFeishuSendInput {
326 #[serde(rename = "larkAppId")]
327 pub(crate) lark_app_id: String,
328 #[serde(rename = "chatId")]
329 pub(crate) chat_id: String,
330 pub(crate) content: String,
331 #[serde(rename = "msgType", default)]
332 pub(crate) _msg_type: Option<String>,
333}
334
335#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
336pub(crate) struct WorkflowFeishuReplyInput {
337 #[serde(rename = "larkAppId")]
338 pub(crate) lark_app_id: String,
339 #[serde(rename = "rootMessageId")]
340 pub(crate) root_message_id: String,
341 pub(crate) content: String,
342 #[serde(rename = "msgType", default)]
343 pub(crate) _msg_type: Option<String>,
344 #[serde(rename = "replyInThread", default)]
345 pub(crate) _reply_in_thread: Option<bool>,
346}
347
348#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
349pub(crate) struct FrozenCard {
350 pub(crate) message_id: String,
351 pub(crate) content: String,
352 pub(crate) title: String,
353 #[serde(default)]
354 pub(crate) display_mode: Option<DisplayMode>,
355 #[serde(default)]
356 pub(crate) image_key: Option<String>,
357}
358
359#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
360pub(crate) struct PendingResponsePatchMarker {
361 pub(crate) session_id: String,
362 pub(crate) card_id: String,
363 pub(crate) state: String,
364 pub(crate) created_at: String,
365 #[serde(default)]
366 pub(crate) patched_at: Option<String>,
367}
368
369pub(crate) const FINAL_OUTPUT_RETRY_BACKOFF_MS: [u64; 3] = [0, 5_000, 15_000];
370
371#[derive(Debug, Clone, Copy, PartialEq, Eq)]
372pub(crate) enum PrivateCardDelivery {
373 Ephemeral,
374 DirectMessage,
375}
376
377#[derive(Debug, Clone, PartialEq, Eq)]
378pub(crate) enum CardRenderTarget {
379 CallbackRaw,
380 PatchMessage(String),
381}
382
383#[derive(Debug, Clone, Copy, PartialEq, Eq)]
384pub(crate) enum LarkCardDeliveryPlan {
385 NotReady,
386 PostNew,
387 PatchExisting,
388}