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