1pub mod agent_node;
2pub mod chrome;
3pub mod hosted;
4pub mod methods;
5pub mod schema;
6pub mod speech;
7pub mod stats;
8pub mod workflows;
9
10use roder_api::artifacts::{
11 ArtifactGrepPage, ArtifactReadPage, ArtifactTailPage, ContextArtifactDescriptor,
12 ContextArtifactKind,
13};
14
15use roder_api::automations::{
16 AutomationConcurrencyPolicy, AutomationDefinition, AutomationId, AutomationProject,
17 AutomationRunId, AutomationRunState, AutomationRunSummary, AutomationSchedule, CatchUpPolicy,
18};
19use roder_api::capabilities::CapabilityStatus;
20use roder_api::code_index::{
21 CodeChunk, CodeIndexGenerationId, CodeIndexSearchResponse, CodeIndexStats, CodeIndexStatus,
22 ContentProof,
23};
24use roder_api::context::ContextBlock;
25use roder_api::discovery::{
26 DiscoveryCatalog, DiscoveryCatalogGroup, DiscoveryCatalogItem, DiscoveryPromotionRecord,
27};
28use roder_api::events::{ThreadId, TurnId};
29use roder_api::extension::{ExtensionId, ExtensionManifest};
30pub use roder_api::forks::WorkspaceFork;
31pub use roder_api::goals::{ThreadGoal, ThreadGoalStatus};
32use roder_api::inference::{
33 HostedWebSearchMode, InferenceCapabilities, ModelDescriptor, ModelSelection, ProviderAuthType,
34 TokenUsage,
35};
36use roder_api::inference_routing::{
37 InferenceRoutingCostDelta, InferenceRoutingDecision, InferenceRoutingOptionDescriptor,
38 InferenceRoutingOutcome, ModelSelectionMode,
39};
40use roder_api::knowledge::{
41 KnowledgeDocId, KnowledgeDocSummary, KnowledgeDocument, KnowledgeKind, KnowledgeLinkType,
42 KnowledgeRevisionInfo, KnowledgeSearchResult as KnowledgeSearchMatch, KnowledgeStatus,
43};
44use roder_api::marketplace::{
45 DedupedMarketplacePlugin, DefaultMarketplaceSelection, InstalledPluginRecord,
46 MarketplaceDescriptor, MarketplaceKind, MarketplacePluginEntry, MarketplaceSource,
47};
48use roder_api::media::{MediaArtifact, MediaArtifactId, MediaAttachment, MediaPreview};
49use roder_api::memory::{
50 MemoryId, MemoryProviderSelection, MemoryRecord, MemoryScope, MemorySearchResult,
51};
52use roder_api::packages::{PackageRecord, PackageResource, PackageResourceFilters, PackageScope};
53use roder_api::plan_review::{
54 HunkId, HunkRecord, PagedHunkDiff, PlanComment, PlanCommentAnchor, PlanReview, PlanReviewId,
55 PlanRewrite,
56};
57use roder_api::policy_mode::PolicyMode;
58use roder_api::processes::{ProcessDescriptor, ProcessId, ProcessOutput, ProcessStopResult};
59use roder_api::retrieval::{RetrievalMeasuredOutcome, RetrievalMode, RetrievalRoutePlan};
60use roder_api::skills::{Skill, SkillDescriptor, SkillExposure, SkillSelector};
61use roder_api::subagents::SubagentPermissionMode;
62use roder_api::tasks::{TaskHandle, TaskOutputStream};
63use roder_api::teams::{
64 AgentTeamDisplayMode, TeamId, TeamMailboxMessage, TeamMemberDescriptor, TeamMemberId,
65 TeamMemberStatus, TeamTaskDescriptor,
66};
67use roder_api::thread::ThreadUsageMetadata;
68use roder_api::tools::ToolSpec;
69use roder_api::trace::{SubagentTraceDelta, SubagentTraceId, SubagentTraceSummary};
70use roder_api::transcript::InputImage;
71use roder_api::version_control::VcsChangeArea;
72use roder_api::workflow::{
73 WorkflowImportDecision, WorkflowImportItem, WorkflowImportScan, WorkflowImportState,
74};
75use roder_api::workspace_changes::WorkspaceChangeObservation;
76use serde::{Deserialize, Serialize};
77use std::collections::BTreeMap;
78use std::collections::HashMap;
79use time::OffsetDateTime;
80
81pub use chrome::*;
82pub use speech::*;
83pub use workflows::*;
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct JsonRpcRequest {
87 #[serde(default = "default_jsonrpc_version")]
88 pub jsonrpc: String,
89 pub id: Option<serde_json::Value>,
90 pub method: String,
91 pub params: Option<serde_json::Value>,
92}
93
94fn default_jsonrpc_version() -> String {
95 "2.0".to_string()
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct JsonRpcResponse {
100 pub jsonrpc: String,
101 pub id: Option<serde_json::Value>,
102 #[serde(skip_serializing_if = "Option::is_none")]
103 pub result: Option<serde_json::Value>,
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub error: Option<JsonRpcError>,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct JsonRpcNotification {
110 #[serde(default = "default_jsonrpc_version")]
111 pub jsonrpc: String,
112 pub method: String,
113 pub params: serde_json::Value,
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct JsonRpcError {
118 pub code: i32,
119 pub message: String,
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub data: Option<serde_json::Value>,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
125#[serde(rename_all = "camelCase")]
126pub struct InitializeResult {
127 pub provider: String,
128 pub model: String,
129 pub cwd: Option<String>,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
133#[serde(rename_all = "camelCase")]
134pub struct ThreadStatus {
135 #[serde(rename = "type")]
136 pub kind: String,
137 pub active_turn_id: Option<TurnId>,
138 pub active_flags: Vec<String>,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
142#[serde(rename_all = "camelCase")]
143pub struct Thread {
144 pub id: ThreadId,
145 pub preview: String,
146 pub model_provider: String,
147 pub model: String,
148 #[serde(default, skip_serializing_if = "Option::is_none")]
149 pub selection_mode: Option<ModelSelectionMode>,
150 pub created_at: i64,
151 pub updated_at: i64,
152 pub status: ThreadStatus,
153 pub cwd: String,
154 #[serde(default, skip_serializing_if = "Option::is_none")]
155 pub workspace_id: Option<String>,
156 #[serde(default, skip_serializing_if = "Option::is_none")]
157 pub root_id: Option<String>,
158 #[serde(default, skip_serializing_if = "Option::is_none")]
159 pub name: Option<String>,
160 #[serde(default, skip_serializing_if = "Option::is_none")]
161 pub message_count: Option<u32>,
162 #[serde(default, skip_serializing_if = "Option::is_none")]
163 pub turns: Option<Vec<Turn>>,
164 #[serde(default, skip_serializing_if = "Option::is_none")]
165 pub usage: Option<ThreadUsageMetadata>,
166 #[serde(default, skip_serializing_if = "Vec::is_empty")]
168 pub tool_allowlist: Vec<String>,
169 #[serde(default, skip_serializing_if = "Option::is_none")]
171 pub developer_instructions: Option<String>,
172 #[serde(default, skip_serializing_if = "Vec::is_empty")]
177 pub external_tools: Vec<ToolSpec>,
178 #[serde(default, skip_serializing_if = "Option::is_none")]
184 pub runner: Option<ThreadRunnerParams>,
185 #[serde(default, skip_serializing_if = "Option::is_none")]
187 pub parent_thread_id: Option<ThreadId>,
188 #[serde(default, skip_serializing_if = "Option::is_none")]
190 pub workspace_fork: Option<WorkspaceFork>,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
194#[serde(rename_all = "camelCase")]
195pub struct Turn {
196 pub id: TurnId,
197 pub items: Vec<Item>,
198 pub items_view: String,
199 pub status: String,
200 #[serde(default, skip_serializing_if = "Option::is_none")]
201 pub error: Option<serde_json::Value>,
202 #[serde(default, skip_serializing_if = "Option::is_none")]
203 pub started_at: Option<i64>,
204 #[serde(default, skip_serializing_if = "Option::is_none")]
205 pub completed_at: Option<i64>,
206 #[serde(default, skip_serializing_if = "Option::is_none")]
207 pub duration_ms: Option<i64>,
208 #[serde(default, skip_serializing_if = "Option::is_none")]
209 pub usage: Option<TokenUsage>,
210 #[serde(default, skip_serializing_if = "Option::is_none")]
216 pub finish_reason: Option<String>,
217}
218
219#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
220#[serde(rename_all = "camelCase")]
221pub enum ThreadItemStatus {
222 InProgress,
223 Completed,
224 Failed,
225}
226
227impl From<roder_api::thread::ThreadItemStatus> for ThreadItemStatus {
228 fn from(value: roder_api::thread::ThreadItemStatus) -> Self {
229 match value {
230 roder_api::thread::ThreadItemStatus::InProgress => Self::InProgress,
231 roder_api::thread::ThreadItemStatus::Completed => Self::Completed,
232 roder_api::thread::ThreadItemStatus::Failed => Self::Failed,
233 }
234 }
235}
236
237#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
238#[serde(tag = "type", rename_all = "camelCase")]
239pub enum Item {
240 UserMessage {
241 id: String,
242 text: String,
243 #[serde(default, skip_serializing_if = "Vec::is_empty")]
244 images: Vec<InputImage>,
245 #[serde(default, skip_serializing_if = "Option::is_none")]
246 status: Option<ThreadItemStatus>,
247 },
248 AgentMessage {
249 id: String,
250 text: String,
251 #[serde(default, skip_serializing_if = "Option::is_none")]
252 phase: Option<String>,
253 #[serde(default, skip_serializing_if = "Option::is_none")]
254 status: Option<ThreadItemStatus>,
255 },
256 Reasoning {
257 id: String,
258 #[serde(default, skip_serializing_if = "Vec::is_empty")]
259 summary: Vec<String>,
260 #[serde(default, skip_serializing_if = "Vec::is_empty")]
261 content: Vec<String>,
262 #[serde(default, skip_serializing_if = "Option::is_none")]
263 status: Option<ThreadItemStatus>,
264 },
265 ToolExecution {
266 id: String,
267 #[serde(rename = "toolCallId")]
268 tool_call_id: String,
269 #[serde(rename = "toolName")]
270 tool_name: String,
271 status: ThreadItemStatus,
272 #[serde(default, skip_serializing_if = "Option::is_none")]
273 input: Option<serde_json::Value>,
274 #[serde(default, skip_serializing_if = "Option::is_none")]
275 output: Option<String>,
276 #[serde(default, skip_serializing_if = "Option::is_none")]
277 error: Option<String>,
278 },
279 RoutingDecision {
280 id: String,
281 decision: InferenceRoutingDecisionEvent,
282 #[serde(default, skip_serializing_if = "Option::is_none")]
283 status: Option<ThreadItemStatus>,
284 },
285 Compaction {
286 id: String,
287 summary: String,
288 #[serde(default, skip_serializing_if = "Option::is_none")]
289 status: Option<ThreadItemStatus>,
290 },
291 Error {
292 id: String,
293 message: String,
294 #[serde(default, skip_serializing_if = "Option::is_none")]
295 status: Option<ThreadItemStatus>,
296 },
297 Raw {
298 id: String,
299 payload: serde_json::Value,
300 #[serde(default, skip_serializing_if = "Option::is_none")]
301 status: Option<ThreadItemStatus>,
302 },
303}
304
305impl From<roder_api::thread::ThreadItem> for Item {
306 fn from(value: roder_api::thread::ThreadItem) -> Self {
307 match value {
308 roder_api::thread::ThreadItem::UserMessage {
309 id,
310 text,
311 images,
312 status,
313 } => Self::UserMessage {
314 id,
315 text,
316 images,
317 status: status.map(Into::into),
318 },
319 roder_api::thread::ThreadItem::AgentMessage {
320 id,
321 text,
322 phase,
323 status,
324 } => Self::AgentMessage {
325 id,
326 text,
327 phase,
328 status: status.map(Into::into),
329 },
330 roder_api::thread::ThreadItem::Reasoning {
331 id,
332 summary,
333 content,
334 status,
335 } => Self::Reasoning {
336 id,
337 summary,
338 content,
339 status: status.map(Into::into),
340 },
341 roder_api::thread::ThreadItem::ToolExecution {
342 id,
343 tool_call_id,
344 tool_name,
345 status,
346 input,
347 output,
348 error,
349 } => Self::ToolExecution {
350 id,
351 tool_call_id,
352 tool_name,
353 status: status.into(),
354 input,
355 output,
356 error,
357 },
358 roder_api::thread::ThreadItem::RoutingDecision {
359 id,
360 decision,
361 status,
362 } => Self::RoutingDecision {
363 id,
364 decision: decision.into(),
365 status: status.map(Into::into),
366 },
367 roder_api::thread::ThreadItem::Compaction {
368 id,
369 summary,
370 status,
371 } => Self::Compaction {
372 id,
373 summary,
374 status: status.map(Into::into),
375 },
376 roder_api::thread::ThreadItem::Error {
377 id,
378 message,
379 status,
380 } => Self::Error {
381 id,
382 message,
383 status: status.map(Into::into),
384 },
385 roder_api::thread::ThreadItem::Raw {
386 id,
387 payload,
388 status,
389 } => Self::Raw {
390 id,
391 payload,
392 status: status.map(Into::into),
393 },
394 }
395 }
396}
397
398#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
399#[serde(tag = "type", rename_all = "camelCase")]
400pub enum ThreadItemDelta {
401 AgentMessageText {
402 delta: String,
403 #[serde(default, skip_serializing_if = "Option::is_none")]
404 phase: Option<String>,
405 },
406 ReasoningText {
407 delta: String,
408 #[serde(rename = "contentIndex")]
409 content_index: usize,
410 },
411 ReasoningSummaryPartAdded {
412 #[serde(rename = "summaryIndex")]
413 summary_index: usize,
414 },
415 ReasoningSummaryText {
416 delta: String,
417 #[serde(rename = "summaryIndex")]
418 summary_index: usize,
419 },
420}
421
422impl From<roder_api::thread::ThreadItemDelta> for ThreadItemDelta {
423 fn from(value: roder_api::thread::ThreadItemDelta) -> Self {
424 match value {
425 roder_api::thread::ThreadItemDelta::AgentMessageText { delta, phase } => {
426 Self::AgentMessageText { delta, phase }
427 }
428 roder_api::thread::ThreadItemDelta::ReasoningText {
429 delta,
430 content_index,
431 } => Self::ReasoningText {
432 delta,
433 content_index,
434 },
435 roder_api::thread::ThreadItemDelta::ReasoningSummaryPartAdded { summary_index } => {
436 Self::ReasoningSummaryPartAdded { summary_index }
437 }
438 roder_api::thread::ThreadItemDelta::ReasoningSummaryText {
439 delta,
440 summary_index,
441 } => Self::ReasoningSummaryText {
442 delta,
443 summary_index,
444 },
445 }
446 }
447}
448
449#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
450#[serde(tag = "type", rename_all = "camelCase")]
451pub enum ThreadItemEventKind {
452 ItemStarted {
453 item: Item,
454 },
455 ItemDelta {
456 #[serde(rename = "itemId")]
457 item_id: String,
458 delta: ThreadItemDelta,
459 },
460 ItemCompleted {
461 item: Item,
462 },
463}
464
465impl From<roder_api::thread::ThreadItemEventKind> for ThreadItemEventKind {
466 fn from(value: roder_api::thread::ThreadItemEventKind) -> Self {
467 match value {
468 roder_api::thread::ThreadItemEventKind::ItemStarted { item } => {
469 Self::ItemStarted { item: item.into() }
470 }
471 roder_api::thread::ThreadItemEventKind::ItemDelta { item_id, delta } => {
472 Self::ItemDelta {
473 item_id,
474 delta: delta.into(),
475 }
476 }
477 roder_api::thread::ThreadItemEventKind::ItemCompleted { item } => {
478 Self::ItemCompleted { item: item.into() }
479 }
480 }
481 }
482}
483
484#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
485#[serde(rename_all = "camelCase")]
486pub struct ThreadItemEvent {
487 pub seq: u64,
488 pub event_id: String,
489 pub thread_id: ThreadId,
490 pub turn_id: TurnId,
491 #[serde(with = "time::serde::rfc3339")]
492 pub timestamp: OffsetDateTime,
493 pub event: ThreadItemEventKind,
494}
495
496impl From<roder_api::thread::ThreadItemEvent> for ThreadItemEvent {
497 fn from(value: roder_api::thread::ThreadItemEvent) -> Self {
498 Self {
499 seq: value.seq,
500 event_id: value.event_id,
501 thread_id: value.thread_id,
502 turn_id: value.turn_id,
503 timestamp: value.timestamp,
504 event: value.event.into(),
505 }
506 }
507}
508
509#[derive(Debug, Clone, Serialize, Deserialize)]
510#[serde(rename_all = "camelCase")]
511pub struct ThreadStartParams {
512 #[serde(default, skip_serializing_if = "Option::is_none")]
513 pub selection: Option<ModelSelectChoice>,
514 pub model: Option<String>,
515 pub model_provider: Option<String>,
516 pub reasoning: Option<String>,
517 pub workspace_id: String,
518 #[serde(default, skip_serializing_if = "Option::is_none")]
519 pub root_id: Option<String>,
520 #[serde(default, skip_serializing_if = "Option::is_none")]
521 pub cwd: Option<String>,
522 #[serde(default, skip_serializing_if = "Option::is_none")]
527 pub tool_allowlist: Option<Vec<String>>,
528 #[serde(default, skip_serializing_if = "Option::is_none")]
530 pub developer_instructions: Option<String>,
531 #[serde(default, skip_serializing_if = "Option::is_none")]
536 pub external_tools: Option<Vec<ToolSpec>>,
537 #[serde(default, skip_serializing_if = "Option::is_none")]
543 pub runner: Option<ThreadRunnerParams>,
544 #[serde(default)]
545 pub ephemeral: bool,
546}
547
548#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
549#[serde(rename_all = "camelCase")]
550pub struct ThreadRunnerParams {
551 pub provider_id: String,
553 #[serde(default, skip_serializing_if = "Option::is_none")]
558 pub config: Option<serde_json::Value>,
559 pub workspace: String,
561 #[serde(default, skip_serializing_if = "Vec::is_empty")]
567 pub read_roots: Vec<String>,
568}
569
570#[derive(Debug, Clone, Serialize, Deserialize)]
571#[serde(rename_all = "camelCase")]
572pub struct ThreadStartResult {
573 pub thread: Thread,
574 pub model: String,
575 pub model_provider: String,
576 pub reasoning: String,
577 #[serde(default, skip_serializing_if = "Option::is_none")]
578 pub selection_mode: Option<ModelSelectionMode>,
579 pub cwd: String,
580 pub workspace_id: String,
581 pub root_id: String,
582}
583
584#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
585#[serde(rename_all = "camelCase")]
586pub struct WorkspaceRoot {
587 pub id: String,
588 pub path: String,
589 pub name: String,
590}
591
592#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
593#[serde(rename_all = "camelCase")]
594pub struct Workspace {
595 pub id: String,
596 pub name: String,
597 pub roots: Vec<WorkspaceRoot>,
598 pub default_root_id: String,
599 pub updated_at: i64,
600}
601
602#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
603#[serde(rename_all = "camelCase")]
604pub struct WorkspaceRootInput {
605 pub path: String,
606 #[serde(default, skip_serializing_if = "Option::is_none")]
607 pub name: Option<String>,
608}
609
610#[derive(Debug, Clone, Serialize, Deserialize)]
611#[serde(rename_all = "camelCase")]
612pub struct WorkspaceListParams {}
613
614#[derive(Debug, Clone, Serialize, Deserialize)]
615#[serde(rename_all = "camelCase")]
616pub struct WorkspaceListResult {
617 pub workspaces: Vec<Workspace>,
618}
619
620#[derive(Debug, Clone, Serialize, Deserialize)]
621#[serde(rename_all = "camelCase")]
622pub struct WorkspaceCreateParams {
623 #[serde(default, skip_serializing_if = "Option::is_none")]
624 pub name: Option<String>,
625 pub roots: Vec<WorkspaceRootInput>,
626 #[serde(default, skip_serializing_if = "Option::is_none")]
627 pub default_root_path: Option<String>,
628}
629
630#[derive(Debug, Clone, Serialize, Deserialize)]
631#[serde(rename_all = "camelCase")]
632pub struct WorkspaceCreateResult {
633 pub workspace: Workspace,
634}
635
636#[derive(Debug, Clone, Serialize, Deserialize)]
637#[serde(rename_all = "camelCase")]
638pub struct WorkspaceUpdateParams {
639 pub workspace_id: String,
640 #[serde(default, skip_serializing_if = "Option::is_none")]
641 pub name: Option<String>,
642 #[serde(default, skip_serializing_if = "Option::is_none")]
643 pub roots: Option<Vec<WorkspaceRootInput>>,
644 #[serde(default, skip_serializing_if = "Option::is_none")]
645 pub default_root_id: Option<String>,
646}
647
648#[derive(Debug, Clone, Serialize, Deserialize)]
649#[serde(rename_all = "camelCase")]
650pub struct WorkspaceUpdateResult {
651 pub workspace: Workspace,
652}
653
654#[derive(Debug, Clone, Serialize, Deserialize)]
655#[serde(rename_all = "camelCase")]
656pub struct WorkspaceForgetParams {
657 pub workspace_id: String,
658}
659
660#[derive(Debug, Clone, Serialize, Deserialize)]
661#[serde(rename_all = "camelCase")]
662pub struct WorkspaceForgetResult {
663 pub workspace_id: String,
664 pub forgotten: bool,
665}
666
667#[derive(Debug, Clone, Serialize, Deserialize)]
668#[serde(rename_all = "camelCase")]
669pub struct ThreadListParams {
670 pub limit: Option<usize>,
671 #[serde(default, skip_serializing_if = "Option::is_none")]
672 pub cursor: Option<String>,
673}
674
675#[derive(Debug, Clone, Serialize, Deserialize)]
676#[serde(rename_all = "camelCase")]
677pub struct ThreadListResult {
678 pub data: Vec<Thread>,
679 pub next_cursor: Option<String>,
680 pub backwards_cursor: Option<String>,
681}
682
683#[derive(Debug, Clone, Serialize, Deserialize)]
684#[serde(rename_all = "camelCase")]
685pub struct ThreadReadParams {
686 pub thread_id: ThreadId,
687 #[serde(default)]
688 pub include_turns: bool,
689}
690
691#[derive(Debug, Clone, Serialize, Deserialize)]
692#[serde(rename_all = "camelCase")]
693pub struct ThreadReadResult {
694 pub thread: Option<Thread>,
695}
696
697#[derive(Debug, Clone, Serialize, Deserialize)]
698#[serde(rename_all = "camelCase")]
699pub struct ThreadArchiveParams {
700 pub thread_id: ThreadId,
701}
702
703#[derive(Debug, Clone, Serialize, Deserialize)]
704#[serde(rename_all = "camelCase")]
705pub struct ThreadArchiveResult {
706 pub thread_id: ThreadId,
707 pub archived: bool,
708}
709
710#[derive(Debug, Clone, Serialize, Deserialize)]
711#[serde(rename_all = "camelCase")]
712pub struct ThreadForkParams {
713 pub thread_id: ThreadId,
715 pub name: String,
717 #[serde(default, skip_serializing_if = "Option::is_none")]
719 pub from_turn_id: Option<TurnId>,
720 #[serde(default, skip_serializing_if = "Option::is_none")]
722 pub provider: Option<String>,
723 #[serde(default, skip_serializing_if = "Option::is_none")]
725 pub provider_config: Option<serde_json::Value>,
726}
727
728#[derive(Debug, Clone, Serialize, Deserialize)]
729#[serde(rename_all = "camelCase")]
730pub struct ThreadForkResult {
731 pub thread: Thread,
733 pub fork: WorkspaceFork,
734 #[serde(default, skip_serializing_if = "Vec::is_empty")]
735 pub warnings: Vec<String>,
736}
737
738#[derive(Debug, Clone, Serialize, Deserialize)]
739#[serde(rename_all = "camelCase")]
740pub struct ThreadForkStatusParams {
741 pub thread_id: ThreadId,
742}
743
744#[derive(Debug, Clone, Serialize, Deserialize)]
745#[serde(rename_all = "camelCase")]
746pub struct ThreadForkStatusResult {
747 pub thread_id: ThreadId,
748 #[serde(default, skip_serializing_if = "Option::is_none")]
749 pub parent_thread_id: Option<ThreadId>,
750 #[serde(default, skip_serializing_if = "Option::is_none")]
751 pub forked_from_turn_id: Option<TurnId>,
752 #[serde(default, skip_serializing_if = "Option::is_none")]
753 pub fork: Option<WorkspaceFork>,
754 pub workspace_missing: bool,
756}
757
758#[derive(Debug, Clone, Serialize, Deserialize)]
759#[serde(rename_all = "camelCase")]
760pub struct ThreadRemoveForkParams {
761 pub thread_id: ThreadId,
762 pub confirm_path: String,
764}
765
766#[derive(Debug, Clone, Serialize, Deserialize)]
767#[serde(rename_all = "camelCase")]
768pub struct ThreadRemoveForkResult {
769 pub thread_id: ThreadId,
770 pub fork: WorkspaceFork,
771}
772
773#[derive(Debug, Clone, Serialize, Deserialize)]
774#[serde(rename_all = "camelCase")]
775pub struct ForksProvidersListResult {
776 pub providers: Vec<roder_api::forks::ForkProviderDescriptor>,
777}
778
779#[derive(Debug, Clone, Serialize, Deserialize)]
780#[serde(rename_all = "camelCase")]
781pub struct ForksListParams {
782 pub source_workspace: String,
784 #[serde(default, skip_serializing_if = "Option::is_none")]
786 pub provider: Option<String>,
787}
788
789#[derive(Debug, Clone, Serialize, Deserialize)]
790#[serde(rename_all = "camelCase")]
791pub struct ForksListResult {
792 pub forks: Vec<WorkspaceFork>,
793}
794
795#[derive(Debug, Clone, Serialize, Deserialize)]
796#[serde(rename_all = "camelCase")]
797pub struct ForksCreateParams {
798 pub source_workspace: String,
799 #[serde(default, skip_serializing_if = "Option::is_none")]
800 pub name: Option<String>,
801 #[serde(default, skip_serializing_if = "Option::is_none")]
802 pub provider: Option<String>,
803 #[serde(default, skip_serializing_if = "Option::is_none")]
804 pub provider_config: Option<serde_json::Value>,
805}
806
807#[derive(Debug, Clone, Serialize, Deserialize)]
808#[serde(rename_all = "camelCase")]
809pub struct ForksCreateResult {
810 pub fork: WorkspaceFork,
811}
812
813#[derive(Debug, Clone, Serialize, Deserialize)]
814#[serde(rename_all = "camelCase")]
815pub struct ForksRemoveParams {
816 pub fork_id: String,
817 #[serde(default, skip_serializing_if = "Option::is_none")]
818 pub provider: Option<String>,
819 pub confirm_workspace: String,
821}
822
823#[derive(Debug, Clone, Serialize, Deserialize)]
824#[serde(rename_all = "camelCase")]
825pub struct ForksRemoveResult {
826 pub fork_id: String,
827 pub removed: bool,
828}
829
830#[derive(Debug, Clone, Serialize, Deserialize)]
831#[serde(rename_all = "camelCase")]
832pub struct ThreadGoalGetParams {
833 pub thread_id: ThreadId,
834}
835
836#[derive(Debug, Clone, Serialize, Deserialize)]
837#[serde(rename_all = "camelCase")]
838pub struct ThreadGoalGetResult {
839 pub goal: Option<ThreadGoal>,
840}
841
842#[derive(Debug, Clone, Serialize, Deserialize)]
843#[serde(rename_all = "camelCase")]
844pub struct ThreadGoalSetParams {
845 pub thread_id: ThreadId,
846 #[serde(default, skip_serializing_if = "Option::is_none")]
847 pub objective: Option<String>,
848 #[serde(default, skip_serializing_if = "Option::is_none")]
849 pub status: Option<ThreadGoalStatus>,
850 #[serde(
851 default,
852 skip_serializing_if = "Option::is_none",
853 deserialize_with = "deserialize_goal_token_budget_patch"
854 )]
855 pub token_budget: Option<Option<i64>>,
856}
857
858fn deserialize_goal_token_budget_patch<'de, D>(
859 deserializer: D,
860) -> Result<Option<Option<i64>>, D::Error>
861where
862 D: serde::Deserializer<'de>,
863{
864 let value = serde_json::Value::deserialize(deserializer)?;
865 match value {
866 serde_json::Value::Null => Ok(Some(None)),
867 value => i64::deserialize(value)
868 .map(Some)
869 .map(Some)
870 .map_err(serde::de::Error::custom),
871 }
872}
873
874#[derive(Debug, Clone, Serialize, Deserialize)]
875#[serde(rename_all = "camelCase")]
876pub struct ThreadGoalSetResult {
877 pub goal: Option<ThreadGoal>,
878}
879
880#[derive(Debug, Clone, Serialize, Deserialize)]
881#[serde(rename_all = "camelCase")]
882pub struct ThreadGoalClearParams {
883 pub thread_id: ThreadId,
884}
885
886#[derive(Debug, Clone, Serialize, Deserialize)]
887#[serde(rename_all = "camelCase")]
888pub struct ThreadGoalClearResult {
889 pub cleared: bool,
890}
891
892#[derive(Debug, Clone, Serialize, Deserialize)]
893#[serde(rename_all = "camelCase")]
894pub struct ThreadCompactParams {
895 pub thread_id: ThreadId,
896 pub turn_id: TurnId,
897 #[serde(default, skip_serializing_if = "Option::is_none")]
898 pub preserve_hint: Option<String>,
899}
900
901#[derive(Debug, Clone, Serialize, Deserialize)]
902#[serde(rename_all = "camelCase")]
903pub struct ThreadCompactResult {
904 pub compacted: bool,
905 #[serde(default, skip_serializing_if = "Option::is_none")]
906 pub reason: Option<String>,
907 pub estimated_tokens_before: u32,
908 pub estimated_tokens_after: u32,
909}
910
911#[derive(Debug, Clone, Serialize, Deserialize)]
912#[serde(rename_all = "camelCase")]
913pub struct TurnInputItem {
914 #[serde(rename = "type")]
915 pub kind: String,
916 pub text: Option<String>,
917 pub path: Option<String>,
918 #[serde(default, alias = "image_url", skip_serializing_if = "Option::is_none")]
919 pub image_url: Option<String>,
920}
921
922#[derive(Debug, Clone, Serialize, Deserialize)]
923#[serde(rename_all = "camelCase")]
924pub struct TurnStartParams {
925 pub thread_id: ThreadId,
926 #[serde(default)]
927 pub input: Vec<TurnInputItem>,
928 pub prompt: Option<String>,
929 #[serde(default, skip_serializing_if = "Option::is_none")]
930 pub model_provider: Option<String>,
931 #[serde(default, skip_serializing_if = "Option::is_none")]
932 pub model: Option<String>,
933 #[serde(default, skip_serializing_if = "Option::is_none")]
934 pub reasoning: Option<String>,
935 #[serde(default, skip_serializing_if = "Option::is_none")]
941 pub developer_context: Option<String>,
942 #[serde(default, skip_serializing_if = "Option::is_none")]
943 pub policy_mode: Option<PolicyMode>,
944 #[serde(default)]
945 pub task_ledger_required: bool,
946}
947
948#[derive(Debug, Clone, Serialize, Deserialize)]
949#[serde(rename_all = "camelCase")]
950pub struct TurnStartResult {
951 pub turn_id: TurnId,
952}
953
954#[derive(Debug, Clone, Serialize, Deserialize)]
955#[serde(rename_all = "camelCase")]
956pub struct TurnSteerParams {
957 pub thread_id: ThreadId,
958 pub expected_turn_id: TurnId,
959 #[serde(default)]
960 pub input: Vec<TurnInputItem>,
961 pub prompt: Option<String>,
962}
963
964#[derive(Debug, Clone, Serialize, Deserialize)]
965#[serde(rename_all = "camelCase")]
966pub struct TurnSteerResult {
967 pub turn_id: TurnId,
968}
969
970#[derive(Debug, Clone, Serialize, Deserialize)]
971#[serde(rename_all = "camelCase")]
972pub struct TurnInterruptParams {
973 pub thread_id: ThreadId,
974 pub turn_id: Option<TurnId>,
975}
976
977#[derive(Debug, Clone, Serialize, Deserialize)]
978#[serde(rename_all = "camelCase")]
979pub struct TurnInterruptResult {
980 pub turn_id: Option<TurnId>,
981}
982
983#[derive(Debug, Clone, Serialize, Deserialize)]
984#[serde(rename_all = "camelCase")]
985pub struct ModelListResult {
986 pub models: Vec<Model>,
987}
988
989#[derive(Debug, Clone, Serialize, Deserialize)]
990#[serde(rename_all = "camelCase")]
991pub struct Model {
992 pub id: String,
993 pub name: String,
994 pub model_provider: String,
995 pub default_reasoning_effort: Option<String>,
996 pub reasoning_efforts: Vec<String>,
997 pub is_default: bool,
998}
999
1000#[derive(Debug, Clone, Serialize, Deserialize)]
1001#[serde(rename_all = "camelCase")]
1002pub struct MemoryListParams {
1003 pub scope: Option<MemoryScope>,
1004 pub limit: Option<usize>,
1005}
1006
1007#[derive(Debug, Clone, Serialize, Deserialize)]
1008#[serde(rename_all = "camelCase")]
1009pub struct MemoryListResult {
1010 pub memories: Vec<MemoryRecord>,
1011}
1012
1013#[derive(Debug, Clone, Serialize, Deserialize)]
1014#[serde(rename_all = "camelCase")]
1015pub struct MemoryReadParams {
1016 pub memory_id: MemoryId,
1017}
1018
1019#[derive(Debug, Clone, Serialize, Deserialize)]
1020#[serde(rename_all = "camelCase")]
1021pub struct MemoryReadResult {
1022 pub memory: Option<MemoryRecord>,
1023}
1024
1025#[derive(Debug, Clone, Serialize, Deserialize)]
1026#[serde(rename_all = "camelCase")]
1027pub struct MemorySaveParams {
1028 pub scope: MemoryScope,
1029 pub text: String,
1030 #[serde(default)]
1031 pub metadata: serde_json::Value,
1032}
1033
1034#[derive(Debug, Clone, Serialize, Deserialize)]
1035#[serde(rename_all = "camelCase")]
1036pub struct MemorySaveResult {
1037 pub memory_id: MemoryId,
1038}
1039
1040#[derive(Debug, Clone, Serialize, Deserialize)]
1041#[serde(rename_all = "camelCase")]
1042pub struct MemoryUpdateParams {
1043 pub memory_id: MemoryId,
1044 pub text: String,
1045 #[serde(default)]
1046 pub metadata: serde_json::Value,
1047}
1048
1049#[derive(Debug, Clone, Serialize, Deserialize)]
1050#[serde(rename_all = "camelCase")]
1051pub struct MemoryDeleteParams {
1052 pub memory_id: MemoryId,
1053}
1054
1055#[derive(Debug, Clone, Serialize, Deserialize)]
1056#[serde(rename_all = "camelCase")]
1057pub struct MemoryDeleteResult {
1058 pub deleted: bool,
1059}
1060
1061#[derive(Debug, Clone, Serialize, Deserialize)]
1062#[serde(rename_all = "camelCase")]
1063pub struct MemoryQueryParams {
1064 pub scope: Option<MemoryScope>,
1065 pub text: String,
1066 pub limit: Option<usize>,
1067 #[serde(default)]
1068 pub include_global: bool,
1069}
1070
1071#[derive(Debug, Clone, Serialize, Deserialize)]
1072#[serde(rename_all = "camelCase")]
1073pub struct MemoryQueryResult {
1074 pub results: Vec<MemorySearchResult>,
1075}
1076
1077#[derive(Debug, Clone, Serialize, Deserialize)]
1078#[serde(rename_all = "camelCase")]
1079pub struct MemoryProviderListResult {
1080 pub providers: Vec<roder_api::embeddings::EmbeddingProviderDescriptor>,
1081 pub selected: MemoryProviderSelection,
1082}
1083
1084#[derive(Debug, Clone, Serialize, Deserialize)]
1085#[serde(rename_all = "camelCase")]
1086pub struct MemoryProviderSetParams {
1087 pub provider_id: String,
1088 pub model: String,
1089}
1090
1091#[derive(Debug, Clone, Serialize, Deserialize)]
1092#[serde(rename_all = "camelCase")]
1093pub struct MemoryRecallPreviewParams {
1094 pub thread_id: ThreadId,
1095 pub turn_id: TurnId,
1096 pub scope: Option<MemoryScope>,
1097 pub text: String,
1098 pub limit: Option<usize>,
1099 #[serde(default)]
1100 pub include_global: bool,
1101}
1102
1103#[derive(Debug, Clone, Serialize, Deserialize)]
1104#[serde(rename_all = "camelCase")]
1105pub struct MemoryRecallPreviewResult {
1106 pub citations: Vec<roder_api::memory::MemoryCitation>,
1107 pub results: Vec<MemorySearchResult>,
1108}
1109
1110#[derive(Debug, Clone, Serialize, Deserialize)]
1111#[serde(rename_all = "camelCase")]
1112pub struct KnowledgeListParams {
1113 pub scope: Option<MemoryScope>,
1114 #[serde(default)]
1115 pub kind: Option<KnowledgeKind>,
1116 #[serde(default)]
1117 pub tag: Option<String>,
1118 #[serde(default)]
1119 pub status: Option<KnowledgeStatus>,
1120 #[serde(default)]
1121 pub include_archived: bool,
1122 pub limit: Option<usize>,
1123}
1124
1125#[derive(Debug, Clone, Serialize, Deserialize)]
1126#[serde(rename_all = "camelCase")]
1127pub struct KnowledgeListResult {
1128 pub documents: Vec<KnowledgeDocSummary>,
1129}
1130
1131#[derive(Debug, Clone, Serialize, Deserialize)]
1132#[serde(rename_all = "camelCase")]
1133pub struct KnowledgeReadParams {
1134 pub doc_id: KnowledgeDocId,
1135 #[serde(default)]
1136 pub revision: Option<u32>,
1137}
1138
1139#[derive(Debug, Clone, Serialize, Deserialize)]
1140#[serde(rename_all = "camelCase")]
1141pub struct KnowledgeReadResult {
1142 pub document: Option<KnowledgeDocument>,
1143}
1144
1145#[derive(Debug, Clone, Serialize, Deserialize)]
1146#[serde(rename_all = "camelCase")]
1147pub struct KnowledgeSaveParams {
1148 pub scope: MemoryScope,
1149 pub kind: KnowledgeKind,
1150 pub title: String,
1151 #[serde(default)]
1152 pub tags: Vec<String>,
1153 pub body: String,
1154}
1155
1156#[derive(Debug, Clone, Serialize, Deserialize)]
1157#[serde(rename_all = "camelCase")]
1158pub struct KnowledgeSaveResult {
1159 pub document: KnowledgeDocument,
1160}
1161
1162#[derive(Debug, Clone, Serialize, Deserialize)]
1163#[serde(rename_all = "camelCase")]
1164pub struct KnowledgeUpdateParams {
1165 pub doc_id: KnowledgeDocId,
1166 #[serde(default)]
1167 pub title: Option<String>,
1168 #[serde(default)]
1169 pub body: Option<String>,
1170 #[serde(default)]
1171 pub status: Option<KnowledgeStatus>,
1172 #[serde(default)]
1173 pub tags: Option<Vec<String>>,
1174}
1175
1176#[derive(Debug, Clone, Serialize, Deserialize)]
1177#[serde(rename_all = "camelCase")]
1178pub struct KnowledgeDeleteParams {
1179 pub doc_id: KnowledgeDocId,
1180}
1181
1182#[derive(Debug, Clone, Serialize, Deserialize)]
1183#[serde(rename_all = "camelCase")]
1184pub struct KnowledgeDeleteResult {
1185 pub archived: bool,
1186}
1187
1188#[derive(Debug, Clone, Serialize, Deserialize)]
1189#[serde(rename_all = "camelCase")]
1190pub struct KnowledgeSearchParams {
1191 pub scope: Option<MemoryScope>,
1192 pub text: String,
1193 #[serde(default)]
1194 pub kind: Option<KnowledgeKind>,
1195 pub limit: Option<usize>,
1196 #[serde(default)]
1197 pub include_global: bool,
1198}
1199
1200#[derive(Debug, Clone, Serialize, Deserialize)]
1201#[serde(rename_all = "camelCase")]
1202pub struct KnowledgeSearchResults {
1203 pub results: Vec<KnowledgeSearchMatch>,
1204}
1205
1206#[derive(Debug, Clone, Serialize, Deserialize)]
1207#[serde(rename_all = "camelCase")]
1208pub struct KnowledgeLinkSetParams {
1209 pub from: KnowledgeDocId,
1210 pub to: KnowledgeDocId,
1211 #[serde(rename = "type")]
1212 pub link_type: KnowledgeLinkType,
1213 #[serde(default)]
1214 pub remove: bool,
1215}
1216
1217#[derive(Debug, Clone, Serialize, Deserialize)]
1218#[serde(rename_all = "camelCase")]
1219pub struct KnowledgeRevisionsParams {
1220 pub doc_id: KnowledgeDocId,
1221}
1222
1223#[derive(Debug, Clone, Serialize, Deserialize)]
1224#[serde(rename_all = "camelCase")]
1225pub struct KnowledgeRevisionsResult {
1226 pub revisions: Vec<KnowledgeRevisionInfo>,
1227}
1228
1229#[derive(Debug, Clone, Serialize, Deserialize)]
1230#[serde(rename_all = "camelCase")]
1231pub struct ThreadStartedNotification {
1232 pub thread: Thread,
1233}
1234
1235#[derive(Debug, Clone, Serialize, Deserialize)]
1236#[serde(rename_all = "camelCase")]
1237pub struct ThreadStatusChangedNotification {
1238 pub thread_id: ThreadId,
1239 pub status: ThreadStatus,
1240}
1241
1242#[derive(Debug, Clone, Serialize, Deserialize)]
1243#[serde(rename_all = "camelCase")]
1244pub struct ThreadGoalUpdatedNotification {
1245 pub thread_id: ThreadId,
1246 pub goal: ThreadGoal,
1247}
1248
1249#[derive(Debug, Clone, Serialize, Deserialize)]
1250#[serde(rename_all = "camelCase")]
1251pub struct ThreadGoalClearedNotification {
1252 pub thread_id: ThreadId,
1253}
1254
1255#[derive(Debug, Clone, Serialize, Deserialize)]
1256#[serde(rename_all = "camelCase")]
1257pub struct TurnStartedNotification {
1258 pub thread_id: ThreadId,
1259 pub turn: Turn,
1260}
1261
1262#[derive(Debug, Clone, Serialize, Deserialize)]
1263#[serde(rename_all = "camelCase")]
1264pub struct TurnCompletedNotification {
1265 pub thread_id: ThreadId,
1266 pub turn: Turn,
1267}
1268
1269#[derive(Debug, Clone, Serialize, Deserialize)]
1270#[serde(rename_all = "camelCase")]
1271pub struct TurnDeadlineExceededNotification {
1272 pub thread_id: ThreadId,
1273 pub turn_id: TurnId,
1274 pub deadline: time::OffsetDateTime,
1275 pub partial_result: String,
1276}
1277
1278#[derive(Debug, Clone, Serialize, Deserialize)]
1279#[serde(rename_all = "camelCase")]
1280pub struct TurnPartialResultNotification {
1281 pub thread_id: ThreadId,
1282 pub turn_id: TurnId,
1283 pub summary: String,
1284}
1285
1286#[derive(Debug, Clone, Serialize, Deserialize)]
1287#[serde(rename_all = "camelCase")]
1288pub struct ApprovalRequestedNotification {
1289 pub thread_id: ThreadId,
1290 pub turn_id: TurnId,
1291 pub approval_id: String,
1292 pub tool_id: String,
1293 pub tool_name: String,
1294 #[serde(default, skip_serializing_if = "Option::is_none")]
1295 pub reason: Option<String>,
1296}
1297
1298#[derive(Debug, Clone, Serialize, Deserialize)]
1299#[serde(rename_all = "camelCase")]
1300pub struct ApprovalResolvedNotification {
1301 pub thread_id: ThreadId,
1302 pub turn_id: TurnId,
1303 pub approval_id: String,
1304 pub tool_id: String,
1305 pub tool_name: String,
1306 pub approved: bool,
1307}
1308
1309#[derive(Debug, Clone, Serialize, Deserialize)]
1311#[serde(rename_all = "camelCase")]
1312pub struct ExternalToolCall {
1313 pub id: String,
1314 pub name: String,
1315 pub arguments: serde_json::Value,
1316}
1317
1318#[derive(Debug, Clone, Serialize, Deserialize)]
1319#[serde(rename_all = "camelCase")]
1320pub struct ToolExecutionRequestedNotification {
1321 pub thread_id: ThreadId,
1322 pub turn_id: TurnId,
1323 pub request_id: String,
1324 pub call: ExternalToolCall,
1325}
1326
1327#[derive(Debug, Clone, Serialize, Deserialize)]
1328#[serde(rename_all = "camelCase")]
1329pub struct ToolExecutionResolvedNotification {
1330 pub thread_id: ThreadId,
1331 pub turn_id: TurnId,
1332 pub request_id: String,
1333 pub tool_id: String,
1334 pub tool_name: String,
1335 pub outcome: roder_api::events::ExternalToolCallOutcome,
1337 pub is_error: bool,
1338}
1339
1340#[derive(Debug, Clone, Serialize, Deserialize)]
1341#[serde(rename_all = "camelCase")]
1342pub struct UserInputRequestedNotification {
1343 pub thread_id: ThreadId,
1344 pub turn_id: TurnId,
1345 pub request_id: String,
1346 pub questions: serde_json::Value,
1347}
1348
1349#[derive(Debug, Clone, Serialize, Deserialize)]
1350#[serde(rename_all = "camelCase")]
1351pub struct UserInputResolvedNotification {
1352 pub thread_id: ThreadId,
1353 pub turn_id: TurnId,
1354 pub request_id: String,
1355 pub answers: serde_json::Value,
1356}
1357
1358#[derive(Debug, Clone, Serialize, Deserialize)]
1359#[serde(rename_all = "camelCase")]
1360pub struct VerificationRequiredNotification {
1361 pub thread_id: ThreadId,
1362 pub turn_id: TurnId,
1363 pub reason: String,
1364 pub changed_files: Vec<String>,
1365 pub tool_evidence: Vec<String>,
1366 pub tests_run: Vec<String>,
1367 pub open_gaps: Vec<String>,
1368}
1369
1370#[derive(Debug, Clone, Serialize, Deserialize)]
1371#[serde(rename_all = "camelCase")]
1372pub struct VerificationCompletedNotification {
1373 pub thread_id: ThreadId,
1374 pub turn_id: TurnId,
1375 pub passed: bool,
1376 pub changed_files: Vec<String>,
1377 pub tool_evidence: Vec<String>,
1378 pub tests_run: Vec<String>,
1379 pub open_gaps: Vec<String>,
1380}
1381
1382#[derive(Debug, Clone, Serialize, Deserialize)]
1383#[serde(rename_all = "camelCase")]
1384pub struct VerificationSkippedNotification {
1385 pub thread_id: ThreadId,
1386 pub turn_id: TurnId,
1387 pub reason: String,
1388}
1389
1390#[derive(Debug, Clone, Serialize, Deserialize)]
1391#[serde(rename_all = "camelCase")]
1392pub struct AutomationRunNotification {
1393 pub run: AutomationRunSummary,
1394}
1395
1396#[derive(Debug, Clone, Serialize, Deserialize)]
1397#[serde(rename_all = "camelCase")]
1398pub struct AutomationRunFailedNotification {
1399 pub run: AutomationRunSummary,
1400 pub error: String,
1401}
1402
1403#[derive(Debug, Clone, Serialize, Deserialize)]
1404#[serde(rename_all = "camelCase")]
1405pub struct AutomationRunSkippedNotification {
1406 pub run: AutomationRunSummary,
1407 pub reason: String,
1408}
1409
1410#[derive(Debug, Clone, Serialize, Deserialize)]
1411#[serde(rename_all = "camelCase")]
1412pub struct PlanExitRequestedNotification {
1413 pub thread_id: ThreadId,
1414 pub turn_id: TurnId,
1415 pub request_id: String,
1416 pub target_mode: roder_api::policy_mode::PolicyMode,
1417 #[serde(default, skip_serializing_if = "Option::is_none")]
1418 pub plan_summary: Option<String>,
1419 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1420 pub next_steps: Vec<String>,
1421}
1422
1423#[derive(Debug, Clone, Serialize, Deserialize)]
1424#[serde(rename_all = "camelCase")]
1425pub struct PlanExitResolvedNotification {
1426 pub thread_id: ThreadId,
1427 pub turn_id: TurnId,
1428 pub request_id: String,
1429 pub approved: bool,
1430 pub target_mode: roder_api::policy_mode::PolicyMode,
1431 pub resolved_mode: roder_api::policy_mode::PolicyMode,
1432}
1433
1434#[derive(Debug, Clone, Serialize, Deserialize)]
1435#[serde(rename_all = "camelCase")]
1436pub struct FsReadFileParams {
1437 pub path: String,
1438}
1439
1440#[derive(Debug, Clone, Serialize, Deserialize)]
1441#[serde(rename_all = "camelCase")]
1442pub struct FsReadFileResponse {
1443 pub data_base64: String,
1444}
1445
1446#[derive(Debug, Clone, Serialize, Deserialize)]
1447#[serde(rename_all = "camelCase")]
1448pub struct FsReadDirectoryParams {
1449 pub path: String,
1450}
1451
1452#[derive(Debug, Clone, Serialize, Deserialize)]
1453#[serde(rename_all = "camelCase")]
1454pub struct FsReadDirectoryEntry {
1455 pub file_name: String,
1456 pub is_directory: bool,
1457 pub is_file: bool,
1458}
1459
1460#[derive(Debug, Clone, Serialize, Deserialize)]
1461#[serde(rename_all = "camelCase")]
1462pub struct FsReadDirectoryResponse {
1463 pub entries: Vec<FsReadDirectoryEntry>,
1464}
1465
1466#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1467#[serde(rename_all = "camelCase")]
1468pub struct WorkspaceFilesStatusParams {
1469 pub workspace_id: String,
1470 #[serde(default, skip_serializing_if = "Option::is_none")]
1471 pub root_id: Option<String>,
1472}
1473
1474#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
1475#[serde(rename_all = "camelCase")]
1476pub enum WorkspaceFilesIndexState {
1477 Missing,
1478 Building,
1479 Ready,
1480 Stale,
1484 Failed,
1485}
1486
1487#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1488#[serde(rename_all = "camelCase")]
1489pub struct WorkspaceFilesRootStatus {
1490 pub root_id: String,
1491 pub root_name: String,
1492 pub state: WorkspaceFilesIndexState,
1493 pub stale: bool,
1494 #[serde(default, skip_serializing_if = "Option::is_none")]
1495 pub file_count: Option<u64>,
1496 #[serde(default, skip_serializing_if = "Option::is_none")]
1497 pub directory_count: Option<u64>,
1498 #[serde(default, skip_serializing_if = "Option::is_none")]
1499 pub build_time_ms: Option<u64>,
1500 #[serde(default, skip_serializing_if = "Option::is_none")]
1501 pub indexed_at_ms: Option<i64>,
1502 #[serde(default, skip_serializing_if = "Option::is_none")]
1503 pub message: Option<String>,
1504}
1505
1506#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1507#[serde(rename_all = "camelCase")]
1508pub struct WorkspaceFilesStatus {
1509 pub workspace_id: String,
1510 pub state: WorkspaceFilesIndexState,
1511 pub stale: bool,
1512 pub roots: Vec<WorkspaceFilesRootStatus>,
1513 pub file_count: u64,
1514 pub directory_count: u64,
1515 #[serde(default, skip_serializing_if = "Option::is_none")]
1516 pub message: Option<String>,
1517}
1518
1519#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1520#[serde(rename_all = "camelCase")]
1521pub struct WorkspaceFilesStatusResult {
1522 pub status: WorkspaceFilesStatus,
1523}
1524
1525#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1526#[serde(rename_all = "camelCase")]
1527pub struct WorkspaceFilesRebuildParams {
1528 pub workspace_id: String,
1529 #[serde(default, skip_serializing_if = "Option::is_none")]
1530 pub root_id: Option<String>,
1531}
1532
1533#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1534#[serde(rename_all = "camelCase")]
1535pub struct WorkspaceFilesRebuildResult {
1536 pub status: WorkspaceFilesStatus,
1537}
1538
1539#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1540#[serde(rename_all = "camelCase")]
1541pub struct WorkspaceFilesChildrenParams {
1542 pub workspace_id: String,
1543 #[serde(default, skip_serializing_if = "Option::is_none")]
1544 pub root_id: Option<String>,
1545 #[serde(default, skip_serializing_if = "Option::is_none")]
1546 pub path: Option<String>,
1547}
1548
1549#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
1550#[serde(rename_all = "camelCase")]
1551pub enum WorkspaceFileKind {
1552 Directory,
1553 File,
1554}
1555
1556#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1557#[serde(rename_all = "camelCase")]
1558pub struct WorkspaceFileEntry {
1559 pub root_id: String,
1560 pub root_name: String,
1561 pub path: String,
1562 pub name: String,
1563 pub kind: WorkspaceFileKind,
1564 pub has_children: bool,
1565 #[serde(default, skip_serializing_if = "Option::is_none")]
1566 pub size: Option<u64>,
1567 #[serde(default, skip_serializing_if = "Option::is_none")]
1568 pub modified_ms: Option<u64>,
1569}
1570
1571#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1572#[serde(rename_all = "camelCase")]
1573pub struct WorkspaceFilesChildrenResult {
1574 pub status: WorkspaceFilesStatus,
1575 pub entries: Vec<WorkspaceFileEntry>,
1576}
1577
1578#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1579#[serde(rename_all = "camelCase")]
1580pub struct WorkspaceFilesQueryParams {
1581 pub workspace_id: String,
1582 #[serde(default, skip_serializing_if = "Option::is_none")]
1583 pub root_id: Option<String>,
1584 pub query: String,
1585 #[serde(default, skip_serializing_if = "Option::is_none")]
1586 pub limit: Option<usize>,
1587}
1588
1589#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1590#[serde(rename_all = "camelCase")]
1591pub struct WorkspaceFileQueryMatch {
1592 pub entry: WorkspaceFileEntry,
1593 pub score: i64,
1594 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1595 pub match_positions: Vec<usize>,
1596}
1597
1598#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1599#[serde(rename_all = "camelCase")]
1600pub struct WorkspaceFilesQueryResult {
1601 pub status: WorkspaceFilesStatus,
1602 pub matches: Vec<WorkspaceFileQueryMatch>,
1603 pub indexed_file_count: u64,
1604}
1605
1606#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1607#[serde(rename_all = "camelCase")]
1608pub struct WorkspaceFilesReadParams {
1609 pub workspace_id: String,
1610 pub root_id: String,
1611 pub path: String,
1612 #[serde(default, skip_serializing_if = "Option::is_none")]
1613 pub offset: Option<usize>,
1614 #[serde(default, skip_serializing_if = "Option::is_none")]
1615 pub limit: Option<usize>,
1616}
1617
1618#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
1619#[serde(rename_all = "camelCase")]
1620pub enum WorkspaceFilesReadEncoding {
1621 Utf8,
1622 Binary,
1623 Unsupported,
1624}
1625
1626#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1627#[serde(rename_all = "camelCase")]
1628pub struct WorkspaceFilesReadResult {
1629 pub entry: WorkspaceFileEntry,
1630 pub encoding: WorkspaceFilesReadEncoding,
1631 #[serde(default, skip_serializing_if = "Option::is_none")]
1632 pub text: Option<String>,
1633 pub offset: usize,
1634 pub limit: usize,
1635 pub total_bytes: u64,
1636 pub has_more: bool,
1637 pub truncated: bool,
1638}
1639
1640#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1641#[serde(rename_all = "camelCase")]
1642pub struct WorkspaceFilesStatusNotification {
1643 pub status: WorkspaceFilesStatus,
1644}
1645
1646#[derive(Debug, Clone, Serialize, Deserialize)]
1647#[serde(rename_all = "camelCase")]
1648pub struct DesignWorkspaceParams {
1649 pub workspace_id: String,
1650 #[serde(default, skip_serializing_if = "Option::is_none")]
1651 pub root_id: Option<String>,
1652}
1653
1654pub type DesignGetVariablesParams = DesignWorkspaceParams;
1655pub type DesignSnapshotLayoutParams = DesignWorkspaceParams;
1656pub type DesignGetGuidelinesParams = DesignWorkspaceParams;
1657
1658#[derive(Debug, Clone, Serialize, Deserialize)]
1659#[serde(rename_all = "camelCase")]
1660pub struct DesignSetSelectionParams {
1661 pub workspace_id: String,
1662 #[serde(default, skip_serializing_if = "Option::is_none")]
1663 pub root_id: Option<String>,
1664 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1665 pub selected_node_ids: Vec<String>,
1666}
1667
1668#[derive(Debug, Clone, Serialize, Deserialize)]
1669#[serde(rename_all = "camelCase")]
1670pub struct DesignSetVariablesParams {
1671 pub workspace_id: String,
1672 #[serde(default, skip_serializing_if = "Option::is_none")]
1673 pub root_id: Option<String>,
1674 pub variables: BTreeMap<String, serde_json::Value>,
1675 #[serde(default)]
1676 pub replace: bool,
1677}
1678
1679#[derive(Debug, Clone, Serialize, Deserialize)]
1680#[serde(rename_all = "camelCase")]
1681pub struct DesignSpawnAgentsParams {
1682 pub workspace_id: String,
1683 #[serde(default, skip_serializing_if = "Option::is_none")]
1684 pub root_id: Option<String>,
1685 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1686 pub scope_node_ids: Vec<String>,
1687 #[serde(default, skip_serializing_if = "Option::is_none")]
1688 pub prompt: Option<String>,
1689 #[serde(default)]
1690 pub allow_patch: bool,
1691 #[serde(default)]
1692 pub allow_export: bool,
1693 #[serde(default)]
1694 pub require_review: bool,
1695}
1696
1697#[derive(Debug, Clone, Serialize, Deserialize)]
1698#[serde(rename_all = "camelCase")]
1699pub struct DesignGetEditorStateParams {
1700 pub workspace_id: String,
1701 #[serde(default, skip_serializing_if = "Option::is_none")]
1702 pub root_id: Option<String>,
1703 #[serde(default)]
1704 pub include_schema: bool,
1705}
1706
1707#[derive(Debug, Clone, Serialize, Deserialize)]
1708#[serde(rename_all = "camelCase")]
1709pub struct RoderDesignDocument {
1710 pub version: String,
1711 pub document_id: String,
1712 pub title: String,
1713 pub created_at: String,
1714 pub updated_at: String,
1715 #[serde(default)]
1716 pub nodes: BTreeMap<String, RoderDesignNode>,
1717 #[serde(default)]
1718 pub root_ids: Vec<String>,
1719 #[serde(default)]
1720 pub variables: BTreeMap<String, serde_json::Value>,
1721 #[serde(default)]
1722 pub assets: BTreeMap<String, serde_json::Value>,
1723 pub metadata: RoderDesignMetadata,
1724}
1725
1726#[derive(Debug, Clone, Serialize, Deserialize)]
1727#[serde(rename_all = "camelCase")]
1728pub struct RoderDesignMetadata {
1729 #[serde(default, skip_serializing_if = "Option::is_none")]
1730 pub workspace_id: Option<String>,
1731 #[serde(default, skip_serializing_if = "Option::is_none")]
1732 pub root_id: Option<String>,
1733 #[serde(default, skip_serializing_if = "Option::is_none")]
1734 pub workspace_root: Option<String>,
1735 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1736 pub selected_node_ids: Vec<String>,
1737}
1738
1739#[derive(Debug, Clone, Serialize, Deserialize)]
1740#[serde(rename_all = "camelCase")]
1741pub struct RoderDesignNode {
1742 pub id: String,
1743 #[serde(rename = "type")]
1744 pub node_type: String,
1745 pub name: String,
1746 #[serde(default, skip_serializing_if = "Option::is_none")]
1747 pub parent_id: Option<String>,
1748 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1749 pub child_ids: Vec<String>,
1750 #[serde(default)]
1751 pub x: f64,
1752 #[serde(default)]
1753 pub y: f64,
1754 #[serde(default)]
1755 pub width: f64,
1756 #[serde(default)]
1757 pub height: f64,
1758 #[serde(default, skip_serializing_if = "Option::is_none")]
1759 pub rotation: Option<f64>,
1760 #[serde(default, skip_serializing_if = "Option::is_none")]
1761 pub opacity: Option<f64>,
1762 #[serde(default, skip_serializing_if = "Option::is_none")]
1763 pub visible: Option<bool>,
1764 #[serde(default, skip_serializing_if = "Option::is_none")]
1765 pub locked: Option<bool>,
1766 #[serde(default, skip_serializing_if = "Option::is_none")]
1767 pub fill: Option<serde_json::Value>,
1768 #[serde(default, skip_serializing_if = "Option::is_none")]
1769 pub stroke: Option<serde_json::Value>,
1770 #[serde(default, skip_serializing_if = "BTreeMap::is_empty", flatten)]
1771 pub extra: BTreeMap<String, serde_json::Value>,
1772}
1773
1774#[derive(Debug, Clone, Serialize, Deserialize)]
1775#[serde(rename_all = "camelCase")]
1776pub struct DesignDocumentResult {
1777 pub path: String,
1778 pub document: RoderDesignDocument,
1779}
1780
1781#[derive(Debug, Clone, Serialize, Deserialize)]
1782#[serde(rename_all = "camelCase")]
1783pub struct DesignNodeAlias {
1784 pub alias: String,
1785 pub node_id: String,
1786 pub name: String,
1787 #[serde(rename = "type")]
1788 pub node_type: String,
1789}
1790
1791#[derive(Debug, Clone, Serialize, Deserialize)]
1792#[serde(rename_all = "camelCase")]
1793pub struct DesignEditorStateResult {
1794 pub path: String,
1795 pub document: RoderDesignDocument,
1796 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1797 pub selected_node_ids: Vec<String>,
1798 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1799 pub node_aliases: Vec<DesignNodeAlias>,
1800 #[serde(default, skip_serializing_if = "Option::is_none")]
1801 pub schema: Option<serde_json::Value>,
1802 #[serde(default, skip_serializing_if = "Option::is_none")]
1803 pub rules: Option<String>,
1804}
1805
1806#[derive(Debug, Clone, Serialize, Deserialize)]
1807#[serde(rename_all = "camelCase")]
1808pub struct DesignBatchGetParams {
1809 pub workspace_id: String,
1810 #[serde(default, skip_serializing_if = "Option::is_none")]
1811 pub root_id: Option<String>,
1812 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1813 pub node_ids: Vec<String>,
1814 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1815 pub patterns: Vec<DesignNodeSearchPattern>,
1816 #[serde(default, skip_serializing_if = "Option::is_none")]
1817 pub parent_id: Option<String>,
1818 #[serde(default, skip_serializing_if = "Option::is_none")]
1819 pub read_depth: Option<u32>,
1820 #[serde(default, skip_serializing_if = "Option::is_none")]
1821 pub search_depth: Option<u32>,
1822}
1823
1824#[derive(Debug, Clone, Serialize, Deserialize)]
1825#[serde(rename_all = "camelCase")]
1826pub struct DesignNodeSearchPattern {
1827 #[serde(default, skip_serializing_if = "Option::is_none")]
1828 pub name: Option<String>,
1829 #[serde(default, skip_serializing_if = "Option::is_none")]
1830 #[serde(rename = "type")]
1831 pub node_type: Option<String>,
1832}
1833
1834#[derive(Debug, Clone, Serialize, Deserialize)]
1835#[serde(rename_all = "camelCase")]
1836pub struct DesignBatchGetResult {
1837 pub path: String,
1838 pub nodes: Vec<RoderDesignNode>,
1839 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1840 pub node_aliases: Vec<DesignNodeAlias>,
1841}
1842
1843#[derive(Debug, Clone, Serialize, Deserialize)]
1844#[serde(rename_all = "camelCase")]
1845pub struct DesignPatchParams {
1846 pub workspace_id: String,
1847 #[serde(default, skip_serializing_if = "Option::is_none")]
1848 pub root_id: Option<String>,
1849 pub operations: Vec<DesignPatchOperation>,
1850}
1851
1852#[derive(Debug, Clone, Serialize, Deserialize)]
1853#[serde(rename_all = "snake_case", tag = "op")]
1854pub enum DesignPatchOperation {
1855 InsertNode {
1856 #[serde(default, alias = "parentId", skip_serializing_if = "Option::is_none")]
1857 parent_id: Option<String>,
1858 #[serde(default, skip_serializing_if = "Option::is_none")]
1859 index: Option<usize>,
1860 node: RoderDesignNode,
1861 },
1862 UpdateNode {
1863 #[serde(alias = "nodeId")]
1864 node_id: String,
1865 patch: serde_json::Value,
1866 },
1867 DeleteNode {
1868 #[serde(alias = "nodeId")]
1869 node_id: String,
1870 #[serde(default)]
1871 recursive: bool,
1872 },
1873 ReorderNode {
1874 #[serde(alias = "nodeId")]
1875 node_id: String,
1876 index: usize,
1877 },
1878 SetVariables {
1879 variables: BTreeMap<String, serde_json::Value>,
1880 #[serde(default)]
1881 replace: bool,
1882 },
1883}
1884
1885#[derive(Debug, Clone, Serialize, Deserialize)]
1886#[serde(rename_all = "camelCase")]
1887pub struct DesignPatchResult {
1888 pub path: String,
1889 pub document: RoderDesignDocument,
1890 pub applied: usize,
1891}
1892
1893#[derive(Debug, Clone, Serialize, Deserialize)]
1894#[serde(rename_all = "camelCase")]
1895pub struct DesignVariablesResult {
1896 pub path: String,
1897 pub variables: BTreeMap<String, serde_json::Value>,
1898}
1899
1900#[derive(Debug, Clone, Serialize, Deserialize)]
1901#[serde(rename_all = "camelCase")]
1902pub struct DesignLayoutNode {
1903 pub id: String,
1904 #[serde(rename = "type")]
1905 pub node_type: String,
1906 pub name: String,
1907 pub x: f64,
1908 pub y: f64,
1909 pub width: f64,
1910 pub height: f64,
1911 #[serde(default, skip_serializing_if = "Option::is_none")]
1912 pub parent_id: Option<String>,
1913 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1914 pub child_ids: Vec<String>,
1915 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1916 pub problems: Vec<String>,
1917}
1918
1919#[derive(Debug, Clone, Serialize, Deserialize)]
1920#[serde(rename_all = "camelCase")]
1921pub struct DesignSnapshotLayoutResult {
1922 pub path: String,
1923 pub nodes: Vec<DesignLayoutNode>,
1924}
1925
1926#[derive(Debug, Clone, Serialize, Deserialize)]
1927#[serde(rename_all = "camelCase")]
1928pub struct DesignGuidelineCategory {
1929 pub name: String,
1930 pub description: String,
1931 pub guidelines: Vec<String>,
1932}
1933
1934#[derive(Debug, Clone, Serialize, Deserialize)]
1935#[serde(rename_all = "camelCase")]
1936pub struct DesignGuidelinesResult {
1937 pub categories: Vec<DesignGuidelineCategory>,
1938}
1939
1940#[derive(Debug, Clone, Serialize, Deserialize)]
1941#[serde(rename_all = "camelCase")]
1942pub struct DesignSpawnedAgentScope {
1943 pub alias: String,
1944 pub scope_node_id: String,
1945 pub scope_name: String,
1946 #[serde(rename = "type")]
1947 pub node_type: String,
1948 pub child_count: usize,
1949 pub prompt: String,
1950}
1951
1952#[derive(Debug, Clone, Serialize, Deserialize)]
1953#[serde(rename_all = "camelCase")]
1954pub struct DesignSpawnAgentsResult {
1955 pub path: String,
1956 pub planned: Vec<DesignSpawnedAgentScope>,
1957 pub allow_patch: bool,
1958 pub allow_export: bool,
1959 pub require_review: bool,
1960 pub instructions: String,
1961}
1962
1963#[derive(Debug, Clone, Serialize, Deserialize)]
1964#[serde(rename_all = "camelCase")]
1965pub struct DesignExportNodesParams {
1966 pub workspace_id: String,
1967 #[serde(default, skip_serializing_if = "Option::is_none")]
1968 pub root_id: Option<String>,
1969 pub node_ids: Vec<String>,
1970 #[serde(default, skip_serializing_if = "Option::is_none")]
1971 pub output_dir: Option<String>,
1972 #[serde(default, skip_serializing_if = "Option::is_none")]
1973 pub format: Option<String>,
1974}
1975
1976#[derive(Debug, Clone, Serialize, Deserialize)]
1977#[serde(rename_all = "camelCase")]
1978pub struct DesignGetScreenshotParams {
1979 pub workspace_id: String,
1980 #[serde(default, skip_serializing_if = "Option::is_none")]
1981 pub root_id: Option<String>,
1982 #[serde(default, skip_serializing_if = "Option::is_none")]
1983 pub node_id: Option<String>,
1984 #[serde(default)]
1985 pub format: Option<String>,
1986}
1987
1988#[derive(Debug, Clone, Serialize, Deserialize)]
1989#[serde(rename_all = "camelCase")]
1990pub struct DesignExportedNode {
1991 pub node_id: String,
1992 pub path: String,
1993}
1994
1995#[derive(Debug, Clone, Serialize, Deserialize)]
1996#[serde(rename_all = "camelCase")]
1997pub struct DesignExportNodesResult {
1998 pub exported: Vec<DesignExportedNode>,
1999}
2000
2001#[derive(Debug, Clone, Serialize, Deserialize)]
2002#[serde(rename_all = "camelCase")]
2003pub struct DesignScreenshotResult {
2004 pub path: String,
2005 #[serde(default, skip_serializing_if = "Option::is_none")]
2006 pub node_id: Option<String>,
2007 pub mime_type: String,
2008 pub data_url: String,
2009}
2010
2011#[derive(Debug, Clone, Serialize, Deserialize)]
2012#[serde(rename_all = "camelCase")]
2013pub struct CommandExecParams {
2014 pub command: Vec<String>,
2015 pub process_id: Option<String>,
2016 #[serde(default)]
2017 pub tty: bool,
2018 #[serde(default)]
2019 pub stream_stdin: bool,
2020 #[serde(default)]
2021 pub stream_stdout_stderr: bool,
2022 pub output_bytes_cap: Option<usize>,
2023 #[serde(default)]
2024 pub disable_output_cap: bool,
2025 #[serde(default)]
2026 pub disable_timeout: bool,
2027 pub timeout_ms: Option<u64>,
2028 pub cwd: Option<String>,
2029 pub env: Option<HashMap<String, Option<String>>>,
2030 #[serde(default)]
2031 pub size: Option<serde_json::Value>,
2032 #[serde(default)]
2033 pub sandbox_policy: Option<serde_json::Value>,
2034}
2035
2036#[derive(Debug, Clone, Serialize, Deserialize)]
2037#[serde(rename_all = "camelCase")]
2038pub struct CommandExecResponse {
2039 pub exit_code: i32,
2040 pub stdout: String,
2041 pub stderr: String,
2042 #[serde(default, skip_serializing_if = "Option::is_none")]
2043 pub stdout_artifact: Option<ContextArtifactDescriptor>,
2044 #[serde(default, skip_serializing_if = "Option::is_none")]
2045 pub stderr_artifact: Option<ContextArtifactDescriptor>,
2046}
2047
2048#[derive(Debug, Clone, Serialize, Deserialize)]
2049#[serde(rename_all = "camelCase")]
2050pub struct CommandExecOutputDeltaNotification {
2051 pub process_id: String,
2052 pub stream: String,
2053 pub delta_base64: String,
2054 pub cap_reached: bool,
2055}
2056
2057#[derive(Debug, Clone, Serialize, Deserialize)]
2058#[serde(rename_all = "camelCase")]
2059pub struct TeamDescriptor {
2060 pub id: TeamId,
2061 pub lead_thread_id: ThreadId,
2062 pub display_mode: AgentTeamDisplayMode,
2063 pub members: Vec<TeamMemberDescriptor>,
2064 pub tasks: Vec<TeamTaskDescriptor>,
2065}
2066
2067#[derive(Debug, Clone, Serialize, Deserialize)]
2068#[serde(rename_all = "camelCase")]
2069pub struct TeamStartMemberParams {
2070 pub name: String,
2071 pub model_provider: Option<String>,
2072 pub model: Option<String>,
2073}
2074
2075#[derive(Debug, Clone, Serialize, Deserialize)]
2076#[serde(rename_all = "camelCase")]
2077pub struct TeamStartParams {
2078 pub lead_thread_id: Option<ThreadId>,
2079 pub display_mode: Option<AgentTeamDisplayMode>,
2080 #[serde(default)]
2081 pub members: Vec<TeamStartMemberParams>,
2082}
2083
2084#[derive(Debug, Clone, Serialize, Deserialize)]
2085#[serde(rename_all = "camelCase")]
2086pub struct TeamStartResult {
2087 pub team: TeamDescriptor,
2088}
2089
2090#[derive(Debug, Clone, Serialize, Deserialize)]
2091#[serde(rename_all = "camelCase")]
2092pub struct TeamListParams {
2093 pub limit: Option<usize>,
2094}
2095
2096#[derive(Debug, Clone, Serialize, Deserialize)]
2097#[serde(rename_all = "camelCase")]
2098pub struct TeamListResult {
2099 pub data: Vec<TeamDescriptor>,
2100 pub next_cursor: Option<String>,
2101}
2102
2103#[derive(Debug, Clone, Serialize, Deserialize)]
2104#[serde(rename_all = "camelCase")]
2105pub struct TeamReadParams {
2106 pub team_id: TeamId,
2107}
2108
2109#[derive(Debug, Clone, Serialize, Deserialize)]
2110#[serde(rename_all = "camelCase")]
2111pub struct TeamReadResult {
2112 pub team: Option<TeamDescriptor>,
2113 pub messages: Vec<TeamMailboxMessage>,
2114}
2115
2116#[derive(Debug, Clone, Serialize, Deserialize)]
2117#[serde(rename_all = "camelCase")]
2118pub struct TeamMemberStartParams {
2119 pub team_id: TeamId,
2120 pub name: String,
2121 pub model_provider: Option<String>,
2122 pub model: Option<String>,
2123}
2124
2125#[derive(Debug, Clone, Serialize, Deserialize)]
2126#[serde(rename_all = "camelCase")]
2127pub struct TeamMemberStartResult {
2128 pub member: TeamMemberDescriptor,
2129}
2130
2131#[derive(Debug, Clone, Serialize, Deserialize)]
2132#[serde(rename_all = "camelCase")]
2133pub struct TeamMemberMessageParams {
2134 pub team_id: TeamId,
2135 pub member_id: TeamMemberId,
2136 pub text: String,
2137 pub expected_turn_id: Option<TurnId>,
2138}
2139
2140#[derive(Debug, Clone, Serialize, Deserialize)]
2141#[serde(rename_all = "camelCase")]
2142pub struct TeamMemberMessageResult {
2143 pub turn_id: TurnId,
2144}
2145
2146#[derive(Debug, Clone, Serialize, Deserialize)]
2147#[serde(rename_all = "camelCase")]
2148pub struct TeamMemberInterruptParams {
2149 pub team_id: TeamId,
2150 pub member_id: TeamMemberId,
2151 pub turn_id: Option<TurnId>,
2152}
2153
2154#[derive(Debug, Clone, Serialize, Deserialize)]
2155#[serde(rename_all = "camelCase")]
2156pub struct TeamMemberInterruptResult {
2157 pub interrupted: bool,
2158 pub turn_id: Option<TurnId>,
2159}
2160
2161#[derive(Debug, Clone, Serialize, Deserialize)]
2162#[serde(rename_all = "camelCase")]
2163pub struct TeamMemberFocusParams {
2164 pub team_id: TeamId,
2165 pub member_id: TeamMemberId,
2166}
2167
2168#[derive(Debug, Clone, Serialize, Deserialize)]
2169#[serde(rename_all = "camelCase")]
2170pub struct TeamMemberFocusResult {
2171 pub focused_member_id: TeamMemberId,
2172}
2173
2174#[derive(Debug, Clone, Serialize, Deserialize)]
2175#[serde(rename_all = "camelCase")]
2176pub struct TeamCleanupParams {
2177 pub team_id: TeamId,
2178 #[serde(default)]
2179 pub force: bool,
2180}
2181
2182#[derive(Debug, Clone, Serialize, Deserialize)]
2183#[serde(rename_all = "camelCase")]
2184pub struct TeamCleanupResult {
2185 pub cleaned: bool,
2186}
2187
2188#[derive(Debug, Clone, Serialize, Deserialize)]
2189#[serde(rename_all = "camelCase")]
2190pub struct TeamStartedNotification {
2191 pub team: TeamDescriptor,
2192}
2193
2194#[derive(Debug, Clone, Serialize, Deserialize)]
2195#[serde(rename_all = "camelCase")]
2196pub struct TeamMemberStartedNotification {
2197 pub team_id: TeamId,
2198 pub member: TeamMemberDescriptor,
2199}
2200
2201#[derive(Debug, Clone, Serialize, Deserialize)]
2202#[serde(rename_all = "camelCase")]
2203pub struct TeamMemberStatusChangedNotification {
2204 pub team_id: TeamId,
2205 pub member_id: TeamMemberId,
2206 pub status: TeamMemberStatus,
2207}
2208
2209#[derive(Debug, Clone, Serialize, Deserialize)]
2210#[serde(rename_all = "camelCase")]
2211pub struct TeamMemberMessageDeltaNotification {
2212 pub team_id: TeamId,
2213 pub member_id: TeamMemberId,
2214 pub turn_id: TurnId,
2215 pub delta: String,
2216}
2217
2218#[derive(Debug, Clone, Serialize, Deserialize)]
2219#[serde(rename_all = "camelCase")]
2220pub struct TeamMemberCompletedNotification {
2221 pub team_id: TeamId,
2222 pub member_id: TeamMemberId,
2223 pub turn_id: Option<TurnId>,
2224 pub status: TeamMemberStatus,
2225}
2226
2227#[derive(Debug, Clone, Serialize, Deserialize)]
2228#[serde(rename_all = "camelCase")]
2229pub struct TeamDisplayModeChangedNotification {
2230 pub team_id: TeamId,
2231 pub display_mode: AgentTeamDisplayMode,
2232}
2233
2234#[derive(Debug, Clone, Serialize, Deserialize)]
2235#[serde(rename_all = "camelCase")]
2236pub struct TeamTaskChangedNotification {
2237 pub team_id: TeamId,
2238 pub task: TeamTaskDescriptor,
2239}
2240
2241#[derive(Debug, Clone, Serialize, Deserialize)]
2242#[serde(rename_all = "camelCase")]
2243pub struct TeamCleanupCompletedNotification {
2244 pub team_id: TeamId,
2245 pub forced: bool,
2246}
2247
2248#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2249pub struct RunnerStatus {
2250 pub destination_id: String,
2251 pub provider_id: String,
2252 pub state: String,
2253 pub session_id: Option<String>,
2254}
2255
2256#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2257pub struct RunnerProviderDescriptor {
2258 pub provider_id: String,
2259 pub capabilities: roder_api::remote_runner::RunnerCapabilities,
2260 #[serde(default, skip_serializing_if = "Option::is_none")]
2263 pub setup_hint: Option<String>,
2264}
2265
2266#[derive(Debug, Clone, Serialize, Deserialize)]
2267pub struct RunnersListResult {
2268 pub active: Option<RunnerStatus>,
2269 pub providers: Vec<RunnerProviderDescriptor>,
2270}
2271
2272#[derive(Debug, Clone, Serialize, Deserialize)]
2273pub struct RunnersSelectParams {
2274 pub destination_id: String,
2275 pub provider_id: Option<String>,
2276 #[serde(default)]
2277 pub config: serde_json::Value,
2278 #[serde(default)]
2279 pub manifest: roder_api::remote_runner::RunnerManifest,
2280}
2281
2282#[derive(Debug, Clone, Serialize, Deserialize)]
2283pub struct RunnersSelectResult {
2284 pub active: Option<RunnerStatus>,
2285}
2286
2287#[derive(Debug, Clone, Serialize, Deserialize)]
2288pub struct RunnersSessionResult {
2289 pub active: Option<RunnerStatus>,
2290}
2291
2292#[derive(Debug, Clone, Serialize, Deserialize)]
2293pub struct RunnersSnapshotResult {
2294 pub snapshot: Option<roder_api::remote_runner::RunnerSnapshotRef>,
2295}
2296
2297#[derive(Debug, Clone, Serialize, Deserialize)]
2298pub struct RunnersDeleteResult {
2299 pub deleted: bool,
2300}
2301
2302#[derive(Debug, Clone, Serialize, Deserialize)]
2303pub struct RunnersPortsResult {
2304 pub ports: Vec<roder_api::remote_runner::RunnerPortResult>,
2305}
2306
2307#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2308pub struct WebSearchSettings {
2309 pub mode: HostedWebSearchMode,
2310}
2311
2312#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2313pub struct SearchIndexSettings {
2314 pub enabled: bool,
2315}
2316
2317#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2318pub struct ShellSettings {
2319 pub shell: String,
2320 pub options: Vec<String>,
2321}
2322
2323#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2324#[serde(rename_all = "camelCase")]
2325pub enum SearchIndexStatusState {
2326 Disabled,
2327 Missing,
2328 Building,
2329 Ready,
2330 Stale,
2331 Failed,
2332 Cleared,
2333}
2334
2335#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2336#[serde(rename_all = "camelCase")]
2337pub struct SearchIndexStatus {
2338 pub state: SearchIndexStatusState,
2339 pub enabled: bool,
2340 pub workspace: String,
2341 pub store_dir: String,
2342 #[serde(default, skip_serializing_if = "Option::is_none")]
2343 pub index_version: Option<String>,
2344 #[serde(default, skip_serializing_if = "Option::is_none")]
2345 pub document_count: Option<u64>,
2346 #[serde(default, skip_serializing_if = "Option::is_none")]
2347 pub index_bytes: Option<u64>,
2348 #[serde(default, skip_serializing_if = "Option::is_none")]
2349 pub build_time_ms: Option<u64>,
2350 pub stale: bool,
2351 #[serde(default, skip_serializing_if = "Option::is_none")]
2352 pub message: Option<String>,
2353}
2354
2355#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2356#[serde(rename_all = "camelCase")]
2357pub struct SearchIndexStatusParams {
2358 pub workspace: Option<String>,
2359}
2360
2361#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2362#[serde(rename_all = "camelCase")]
2363pub struct SearchIndexWarmupParams {
2364 pub workspace: Option<String>,
2365}
2366
2367#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2368#[serde(rename_all = "camelCase")]
2369pub struct SearchIndexRebuildParams {
2370 pub workspace: Option<String>,
2371}
2372
2373#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2374#[serde(rename_all = "camelCase")]
2375pub struct SearchIndexClearParams {
2376 pub workspace: Option<String>,
2377}
2378
2379#[derive(Debug, Clone, Serialize, Deserialize)]
2380#[serde(rename_all = "camelCase")]
2381pub struct SearchIndexStatusResult {
2382 pub status: SearchIndexStatus,
2383}
2384
2385#[derive(Debug, Clone, Serialize, Deserialize)]
2386#[serde(rename_all = "camelCase")]
2387pub struct SearchIndexWarmupResult {
2388 pub status: SearchIndexStatus,
2389}
2390
2391#[derive(Debug, Clone, Serialize, Deserialize)]
2392#[serde(rename_all = "camelCase")]
2393pub struct SearchIndexRebuildResult {
2394 pub status: SearchIndexStatus,
2395}
2396
2397#[derive(Debug, Clone, Serialize, Deserialize)]
2398#[serde(rename_all = "camelCase")]
2399pub struct SearchIndexClearResult {
2400 pub status: SearchIndexStatus,
2401}
2402
2403#[derive(Debug, Clone, Serialize, Deserialize)]
2404#[serde(rename_all = "camelCase")]
2405pub struct SearchIndexStatusNotification {
2406 pub status: SearchIndexStatus,
2407}
2408
2409#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2410#[serde(rename_all = "camelCase")]
2411pub struct CodeIndexStatusView {
2412 pub status: CodeIndexStatus,
2413 pub workspace: String,
2414 pub store_path: String,
2415 pub generation_id: Option<CodeIndexGenerationId>,
2416 pub root_hash: Option<String>,
2417 pub stale: bool,
2418 pub stats: CodeIndexStats,
2419 #[serde(default, skip_serializing_if = "Option::is_none")]
2420 pub message: Option<String>,
2421}
2422
2423#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2424#[serde(rename_all = "camelCase")]
2425pub struct CodeIndexStatusParams {
2426 pub workspace: Option<String>,
2427}
2428
2429#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2430#[serde(rename_all = "camelCase")]
2431pub struct CodeIndexRebuildParams {
2432 pub workspace: Option<String>,
2433}
2434
2435#[derive(Debug, Clone, Serialize, Deserialize)]
2436#[serde(rename_all = "camelCase")]
2437pub struct CodeIndexSearchParams {
2438 pub query: String,
2439 #[serde(default, skip_serializing_if = "Option::is_none")]
2440 pub workspace: Option<String>,
2441 #[serde(default)]
2442 pub limit: Option<usize>,
2443}
2444
2445#[derive(Debug, Clone, Serialize, Deserialize)]
2446#[serde(rename_all = "camelCase")]
2447pub struct CodeIndexReadChunkParams {
2448 pub chunk_hash: String,
2449 #[serde(default, skip_serializing_if = "Option::is_none")]
2450 pub workspace: Option<String>,
2451 #[serde(default)]
2452 pub offset: Option<usize>,
2453 #[serde(default)]
2454 pub limit: Option<usize>,
2455 #[serde(default)]
2456 pub include_source: bool,
2457}
2458
2459#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2460#[serde(rename_all = "camelCase")]
2461pub struct CodeIndexProofsListParams {
2462 #[serde(default, skip_serializing_if = "Option::is_none")]
2463 pub workspace: Option<String>,
2464}
2465
2466#[derive(Debug, Clone, Serialize, Deserialize)]
2467#[serde(rename_all = "camelCase")]
2468pub struct CodeIndexStatusResult {
2469 pub status: CodeIndexStatusView,
2470}
2471
2472#[derive(Debug, Clone, Serialize, Deserialize)]
2473#[serde(rename_all = "camelCase")]
2474pub struct CodeIndexRebuildResult {
2475 pub status: CodeIndexStatusView,
2476}
2477
2478#[derive(Debug, Clone, Serialize, Deserialize)]
2479#[serde(rename_all = "camelCase")]
2480pub struct CodeIndexSearchResultEnvelope {
2481 pub status: CodeIndexStatusView,
2482 pub response: CodeIndexSearchResponse,
2483}
2484
2485#[derive(Debug, Clone, Serialize, Deserialize)]
2486#[serde(rename_all = "camelCase")]
2487pub struct CodeIndexChunkReadPage {
2488 pub chunk: CodeChunk,
2489 pub text: String,
2490 pub offset: usize,
2491 pub limit: usize,
2492 pub total_bytes: usize,
2493 pub has_more: bool,
2494}
2495
2496#[derive(Debug, Clone, Serialize, Deserialize)]
2497#[serde(rename_all = "camelCase")]
2498pub struct CodeIndexReadChunkResult {
2499 pub status: CodeIndexStatusView,
2500 pub page: CodeIndexChunkReadPage,
2501}
2502
2503#[derive(Debug, Clone, Serialize, Deserialize)]
2504#[serde(rename_all = "camelCase")]
2505pub struct CodeIndexProofsListResult {
2506 pub status: CodeIndexStatusView,
2507 pub proofs: Vec<ContentProof>,
2508}
2509
2510#[derive(Debug, Clone, Serialize, Deserialize)]
2511#[serde(rename_all = "camelCase")]
2512pub struct CodeIndexStatusNotification {
2513 pub status: CodeIndexStatusView,
2514}
2515
2516#[derive(Debug, Clone, Serialize, Deserialize)]
2517pub struct ExtensionsListResult {
2518 pub extensions: Vec<ExtensionManifest>,
2519 #[serde(default)]
2520 pub capability_statuses: std::collections::BTreeMap<ExtensionId, Vec<CapabilityStatus>>,
2521}
2522
2523#[derive(Debug, Clone, Serialize, Deserialize)]
2524pub struct ProviderDescriptor {
2525 pub id: String,
2526 pub name: String,
2527 pub description: Option<String>,
2528 pub auth_type: ProviderAuthType,
2529 pub auth_label: Option<String>,
2530 pub authenticated: bool,
2531 pub auth_detail: Option<String>,
2532 pub recommended: bool,
2533 pub sort_order: i32,
2534 pub capabilities: InferenceCapabilities,
2535 pub models: Vec<ModelDescriptor>,
2536}
2537
2538#[derive(Debug, Clone, Serialize, Deserialize)]
2539pub struct ProvidersListResult {
2540 pub active_provider: String,
2541 pub active_model: String,
2542 pub active_reasoning: String,
2543 #[serde(
2544 default,
2545 rename = "selectionMode",
2546 skip_serializing_if = "Option::is_none"
2547 )]
2548 pub selection_mode: Option<ModelSelectionMode>,
2549 #[serde(default, rename = "routingOptions")]
2550 pub routing_options: Vec<InferenceRoutingOptionDescriptor>,
2551 pub providers: Vec<ProviderDescriptor>,
2552}
2553
2554#[derive(Debug, Clone, Serialize, Deserialize)]
2555pub struct ProviderConfigureParams {
2556 pub provider: String,
2557 pub api_key: String,
2558}
2559
2560#[derive(Debug, Clone, Serialize, Deserialize)]
2561pub struct ProviderConfigureResult {
2562 pub provider: String,
2563 pub authenticated: bool,
2564}
2565
2566#[derive(Debug, Clone, Serialize, Deserialize)]
2567pub struct ProviderClearParams {
2568 pub provider: String,
2569}
2570
2571#[derive(Debug, Clone, Serialize, Deserialize)]
2572pub struct ProviderClearResult {
2573 pub provider: String,
2574}
2575
2576#[derive(Debug, Clone, Serialize, Deserialize)]
2577#[serde(rename_all = "camelCase")]
2578pub struct SubagentTracesListParams {
2579 pub thread_id: ThreadId,
2580 pub turn_id: TurnId,
2581}
2582
2583#[derive(Debug, Clone, Serialize, Deserialize)]
2584#[serde(rename_all = "camelCase")]
2585pub struct SubagentTracesListResult {
2586 pub traces: Vec<SubagentTraceSummary>,
2587}
2588
2589#[derive(Debug, Clone, Serialize, Deserialize)]
2590#[serde(rename_all = "camelCase")]
2591pub struct SubagentTraceReadParams {
2592 pub thread_id: ThreadId,
2593 pub trace_id: SubagentTraceId,
2594 #[serde(default)]
2595 pub offset: usize,
2596 #[serde(default, skip_serializing_if = "Option::is_none")]
2597 pub limit: Option<usize>,
2598}
2599
2600#[derive(Debug, Clone, Serialize, Deserialize)]
2601#[serde(rename_all = "camelCase")]
2602pub struct SubagentTraceReadResult {
2603 pub trace_id: SubagentTraceId,
2604 pub events: Vec<SubagentTraceDelta>,
2605 #[serde(default, skip_serializing_if = "Option::is_none")]
2606 pub next_offset: Option<usize>,
2607}
2608
2609#[derive(Debug, Clone, Serialize, Deserialize)]
2610#[serde(rename_all = "camelCase")]
2611pub struct PlanReviewReadParams {
2612 pub thread_id: ThreadId,
2613 pub review_id: PlanReviewId,
2614}
2615
2616#[derive(Debug, Clone, Serialize, Deserialize)]
2617#[serde(rename_all = "camelCase")]
2618pub struct PlanReviewReadResult {
2619 pub review: Option<PlanReview>,
2620}
2621
2622#[derive(Debug, Clone, Serialize, Deserialize)]
2623#[serde(rename_all = "camelCase")]
2624pub struct PlanReviewCommentParams {
2625 pub thread_id: ThreadId,
2626 pub review_id: PlanReviewId,
2627 pub anchor: PlanCommentAnchor,
2628 pub body: String,
2629}
2630
2631#[derive(Debug, Clone, Serialize, Deserialize)]
2632#[serde(rename_all = "camelCase")]
2633pub struct PlanReviewCommentResult {
2634 pub comment: PlanComment,
2635}
2636
2637#[derive(Debug, Clone, Serialize, Deserialize)]
2638#[serde(rename_all = "camelCase")]
2639pub struct PlanReviewRewriteParams {
2640 pub thread_id: ThreadId,
2641 pub review_id: PlanReviewId,
2642 pub replacement_markdown: String,
2643}
2644
2645#[derive(Debug, Clone, Serialize, Deserialize)]
2646#[serde(rename_all = "camelCase")]
2647pub struct PlanReviewRewriteResult {
2648 pub rewrite: PlanRewrite,
2649}
2650
2651#[derive(Debug, Clone, Serialize, Deserialize)]
2652#[serde(rename_all = "camelCase")]
2653pub struct PlanReviewApproveParams {
2654 pub thread_id: ThreadId,
2655 pub review_id: PlanReviewId,
2656}
2657
2658#[derive(Debug, Clone, Serialize, Deserialize)]
2659#[serde(rename_all = "camelCase")]
2660pub struct PlanReviewApproveResult {
2661 pub approved: bool,
2662}
2663
2664#[derive(Debug, Clone, Serialize, Deserialize)]
2665#[serde(rename_all = "camelCase")]
2666pub struct PlanReviewRejectParams {
2667 pub thread_id: ThreadId,
2668 pub review_id: PlanReviewId,
2669 #[serde(default, skip_serializing_if = "Option::is_none")]
2670 pub reason: Option<String>,
2671}
2672
2673#[derive(Debug, Clone, Serialize, Deserialize)]
2674#[serde(rename_all = "camelCase")]
2675pub struct PlanReviewRejectResult {
2676 pub rejected: bool,
2677}
2678
2679#[derive(Debug, Clone, Serialize, Deserialize)]
2680#[serde(rename_all = "camelCase")]
2681pub struct HunkListParams {
2682 pub thread_id: ThreadId,
2683 #[serde(default, skip_serializing_if = "Option::is_none")]
2684 pub turn_id: Option<TurnId>,
2685 #[serde(default, skip_serializing_if = "Option::is_none")]
2686 pub review_id: Option<PlanReviewId>,
2687}
2688
2689#[derive(Debug, Clone, Serialize, Deserialize)]
2690#[serde(rename_all = "camelCase")]
2691pub struct HunkListResult {
2692 pub hunks: Vec<HunkRecord>,
2693}
2694
2695#[derive(Debug, Clone, Serialize, Deserialize)]
2696#[serde(rename_all = "camelCase")]
2697pub struct HunkReadParams {
2698 pub thread_id: ThreadId,
2699 pub hunk_id: HunkId,
2700 #[serde(default)]
2701 pub offset: usize,
2702 #[serde(default, skip_serializing_if = "Option::is_none")]
2703 pub limit: Option<usize>,
2704}
2705
2706#[derive(Debug, Clone, Serialize, Deserialize)]
2707#[serde(rename_all = "camelCase")]
2708pub struct HunkReadResult {
2709 pub page: Option<PagedHunkDiff>,
2710}
2711
2712#[derive(Debug, Clone, Serialize, Deserialize)]
2713#[serde(rename_all = "camelCase")]
2714pub struct WorkspaceChangesListParams {
2715 pub thread_id: ThreadId,
2716 #[serde(default, skip_serializing_if = "Option::is_none")]
2717 pub turn_id: Option<TurnId>,
2718}
2719
2720#[derive(Debug, Clone, Serialize, Deserialize)]
2721#[serde(rename_all = "camelCase")]
2722pub struct WorkspaceChangesListResult {
2723 pub changes: Vec<WorkspaceChangeObservation>,
2724}
2725
2726#[derive(Debug, Clone, Serialize, Deserialize)]
2727#[serde(rename_all = "camelCase")]
2728pub struct HunkRollbackParams {
2729 pub thread_id: ThreadId,
2730 pub hunk_id: HunkId,
2731 #[serde(default)]
2732 pub confirmed: bool,
2733}
2734
2735#[derive(Debug, Clone, Serialize, Deserialize)]
2736#[serde(rename_all = "camelCase")]
2737pub struct HunkRollbackResult {
2738 pub rolled_back: bool,
2739 #[serde(default, skip_serializing_if = "Option::is_none")]
2740 pub error: Option<String>,
2741}
2742
2743#[derive(Debug, Clone, Serialize, Deserialize)]
2744#[serde(rename_all = "camelCase")]
2745pub struct VcsWorkspaceParams {
2746 pub workspace_id: String,
2747 #[serde(default, skip_serializing_if = "Option::is_none")]
2748 pub root_id: Option<String>,
2749 #[serde(default, skip_serializing_if = "Option::is_none")]
2750 pub provider_id: Option<String>,
2751}
2752
2753#[derive(Debug, Clone, Serialize, Deserialize)]
2754#[serde(rename_all = "camelCase")]
2755pub struct VcsChangesListParams {
2756 pub workspace_id: String,
2757 #[serde(default, skip_serializing_if = "Option::is_none")]
2758 pub root_id: Option<String>,
2759 #[serde(default, skip_serializing_if = "Option::is_none")]
2760 pub provider_id: Option<String>,
2761 #[serde(default, skip_serializing_if = "Option::is_none")]
2762 pub limit: Option<usize>,
2763}
2764
2765#[derive(Debug, Clone, Serialize, Deserialize)]
2766#[serde(rename_all = "camelCase")]
2767pub struct VcsChangesReadParams {
2768 pub workspace_id: String,
2769 #[serde(default, skip_serializing_if = "Option::is_none")]
2770 pub root_id: Option<String>,
2771 #[serde(default, skip_serializing_if = "Option::is_none")]
2772 pub provider_id: Option<String>,
2773 pub path: String,
2774 #[serde(default)]
2775 pub offset: usize,
2776 #[serde(default, skip_serializing_if = "Option::is_none")]
2777 pub limit: Option<usize>,
2778 #[serde(default, skip_serializing_if = "Option::is_none")]
2779 pub area: Option<VcsChangeArea>,
2780 #[serde(default)]
2781 pub ignore_whitespace: bool,
2782}
2783
2784#[derive(Debug, Clone, Serialize, Deserialize)]
2785#[serde(rename_all = "camelCase")]
2786pub struct VcsChangesTotals {
2787 pub files: u32,
2788 pub additions: u32,
2789 pub deletions: u32,
2790}
2791
2792#[derive(Debug, Clone, Serialize, Deserialize)]
2793#[serde(rename_all = "camelCase")]
2794pub struct VcsChangesListResult {
2795 pub status: roder_api::version_control::VcsStatus,
2796 pub files: Vec<roder_api::version_control::VcsChangedFile>,
2797 pub totals: VcsChangesTotals,
2798 pub truncated: bool,
2799}
2800
2801#[derive(Debug, Clone, Serialize, Deserialize)]
2802#[serde(rename_all = "camelCase")]
2803pub struct VcsSelectionParams {
2804 pub workspace_id: String,
2805 #[serde(default, skip_serializing_if = "Option::is_none")]
2806 pub root_id: Option<String>,
2807 #[serde(default, skip_serializing_if = "Option::is_none")]
2808 pub provider_id: Option<String>,
2809 pub paths: Vec<String>,
2810 pub granularity: roder_api::version_control::VcsSelectionGranularity,
2811}
2812
2813#[derive(Debug, Clone, Serialize, Deserialize)]
2814#[serde(rename_all = "camelCase")]
2815pub struct VcsSnapshotCreateParams {
2816 pub workspace_id: String,
2817 #[serde(default, skip_serializing_if = "Option::is_none")]
2818 pub root_id: Option<String>,
2819 #[serde(default, skip_serializing_if = "Option::is_none")]
2820 pub provider_id: Option<String>,
2821 pub message: String,
2822 #[serde(default)]
2823 pub paths: Vec<String>,
2824}
2825
2826#[derive(Debug, Clone, Serialize, Deserialize)]
2827#[serde(rename_all = "camelCase")]
2828pub struct VcsRestoreParams {
2829 pub workspace_id: String,
2830 #[serde(default, skip_serializing_if = "Option::is_none")]
2831 pub root_id: Option<String>,
2832 #[serde(default, skip_serializing_if = "Option::is_none")]
2833 pub provider_id: Option<String>,
2834 pub paths: Vec<String>,
2835}
2836
2837#[derive(Debug, Clone, Serialize, Deserialize)]
2838#[serde(rename_all = "camelCase")]
2839pub struct VcsLineSwitchParams {
2840 pub workspace_id: String,
2841 #[serde(default, skip_serializing_if = "Option::is_none")]
2842 pub root_id: Option<String>,
2843 #[serde(default, skip_serializing_if = "Option::is_none")]
2844 pub provider_id: Option<String>,
2845 pub line_id: String,
2846}
2847
2848#[derive(Debug, Clone, Serialize, Deserialize)]
2849#[serde(rename_all = "camelCase")]
2850pub struct VcsSyncParams {
2851 pub workspace_id: String,
2852 #[serde(default, skip_serializing_if = "Option::is_none")]
2853 pub root_id: Option<String>,
2854 #[serde(default, skip_serializing_if = "Option::is_none")]
2855 pub provider_id: Option<String>,
2856 pub operation: roder_api::version_control::VcsSyncOperation,
2857}
2858
2859#[derive(Debug, Clone, Serialize, Deserialize)]
2860#[serde(rename_all = "camelCase")]
2861pub struct MediaListParams {
2862 #[serde(default, skip_serializing_if = "Option::is_none")]
2863 pub thread_id: Option<ThreadId>,
2864 #[serde(default, skip_serializing_if = "Option::is_none")]
2865 pub kind: Option<roder_api::media::MediaKind>,
2866}
2867
2868#[derive(Debug, Clone, Serialize, Deserialize)]
2869#[serde(rename_all = "camelCase")]
2870pub struct MediaListResult {
2871 pub artifacts: Vec<MediaArtifact>,
2872}
2873
2874#[derive(Debug, Clone, Serialize, Deserialize)]
2875#[serde(rename_all = "camelCase")]
2876pub struct ArtifactListParams {
2877 pub thread_id: ThreadId,
2878 #[serde(default, skip_serializing_if = "Option::is_none")]
2879 pub kind: Option<ContextArtifactKind>,
2880 #[serde(default, skip_serializing_if = "Option::is_none")]
2881 pub limit: Option<usize>,
2882}
2883
2884#[derive(Debug, Clone, Serialize, Deserialize)]
2885#[serde(rename_all = "camelCase")]
2886pub struct ArtifactListResult {
2887 pub artifacts: Vec<ContextArtifactDescriptor>,
2888}
2889
2890#[derive(Debug, Clone, Serialize, Deserialize)]
2891#[serde(rename_all = "camelCase")]
2892pub struct ArtifactReadParams {
2893 pub thread_id: ThreadId,
2894 pub artifact_id: String,
2895 #[serde(default, skip_serializing_if = "Option::is_none")]
2896 pub start_line: Option<usize>,
2897 #[serde(default, skip_serializing_if = "Option::is_none")]
2898 pub limit: Option<usize>,
2899}
2900
2901#[derive(Debug, Clone, Serialize, Deserialize)]
2902#[serde(rename_all = "camelCase")]
2903pub struct ArtifactReadResult {
2904 pub page: ArtifactReadPage,
2905}
2906
2907#[derive(Debug, Clone, Serialize, Deserialize)]
2908#[serde(rename_all = "camelCase")]
2909pub struct ArtifactGrepParams {
2910 pub thread_id: ThreadId,
2911 pub artifact_id: String,
2912 pub query: String,
2913 #[serde(default, skip_serializing_if = "Option::is_none")]
2914 pub offset: Option<usize>,
2915 #[serde(default, skip_serializing_if = "Option::is_none")]
2916 pub limit: Option<usize>,
2917}
2918
2919#[derive(Debug, Clone, Serialize, Deserialize)]
2920#[serde(rename_all = "camelCase")]
2921pub struct ArtifactGrepResult {
2922 pub page: ArtifactGrepPage,
2923}
2924
2925#[derive(Debug, Clone, Serialize, Deserialize)]
2926#[serde(rename_all = "camelCase")]
2927pub struct ArtifactTailParams {
2928 pub thread_id: ThreadId,
2929 pub artifact_id: String,
2930 #[serde(default, skip_serializing_if = "Option::is_none")]
2931 pub lines: Option<usize>,
2932}
2933
2934#[derive(Debug, Clone, Serialize, Deserialize)]
2935#[serde(rename_all = "camelCase")]
2936pub struct ArtifactTailResult {
2937 pub page: ArtifactTailPage,
2938}
2939
2940#[derive(Debug, Clone, Serialize, Deserialize)]
2941#[serde(rename_all = "camelCase")]
2942pub struct ArtifactDeleteParams {
2943 pub thread_id: ThreadId,
2944 pub artifact_id: String,
2945}
2946
2947#[derive(Debug, Clone, Serialize, Deserialize)]
2948#[serde(rename_all = "camelCase")]
2949pub struct ArtifactDeleteResult {
2950 pub deleted: bool,
2951}
2952
2953#[derive(Debug, Clone, Serialize, Deserialize)]
2954#[serde(rename_all = "camelCase")]
2955pub struct DiscoveryGroupsParams {
2956 #[serde(default, skip_serializing_if = "Option::is_none")]
2957 pub refresh: Option<bool>,
2958 #[serde(default, skip_serializing_if = "Option::is_none")]
2959 pub limit: Option<usize>,
2960}
2961
2962#[derive(Debug, Clone, Serialize, Deserialize)]
2963#[serde(rename_all = "camelCase")]
2964pub struct DiscoveryGroupsResult {
2965 pub catalog_id: String,
2966 pub title: String,
2967 pub hidden_item_count: u64,
2968 pub groups: Vec<DiscoveryCatalogGroup>,
2969}
2970
2971#[derive(Debug, Clone, Serialize, Deserialize)]
2972#[serde(rename_all = "camelCase")]
2973pub struct DiscoverySearchParams {
2974 pub query: String,
2975 #[serde(default, skip_serializing_if = "Option::is_none")]
2976 pub refresh: Option<bool>,
2977 #[serde(default, skip_serializing_if = "Option::is_none")]
2978 pub limit: Option<usize>,
2979}
2980
2981#[derive(Debug, Clone, Serialize, Deserialize)]
2982#[serde(rename_all = "camelCase")]
2983pub struct DiscoverySearchResult {
2984 pub query: String,
2985 pub items: Vec<DiscoveryCatalogItem>,
2986}
2987
2988#[derive(Debug, Clone, Serialize, Deserialize)]
2989#[serde(rename_all = "camelCase")]
2990pub struct DiscoveryReadParams {
2991 pub item_id: String,
2992 #[serde(default, skip_serializing_if = "Option::is_none")]
2993 pub refresh: Option<bool>,
2994 #[serde(default, skip_serializing_if = "Option::is_none")]
2995 pub start_line: Option<usize>,
2996 #[serde(default, skip_serializing_if = "Option::is_none")]
2997 pub limit: Option<usize>,
2998 #[serde(default, skip_serializing_if = "Option::is_none")]
2999 pub promote: Option<bool>,
3000 #[serde(default, skip_serializing_if = "Option::is_none")]
3001 pub thread_id: Option<ThreadId>,
3002 #[serde(default, skip_serializing_if = "Option::is_none")]
3003 pub turn_id: Option<TurnId>,
3004}
3005
3006#[derive(Debug, Clone, Serialize, Deserialize)]
3007#[serde(rename_all = "camelCase")]
3008pub struct DiscoveryReadPage {
3009 pub text: String,
3010 pub start_line: usize,
3011 pub end_line: usize,
3012 pub total_lines: usize,
3013 pub truncated: bool,
3014}
3015
3016#[derive(Debug, Clone, Serialize, Deserialize)]
3017#[serde(rename_all = "camelCase")]
3018pub struct DiscoveryReadResult {
3019 pub item: DiscoveryCatalogItem,
3020 pub page: DiscoveryReadPage,
3021 pub promoted: bool,
3022}
3023
3024#[derive(Debug, Clone, Serialize, Deserialize)]
3025#[serde(rename_all = "camelCase")]
3026pub struct DiscoveryRefreshResult {
3027 pub catalog: DiscoveryCatalog,
3028 pub catalog_root: String,
3029 pub promotion_state_dir: String,
3030 pub written_files: Vec<String>,
3031}
3032
3033#[derive(Debug, Clone, Serialize, Deserialize)]
3034#[serde(rename_all = "camelCase")]
3035pub struct DiscoveryPromoteParams {
3036 pub item_id: String,
3037 pub thread_id: ThreadId,
3038 #[serde(default, skip_serializing_if = "Option::is_none")]
3039 pub turn_id: Option<TurnId>,
3040}
3041
3042#[derive(Debug, Clone, Serialize, Deserialize)]
3043#[serde(rename_all = "camelCase")]
3044pub struct DiscoveryPromoteResult {
3045 pub record: DiscoveryPromotionRecord,
3046}
3047
3048#[derive(Debug, Clone, Serialize, Deserialize)]
3049#[serde(rename_all = "camelCase")]
3050pub struct DiscoveryPromotedListParams {
3051 #[serde(default, skip_serializing_if = "Option::is_none")]
3052 pub thread_id: Option<ThreadId>,
3053}
3054
3055#[derive(Debug, Clone, Serialize, Deserialize)]
3056#[serde(rename_all = "camelCase")]
3057pub struct DiscoveryPromotedListResult {
3058 pub records: Vec<DiscoveryPromotionRecord>,
3059}
3060
3061#[derive(Debug, Clone, Serialize, Deserialize)]
3062#[serde(rename_all = "camelCase")]
3063pub struct DiscoveryPromotedClearParams {
3064 #[serde(default, skip_serializing_if = "Option::is_none")]
3065 pub thread_id: Option<ThreadId>,
3066 #[serde(default, skip_serializing_if = "Option::is_none")]
3067 pub item_id: Option<String>,
3068}
3069
3070#[derive(Debug, Clone, Serialize, Deserialize)]
3071#[serde(rename_all = "camelCase")]
3072pub struct DiscoveryPromotedClearResult {
3073 pub cleared: usize,
3074}
3075
3076#[derive(Debug, Clone, Serialize, Deserialize)]
3077#[serde(rename_all = "camelCase")]
3078pub struct RetrievalTurnParams {
3079 pub thread_id: ThreadId,
3080 pub turn_id: TurnId,
3081 #[serde(default, skip_serializing_if = "Option::is_none")]
3082 pub limit: Option<usize>,
3083}
3084
3085#[derive(Debug, Clone, Serialize, Deserialize)]
3086#[serde(rename_all = "camelCase")]
3087pub struct RetrievalDebugSummary {
3088 pub text: String,
3089 #[serde(default)]
3090 pub notes: Vec<String>,
3091 pub truncated: bool,
3092}
3093
3094#[derive(Debug, Clone, Serialize, Deserialize)]
3095#[serde(rename_all = "camelCase")]
3096pub struct RetrievalRecommendationsResult {
3097 pub thread_id: ThreadId,
3098 pub turn_id: TurnId,
3099 pub plans: Vec<RetrievalRoutePlan>,
3100 pub summary: RetrievalDebugSummary,
3101}
3102
3103#[derive(Debug, Clone, Serialize, Deserialize)]
3104#[serde(rename_all = "camelCase")]
3105pub struct RetrievalMetricsResult {
3106 pub thread_id: ThreadId,
3107 pub turn_id: TurnId,
3108 pub outcomes: Vec<RetrievalMeasuredOutcome>,
3109 pub accepted_count: u64,
3110 pub ignored_count: u64,
3111 pub failed_count: u64,
3112 pub outcome_counts: BTreeMap<String, u64>,
3113 pub mode_counts: BTreeMap<RetrievalMode, u64>,
3114 pub summary: RetrievalDebugSummary,
3115}
3116
3117#[derive(Debug, Clone, Serialize, Deserialize)]
3118#[serde(rename_all = "camelCase")]
3119pub struct InferenceRoutingMetricsParams {
3120 pub thread_id: ThreadId,
3121 pub turn_id: TurnId,
3122 #[serde(default, skip_serializing_if = "Option::is_none")]
3123 pub limit: Option<usize>,
3124}
3125
3126#[derive(Debug, Clone, Serialize, Deserialize)]
3127#[serde(rename_all = "camelCase")]
3128pub struct InferenceRoutingStatusParams {
3129 pub thread_id: ThreadId,
3130 #[serde(default, skip_serializing_if = "Option::is_none")]
3131 pub turn_id: Option<TurnId>,
3132}
3133
3134#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
3135#[serde(rename_all = "camelCase")]
3136pub struct InferenceRoutingDecisionEvent {
3137 pub thread_id: ThreadId,
3138 pub turn_id: TurnId,
3139 #[serde(default)]
3140 pub round_index: u32,
3141 pub default_selection: ModelSelection,
3142 pub selected_selection: ModelSelection,
3143 pub decision: InferenceRoutingDecision,
3144 #[serde(with = "time::serde::rfc3339")]
3145 pub timestamp: OffsetDateTime,
3146}
3147
3148impl From<roder_api::events::InferenceRoutingDecisionEvent> for InferenceRoutingDecisionEvent {
3149 fn from(event: roder_api::events::InferenceRoutingDecisionEvent) -> Self {
3150 Self {
3151 thread_id: event.thread_id,
3152 turn_id: event.turn_id,
3153 round_index: event.round_index,
3154 default_selection: event.default_selection,
3155 selected_selection: event.selected_selection,
3156 decision: event.decision,
3157 timestamp: event.timestamp,
3158 }
3159 }
3160}
3161
3162#[derive(Debug, Clone, Serialize, Deserialize)]
3163#[serde(rename_all = "camelCase")]
3164pub struct InferenceRoutingStatusResult {
3165 pub thread_id: ThreadId,
3166 #[serde(default, skip_serializing_if = "Option::is_none")]
3167 pub turn_id: Option<TurnId>,
3168 pub active: bool,
3169 pub decision_count: u64,
3170 #[serde(default, skip_serializing_if = "Option::is_none")]
3171 pub router_id: Option<String>,
3172 #[serde(default, skip_serializing_if = "Option::is_none")]
3173 pub latest_outcome: Option<InferenceRoutingOutcome>,
3174 #[serde(default, skip_serializing_if = "Option::is_none")]
3175 pub default_selection: Option<ModelSelection>,
3176 #[serde(default, skip_serializing_if = "Option::is_none")]
3177 pub selected_selection: Option<ModelSelection>,
3178 #[serde(default, skip_serializing_if = "Option::is_none")]
3179 pub latest_decision: Option<InferenceRoutingDecisionEvent>,
3180 pub summary: RetrievalDebugSummary,
3181}
3182
3183#[derive(Debug, Clone, Serialize, Deserialize)]
3184#[serde(rename_all = "camelCase")]
3185pub struct InferenceRoutingCostSummary {
3186 pub selected_estimated_cost_usd: f64,
3187 pub baseline_estimated_cost_usd: f64,
3188 pub estimated_savings_usd: f64,
3189 #[serde(default, skip_serializing_if = "Option::is_none")]
3190 pub classifier_overhead_usd: Option<f64>,
3191 pub incomplete_estimate_count: u64,
3192 pub priced_decision_count: u64,
3193}
3194
3195#[derive(Debug, Clone, Serialize, Deserialize)]
3196#[serde(rename_all = "camelCase")]
3197pub struct InferenceRoutingRegretSummary {
3198 pub retry_count: u64,
3199 pub failure_count: u64,
3200 pub turn_failed: bool,
3201 pub escalation_count: u64,
3202 pub fallback_count: u64,
3203}
3204
3205#[derive(Debug, Clone, Serialize, Deserialize)]
3206#[serde(rename_all = "camelCase")]
3207pub struct InferenceRoutingMetricsResult {
3208 pub thread_id: ThreadId,
3209 pub turn_id: TurnId,
3210 pub decisions: Vec<InferenceRoutingDecisionEvent>,
3211 pub decision_count: u64,
3212 pub outcome_counts: BTreeMap<String, u64>,
3213 pub cost: InferenceRoutingCostSummary,
3214 pub regret: InferenceRoutingRegretSummary,
3215 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3216 pub cost_deltas: Vec<InferenceRoutingCostDelta>,
3217 pub summary: RetrievalDebugSummary,
3218}
3219
3220#[derive(Debug, Clone, Serialize, Deserialize)]
3221#[serde(rename_all = "camelCase")]
3222pub struct RetrievalPromotedCapabilityState {
3223 pub item_id: String,
3224 #[serde(default, skip_serializing_if = "Option::is_none")]
3225 pub route_id: Option<String>,
3226 pub state: String,
3227 #[serde(default, skip_serializing_if = "Option::is_none")]
3228 pub cache_status: Option<String>,
3229 #[serde(default, skip_serializing_if = "Option::is_none")]
3230 pub reason: Option<String>,
3231 pub thread_id: ThreadId,
3232 #[serde(default, skip_serializing_if = "Option::is_none")]
3233 pub turn_id: Option<TurnId>,
3234 #[serde(with = "time::serde::rfc3339")]
3235 pub timestamp: OffsetDateTime,
3236}
3237
3238#[derive(Debug, Clone, Serialize, Deserialize)]
3239#[serde(rename_all = "camelCase")]
3240pub struct RetrievalPromotedResult {
3241 pub thread_id: ThreadId,
3242 pub turn_id: TurnId,
3243 pub states: Vec<RetrievalPromotedCapabilityState>,
3244 pub summary: RetrievalDebugSummary,
3245}
3246
3247#[derive(Debug, Clone, Serialize, Deserialize)]
3248#[serde(rename_all = "camelCase")]
3249pub struct MediaReadParams {
3250 pub artifact_id: MediaArtifactId,
3251 #[serde(default, skip_serializing_if = "Option::is_none")]
3252 pub max_bytes: Option<u64>,
3253}
3254
3255#[derive(Debug, Clone, Serialize, Deserialize)]
3256#[serde(rename_all = "camelCase")]
3257pub struct MediaReadResult {
3258 pub artifact: MediaArtifact,
3259 pub bytes_base64: String,
3260}
3261
3262#[derive(Debug, Clone, Serialize, Deserialize)]
3263#[serde(rename_all = "camelCase")]
3264pub struct MediaThumbnailParams {
3265 pub artifact_id: MediaArtifactId,
3266}
3267
3268#[derive(Debug, Clone, Serialize, Deserialize)]
3269#[serde(rename_all = "camelCase")]
3270pub struct MediaThumbnailResult {
3271 pub preview: MediaPreview,
3272}
3273
3274#[derive(Debug, Clone, Serialize, Deserialize)]
3275#[serde(rename_all = "camelCase")]
3276pub struct MediaDeleteParams {
3277 pub artifact_id: MediaArtifactId,
3278}
3279
3280#[derive(Debug, Clone, Serialize, Deserialize)]
3281#[serde(rename_all = "camelCase")]
3282pub struct MediaDeleteResult {
3283 pub deleted: bool,
3284}
3285
3286#[derive(Debug, Clone, Serialize, Deserialize)]
3287#[serde(rename_all = "camelCase")]
3288pub struct MediaAttachToTurnParams {
3289 pub artifact_id: MediaArtifactId,
3290}
3291
3292#[derive(Debug, Clone, Serialize, Deserialize)]
3293#[serde(rename_all = "camelCase")]
3294pub struct MediaAttachToTurnResult {
3295 pub attachment: MediaAttachment,
3296 pub image: Option<InputImage>,
3297}
3298
3299#[derive(Debug, Clone, Default, Serialize, Deserialize)]
3300#[serde(rename_all = "camelCase")]
3301pub struct MediaImageProvidersListParams {}
3302
3303#[derive(Debug, Clone, Serialize, Deserialize)]
3304#[serde(rename_all = "camelCase")]
3305pub struct MediaImageProvidersListResult {
3306 pub default_provider: String,
3307 pub providers: Vec<roder_api::media::MediaProviderDescriptor>,
3308}
3309
3310#[derive(Debug, Clone, Serialize, Deserialize)]
3311#[serde(rename_all = "camelCase")]
3312pub struct MediaImageGenerateParams {
3313 #[serde(flatten)]
3315 pub request: roder_api::media::MediaGenerationRequest,
3316 #[serde(default, skip_serializing_if = "Option::is_none")]
3318 pub thread_id: Option<ThreadId>,
3319}
3320
3321#[derive(Debug, Clone, Serialize, Deserialize)]
3322#[serde(rename_all = "camelCase")]
3323pub struct MediaImageGenerateResult {
3324 pub response: roder_api::media::MediaGenerationResponse,
3325}
3326
3327#[derive(Debug, Clone, Serialize, Deserialize)]
3328#[serde(rename_all = "camelCase")]
3329pub struct WorkflowScanParams {
3330 pub workspace: Option<String>,
3331 #[serde(default)]
3332 pub include_user: bool,
3333}
3334
3335#[derive(Debug, Clone, Serialize, Deserialize)]
3336#[serde(rename_all = "camelCase")]
3337pub struct WorkflowScanResult {
3338 pub scan: WorkflowImportScan,
3339}
3340
3341#[derive(Debug, Clone, Serialize, Deserialize)]
3342#[serde(rename_all = "camelCase")]
3343pub struct WorkflowPreviewParams {
3344 pub workspace: Option<String>,
3345 #[serde(default, skip_serializing_if = "Option::is_none")]
3346 pub item_id: Option<String>,
3347}
3348
3349#[derive(Debug, Clone, Serialize, Deserialize)]
3350#[serde(rename_all = "camelCase")]
3351pub struct WorkflowPreviewResult {
3352 pub items: Vec<WorkflowImportItem>,
3353}
3354
3355#[derive(Debug, Clone, Serialize, Deserialize)]
3356#[serde(rename_all = "camelCase")]
3357pub struct WorkflowEnableParams {
3358 pub workspace: Option<String>,
3359 pub item_id: String,
3360 #[serde(default)]
3361 pub approve_side_effects: bool,
3362}
3363
3364#[derive(Debug, Clone, Serialize, Deserialize)]
3365#[serde(rename_all = "camelCase")]
3366pub struct WorkflowEnableResult {
3367 pub item: WorkflowImportItem,
3368 pub decision: WorkflowImportDecision,
3369}
3370
3371#[derive(Debug, Clone, Serialize, Deserialize)]
3372#[serde(rename_all = "camelCase")]
3373pub struct WorkflowIgnoreParams {
3374 pub workspace: Option<String>,
3375 pub item_id: String,
3376}
3377
3378#[derive(Debug, Clone, Serialize, Deserialize)]
3379#[serde(rename_all = "camelCase")]
3380pub struct WorkflowIgnoreResult {
3381 pub item_id: String,
3382 pub decision: WorkflowImportDecision,
3383}
3384
3385#[derive(Debug, Clone, Serialize, Deserialize)]
3386#[serde(rename_all = "camelCase")]
3387pub struct WorkflowRefreshParams {
3388 pub workspace: Option<String>,
3389}
3390
3391#[derive(Debug, Clone, Serialize, Deserialize)]
3392#[serde(rename_all = "camelCase")]
3393pub struct WorkflowRefreshResult {
3394 pub scan: WorkflowImportScan,
3395 pub stale: Vec<WorkflowImportItem>,
3396}
3397
3398#[derive(Debug, Clone, Serialize, Deserialize)]
3399#[serde(rename_all = "camelCase")]
3400pub struct WorkflowRemoveParams {
3401 pub workspace: Option<String>,
3402 pub item_id: String,
3403}
3404
3405#[derive(Debug, Clone, Serialize, Deserialize)]
3406#[serde(rename_all = "camelCase")]
3407pub struct WorkflowRemoveResult {
3408 pub item_id: String,
3409 pub state: WorkflowImportState,
3410 pub decision: WorkflowImportDecision,
3411}
3412
3413#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3414#[serde(rename_all = "camelCase")]
3415pub struct EvalReportsListParams {
3416 pub limit: Option<usize>,
3417}
3418
3419#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
3420#[serde(rename_all = "camelCase")]
3421pub struct EvalReliabilitySummary {
3422 #[serde(default)]
3423 pub error_class_counts: BTreeMap<String, u64>,
3424 pub retry_attempts: u64,
3425 pub retry_recoveries: u64,
3426 pub failure_limit_stops: u64,
3427 pub unknown_errors: u64,
3428}
3429
3430#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3431#[serde(rename_all = "camelCase")]
3432pub struct EvalReportSummary {
3433 pub id: String,
3434 pub suite_id: String,
3435 pub fixture_count: usize,
3436 pub passed: usize,
3437 pub failed: usize,
3438 #[serde(default)]
3439 pub reliability: EvalReliabilitySummary,
3440 #[serde(with = "time::serde::rfc3339")]
3441 pub generated_at: time::OffsetDateTime,
3442}
3443
3444#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3445#[serde(rename_all = "camelCase")]
3446pub struct EvalReportsListResult {
3447 pub reports: Vec<EvalReportSummary>,
3448}
3449
3450#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3451#[serde(rename_all = "camelCase")]
3452pub struct EvalReportReadParams {
3453 pub report_id: String,
3454 pub max_bytes: Option<usize>,
3455}
3456
3457#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3458#[serde(rename_all = "camelCase")]
3459pub struct EvalReportReadResult {
3460 pub summary: EvalReportSummary,
3461 pub markdown: String,
3462 pub truncated: bool,
3463}
3464
3465#[derive(Debug, Clone, Serialize, Deserialize)]
3466#[serde(rename_all = "camelCase")]
3467pub struct MarketplacesListResult {
3468 pub marketplaces: Vec<MarketplaceDescriptor>,
3469}
3470
3471#[derive(Debug, Clone, Serialize, Deserialize)]
3472#[serde(rename_all = "camelCase")]
3473pub struct MarketplacesInstallDefaultParams {
3474 pub selection: DefaultMarketplaceSelection,
3475}
3476
3477#[derive(Debug, Clone, Serialize, Deserialize)]
3478#[serde(rename_all = "camelCase")]
3479pub struct MarketplacesInstallDefaultResult {
3480 pub marketplaces: Vec<MarketplaceDescriptor>,
3481}
3482
3483#[derive(Debug, Clone, Serialize, Deserialize)]
3484#[serde(rename_all = "camelCase")]
3485pub struct MarketplacesAddParams {
3486 pub id: String,
3487 #[serde(default, skip_serializing_if = "Option::is_none")]
3488 pub kind: Option<MarketplaceKind>,
3489 pub display_name: String,
3490 pub source: MarketplaceSource,
3491}
3492
3493#[derive(Debug, Clone, Serialize, Deserialize)]
3494#[serde(rename_all = "camelCase")]
3495pub struct MarketplacesAddResult {
3496 pub marketplace: MarketplaceDescriptor,
3497}
3498
3499#[derive(Debug, Clone, Serialize, Deserialize)]
3500#[serde(rename_all = "camelCase")]
3501pub struct MarketplacesRemoveParams {
3502 pub marketplace_id: String,
3503}
3504
3505#[derive(Debug, Clone, Serialize, Deserialize)]
3506#[serde(rename_all = "camelCase")]
3507pub struct MarketplacesRemoveResult {
3508 pub removed: bool,
3509}
3510
3511#[derive(Debug, Clone, Serialize, Deserialize)]
3512#[serde(rename_all = "camelCase")]
3513pub struct MarketplacesRefreshParams {
3514 pub marketplace_id: String,
3515}
3516
3517#[derive(Debug, Clone, Serialize, Deserialize)]
3518#[serde(rename_all = "camelCase")]
3519pub struct MarketplacesRefreshResult {
3520 pub marketplace: MarketplaceDescriptor,
3521 pub plugins: Vec<MarketplacePluginEntry>,
3522}
3523
3524#[derive(Debug, Clone, Serialize, Deserialize)]
3525#[serde(rename_all = "camelCase")]
3526pub struct MarketplacesSearchParams {
3527 #[serde(default, skip_serializing_if = "Option::is_none")]
3528 pub query: Option<String>,
3529}
3530
3531#[derive(Debug, Clone, Serialize, Deserialize)]
3532#[serde(rename_all = "camelCase")]
3533pub struct MarketplacesSearchResult {
3534 pub plugins: Vec<DedupedMarketplacePlugin>,
3535}
3536
3537#[derive(Debug, Clone, Serialize, Deserialize)]
3538#[serde(rename_all = "camelCase")]
3539pub struct MarketplacePluginParams {
3540 pub marketplace_id: String,
3541 pub plugin_id: String,
3542}
3543
3544#[derive(Debug, Clone, Serialize, Deserialize)]
3545#[serde(rename_all = "camelCase")]
3546pub struct MarketplacePluginResult {
3547 pub plugin: Option<MarketplacePluginEntry>,
3548}
3549
3550#[derive(Debug, Clone, Serialize, Deserialize)]
3551#[serde(rename_all = "camelCase")]
3552pub struct PluginPreviewInstallParams {
3553 pub marketplace_id: String,
3554 pub plugin_id: String,
3555}
3556
3557#[derive(Debug, Clone, Serialize, Deserialize)]
3558#[serde(rename_all = "camelCase")]
3559pub struct PluginPreviewInstallResult {
3560 pub preview: serde_json::Value,
3561}
3562
3563#[derive(Debug, Clone, Serialize, Deserialize)]
3564#[serde(rename_all = "camelCase")]
3565pub struct PluginInstallParams {
3566 pub marketplace_id: String,
3567 pub plugin_id: String,
3568}
3569
3570#[derive(Debug, Clone, Serialize, Deserialize)]
3571#[serde(rename_all = "camelCase")]
3572pub struct PluginInstallResult {
3573 pub plugin: InstalledPluginRecord,
3574}
3575
3576#[derive(Debug, Clone, Serialize, Deserialize)]
3577#[serde(rename_all = "camelCase")]
3578pub struct PluginInstallAllVariantsParams {
3579 pub marketplace_id: String,
3580 pub plugin_id: String,
3581}
3582
3583#[derive(Debug, Clone, Serialize, Deserialize)]
3584#[serde(rename_all = "camelCase")]
3585pub struct PluginInstallAllVariantsResult {
3586 pub plugins: Vec<InstalledPluginRecord>,
3587}
3588
3589#[derive(Debug, Clone, Serialize, Deserialize)]
3590#[serde(rename_all = "camelCase")]
3591pub struct PluginListInstalledResult {
3592 pub plugins: Vec<InstalledPluginRecord>,
3593}
3594
3595#[derive(Debug, Clone, Serialize, Deserialize)]
3596#[serde(rename_all = "camelCase")]
3597pub struct PluginDisableParams {
3598 pub variant_key: String,
3599}
3600
3601#[derive(Debug, Clone, Serialize, Deserialize)]
3602#[serde(rename_all = "camelCase")]
3603pub struct PluginDisableResult {
3604 pub plugin: Option<InstalledPluginRecord>,
3605}
3606
3607#[derive(Debug, Clone, Serialize, Deserialize)]
3608#[serde(rename_all = "camelCase")]
3609pub struct PluginUninstallParams {
3610 pub variant_key: String,
3611}
3612
3613#[derive(Debug, Clone, Serialize, Deserialize)]
3614#[serde(rename_all = "camelCase")]
3615pub struct PluginUninstallResult {
3616 pub removed: bool,
3617}
3618
3619#[derive(Debug, Clone, Serialize, Deserialize)]
3622#[serde(rename_all = "camelCase")]
3623pub struct PackageResourceDescriptor {
3624 #[serde(flatten)]
3625 pub resource: PackageResource,
3626 pub id: String,
3627}
3628
3629impl From<PackageResource> for PackageResourceDescriptor {
3630 fn from(resource: PackageResource) -> Self {
3631 let id = resource.id();
3632 Self { resource, id }
3633 }
3634}
3635
3636#[derive(Debug, Clone, Serialize, Deserialize)]
3638#[serde(rename_all = "camelCase")]
3639pub struct PackageDescriptor {
3640 #[serde(flatten)]
3641 pub record: PackageRecord,
3642 pub shadowed_by_project: bool,
3643 pub resources: Vec<PackageResourceDescriptor>,
3644}
3645
3646#[derive(Debug, Clone, Serialize, Deserialize)]
3647#[serde(rename_all = "camelCase")]
3648pub struct PackagesListResult {
3649 pub packages: Vec<PackageDescriptor>,
3650 pub diagnostics: Vec<String>,
3651}
3652
3653#[derive(Debug, Clone, Serialize, Deserialize)]
3654#[serde(rename_all = "camelCase")]
3655pub struct PackagesInstallParams {
3656 pub spec: String,
3657 pub scope: PackageScope,
3658 #[serde(default, skip_serializing_if = "Option::is_none")]
3659 pub allow_scripts: Option<bool>,
3660}
3661
3662#[derive(Debug, Clone, Serialize, Deserialize)]
3663#[serde(rename_all = "camelCase")]
3664pub struct PackagesInstallResult {
3665 pub package: PackageDescriptor,
3666 pub diagnostics: Vec<String>,
3667}
3668
3669#[derive(Debug, Clone, Serialize, Deserialize)]
3670#[serde(rename_all = "camelCase")]
3671pub struct PackagesRemoveParams {
3672 pub spec_or_id: String,
3673 #[serde(default, skip_serializing_if = "Option::is_none")]
3674 pub scope: Option<PackageScope>,
3675}
3676
3677#[derive(Debug, Clone, Serialize, Deserialize)]
3678#[serde(rename_all = "camelCase")]
3679pub struct PackagesRemoveResult {
3680 pub removed: PackageRecord,
3681}
3682
3683#[derive(Debug, Clone, Serialize, Deserialize)]
3684#[serde(rename_all = "camelCase")]
3685pub struct PackagesUpdateParams {
3686 #[serde(default, skip_serializing_if = "Option::is_none")]
3687 pub target: Option<String>,
3688}
3689
3690#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
3691#[serde(rename_all = "camelCase")]
3692pub enum PackageUpdateStatus {
3693 Updated,
3694 SkippedPinned,
3695 Failed,
3696}
3697
3698#[derive(Debug, Clone, Serialize, Deserialize)]
3699#[serde(rename_all = "camelCase")]
3700pub struct PackageUpdateOutcome {
3701 pub package_id: String,
3702 pub identity: String,
3703 pub scope: PackageScope,
3704 pub status: PackageUpdateStatus,
3705 #[serde(default, skip_serializing_if = "Option::is_none")]
3706 pub resolved: Option<String>,
3707 #[serde(default, skip_serializing_if = "Option::is_none")]
3708 pub message: Option<String>,
3709}
3710
3711#[derive(Debug, Clone, Serialize, Deserialize)]
3712#[serde(rename_all = "camelCase")]
3713pub struct PackagesUpdateResult {
3714 pub outcomes: Vec<PackageUpdateOutcome>,
3715}
3716
3717#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
3718#[serde(rename_all = "camelCase")]
3719pub enum PackageSyncStatus {
3720 Materialized,
3721 AlreadyPresent,
3722 Failed,
3723}
3724
3725#[derive(Debug, Clone, Serialize, Deserialize)]
3726#[serde(rename_all = "camelCase")]
3727pub struct PackageSyncOutcome {
3728 pub package_id: String,
3729 pub identity: String,
3730 pub status: PackageSyncStatus,
3731 #[serde(default, skip_serializing_if = "Option::is_none")]
3732 pub resolved: Option<String>,
3733 #[serde(default, skip_serializing_if = "Option::is_none")]
3734 pub message: Option<String>,
3735}
3736
3737#[derive(Debug, Clone, Serialize, Deserialize)]
3738#[serde(rename_all = "camelCase")]
3739pub struct PackagesSyncResult {
3740 pub outcomes: Vec<PackageSyncOutcome>,
3741}
3742
3743#[derive(Debug, Clone, Serialize, Deserialize)]
3744#[serde(rename_all = "camelCase")]
3745pub struct PackagesSetEnabledParams {
3746 pub id: String,
3748 pub enabled: bool,
3749}
3750
3751#[derive(Debug, Clone, Serialize, Deserialize)]
3752#[serde(rename_all = "camelCase")]
3753pub struct PackagesSetEnabledResult {
3754 pub package: PackageDescriptor,
3755}
3756
3757#[derive(Debug, Clone, Serialize, Deserialize)]
3758#[serde(rename_all = "camelCase")]
3759pub struct PackagesApproveExtensionsParams {
3760 pub package_id: String,
3761 pub approved: bool,
3762}
3763
3764#[derive(Debug, Clone, Serialize, Deserialize)]
3765#[serde(rename_all = "camelCase")]
3766pub struct PackagesApproveExtensionsResult {
3767 pub package: PackageDescriptor,
3768}
3769
3770#[derive(Debug, Clone, Serialize, Deserialize)]
3771#[serde(rename_all = "camelCase")]
3772pub struct PackagesSetFiltersParams {
3773 pub package_id: String,
3774 pub filters: PackageResourceFilters,
3775}
3776
3777#[derive(Debug, Clone, Serialize, Deserialize)]
3778#[serde(rename_all = "camelCase")]
3779pub struct PackagesSetFiltersResult {
3780 pub package: PackageDescriptor,
3781}
3782
3783#[derive(Debug, Clone, Serialize, Deserialize)]
3784pub struct ProviderSelectParams {
3785 pub provider: String,
3786 pub model: Option<String>,
3787 pub reasoning: Option<String>,
3788 #[serde(default, skip_serializing_if = "Option::is_none")]
3789 pub thread_id: Option<ThreadId>,
3790}
3791
3792#[derive(Debug, Clone, Serialize, Deserialize)]
3793#[serde(rename_all = "camelCase")]
3794pub struct ProviderSelectResult {
3795 pub provider: String,
3796 pub model: String,
3797 pub reasoning: String,
3798 #[serde(default, skip_serializing_if = "Option::is_none")]
3799 pub model_profile: Option<String>,
3800 #[serde(default, skip_serializing_if = "Option::is_none")]
3801 pub model_switch_summary: Option<String>,
3802}
3803
3804#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3805#[serde(tag = "type", rename_all = "camelCase")]
3806pub enum ModelSelectChoice {
3807 Manual {
3808 provider: String,
3809 #[serde(default, skip_serializing_if = "Option::is_none")]
3810 model: Option<String>,
3811 #[serde(default, skip_serializing_if = "Option::is_none")]
3812 reasoning: Option<String>,
3813 },
3814 Auto {
3815 option_id: String,
3816 },
3817}
3818
3819#[derive(Debug, Clone, Serialize, Deserialize)]
3820#[serde(rename_all = "camelCase")]
3821pub struct ModelSelectParams {
3822 pub selection: ModelSelectChoice,
3823 #[serde(default, skip_serializing_if = "Option::is_none")]
3824 pub thread_id: Option<ThreadId>,
3825}
3826
3827#[derive(Debug, Clone, Serialize, Deserialize)]
3828#[serde(rename_all = "camelCase")]
3829pub struct ModelSelectResult {
3830 pub selection_mode: ModelSelectionMode,
3831 pub provider: String,
3832 pub model: String,
3833 pub reasoning: String,
3834 #[serde(default, skip_serializing_if = "Option::is_none")]
3835 pub model_profile: Option<String>,
3836 #[serde(default, skip_serializing_if = "Option::is_none")]
3837 pub model_switch_summary: Option<String>,
3838}
3839
3840#[derive(Debug, Clone, Serialize, Deserialize)]
3841pub struct SettingsGetResult {
3842 pub web_search: WebSearchSettings,
3843 pub search_index: SearchIndexSettings,
3844 pub shell: ShellSettings,
3845 pub default_provider: String,
3846 pub default_model: String,
3847 pub default_reasoning: String,
3848 pub default_mode: PolicyMode,
3849 pub file_backed_dynamic_context: bool,
3850}
3851
3852#[derive(Debug, Clone, Serialize, Deserialize)]
3853pub struct SettingsSetWebSearchParams {
3854 pub mode: HostedWebSearchMode,
3855}
3856
3857#[derive(Debug, Clone, Serialize, Deserialize)]
3858pub struct SettingsSetWebSearchResult {
3859 pub web_search: WebSearchSettings,
3860}
3861
3862#[derive(Debug, Clone, Serialize, Deserialize)]
3863pub struct SettingsSetSearchIndexParams {
3864 pub enabled: bool,
3865}
3866
3867#[derive(Debug, Clone, Serialize, Deserialize)]
3868pub struct SettingsSetSearchIndexResult {
3869 pub search_index: SearchIndexSettings,
3870}
3871
3872#[derive(Debug, Clone, Serialize, Deserialize)]
3873pub struct SettingsSetShellParams {
3874 pub shell: String,
3875}
3876
3877#[derive(Debug, Clone, Serialize, Deserialize)]
3878pub struct SettingsSetShellResult {
3879 pub shell: ShellSettings,
3880}
3881
3882#[derive(Debug, Clone, Serialize, Deserialize)]
3883pub struct SettingsSetDefaultModeParams {
3884 pub mode: PolicyMode,
3885}
3886
3887#[derive(Debug, Clone, Serialize, Deserialize)]
3888pub struct SettingsSetDefaultModeResult {
3889 pub default_mode: PolicyMode,
3890}
3891
3892#[derive(Debug, Clone, Serialize, Deserialize)]
3893pub struct SettingsSetFileBackedDynamicContextParams {
3894 pub enabled: bool,
3895}
3896
3897#[derive(Debug, Clone, Serialize, Deserialize)]
3898pub struct SettingsSetFileBackedDynamicContextResult {
3899 pub enabled: bool,
3900}
3901
3902#[derive(Debug, Clone, Serialize, Deserialize)]
3903pub struct ProviderAuthResult {
3904 pub signed_in: bool,
3905 pub account_id: Option<String>,
3906}
3907
3908#[derive(Debug, Clone, Serialize, Deserialize)]
3909#[serde(rename_all = "camelCase")]
3910pub struct ThreadStateResult {
3911 pub mode: PolicyMode,
3912 pub pending_plan_exit: Option<PendingPlanExitDescriptor>,
3913}
3914
3915#[derive(Debug, Clone, Serialize, Deserialize)]
3916#[serde(rename_all = "camelCase")]
3917pub struct PendingPlanExitDescriptor {
3918 pub thread_id: ThreadId,
3919 pub turn_id: TurnId,
3920 pub request_id: String,
3921 pub target_mode: PolicyMode,
3922 pub plan_summary: Option<String>,
3923 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3924 pub next_steps: Vec<String>,
3925 pub requested_at: OffsetDateTime,
3926 pub expires_at: Option<OffsetDateTime>,
3927}
3928
3929#[derive(Debug, Clone, Serialize, Deserialize)]
3930#[serde(rename_all = "camelCase")]
3931pub struct ThreadSetModeParams {
3932 pub mode: PolicyMode,
3933 pub reason: Option<String>,
3934}
3935
3936#[derive(Debug, Clone, Serialize, Deserialize)]
3937#[serde(rename_all = "camelCase")]
3938pub struct ThreadSetModeResult {
3939 pub mode: PolicyMode,
3940}
3941
3942#[derive(Debug, Clone, Serialize, Deserialize)]
3943#[serde(rename_all = "camelCase")]
3944pub struct ThreadExitPlanParams {
3945 pub request_id: String,
3946 pub approved: bool,
3947}
3948
3949#[derive(Debug, Clone, Serialize, Deserialize)]
3950#[serde(rename_all = "camelCase")]
3951pub struct ThreadExitPlanResult {
3952 pub resolved: bool,
3953 pub mode: PolicyMode,
3954}
3955
3956#[derive(Debug, Clone, Serialize, Deserialize)]
3957#[serde(rename_all = "camelCase")]
3958pub struct ThreadResolveApprovalParams {
3959 pub approval_id: String,
3960 pub approved: bool,
3961}
3962
3963#[derive(Debug, Clone, Serialize, Deserialize)]
3964#[serde(rename_all = "camelCase")]
3965pub struct ThreadResolveApprovalResult {
3966 pub resolved: bool,
3967}
3968
3969#[derive(Debug, Clone, Serialize, Deserialize)]
3971#[serde(rename_all = "camelCase")]
3972pub struct ToolsResolveParams {
3973 pub request_id: String,
3974 pub output: String,
3975 #[serde(default)]
3976 pub is_error: bool,
3977}
3978
3979#[derive(Debug, Clone, Serialize, Deserialize)]
3980#[serde(rename_all = "camelCase")]
3981pub struct ToolsResolveResult {
3982 pub resolved: bool,
3983}
3984
3985#[derive(Debug, Clone, Serialize, Deserialize)]
3986#[serde(rename_all = "camelCase")]
3987pub struct ThreadResolveUserInputParams {
3988 pub request_id: String,
3989 pub answers: serde_json::Value,
3990}
3991
3992#[derive(Debug, Clone, Serialize, Deserialize)]
3993#[serde(rename_all = "camelCase")]
3994pub struct ThreadResolveUserInputResult {
3995 pub resolved: bool,
3996}
3997
3998#[derive(Debug, Clone, Serialize, Deserialize)]
3999pub struct CommandDescriptor {
4000 pub name: String,
4001 pub description: Option<String>,
4002 pub argument_hint: Option<String>,
4003 pub source: String,
4004 pub model: Option<String>,
4005 pub agent: Option<String>,
4006 pub has_shell_includes: bool,
4007 pub has_url_includes: bool,
4008}
4009
4010#[derive(Debug, Clone, Serialize, Deserialize)]
4011pub struct CommandsListResult {
4012 pub commands: Vec<CommandDescriptor>,
4013}
4014
4015#[derive(Debug, Clone, Serialize, Deserialize)]
4016pub struct CommandsExpandParams {
4017 pub name: String,
4018 #[serde(default)]
4019 pub arguments: String,
4020 pub workspace: Option<String>,
4021}
4022
4023#[derive(Debug, Clone, Serialize, Deserialize)]
4024pub struct CommandsExpandResult {
4025 pub command: CommandDescriptor,
4026 pub message: String,
4027 pub context_blocks: Vec<ContextBlock>,
4028 pub allowed_tools: Vec<String>,
4029 pub model: Option<String>,
4030 pub agent: Option<String>,
4031}
4032
4033#[derive(Debug, Clone, Serialize, Deserialize)]
4034pub struct CommandsRunParams {
4035 pub thread_id: ThreadId,
4036 pub name: String,
4037 #[serde(default)]
4038 pub arguments: String,
4039 pub workspace: Option<String>,
4040}
4041
4042#[derive(Debug, Clone, Serialize, Deserialize)]
4043pub struct CommandsRunResult {
4044 pub turn_id: TurnId,
4045 pub expanded: CommandsExpandResult,
4046}
4047
4048#[derive(Debug, Clone, Default, Serialize, Deserialize)]
4049#[serde(rename_all = "camelCase")]
4050pub struct SkillsListParams {
4051 #[serde(default, skip_serializing_if = "Option::is_none")]
4052 pub workspace_id: Option<String>,
4053 #[serde(default, skip_serializing_if = "Option::is_none")]
4054 pub root_id: Option<String>,
4055 #[serde(default, skip_serializing_if = "Option::is_none")]
4056 pub cwd: Option<String>,
4057}
4058
4059#[derive(Debug, Clone, Serialize, Deserialize)]
4060#[serde(rename_all = "camelCase")]
4061pub struct SkillsListResult {
4062 pub skills: Vec<SkillDescriptor>,
4063 #[serde(default)]
4064 pub diagnostics: Vec<String>,
4065}
4066
4067#[derive(Debug, Clone, Serialize, Deserialize)]
4068#[serde(rename_all = "camelCase")]
4069pub struct SkillsReadParams {
4070 pub selector: SkillSelector,
4071}
4072
4073#[derive(Debug, Clone, Serialize, Deserialize)]
4074#[serde(rename_all = "camelCase")]
4075pub struct SkillsReadResult {
4076 pub skill: Option<Skill>,
4077}
4078
4079#[derive(Debug, Clone, Serialize, Deserialize)]
4080#[serde(rename_all = "camelCase")]
4081pub struct SkillsSetEnabledParams {
4082 pub selector: SkillSelector,
4083 pub enabled: bool,
4084}
4085
4086#[derive(Debug, Clone, Serialize, Deserialize)]
4087#[serde(rename_all = "camelCase")]
4088pub struct SkillsSetExposureParams {
4089 pub selector: SkillSelector,
4090 pub exposure: SkillExposure,
4091}
4092
4093#[derive(Debug, Clone, Serialize, Deserialize)]
4094#[serde(rename_all = "camelCase")]
4095pub struct SkillsUpdateResult {
4096 pub skills: Vec<SkillDescriptor>,
4097 #[serde(default)]
4098 pub diagnostics: Vec<String>,
4099}
4100
4101#[derive(Debug, Clone, Default, Serialize, Deserialize)]
4102#[serde(rename_all = "camelCase")]
4103pub struct AutomationsListParams {
4104 #[serde(default, skip_serializing_if = "Option::is_none")]
4105 pub project_cwd: Option<String>,
4106 #[serde(default, skip_serializing_if = "Option::is_none")]
4107 pub include_disabled: Option<bool>,
4108}
4109
4110#[derive(Debug, Clone, Serialize, Deserialize)]
4111#[serde(rename_all = "camelCase")]
4112pub struct AutomationsListResult {
4113 pub automations: Vec<AutomationDefinition>,
4114}
4115
4116#[derive(Debug, Clone, Serialize, Deserialize)]
4117#[serde(rename_all = "camelCase")]
4118pub struct AutomationsCreateParams {
4119 pub name: String,
4120 pub project: AutomationProject,
4121 pub schedule: AutomationSchedule,
4122 pub prompt: String,
4123 #[serde(default = "default_true_bool")]
4124 pub enabled: bool,
4125 #[serde(default, skip_serializing_if = "Option::is_none")]
4126 pub model_provider: Option<String>,
4127 #[serde(default, skip_serializing_if = "Option::is_none")]
4128 pub model: Option<String>,
4129 #[serde(default, skip_serializing_if = "Option::is_none")]
4130 pub policy_mode: Option<roder_api::policy_mode::PolicyMode>,
4131 pub catch_up: CatchUpPolicy,
4132 pub concurrency: AutomationConcurrencyPolicy,
4133}
4134
4135fn default_true_bool() -> bool {
4136 true
4137}
4138
4139#[derive(Debug, Clone, Serialize, Deserialize)]
4140#[serde(rename_all = "camelCase")]
4141pub struct AutomationsCreateResult {
4142 pub automation: AutomationDefinition,
4143}
4144
4145#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4146#[serde(rename_all = "camelCase")]
4147pub struct AutomationsUpdatePatch {
4148 #[serde(default, skip_serializing_if = "Option::is_none")]
4149 pub name: Option<String>,
4150 #[serde(default, skip_serializing_if = "Option::is_none")]
4151 pub project: Option<AutomationProject>,
4152 #[serde(default, skip_serializing_if = "Option::is_none")]
4153 pub schedule: Option<AutomationSchedule>,
4154 #[serde(default, skip_serializing_if = "Option::is_none")]
4155 pub prompt: Option<String>,
4156 #[serde(default, skip_serializing_if = "Option::is_none")]
4157 pub enabled: Option<bool>,
4158 #[serde(default, skip_serializing_if = "Option::is_none")]
4159 pub model_provider: Option<String>,
4160 #[serde(default, skip_serializing_if = "Option::is_none")]
4161 pub model: Option<String>,
4162 #[serde(default, skip_serializing_if = "Option::is_none")]
4163 pub policy_mode: Option<roder_api::policy_mode::PolicyMode>,
4164 #[serde(default, skip_serializing_if = "Option::is_none")]
4165 pub catch_up: Option<CatchUpPolicy>,
4166 #[serde(default, skip_serializing_if = "Option::is_none")]
4167 pub concurrency: Option<AutomationConcurrencyPolicy>,
4168}
4169
4170#[derive(Debug, Clone, Serialize, Deserialize)]
4171#[serde(rename_all = "camelCase")]
4172pub struct AutomationsUpdateParams {
4173 pub automation_id: AutomationId,
4174 pub patch: AutomationsUpdatePatch,
4175}
4176
4177#[derive(Debug, Clone, Serialize, Deserialize)]
4178#[serde(rename_all = "camelCase")]
4179pub struct AutomationsUpdateResult {
4180 pub automation: AutomationDefinition,
4181}
4182
4183#[derive(Debug, Clone, Serialize, Deserialize)]
4184#[serde(rename_all = "camelCase")]
4185pub struct AutomationsDeleteParams {
4186 pub automation_id: AutomationId,
4187}
4188
4189#[derive(Debug, Clone, Serialize, Deserialize)]
4190#[serde(rename_all = "camelCase")]
4191pub struct AutomationsDeleteResult {
4192 pub automation_id: AutomationId,
4193 pub deleted: bool,
4194}
4195
4196#[derive(Debug, Clone, Serialize, Deserialize)]
4197#[serde(rename_all = "camelCase")]
4198pub struct AutomationsRunNowParams {
4199 pub automation_id: AutomationId,
4200 #[serde(default, skip_serializing_if = "Option::is_none")]
4201 pub prompt_override: Option<String>,
4202}
4203
4204#[derive(Debug, Clone, Serialize, Deserialize)]
4205#[serde(rename_all = "camelCase")]
4206pub struct AutomationsRunNowResult {
4207 pub run: AutomationRunSummary,
4208}
4209
4210#[derive(Debug, Clone, Serialize, Deserialize)]
4211#[serde(rename_all = "camelCase")]
4212pub struct AutomationsRunsParams {
4213 pub automation_id: AutomationId,
4214 #[serde(default, skip_serializing_if = "Option::is_none")]
4215 pub state: Option<AutomationRunState>,
4216 #[serde(default, skip_serializing_if = "Option::is_none")]
4217 pub limit: Option<usize>,
4218}
4219
4220#[derive(Debug, Clone, Serialize, Deserialize)]
4221#[serde(rename_all = "camelCase")]
4222pub struct AutomationsRunsResult {
4223 pub runs: Vec<AutomationRunSummary>,
4224 #[serde(default, skip_serializing_if = "Option::is_none")]
4225 pub next_cursor: Option<String>,
4226}
4227
4228#[derive(Debug, Clone, Serialize, Deserialize)]
4229#[serde(rename_all = "camelCase")]
4230pub struct AutomationsCancelRunParams {
4231 pub run_id: AutomationRunId,
4232 #[serde(default, skip_serializing_if = "Option::is_none")]
4233 pub reason: Option<String>,
4234}
4235
4236#[derive(Debug, Clone, Serialize, Deserialize)]
4237#[serde(rename_all = "camelCase")]
4238pub struct AutomationsCancelRunResult {
4239 pub run_id: AutomationRunId,
4240 pub cancelled: bool,
4241}
4242
4243#[derive(Debug, Clone, Serialize, Deserialize)]
4244#[serde(rename_all = "camelCase")]
4245pub struct AutomationsStatusResult {
4246 pub scheduler_enabled: bool,
4247 pub read_api_enabled: bool,
4248 pub server_id: String,
4249 pub server_role: String,
4250 pub store_path: String,
4251 #[serde(default, skip_serializing_if = "Option::is_none")]
4252 pub last_tick_at: Option<OffsetDateTime>,
4253 #[serde(default, skip_serializing_if = "Option::is_none")]
4254 pub next_tick_at: Option<OffsetDateTime>,
4255 #[serde(default)]
4256 pub active_runs: usize,
4257 #[serde(default)]
4258 pub due_count: usize,
4259 #[serde(default)]
4260 pub leased_count: usize,
4261}
4262
4263#[derive(Debug, Clone, Serialize, Deserialize)]
4264pub struct ToolsListResult {
4265 pub tools: Vec<ToolSpec>,
4266}
4267
4268#[derive(Debug, Clone, Serialize, Deserialize)]
4269pub struct ToolCallParams {
4270 pub thread_id: ThreadId,
4271 pub tool_name: String,
4272 pub arguments: serde_json::Value,
4273}
4274
4275#[derive(Debug, Clone, Serialize, Deserialize)]
4276pub struct ToolCallResult {
4277 pub text: String,
4278 pub data: serde_json::Value,
4279 pub is_error: bool,
4280}
4281
4282#[derive(Debug, Clone, Serialize, Deserialize)]
4283pub struct AgentsListResult {
4284 pub agents: Vec<AgentDescriptor>,
4285}
4286
4287#[derive(Debug, Clone, Serialize, Deserialize)]
4288pub struct TasksSubmitParams {
4289 pub executor_id: String,
4290 #[serde(default)]
4291 pub input: serde_json::Value,
4292 pub thread_id: Option<ThreadId>,
4293 pub turn_id: Option<TurnId>,
4294 pub workspace: Option<String>,
4295}
4296
4297#[derive(Debug, Clone, Serialize, Deserialize)]
4298pub struct TasksSubmitResult {
4299 pub task: TaskHandle,
4300}
4301
4302#[derive(Debug, Clone, Serialize, Deserialize)]
4303pub struct TasksListResult {
4304 pub tasks: Vec<TaskHandle>,
4305}
4306
4307#[derive(Debug, Clone, Serialize, Deserialize)]
4308pub struct TasksGetParams {
4309 pub task_id: String,
4310}
4311
4312#[derive(Debug, Clone, Serialize, Deserialize)]
4313pub struct TaskLogDescriptor {
4314 pub stream: TaskOutputStream,
4315 pub chunk: String,
4316 pub timestamp: OffsetDateTime,
4317}
4318
4319#[derive(Debug, Clone, Serialize, Deserialize)]
4320pub struct TasksGetResult {
4321 pub task: TaskHandle,
4322 pub logs: Vec<TaskLogDescriptor>,
4323 pub dropped_bytes: u64,
4324}
4325
4326#[derive(Debug, Clone, Serialize, Deserialize)]
4327pub struct TasksCancelParams {
4328 pub task_id: String,
4329 pub reason: Option<String>,
4330}
4331
4332#[derive(Debug, Clone, Serialize, Deserialize)]
4333pub struct TasksCancelResult {
4334 pub cancelled: bool,
4335}
4336
4337#[derive(Debug, Clone, Serialize, Deserialize)]
4338pub struct TasksSubscribeResult {
4339 pub subscribed: bool,
4340 pub event_kinds: Vec<String>,
4341}
4342
4343#[derive(Debug, Clone, Serialize, Deserialize)]
4344#[serde(rename_all = "camelCase")]
4345pub struct WebwrightPrepareParams {
4346 pub task: String,
4347 #[serde(default)]
4348 pub mode: Option<String>,
4349 #[serde(default)]
4350 pub start_url: Option<String>,
4351 #[serde(default)]
4352 pub task_id: Option<String>,
4353 #[serde(default)]
4354 pub browser: Option<String>,
4355 #[serde(default)]
4356 pub headless: Option<bool>,
4357 #[serde(default)]
4358 pub output_dir: Option<String>,
4359 #[serde(default)]
4360 pub workspace: Option<String>,
4361}
4362
4363#[derive(Debug, Clone, Serialize, Deserialize)]
4364#[serde(rename_all = "camelCase")]
4365pub struct WebwrightWorkspaceParams {
4366 pub workspace: String,
4367 #[serde(default)]
4368 pub workspace_root: Option<String>,
4369}
4370
4371#[derive(Debug, Clone, Serialize, Deserialize)]
4372#[serde(rename_all = "camelCase")]
4373pub struct WebwrightSubmitParams {
4374 pub task: String,
4375 #[serde(default)]
4376 pub mode: Option<String>,
4377 #[serde(default)]
4378 pub start_url: Option<String>,
4379 #[serde(default)]
4380 pub task_id: Option<String>,
4381 #[serde(default)]
4382 pub browser: Option<String>,
4383 #[serde(default)]
4384 pub headless: Option<bool>,
4385 #[serde(default)]
4386 pub output_dir: Option<String>,
4387 #[serde(default)]
4388 pub timeout_seconds: Option<u64>,
4389 #[serde(default)]
4390 pub thread_id: Option<ThreadId>,
4391 #[serde(default)]
4392 pub turn_id: Option<TurnId>,
4393 #[serde(default)]
4394 pub workspace: Option<String>,
4395}
4396
4397#[derive(Debug, Clone, Serialize, Deserialize)]
4398#[serde(rename_all = "camelCase")]
4399pub struct WebwrightSetupParams {
4400 #[serde(default)]
4401 pub python: Option<String>,
4402 #[serde(default)]
4403 pub browser: Option<String>,
4404 #[serde(default)]
4405 pub dry_run: bool,
4406}
4407
4408#[derive(Debug, Clone, Serialize, Deserialize)]
4409#[serde(rename_all = "camelCase")]
4410pub struct WebwrightRerunParams {
4411 pub workspace: String,
4412 #[serde(default)]
4413 pub workspace_root: Option<String>,
4414 #[serde(default)]
4415 pub python: Option<String>,
4416 #[serde(default)]
4417 pub thread_id: Option<ThreadId>,
4418 #[serde(default)]
4419 pub turn_id: Option<TurnId>,
4420}
4421
4422#[derive(Debug, Clone, Serialize, Deserialize)]
4423#[serde(rename_all = "camelCase")]
4424pub struct WebwrightExportParams {
4425 pub workspace: String,
4426 #[serde(default)]
4427 pub workspace_root: Option<String>,
4428 pub output_dir: String,
4429}
4430
4431#[derive(Debug, Clone, Serialize, Deserialize)]
4432#[serde(rename_all = "camelCase")]
4433pub struct WebwrightVisualJudgeParams {
4434 pub workspace: String,
4435 #[serde(default)]
4436 pub workspace_root: Option<String>,
4437 #[serde(default)]
4438 pub run_id: Option<u32>,
4439 #[serde(default)]
4440 pub enabled: Option<bool>,
4441}
4442
4443#[derive(Debug, Clone, Serialize, Deserialize)]
4444#[serde(rename_all = "camelCase")]
4445pub struct WebwrightPrepareResult {
4446 pub task_id: String,
4447 pub workspace: serde_json::Value,
4448}
4449
4450#[derive(Debug, Clone, Serialize, Deserialize)]
4451#[serde(rename_all = "camelCase")]
4452pub struct WebwrightArtifactsResult {
4453 pub workspace: serde_json::Value,
4454}
4455
4456#[derive(Debug, Clone, Serialize, Deserialize)]
4457#[serde(rename_all = "camelCase")]
4458pub struct WebwrightLatestRunResult {
4459 pub latest_run: Option<u32>,
4460 pub run: Option<serde_json::Value>,
4461}
4462
4463#[derive(Debug, Clone, Serialize, Deserialize)]
4464#[serde(rename_all = "camelCase")]
4465pub struct WebwrightReportResult {
4466 pub task_definition: Option<serde_json::Value>,
4467 pub report: Option<serde_json::Value>,
4468 pub rendered_text: Option<String>,
4469}
4470
4471#[derive(Debug, Clone, Serialize, Deserialize)]
4472#[serde(rename_all = "camelCase")]
4473pub struct WebwrightVerifyResult {
4474 pub verification: serde_json::Value,
4475}
4476
4477#[derive(Debug, Clone, Serialize, Deserialize)]
4478#[serde(rename_all = "camelCase")]
4479pub struct WebwrightSubmitResult {
4480 pub task: TaskHandle,
4481}
4482
4483#[derive(Debug, Clone, Serialize, Deserialize)]
4484#[serde(rename_all = "camelCase")]
4485pub struct WebwrightSetupStepResult {
4486 pub label: String,
4487 pub command: Vec<String>,
4488 pub status: String,
4489 pub stdout_tail: String,
4490 pub stderr_tail: String,
4491}
4492
4493#[derive(Debug, Clone, Serialize, Deserialize)]
4494#[serde(rename_all = "camelCase")]
4495pub struct WebwrightSetupResult {
4496 pub roder_home: String,
4497 pub runtime_dir: String,
4498 pub python: String,
4499 pub browser: String,
4500 pub dry_run: bool,
4501 pub installed: bool,
4502 pub steps: Vec<WebwrightSetupStepResult>,
4503 pub message: String,
4504}
4505
4506#[derive(Debug, Clone, Serialize, Deserialize)]
4507#[serde(rename_all = "camelCase")]
4508pub struct WebwrightRerunResult {
4509 pub task: TaskHandle,
4510 pub run_id: u32,
4511 pub run_dir: String,
4512}
4513
4514#[derive(Debug, Clone, Serialize, Deserialize)]
4515#[serde(rename_all = "camelCase")]
4516pub struct WebwrightExportResult {
4517 pub export_dir: String,
4518 pub files: Vec<String>,
4519 pub excluded: Vec<String>,
4520}
4521
4522#[derive(Debug, Clone, Serialize, Deserialize)]
4523#[serde(rename_all = "camelCase")]
4524pub struct WebwrightVisualJudgeResult {
4525 pub visual_judge: serde_json::Value,
4526}
4527
4528#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4529#[serde(rename_all = "camelCase")]
4530pub struct ProcessesListParams {
4531 #[serde(default)]
4532 pub include_completed: bool,
4533}
4534
4535#[derive(Debug, Clone, Serialize, Deserialize)]
4536#[serde(rename_all = "camelCase")]
4537pub struct ProcessesListResult {
4538 pub processes: Vec<ProcessDescriptor>,
4539}
4540
4541#[derive(Debug, Clone, Serialize, Deserialize)]
4542#[serde(rename_all = "camelCase")]
4543pub struct ProcessesGetParams {
4544 pub process_id: ProcessId,
4545 #[serde(default, skip_serializing_if = "Option::is_none")]
4546 pub output_bytes: Option<usize>,
4547}
4548
4549#[derive(Debug, Clone, Serialize, Deserialize)]
4550#[serde(rename_all = "camelCase")]
4551pub struct ProcessesGetResult {
4552 #[serde(default, skip_serializing_if = "Option::is_none")]
4553 pub process: Option<ProcessDescriptor>,
4554 #[serde(default)]
4555 pub output: Vec<ProcessOutput>,
4556}
4557
4558#[derive(Debug, Clone, Serialize, Deserialize)]
4559#[serde(rename_all = "camelCase")]
4560pub struct ProcessesStopParams {
4561 pub process_id: ProcessId,
4562 #[serde(default, skip_serializing_if = "Option::is_none")]
4563 pub reason: Option<String>,
4564}
4565
4566#[derive(Debug, Clone, Serialize, Deserialize)]
4567#[serde(rename_all = "camelCase")]
4568pub struct ProcessesStopResult {
4569 pub result: ProcessStopResult,
4570}
4571
4572#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4573#[serde(rename_all = "camelCase")]
4574pub struct ProcessesStopAllParams {
4575 #[serde(default, skip_serializing_if = "Option::is_none")]
4576 pub reason: Option<String>,
4577}
4578
4579#[derive(Debug, Clone, Serialize, Deserialize)]
4580#[serde(rename_all = "camelCase")]
4581pub struct ProcessesStopAllResult {
4582 pub results: Vec<ProcessStopResult>,
4583}
4584
4585#[derive(Debug, Clone, Serialize, Deserialize)]
4586#[serde(rename_all = "camelCase")]
4587pub struct ProcessesSubscribeResult {
4588 pub subscribed: bool,
4589 pub event_kinds: Vec<String>,
4590}
4591
4592#[derive(Debug, Clone, Serialize, Deserialize)]
4593pub struct AgentDescriptor {
4594 pub agent_type: String,
4595 pub description: String,
4596 pub tools: Vec<String>,
4597 pub model: Option<String>,
4598 pub permission_mode: SubagentPermissionMode,
4599 pub max_turns: Option<u32>,
4600 pub max_result_chars: Option<usize>,
4601}
4602
4603#[cfg(test)]
4604mod tests {
4605 use super::*;
4606 use time::OffsetDateTime;
4607
4608 #[test]
4609 fn protocol_turn_start_params_accept_input_shape() {
4610 let params: TurnStartParams = serde_json::from_value(serde_json::json!({
4611 "threadId": "thread-1",
4612 "input": [
4613 { "type": "text", "text": "hello" },
4614 { "type": "image", "imageUrl": "data:image/png;base64,YWJj" }
4615 ]
4616 }))
4617 .unwrap();
4618
4619 assert_eq!(params.thread_id, "thread-1");
4620 assert_eq!(params.input[0].kind, "text");
4621 assert_eq!(params.input[0].text.as_deref(), Some("hello"));
4622 assert_eq!(params.input[1].kind, "image");
4623 assert_eq!(
4624 params.input[1].image_url.as_deref(),
4625 Some("data:image/png;base64,YWJj")
4626 );
4627 assert!(!params.task_ledger_required);
4628 }
4629
4630 #[test]
4631 fn protocol_turn_start_params_accept_task_ledger_required() {
4632 let params: TurnStartParams = serde_json::from_value(serde_json::json!({
4633 "threadId": "thread-1",
4634 "taskLedgerRequired": true
4635 }))
4636 .unwrap();
4637
4638 assert!(params.task_ledger_required);
4639 }
4640
4641 #[test]
4642 fn protocol_turn_start_params_round_trip_developer_context() {
4643 let params: TurnStartParams = serde_json::from_value(serde_json::json!({
4644 "threadId": "thread-1",
4645 "developerContext": "Connected accounts: example-service."
4646 }))
4647 .unwrap();
4648 assert_eq!(
4649 params.developer_context.as_deref(),
4650 Some("Connected accounts: example-service.")
4651 );
4652
4653 let encoded = serde_json::to_value(¶ms).unwrap();
4654 assert_eq!(
4655 encoded["developerContext"],
4656 "Connected accounts: example-service."
4657 );
4658
4659 let without: TurnStartParams = serde_json::from_value(serde_json::json!({
4661 "threadId": "thread-1"
4662 }))
4663 .unwrap();
4664 assert!(without.developer_context.is_none());
4665 assert!(
4666 serde_json::to_value(&without)
4667 .unwrap()
4668 .get("developerContext")
4669 .is_none()
4670 );
4671 }
4672
4673 #[test]
4674 fn protocol_thread_start_params_round_trip_runner_selection() {
4675 let params: ThreadStartParams = serde_json::from_value(serde_json::json!({
4676 "workspaceId": "ws-1",
4677 "model": null,
4678 "modelProvider": null,
4679 "reasoning": null,
4680 "runner": {
4681 "providerId": "acme",
4682 "config": { "space_id": "space-1", "mode": "readwrite" },
4683 "workspace": "/workspace"
4684 }
4685 }))
4686 .unwrap();
4687
4688 let runner = params.runner.clone().expect("runner params");
4689 assert_eq!(runner.provider_id, "acme");
4690 assert_eq!(
4691 runner.config,
4692 Some(serde_json::json!({ "space_id": "space-1", "mode": "readwrite" }))
4693 );
4694 assert_eq!(runner.workspace, "/workspace");
4695
4696 let encoded = serde_json::to_value(¶ms).unwrap();
4697 assert_eq!(encoded["runner"]["providerId"], "acme");
4698 assert_eq!(encoded["runner"]["workspace"], "/workspace");
4699
4700 let without: ThreadStartParams = serde_json::from_value(serde_json::json!({
4702 "workspaceId": "ws-1",
4703 "model": null,
4704 "modelProvider": null,
4705 "reasoning": null
4706 }))
4707 .unwrap();
4708 assert!(without.runner.is_none());
4709 assert!(
4710 serde_json::to_value(&without)
4711 .unwrap()
4712 .get("runner")
4713 .is_none()
4714 );
4715 }
4716
4717 #[test]
4718 fn protocol_turn_start_params_accept_selected_controls() {
4719 let params: TurnStartParams = serde_json::from_value(serde_json::json!({
4720 "threadId": "thread-1",
4721 "modelProvider": "mock",
4722 "model": "gpt-5.5",
4723 "reasoning": "high",
4724 "policyMode": "plan"
4725 }))
4726 .unwrap();
4727
4728 assert_eq!(params.model_provider.as_deref(), Some("mock"));
4729 assert_eq!(params.model.as_deref(), Some("gpt-5.5"));
4730 assert_eq!(params.reasoning.as_deref(), Some("high"));
4731 assert_eq!(params.policy_mode, Some(PolicyMode::Plan));
4732 }
4733
4734 #[test]
4735 fn protocol_notifications_serialize_with_json_rpc_method_and_camel_case_params() {
4736 let notification = JsonRpcNotification {
4737 jsonrpc: "2.0".to_string(),
4738 method: "item/agentMessage/delta".to_string(),
4739 params: serde_json::to_value(ThreadItemEvent {
4740 seq: 1,
4741 event_id: "event-1".to_string(),
4742 thread_id: "thread-1".to_string(),
4743 turn_id: "turn-1".to_string(),
4744 timestamp: OffsetDateTime::UNIX_EPOCH,
4745 event: ThreadItemEventKind::ItemDelta {
4746 item_id: "turn-1-assistant".to_string(),
4747 delta: ThreadItemDelta::AgentMessageText {
4748 delta: "hello".to_string(),
4749 phase: Some("final_answer".to_string()),
4750 },
4751 },
4752 })
4753 .unwrap(),
4754 };
4755
4756 let value = serde_json::to_value(notification).unwrap();
4757 assert_eq!(value["jsonrpc"], "2.0");
4758 assert_eq!(value["method"], "item/agentMessage/delta");
4759 assert_eq!(value["params"]["seq"], 1);
4760 assert_eq!(value["params"]["eventId"], "event-1");
4761 assert_eq!(value["params"]["threadId"], "thread-1");
4762 assert_eq!(value["params"]["turnId"], "turn-1");
4763 assert_eq!(value["params"]["event"]["type"], "itemDelta");
4764 assert_eq!(value["params"]["event"]["itemId"], "turn-1-assistant");
4765 assert_eq!(
4766 value["params"]["event"]["delta"]["type"],
4767 "agentMessageText"
4768 );
4769 assert_eq!(value["params"]["event"]["delta"]["delta"], "hello");
4770 assert_eq!(value["params"]["event"]["delta"]["phase"], "final_answer");
4771 }
4772
4773 #[test]
4774 fn thread_item_reasoning_serializes_as_typed_public_item() {
4775 let value = serde_json::to_value(Item::Reasoning {
4776 id: "turn-1-agent-reasoning".to_string(),
4777 summary: vec!["Inspecting project".to_string()],
4778 content: vec!["I need to inspect files.".to_string()],
4779 status: Some(ThreadItemStatus::Completed),
4780 })
4781 .unwrap();
4782
4783 assert_eq!(
4784 value,
4785 serde_json::json!({
4786 "type": "reasoning",
4787 "id": "turn-1-agent-reasoning",
4788 "summary": ["Inspecting project"],
4789 "content": ["I need to inspect files."],
4790 "status": "completed"
4791 })
4792 );
4793 }
4794
4795 #[test]
4796 fn thread_item_routing_decision_serializes_as_typed_public_item() {
4797 let selected = roder_api::inference::ModelSelection {
4798 provider: "anthropic".to_string(),
4799 model: "claude-sonnet-5".to_string(),
4800 };
4801 let value = serde_json::to_value(Item::RoutingDecision {
4802 id: "turn-1-routing-decision-0".to_string(),
4803 decision: InferenceRoutingDecisionEvent {
4804 thread_id: "thread-1".to_string(),
4805 turn_id: "turn-1".to_string(),
4806 round_index: 0,
4807 default_selection: roder_api::inference::ModelSelection {
4808 provider: "openai".to_string(),
4809 model: "gpt-5.5".to_string(),
4810 },
4811 selected_selection: selected.clone(),
4812 decision: roder_api::inference_routing::InferenceRoutingDecision::selected(
4813 "local",
4814 selected,
4815 "Large diff and failing tests",
4816 ),
4817 timestamp: OffsetDateTime::UNIX_EPOCH,
4818 },
4819 status: Some(ThreadItemStatus::Completed),
4820 })
4821 .unwrap();
4822
4823 assert_eq!(value["type"], "routingDecision");
4824 assert_eq!(value["id"], "turn-1-routing-decision-0");
4825 assert_eq!(
4826 value["decision"]["selectedSelection"]["model"],
4827 "claude-sonnet-5"
4828 );
4829 assert_eq!(
4830 value["decision"]["decision"]["reason"],
4831 "Large diff and failing tests"
4832 );
4833 assert_eq!(value["status"], "completed");
4834 }
4835
4836 #[test]
4837 fn reasoning_text_delta_notification_targets_reasoning_content_index() {
4838 let notification = JsonRpcNotification {
4839 jsonrpc: "2.0".to_string(),
4840 method: "item/reasoning/textDelta".to_string(),
4841 params: serde_json::to_value(ThreadItemEvent {
4842 seq: 1,
4843 event_id: "event-1".to_string(),
4844 thread_id: "thread-1".to_string(),
4845 turn_id: "turn-1".to_string(),
4846 timestamp: OffsetDateTime::UNIX_EPOCH,
4847 event: ThreadItemEventKind::ItemDelta {
4848 item_id: "turn-1-agent-reasoning".to_string(),
4849 delta: ThreadItemDelta::ReasoningText {
4850 delta: "thinking".to_string(),
4851 content_index: 0,
4852 },
4853 },
4854 })
4855 .unwrap(),
4856 };
4857
4858 let value = serde_json::to_value(notification).unwrap();
4859 assert_eq!(value["method"], "item/reasoning/textDelta");
4860 assert_eq!(value["params"]["threadId"], "thread-1");
4861 assert_eq!(value["params"]["turnId"], "turn-1");
4862 assert_eq!(value["params"]["event"]["itemId"], "turn-1-agent-reasoning");
4863 assert_eq!(value["params"]["event"]["delta"]["delta"], "thinking");
4864 assert_eq!(value["params"]["event"]["delta"]["contentIndex"], 0);
4865 }
4866
4867 #[test]
4868 fn thread_status_serializes_required_activity_fields() {
4869 let idle = serde_json::to_value(ThreadStatus {
4870 kind: "idle".to_string(),
4871 active_turn_id: None,
4872 active_flags: Vec::new(),
4873 })
4874 .unwrap();
4875 assert_eq!(
4876 idle,
4877 serde_json::json!({
4878 "type": "idle",
4879 "activeTurnId": null,
4880 "activeFlags": []
4881 })
4882 );
4883
4884 let running = serde_json::to_value(ThreadStatus {
4885 kind: "running".to_string(),
4886 active_turn_id: Some("turn-1".to_string()),
4887 active_flags: vec!["approvalRequired".to_string()],
4888 })
4889 .unwrap();
4890 assert_eq!(
4891 running,
4892 serde_json::json!({
4893 "type": "running",
4894 "activeTurnId": "turn-1",
4895 "activeFlags": ["approvalRequired"]
4896 })
4897 );
4898 }
4899
4900 #[test]
4901 fn verification_notifications_use_camel_case_fields() {
4902 let value = serde_json::to_value(VerificationRequiredNotification {
4903 thread_id: "thread-1".to_string(),
4904 turn_id: "turn-1".to_string(),
4905 reason: "code_changes_without_verification".to_string(),
4906 changed_files: vec!["src/lib.rs".to_string()],
4907 tool_evidence: vec!["write_file: wrote src/lib.rs".to_string()],
4908 tests_run: vec!["cargo test".to_string()],
4909 open_gaps: Vec::new(),
4910 })
4911 .unwrap();
4912
4913 assert_eq!(value["threadId"], "thread-1");
4914 assert_eq!(value["turnId"], "turn-1");
4915 assert_eq!(value["changedFiles"][0], "src/lib.rs");
4916 assert_eq!(value["toolEvidence"][0], "write_file: wrote src/lib.rs");
4917 assert_eq!(value["testsRun"][0], "cargo test");
4918 assert!(value.get("changed_files").is_none());
4919 }
4920
4921 #[test]
4922 fn search_index_status_protocol_uses_camel_case_fields() {
4923 let value = serde_json::to_value(SearchIndexStatusNotification {
4924 status: SearchIndexStatus {
4925 state: SearchIndexStatusState::Ready,
4926 enabled: true,
4927 workspace: "/tmp/workspace".to_string(),
4928 store_dir: "/tmp/home/.roder/indexes/abc".to_string(),
4929 index_version: Some("fastregex-v1".to_string()),
4930 document_count: Some(7),
4931 index_bytes: Some(128),
4932 build_time_ms: Some(4),
4933 stale: false,
4934 message: None,
4935 },
4936 })
4937 .unwrap();
4938
4939 assert_eq!(value["status"]["state"], "ready");
4940 assert_eq!(value["status"]["storeDir"], "/tmp/home/.roder/indexes/abc");
4941 assert_eq!(value["status"]["indexVersion"], "fastregex-v1");
4942 assert_eq!(value["status"]["documentCount"], 7);
4943 assert_eq!(value["status"]["buildTimeMs"], 4);
4944 assert!(value["status"].get("store_dir").is_none());
4945 assert!(value["status"].get("document_count").is_none());
4946 }
4947
4948 #[test]
4949 fn code_index_status_protocol_uses_camel_case_fields() {
4950 let value = serde_json::to_value(CodeIndexStatusNotification {
4951 status: CodeIndexStatusView {
4952 status: CodeIndexStatus::Ready,
4953 workspace: "/tmp/workspace".to_string(),
4954 store_path: "/tmp/home/.roder/code-index/abc/code-index.sqlite3".to_string(),
4955 generation_id: Some("gen-1".to_string()),
4956 root_hash: Some("root-hash".to_string()),
4957 stale: false,
4958 stats: roder_api::code_index::CodeIndexStats {
4959 file_count: 2,
4960 chunk_count: 3,
4961 embedded_chunk_count: 3,
4962 cached_embedding_count: 1,
4963 index_bytes: 256,
4964 },
4965 message: None,
4966 },
4967 })
4968 .unwrap();
4969
4970 assert_eq!(value["status"]["status"], "ready");
4971 assert_eq!(
4972 value["status"]["storePath"],
4973 "/tmp/home/.roder/code-index/abc/code-index.sqlite3"
4974 );
4975 assert_eq!(value["status"]["generationId"], "gen-1");
4976 assert_eq!(value["status"]["stats"]["chunkCount"], 3);
4977 assert_eq!(value["status"]["stats"]["cachedEmbeddingCount"], 1);
4978 assert!(value["status"].get("store_path").is_none());
4979 assert!(value["status"]["stats"].get("chunk_count").is_none());
4980 }
4981
4982 #[test]
4983 fn workspace_files_protocol_structs_use_workspace_scoped_locators() {
4984 let children: WorkspaceFilesChildrenParams = serde_json::from_value(serde_json::json!({
4985 "workspaceId": "ws-1",
4986 "rootId": "root-1",
4987 "path": "roadmap"
4988 }))
4989 .unwrap();
4990 assert_eq!(children.workspace_id, "ws-1");
4991 assert_eq!(children.root_id.as_deref(), Some("root-1"));
4992 assert_eq!(children.path.as_deref(), Some("roadmap"));
4993
4994 let status = WorkspaceFilesStatus {
4995 workspace_id: "ws-1".to_string(),
4996 state: WorkspaceFilesIndexState::Ready,
4997 stale: false,
4998 roots: vec![WorkspaceFilesRootStatus {
4999 root_id: "root-1".to_string(),
5000 root_name: "repo".to_string(),
5001 state: WorkspaceFilesIndexState::Ready,
5002 stale: false,
5003 file_count: Some(1),
5004 directory_count: Some(1),
5005 build_time_ms: Some(4),
5006 indexed_at_ms: Some(42),
5007 message: None,
5008 }],
5009 file_count: 1,
5010 directory_count: 1,
5011 message: None,
5012 };
5013 let entry = WorkspaceFileEntry {
5014 root_id: "root-1".to_string(),
5015 root_name: "repo".to_string(),
5016 path: "roadmap/status.md".to_string(),
5017 name: "status.md".to_string(),
5018 kind: WorkspaceFileKind::File,
5019 has_children: false,
5020 size: Some(12),
5021 modified_ms: Some(99),
5022 };
5023 let result = WorkspaceFilesQueryResult {
5024 status,
5025 matches: vec![WorkspaceFileQueryMatch {
5026 entry,
5027 score: 120,
5028 match_positions: vec![0, 8],
5029 }],
5030 indexed_file_count: 1,
5031 };
5032 let value = serde_json::to_value(result).unwrap();
5033
5034 assert_eq!(value["status"]["workspaceId"], "ws-1");
5035 assert_eq!(value["status"]["roots"][0]["rootId"], "root-1");
5036 assert_eq!(value["matches"][0]["entry"]["rootName"], "repo");
5037 assert_eq!(value["matches"][0]["entry"]["kind"], "file");
5038 assert_eq!(
5039 value["matches"][0]["matchPositions"],
5040 serde_json::json!([0, 8])
5041 );
5042 assert!(value["matches"][0]["entry"].get("root_id").is_none());
5043 assert!(value.get("indexed_file_count").is_none());
5044 }
5045
5046 #[test]
5047 fn team_start_params_round_trip_camel_case_display_mode() {
5048 let params: TeamStartParams = serde_json::from_value(serde_json::json!({
5049 "leadThreadId": "lead-thread",
5050 "displayMode": "tmux",
5051 "members": [{
5052 "name": "reviewer",
5053 "modelProvider": "mock",
5054 "model": "mock"
5055 }]
5056 }))
5057 .unwrap();
5058
5059 assert_eq!(params.lead_thread_id.as_deref(), Some("lead-thread"));
5060 assert_eq!(params.display_mode, Some(AgentTeamDisplayMode::Tmux));
5061 assert_eq!(params.members[0].model_provider.as_deref(), Some("mock"));
5062
5063 let value = serde_json::to_value(params).unwrap();
5064 assert_eq!(value["leadThreadId"], "lead-thread");
5065 assert_eq!(value["displayMode"], "tmux");
5066 assert_eq!(value["members"][0]["modelProvider"], "mock");
5067 }
5068
5069 #[test]
5070 fn subagent_trace_protocol_structs_use_camel_case_fields() {
5071 let list_params: SubagentTracesListParams = serde_json::from_value(serde_json::json!({
5072 "threadId": "thread-1",
5073 "turnId": "turn-1"
5074 }))
5075 .unwrap();
5076 assert_eq!(list_params.thread_id, "thread-1");
5077 assert_eq!(list_params.turn_id, "turn-1");
5078
5079 let read_params: SubagentTraceReadParams = serde_json::from_value(serde_json::json!({
5080 "threadId": "thread-1",
5081 "traceId": "trace-1",
5082 "offset": 10,
5083 "limit": 20
5084 }))
5085 .unwrap();
5086 assert_eq!(read_params.thread_id, "thread-1");
5087 assert_eq!(read_params.trace_id, "trace-1");
5088 assert_eq!(read_params.offset, 10);
5089 assert_eq!(read_params.limit, Some(20));
5090
5091 let result = SubagentTraceReadResult {
5092 trace_id: "trace-1".to_string(),
5093 events: Vec::new(),
5094 next_offset: Some(30),
5095 };
5096 let value = serde_json::to_value(result).unwrap();
5097 assert_eq!(value["traceId"], "trace-1");
5098 assert_eq!(value["nextOffset"], 30);
5099 }
5100
5101 #[test]
5102 fn artifacts_protocol_structs_use_camel_case_fields() {
5103 let params: ArtifactReadParams = serde_json::from_value(serde_json::json!({
5104 "threadId": "thread-1",
5105 "artifactId": "artifact-1",
5106 "startLine": 2,
5107 "limit": 10
5108 }))
5109 .unwrap();
5110
5111 assert_eq!(params.thread_id, "thread-1");
5112 assert_eq!(params.artifact_id, "artifact-1");
5113 assert_eq!(params.start_line, Some(2));
5114
5115 let command = serde_json::to_value(CommandExecResponse {
5116 exit_code: 0,
5117 stdout: "short".to_string(),
5118 stderr: String::new(),
5119 stdout_artifact: None,
5120 stderr_artifact: None,
5121 })
5122 .unwrap();
5123
5124 assert_eq!(command["exitCode"], 0);
5125 assert!(command.get("stdoutArtifact").is_none());
5126 }
5127
5128 #[test]
5129 fn discovery_protocol_structs_use_camel_case_fields() {
5130 let params: DiscoveryReadParams = serde_json::from_value(serde_json::json!({
5131 "itemId": "tool:builtin/grep",
5132 "startLine": 2,
5133 "limit": 10,
5134 "threadId": "thread-1",
5135 "turnId": "turn-1"
5136 }))
5137 .unwrap();
5138
5139 assert_eq!(params.item_id, "tool:builtin/grep");
5140 assert_eq!(params.start_line, Some(2));
5141 assert_eq!(params.thread_id.as_deref(), Some("thread-1"));
5142
5143 let clear = serde_json::to_value(DiscoveryPromotedClearResult { cleared: 2 }).unwrap();
5144 assert_eq!(clear["cleared"], 2);
5145 }
5146
5147 #[test]
5148 fn retrieval_protocol_structs_use_camel_case_fields() {
5149 let params: RetrievalTurnParams = serde_json::from_value(serde_json::json!({
5150 "threadId": "thread-1",
5151 "turnId": "turn-1",
5152 "limit": 5
5153 }))
5154 .unwrap();
5155 assert_eq!(params.thread_id, "thread-1");
5156 assert_eq!(params.turn_id, "turn-1");
5157 assert_eq!(params.limit, Some(5));
5158
5159 let result = RetrievalRecommendationsResult {
5160 thread_id: "thread-1".to_string(),
5161 turn_id: "turn-1".to_string(),
5162 plans: Vec::new(),
5163 summary: RetrievalDebugSummary {
5164 text: "no route recommendations recorded".to_string(),
5165 notes: vec!["router did not emit retrieval/routePlanned".to_string()],
5166 truncated: false,
5167 },
5168 };
5169 let value = serde_json::to_value(result).unwrap();
5170 assert_eq!(value["threadId"], "thread-1");
5171 assert_eq!(value["turnId"], "turn-1");
5172 assert_eq!(value["summary"]["truncated"], false);
5173
5174 let state = RetrievalPromotedCapabilityState {
5175 item_id: "tool:builtin/grep".to_string(),
5176 route_id: Some("route-1".to_string()),
5177 state: "skipped".to_string(),
5178 cache_status: None,
5179 reason: Some("already warm".to_string()),
5180 thread_id: "thread-1".to_string(),
5181 turn_id: Some("turn-1".to_string()),
5182 timestamp: OffsetDateTime::UNIX_EPOCH,
5183 };
5184 let value = serde_json::to_value(state).unwrap();
5185 assert_eq!(value["itemId"], "tool:builtin/grep");
5186 assert_eq!(value["routeId"], "route-1");
5187 assert!(value.get("cacheStatus").is_none());
5188 }
5189
5190 #[test]
5191 fn plan_review_and_hunk_protocol_structs_use_camel_case_fields() {
5192 let comment_params: PlanReviewCommentParams = serde_json::from_value(serde_json::json!({
5193 "threadId": "thread-1",
5194 "reviewId": "review-1",
5195 "anchor": { "step": { "stepId": "step-1" } },
5196 "body": "Use the smaller patch."
5197 }))
5198 .unwrap();
5199 assert_eq!(comment_params.thread_id, "thread-1");
5200 assert_eq!(comment_params.review_id, "review-1");
5201
5202 let hunk_params: HunkReadParams = serde_json::from_value(serde_json::json!({
5203 "threadId": "thread-1",
5204 "hunkId": "hunk-1",
5205 "offset": 4,
5206 "limit": 20
5207 }))
5208 .unwrap();
5209 assert_eq!(hunk_params.hunk_id, "hunk-1");
5210 assert_eq!(hunk_params.limit, Some(20));
5211
5212 let result = HunkRollbackResult {
5213 rolled_back: false,
5214 error: Some("checkpoint data is unavailable".to_string()),
5215 };
5216 let value = serde_json::to_value(result).unwrap();
5217 assert_eq!(value["rolledBack"], false);
5218 assert_eq!(value["error"], "checkpoint data is unavailable");
5219 }
5220
5221 #[test]
5222 fn workflow_import_protocol_structs_use_camel_case_fields() {
5223 let scan_params: WorkflowScanParams = serde_json::from_value(serde_json::json!({
5224 "workspace": "/tmp/repo",
5225 "includeUser": true
5226 }))
5227 .unwrap();
5228 assert_eq!(scan_params.workspace.as_deref(), Some("/tmp/repo"));
5229 assert!(scan_params.include_user);
5230
5231 let enable_params: WorkflowEnableParams = serde_json::from_value(serde_json::json!({
5232 "workspace": "/tmp/repo",
5233 "itemId": "workflow-1",
5234 "approveSideEffects": true
5235 }))
5236 .unwrap();
5237 assert_eq!(enable_params.item_id, "workflow-1");
5238 assert!(enable_params.approve_side_effects);
5239
5240 let remove = WorkflowRemoveResult {
5241 item_id: "workflow-1".to_string(),
5242 state: WorkflowImportState::Removed,
5243 decision: WorkflowImportDecision {
5244 item_id: "workflow-1".to_string(),
5245 decision: roder_api::workflow::WorkflowImportDecisionKind::Remove,
5246 source_hash: "hash".to_string(),
5247 approved_side_effects: false,
5248 decided_at: OffsetDateTime::UNIX_EPOCH,
5249 },
5250 };
5251 let value = serde_json::to_value(remove).unwrap();
5252 assert_eq!(value["itemId"], "workflow-1");
5253 assert_eq!(value["state"], "removed");
5254 assert_eq!(value["decision"]["sourceHash"], "hash");
5255 }
5256
5257 #[test]
5258 fn marketplace_protocol_structs_use_camel_case_fields() {
5259 let params: MarketplacesInstallDefaultParams = serde_json::from_value(serde_json::json!({
5260 "selection": "all"
5261 }))
5262 .unwrap();
5263 assert_eq!(params.selection, DefaultMarketplaceSelection::All);
5264
5265 let add: MarketplacesAddParams = serde_json::from_value(serde_json::json!({
5266 "id": "local-cursor",
5267 "kind": "cursor",
5268 "displayName": "Local Cursor",
5269 "source": {
5270 "kind": "localPath",
5271 "path": "/tmp/cursor"
5272 }
5273 }))
5274 .unwrap();
5275 assert_eq!(add.id, "local-cursor");
5276 assert_eq!(add.kind, Some(MarketplaceKind::Cursor));
5277 assert_eq!(
5278 add.source,
5279 MarketplaceSource::LocalPath {
5280 path: "/tmp/cursor".to_string()
5281 }
5282 );
5283
5284 let remove = MarketplacesRemoveParams {
5285 marketplace_id: "local-cursor".to_string(),
5286 };
5287 let value = serde_json::to_value(remove).unwrap();
5288 assert_eq!(value["marketplaceId"], "local-cursor");
5289
5290 let disable = PluginDisableParams {
5291 variant_key: "codex-plugins:superpowers".to_string(),
5292 };
5293 let value = serde_json::to_value(disable).unwrap();
5294 assert_eq!(value["variantKey"], "codex-plugins:superpowers");
5295
5296 let all = PluginInstallAllVariantsParams {
5297 marketplace_id: "codex-plugins".to_string(),
5298 plugin_id: "superpowers".to_string(),
5299 };
5300 let value = serde_json::to_value(all).unwrap();
5301 assert_eq!(value["marketplaceId"], "codex-plugins");
5302
5303 let uninstall = PluginUninstallParams {
5304 variant_key: "codex-plugins:superpowers".to_string(),
5305 };
5306 let value = serde_json::to_value(uninstall).unwrap();
5307 assert_eq!(value["variantKey"], "codex-plugins:superpowers");
5308 }
5309
5310 #[test]
5311 fn skills_protocol_structs_use_camel_case_fields() {
5312 let params: SkillsSetExposureParams = serde_json::from_value(serde_json::json!({
5313 "selector": { "name": { "name": "commit" } },
5314 "exposure": "direct_only"
5315 }))
5316 .unwrap();
5317 assert_eq!(
5318 params.selector,
5319 SkillSelector::Name {
5320 name: "commit".to_string()
5321 }
5322 );
5323 assert_eq!(params.exposure, SkillExposure::DirectOnly);
5324
5325 let enabled = SkillsSetEnabledParams {
5326 selector: SkillSelector::Path {
5327 path: "roder-builtin://commit/SKILL.md".to_string(),
5328 },
5329 enabled: false,
5330 };
5331 let value = serde_json::to_value(enabled).unwrap();
5332 assert_eq!(
5333 value["selector"]["path"]["path"],
5334 "roder-builtin://commit/SKILL.md"
5335 );
5336 assert_eq!(value["enabled"], false);
5337 }
5338
5339 #[test]
5340 fn automations_protocol_structs_use_camel_case_fields() {
5341 let create: AutomationsCreateParams = serde_json::from_value(serde_json::json!({
5342 "name": "Nightly cleanup",
5343 "project": { "cwd": "/repo", "displayName": "repo" },
5344 "schedule": { "interval": { "seconds": 300 } },
5345 "prompt": "summarize status",
5346 "modelProvider": "codex",
5347 "model": "gpt-5.5",
5348 "policyMode": "plan",
5349 "catchUp": { "runLatestOnly": null },
5350 "concurrency": "forbid"
5351 }))
5352 .unwrap();
5353
5354 assert_eq!(create.name, "Nightly cleanup");
5355 assert_eq!(create.project.display_name.as_deref(), Some("repo"));
5356 assert_eq!(create.model_provider.as_deref(), Some("codex"));
5357 assert_eq!(
5358 create.policy_mode,
5359 Some(roder_api::policy_mode::PolicyMode::Plan)
5360 );
5361 assert_eq!(create.catch_up, CatchUpPolicy::RunLatestOnly);
5362
5363 let update = AutomationsUpdateParams {
5364 automation_id: "automation-1".to_string(),
5365 patch: AutomationsUpdatePatch {
5366 model_provider: Some("codex".to_string()),
5367 catch_up: Some(CatchUpPolicy::SkipExpired { grace_seconds: 60 }),
5368 ..AutomationsUpdatePatch::default()
5369 },
5370 };
5371 let value = serde_json::to_value(update).unwrap();
5372 assert_eq!(value["automationId"], "automation-1");
5373 assert_eq!(value["patch"]["modelProvider"], "codex");
5374 assert_eq!(value["patch"]["catchUp"]["skipExpired"]["graceSeconds"], 60);
5375 assert!(value.get("automation_id").is_none());
5376 }
5377
5378 #[test]
5379 fn processes_protocol_structs_cover_list_detail_stop_and_subscribe() {
5380 let descriptor = ProcessDescriptor {
5381 process_id: "process-1".to_string(),
5382 origin: roder_api::processes::ProcessOrigin::CommandExec,
5383 state: roder_api::processes::ProcessState::Running,
5384 command: vec!["sleep".to_string(), "10".to_string()],
5385 command_summary: "sleep 10".to_string(),
5386 cwd: Some("/repo".to_string()),
5387 pid: Some(1234),
5388 task_id: Some("task-1".to_string()),
5389 thread_id: Some("thread-1".to_string()),
5390 turn_id: Some("turn-1".to_string()),
5391 runner_destination_id: None,
5392 runner_session_id: None,
5393 stoppable: true,
5394 started_at: OffsetDateTime::UNIX_EPOCH,
5395 updated_at: OffsetDateTime::UNIX_EPOCH,
5396 stdout_tail: Some("ready\n".to_string()),
5397 stderr_tail: None,
5398 };
5399
5400 let list_params: ProcessesListParams = serde_json::from_value(serde_json::json!({
5401 "includeCompleted": true
5402 }))
5403 .unwrap();
5404 assert!(list_params.include_completed);
5405
5406 let list = serde_json::to_value(ProcessesListResult {
5407 processes: vec![descriptor.clone()],
5408 })
5409 .unwrap();
5410 assert_eq!(list["processes"][0]["processId"], "process-1");
5411 assert_eq!(list["processes"][0]["pid"], 1234);
5412 assert!(list["processes"][0].get("process_id").is_none());
5413
5414 let get: ProcessesGetParams = serde_json::from_value(serde_json::json!({
5415 "processId": "process-1",
5416 "outputBytes": 1024
5417 }))
5418 .unwrap();
5419 assert_eq!(get.process_id, "process-1");
5420 assert_eq!(get.output_bytes, Some(1024));
5421
5422 let stop: ProcessesStopParams = serde_json::from_value(serde_json::json!({
5423 "processId": "process-1",
5424 "reason": "user requested stop"
5425 }))
5426 .unwrap();
5427 assert_eq!(stop.process_id, "process-1");
5428 assert_eq!(stop.reason.as_deref(), Some("user requested stop"));
5429
5430 let stop_all: ProcessesStopAllResult = serde_json::from_value(serde_json::json!({
5431 "results": [{
5432 "processId": "process-1",
5433 "stopped": true,
5434 "process": list["processes"][0].clone()
5435 }]
5436 }))
5437 .unwrap();
5438 assert_eq!(stop_all.results[0].process_id, "process-1");
5439 assert!(stop_all.results[0].stopped);
5440
5441 let subscribe = ProcessesSubscribeResult {
5442 subscribed: true,
5443 event_kinds: vec!["process.started".to_string(), "process.output".to_string()],
5444 };
5445 let value = serde_json::to_value(subscribe).unwrap();
5446 assert_eq!(value["subscribed"], true);
5447 assert_eq!(value["eventKinds"][0], "process.started");
5448 assert!(value.get("event_kinds").is_none());
5449 }
5450
5451 #[test]
5452 fn eval_report_protocol_structs_use_camel_case_fields() {
5453 let list: EvalReportsListParams = serde_json::from_value(serde_json::json!({
5454 "limit": 5
5455 }))
5456 .unwrap();
5457 assert_eq!(list.limit, Some(5));
5458
5459 let read: EvalReportReadParams = serde_json::from_value(serde_json::json!({
5460 "reportId": "eval-run",
5461 "maxBytes": 1024
5462 }))
5463 .unwrap();
5464 assert_eq!(read.report_id, "eval-run");
5465 assert_eq!(read.max_bytes, Some(1024));
5466
5467 let result = EvalReportReadResult {
5468 summary: EvalReportSummary {
5469 id: "eval-run".to_string(),
5470 suite_id: "tool-calls".to_string(),
5471 fixture_count: 2,
5472 passed: 1,
5473 failed: 1,
5474 reliability: EvalReliabilitySummary {
5475 retry_attempts: 2,
5476 retry_recoveries: 1,
5477 ..EvalReliabilitySummary::default()
5478 },
5479 generated_at: OffsetDateTime::UNIX_EPOCH,
5480 },
5481 markdown: "# Report".to_string(),
5482 truncated: false,
5483 };
5484 let value = serde_json::to_value(result).unwrap();
5485 assert_eq!(value["summary"]["suiteId"], "tool-calls");
5486 assert_eq!(value["summary"]["fixtureCount"], 2);
5487 assert_eq!(value["summary"]["reliability"]["retryAttempts"], 2);
5488 assert_eq!(value["summary"]["reliability"]["retryRecoveries"], 1);
5489 assert_eq!(value["markdown"], "# Report");
5490 }
5491
5492 #[test]
5493 fn deadline_notifications_use_camel_case_fields() {
5494 let value = serde_json::to_value(TurnDeadlineExceededNotification {
5495 thread_id: "thread-a".to_string(),
5496 turn_id: "turn-a".to_string(),
5497 deadline: OffsetDateTime::UNIX_EPOCH,
5498 partial_result: "partial evidence".to_string(),
5499 })
5500 .unwrap();
5501 assert_eq!(value["threadId"], "thread-a");
5502 assert_eq!(value["turnId"], "turn-a");
5503 assert_eq!(value["partialResult"], "partial evidence");
5504
5505 let value = serde_json::to_value(TurnPartialResultNotification {
5506 thread_id: "thread-a".to_string(),
5507 turn_id: "turn-a".to_string(),
5508 summary: "partial evidence".to_string(),
5509 })
5510 .unwrap();
5511 assert_eq!(value["summary"], "partial evidence");
5512 }
5513
5514 #[test]
5515 fn thread_goal_set_params_preserve_null_budget_clear() {
5516 let params: ThreadGoalSetParams = serde_json::from_value(serde_json::json!({
5517 "threadId": "thread-a",
5518 "tokenBudget": null
5519 }))
5520 .unwrap();
5521 assert_eq!(params.thread_id, "thread-a");
5522 assert_eq!(params.token_budget, Some(None));
5523
5524 let params: ThreadGoalSetParams = serde_json::from_value(serde_json::json!({
5525 "threadId": "thread-a"
5526 }))
5527 .unwrap();
5528 assert_eq!(params.token_budget, None);
5529 }
5530
5531 #[test]
5532 fn media_protocol_structs_use_camel_case_fields() {
5533 let read: MediaReadParams = serde_json::from_value(serde_json::json!({
5534 "artifactId": "media-1",
5535 "maxBytes": 1024
5536 }))
5537 .unwrap();
5538 assert_eq!(read.artifact_id, "media-1");
5539 assert_eq!(read.max_bytes, Some(1024));
5540
5541 let attach = MediaAttachToTurnResult {
5542 attachment: MediaAttachment {
5543 artifact_id: "media-1".to_string(),
5544 mime_type: "image/png".to_string(),
5545 data_url: "data:image/png;base64,YWJj".to_string(),
5546 },
5547 image: Some(InputImage {
5548 image_url: "data:image/png;base64,YWJj".to_string(),
5549 }),
5550 };
5551 let value = serde_json::to_value(attach).unwrap();
5552 assert_eq!(value["attachment"]["artifactId"], "media-1");
5553 assert_eq!(value["attachment"]["mimeType"], "image/png");
5554 assert_eq!(value["image"]["image_url"], "data:image/png;base64,YWJj");
5555 }
5556
5557 #[test]
5558 fn media_image_generation_params_flatten_the_canonical_request() {
5559 let params: MediaImageGenerateParams = serde_json::from_value(serde_json::json!({
5560 "prompt": "a tiny test image",
5561 "provider": "openai",
5562 "model": "gpt-image-2",
5563 "count": 2,
5564 "size": "1024x1024",
5565 "threadId": "thread-1"
5566 }))
5567 .unwrap();
5568 assert_eq!(params.request.prompt, "a tiny test image");
5569 assert_eq!(params.request.provider.as_deref(), Some("openai"));
5570 assert_eq!(params.request.count, Some(2));
5571 assert_eq!(params.thread_id.as_deref(), Some("thread-1"));
5572
5573 let result = MediaImageProvidersListResult {
5574 default_provider: "fake".to_string(),
5575 providers: vec![roder_api::media::MediaProviderDescriptor {
5576 id: "fake".to_string(),
5577 display_name: "Fake Media (offline)".to_string(),
5578 supports_images: true,
5579 configured: true,
5580 ..roder_api::media::MediaProviderDescriptor::default()
5581 }],
5582 };
5583 let value = serde_json::to_value(result).unwrap();
5584 assert_eq!(value["defaultProvider"], "fake");
5585 assert_eq!(value["providers"][0]["supportsImages"], true);
5586 }
5587
5588 #[test]
5589 fn transcript_json_rpc_boundary_values_round_trip() {
5590 let request = JsonRpcRequest {
5591 jsonrpc: "2.0".to_string(),
5592 id: Some(serde_json::json!(7)),
5593 method: "processes/list".to_string(),
5594 params: Some(serde_json::json!({"includeCompleted": true})),
5595 };
5596 let response = JsonRpcResponse {
5597 jsonrpc: "2.0".to_string(),
5598 id: Some(serde_json::json!(7)),
5599 result: Some(serde_json::json!({"processes": []})),
5600 error: None,
5601 };
5602 let notification = JsonRpcNotification {
5603 jsonrpc: "2.0".to_string(),
5604 method: "processes/changed".to_string(),
5605 params: serde_json::json!({"processId": "proc-a"}),
5606 };
5607
5608 assert_eq!(
5609 serde_json::to_value(&request).unwrap()["method"],
5610 "processes/list"
5611 );
5612 assert_eq!(
5613 serde_json::to_value(&response).unwrap()["result"]["processes"],
5614 serde_json::json!([])
5615 );
5616 assert_eq!(
5617 serde_json::to_value(¬ification).unwrap()["method"],
5618 "processes/changed"
5619 );
5620 }
5621}