1use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::sync::Arc;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum ConnectionState {
19 Disconnected,
20 Connecting,
21 Connected,
22 Error,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
31#[serde(rename_all = "camelCase")]
32pub enum ToolResultType {
33 Success,
34 Failure,
35 Rejected,
36 Denied,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
41#[serde(rename_all = "camelCase")]
42pub struct ToolBinaryResult {
43 pub data: String,
44 pub mime_type: String,
45 #[serde(rename = "type")]
46 pub result_type: String,
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub description: Option<String>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub struct ToolResultObject {
55 pub text_result_for_llm: String,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub binary_results_for_llm: Option<Vec<ToolBinaryResult>>,
58 pub result_type: ToolResultType,
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub error: Option<String>,
61 #[serde(skip_serializing_if = "Option::is_none")]
62 pub session_log: Option<String>,
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub tool_telemetry: Option<HashMap<String, serde_json::Value>>,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
69#[serde(untagged)]
70pub enum ToolResult {
71 Text(String),
72 Object(ToolResultObject),
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77#[serde(rename_all = "camelCase")]
78pub struct ToolInvocation {
79 pub session_id: String,
80 pub tool_call_id: String,
81 pub tool_name: String,
82 pub arguments: serde_json::Value,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
87#[serde(rename_all = "camelCase")]
88pub struct ToolDefinition {
89 pub name: String,
90 #[serde(skip_serializing_if = "Option::is_none")]
91 pub description: Option<String>,
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub parameters: Option<serde_json::Value>,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98#[serde(rename_all = "camelCase")]
99pub struct ToolCallRequestPayload {
100 pub session_id: String,
101 pub tool_call_id: String,
102 pub tool_name: String,
103 pub arguments: serde_json::Value,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct ToolCallResponsePayload {
109 pub result: ToolResultObject,
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
118pub enum SystemPromptSection {
119 #[serde(rename = "identity")]
120 Identity,
121 #[serde(rename = "tone")]
122 Tone,
123 #[serde(rename = "tool_efficiency")]
124 ToolEfficiency,
125 #[serde(rename = "environment_context")]
126 EnvironmentContext,
127 #[serde(rename = "code_change_rules")]
128 CodeChangeRules,
129 #[serde(rename = "guidelines")]
130 Guidelines,
131 #[serde(rename = "safety")]
132 Safety,
133 #[serde(rename = "tool_instructions")]
134 ToolInstructions,
135 #[serde(rename = "custom_instructions")]
136 CustomInstructions,
137 #[serde(rename = "last_instructions")]
138 LastInstructions,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
143#[serde(rename_all = "lowercase")]
144pub enum SectionOverrideAction {
145 Replace,
146 Remove,
147 Append,
148 Prepend,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct SectionOverride {
154 pub action: SectionOverrideAction,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub content: Option<String>,
157}
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
161#[serde(tag = "mode", rename_all = "camelCase")]
162pub enum SystemMessageConfig {
163 #[serde(rename = "append")]
165 Append {
166 #[serde(skip_serializing_if = "Option::is_none")]
167 content: Option<String>,
168 },
169 #[serde(rename = "replace")]
171 Replace { content: String },
172 #[serde(rename = "customize")]
174 Customize {
175 #[serde(skip_serializing_if = "Option::is_none")]
176 sections: Option<HashMap<SystemPromptSection, SectionOverride>>,
177 #[serde(skip_serializing_if = "Option::is_none")]
178 content: Option<String>,
179 },
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
188#[serde(rename_all = "lowercase")]
189pub enum PermissionKind {
190 Shell,
191 Write,
192 Mcp,
193 Read,
194 Url,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
199#[serde(rename_all = "camelCase")]
200pub struct PermissionRequest {
201 pub kind: PermissionKind,
202 #[serde(skip_serializing_if = "Option::is_none")]
203 pub tool_call_id: Option<String>,
204 #[serde(flatten)]
206 pub extra: HashMap<String, serde_json::Value>,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
211#[serde(rename_all = "kebab-case")]
212pub enum PermissionResultKind {
213 Approved,
214 DeniedByRules,
215 DeniedNoApprovalRuleAndCouldNotRequestFromUser,
216 DeniedInteractivelyByUser,
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct PermissionRequestResult {
222 pub kind: PermissionResultKind,
223 #[serde(skip_serializing_if = "Option::is_none")]
224 pub rules: Option<Vec<serde_json::Value>>,
225}
226
227#[derive(Debug, Clone, Serialize, Deserialize)]
233#[serde(rename_all = "camelCase")]
234pub struct UserInputRequest {
235 pub question: String,
236 #[serde(skip_serializing_if = "Option::is_none")]
237 pub choices: Option<Vec<String>>,
238 #[serde(skip_serializing_if = "Option::is_none")]
239 pub allow_freeform: Option<bool>,
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize)]
244#[serde(rename_all = "camelCase")]
245pub struct UserInputResponse {
246 pub answer: String,
247 pub was_freeform: bool,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct BaseHookInput {
257 pub timestamp: f64,
258 pub cwd: String,
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize)]
263#[serde(rename_all = "camelCase")]
264pub struct PreToolUseHookInput {
265 pub timestamp: f64,
266 pub cwd: String,
267 pub tool_name: String,
268 pub tool_args: serde_json::Value,
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize, Default)]
273#[serde(rename_all = "camelCase")]
274pub struct PreToolUseHookOutput {
275 #[serde(skip_serializing_if = "Option::is_none")]
276 pub permission_decision: Option<String>,
277 #[serde(skip_serializing_if = "Option::is_none")]
278 pub permission_decision_reason: Option<String>,
279 #[serde(skip_serializing_if = "Option::is_none")]
280 pub modified_args: Option<serde_json::Value>,
281 #[serde(skip_serializing_if = "Option::is_none")]
282 pub additional_context: Option<String>,
283 #[serde(skip_serializing_if = "Option::is_none")]
284 pub suppress_output: Option<bool>,
285}
286
287#[derive(Debug, Clone, Serialize, Deserialize)]
289#[serde(rename_all = "camelCase")]
290pub struct PostToolUseHookInput {
291 pub timestamp: f64,
292 pub cwd: String,
293 pub tool_name: String,
294 pub tool_args: serde_json::Value,
295 pub tool_result: ToolResultObject,
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize, Default)]
300#[serde(rename_all = "camelCase")]
301pub struct PostToolUseHookOutput {
302 #[serde(skip_serializing_if = "Option::is_none")]
303 pub modified_result: Option<ToolResultObject>,
304 #[serde(skip_serializing_if = "Option::is_none")]
305 pub additional_context: Option<String>,
306 #[serde(skip_serializing_if = "Option::is_none")]
307 pub suppress_output: Option<bool>,
308}
309
310#[derive(Debug, Clone, Serialize, Deserialize)]
312pub struct UserPromptSubmittedHookInput {
313 pub timestamp: f64,
314 pub cwd: String,
315 pub prompt: String,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize, Default)]
320#[serde(rename_all = "camelCase")]
321pub struct UserPromptSubmittedHookOutput {
322 #[serde(skip_serializing_if = "Option::is_none")]
323 pub modified_prompt: Option<String>,
324 #[serde(skip_serializing_if = "Option::is_none")]
325 pub additional_context: Option<String>,
326 #[serde(skip_serializing_if = "Option::is_none")]
327 pub suppress_output: Option<bool>,
328}
329
330#[derive(Debug, Clone, Serialize, Deserialize)]
332#[serde(rename_all = "camelCase")]
333pub struct SessionStartHookInput {
334 pub timestamp: f64,
335 pub cwd: String,
336 pub source: String,
337 #[serde(skip_serializing_if = "Option::is_none")]
338 pub initial_prompt: Option<String>,
339}
340
341#[derive(Debug, Clone, Serialize, Deserialize, Default)]
343#[serde(rename_all = "camelCase")]
344pub struct SessionStartHookOutput {
345 #[serde(skip_serializing_if = "Option::is_none")]
346 pub additional_context: Option<String>,
347 #[serde(skip_serializing_if = "Option::is_none")]
348 pub modified_config: Option<HashMap<String, serde_json::Value>>,
349}
350
351#[derive(Debug, Clone, Serialize, Deserialize)]
353#[serde(rename_all = "camelCase")]
354pub struct SessionEndHookInput {
355 pub timestamp: f64,
356 pub cwd: String,
357 pub reason: String,
358 #[serde(skip_serializing_if = "Option::is_none")]
359 pub final_message: Option<String>,
360 #[serde(skip_serializing_if = "Option::is_none")]
361 pub error: Option<String>,
362}
363
364#[derive(Debug, Clone, Serialize, Deserialize, Default)]
366#[serde(rename_all = "camelCase")]
367pub struct SessionEndHookOutput {
368 #[serde(skip_serializing_if = "Option::is_none")]
369 pub suppress_output: Option<bool>,
370 #[serde(skip_serializing_if = "Option::is_none")]
371 pub cleanup_actions: Option<Vec<String>>,
372 #[serde(skip_serializing_if = "Option::is_none")]
373 pub session_summary: Option<String>,
374}
375
376#[derive(Debug, Clone, Serialize, Deserialize)]
378#[serde(rename_all = "camelCase")]
379pub struct ErrorOccurredHookInput {
380 pub timestamp: f64,
381 pub cwd: String,
382 pub error: String,
383 pub error_context: String,
384 pub recoverable: bool,
385}
386
387#[derive(Debug, Clone, Serialize, Deserialize, Default)]
389#[serde(rename_all = "camelCase")]
390pub struct ErrorOccurredHookOutput {
391 #[serde(skip_serializing_if = "Option::is_none")]
392 pub suppress_output: Option<bool>,
393 #[serde(skip_serializing_if = "Option::is_none")]
394 pub error_handling: Option<String>,
395 #[serde(skip_serializing_if = "Option::is_none")]
396 pub retry_count: Option<u32>,
397 #[serde(skip_serializing_if = "Option::is_none")]
398 pub user_notification: Option<String>,
399}
400
401#[derive(Debug, Clone, Serialize, Deserialize)]
407#[serde(rename_all = "camelCase")]
408pub struct McpLocalServerConfig {
409 pub tools: Vec<String>,
410 #[serde(skip_serializing_if = "Option::is_none")]
411 #[serde(rename = "type")]
412 pub server_type: Option<String>,
413 #[serde(skip_serializing_if = "Option::is_none")]
414 pub timeout: Option<u64>,
415 pub command: String,
416 pub args: Vec<String>,
417 #[serde(skip_serializing_if = "Option::is_none")]
418 pub env: Option<HashMap<String, String>>,
419 #[serde(skip_serializing_if = "Option::is_none")]
420 pub cwd: Option<String>,
421}
422
423#[derive(Debug, Clone, Serialize, Deserialize)]
425#[serde(rename_all = "camelCase")]
426pub struct McpRemoteServerConfig {
427 pub tools: Vec<String>,
428 #[serde(rename = "type")]
429 pub server_type: String,
430 #[serde(skip_serializing_if = "Option::is_none")]
431 pub timeout: Option<u64>,
432 pub url: String,
433 #[serde(skip_serializing_if = "Option::is_none")]
434 pub headers: Option<HashMap<String, String>>,
435}
436
437#[derive(Debug, Clone, Serialize, Deserialize)]
439#[serde(untagged)]
440pub enum McpServerConfig {
441 Local(McpLocalServerConfig),
442 Remote(McpRemoteServerConfig),
443}
444
445#[derive(Debug, Clone, Serialize, Deserialize)]
451#[serde(rename_all = "camelCase")]
452pub struct CustomAgentConfig {
453 pub name: String,
454 #[serde(skip_serializing_if = "Option::is_none")]
455 pub display_name: Option<String>,
456 #[serde(skip_serializing_if = "Option::is_none")]
457 pub description: Option<String>,
458 #[serde(skip_serializing_if = "Option::is_none")]
459 pub tools: Option<Vec<String>>,
460 pub prompt: String,
461 #[serde(skip_serializing_if = "Option::is_none")]
462 pub mcp_servers: Option<HashMap<String, McpServerConfig>>,
463 #[serde(skip_serializing_if = "Option::is_none")]
464 pub infer: Option<bool>,
465 #[serde(skip_serializing_if = "Option::is_none")]
467 pub skills: Option<Vec<String>>,
468}
469
470#[derive(Debug, Clone, Serialize, Deserialize)]
476#[serde(rename_all = "camelCase")]
477pub struct InfiniteSessionConfig {
478 #[serde(skip_serializing_if = "Option::is_none")]
479 pub enabled: Option<bool>,
480 #[serde(skip_serializing_if = "Option::is_none")]
481 pub background_compaction_threshold: Option<f64>,
482 #[serde(skip_serializing_if = "Option::is_none")]
483 pub buffer_exhaustion_threshold: Option<f64>,
484}
485
486#[derive(Debug, Clone, Serialize, Deserialize)]
492#[serde(rename_all = "camelCase")]
493pub struct AzureProviderOptions {
494 #[serde(skip_serializing_if = "Option::is_none")]
495 pub api_version: Option<String>,
496}
497
498#[derive(Debug, Clone, Serialize, Deserialize)]
500#[serde(rename_all = "camelCase")]
501pub struct ProviderConfig {
502 #[serde(skip_serializing_if = "Option::is_none")]
503 #[serde(rename = "type")]
504 pub provider_type: Option<String>,
505 #[serde(skip_serializing_if = "Option::is_none")]
506 pub wire_api: Option<String>,
507 pub base_url: String,
508 #[serde(skip_serializing_if = "Option::is_none")]
509 pub api_key: Option<String>,
510 #[serde(skip_serializing_if = "Option::is_none")]
511 pub bearer_token: Option<String>,
512 #[serde(skip_serializing_if = "Option::is_none")]
513 pub azure: Option<AzureProviderOptions>,
514}
515
516#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
522#[serde(rename_all = "lowercase")]
523pub enum ReasoningEffort {
524 Low,
525 Medium,
526 High,
527 Xhigh,
528}
529
530#[derive(Debug, Clone, Default, Serialize, Deserialize)]
540#[serde(rename_all = "camelCase")]
541pub struct SessionConfig {
542 #[serde(skip_serializing_if = "Option::is_none")]
543 pub session_id: Option<String>,
544 #[serde(skip_serializing_if = "Option::is_none")]
545 pub model: Option<String>,
546 #[serde(skip_serializing_if = "Option::is_none")]
547 pub reasoning_effort: Option<ReasoningEffort>,
548 #[serde(skip_serializing_if = "Option::is_none")]
549 pub config_dir: Option<String>,
550 #[serde(skip_serializing_if = "Option::is_none")]
551 pub tools: Option<Vec<ToolDefinition>>,
552 #[serde(skip_serializing_if = "Option::is_none")]
553 pub system_message: Option<SystemMessageConfig>,
554 #[serde(skip_serializing_if = "Option::is_none")]
555 pub available_tools: Option<Vec<String>>,
556 #[serde(skip_serializing_if = "Option::is_none")]
557 pub excluded_tools: Option<Vec<String>>,
558 #[serde(skip_serializing_if = "Option::is_none")]
559 pub provider: Option<ProviderConfig>,
560 #[serde(skip_serializing_if = "Option::is_none")]
561 pub working_directory: Option<String>,
562 #[serde(skip_serializing_if = "Option::is_none")]
563 pub streaming: Option<bool>,
564 #[serde(skip_serializing_if = "Option::is_none")]
566 pub include_sub_agent_streaming_events: Option<bool>,
567 #[serde(skip_serializing_if = "Option::is_none")]
568 pub mcp_servers: Option<HashMap<String, McpServerConfig>>,
569 #[serde(skip_serializing_if = "Option::is_none")]
570 pub custom_agents: Option<Vec<CustomAgentConfig>>,
571 #[serde(skip_serializing_if = "Option::is_none")]
572 pub skill_directories: Option<Vec<String>>,
573 #[serde(skip_serializing_if = "Option::is_none")]
574 pub disabled_skills: Option<Vec<String>>,
575 #[serde(skip_serializing_if = "Option::is_none")]
576 pub infinite_sessions: Option<InfiniteSessionConfig>,
577 #[serde(skip_serializing_if = "Option::is_none")]
579 pub model_capabilities: Option<HashMap<String, serde_json::Value>>,
580 #[serde(skip_serializing_if = "Option::is_none")]
582 pub enable_config_discovery: Option<bool>,
583 #[serde(skip_serializing_if = "Option::is_none")]
585 pub github_token: Option<String>,
586 #[serde(skip_serializing_if = "Option::is_none")]
588 pub request_permission: Option<bool>,
589 #[serde(skip_serializing_if = "Option::is_none")]
591 pub request_user_input: Option<bool>,
592 #[serde(skip_serializing_if = "Option::is_none")]
594 pub hooks: Option<bool>,
595 #[serde(skip)]
597 pub commands: Option<Vec<CommandDefinition>>,
598 #[serde(skip)]
600 pub on_elicitation_request: Option<ElicitationHandlerFn>,
601}
602
603#[derive(Debug, Clone, Serialize, Deserialize)]
609#[serde(rename_all = "camelCase")]
610pub struct CommandContext {
611 pub session_id: String,
612 pub command: String,
613 pub command_name: String,
614 pub args: String,
615}
616
617#[derive(Clone)]
619pub struct CommandHandlerFn(
620 pub Arc<dyn Fn(CommandContext) -> Result<(), Box<dyn std::error::Error + Send + Sync>> + Send + Sync>,
621);
622
623impl std::fmt::Debug for CommandHandlerFn {
624 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
625 f.write_str("<command_handler>")
626 }
627}
628
629#[derive(Debug, Clone)]
631pub struct CommandDefinition {
632 pub name: String,
634 pub description: Option<String>,
636 pub handler: CommandHandlerFn,
638}
639
640#[derive(Debug, Clone, Serialize, Deserialize)]
646#[serde(rename_all = "camelCase")]
647pub struct ElicitationContext {
648 pub session_id: String,
649 pub message: String,
650 #[serde(skip_serializing_if = "Option::is_none")]
651 pub requested_schema: Option<HashMap<String, serde_json::Value>>,
652 #[serde(skip_serializing_if = "Option::is_none")]
653 pub mode: Option<String>,
654 #[serde(skip_serializing_if = "Option::is_none")]
655 pub elicitation_source: Option<String>,
656 #[serde(skip_serializing_if = "Option::is_none")]
657 pub url: Option<String>,
658}
659
660#[derive(Debug, Clone, Serialize, Deserialize)]
662#[serde(rename_all = "camelCase")]
663pub struct ElicitationResult {
664 pub action: String,
666 #[serde(skip_serializing_if = "Option::is_none")]
668 pub content: Option<HashMap<String, serde_json::Value>>,
669}
670
671#[derive(Clone)]
673pub struct ElicitationHandlerFn(
674 pub Arc<dyn Fn(ElicitationContext) -> Result<ElicitationResult, Box<dyn std::error::Error + Send + Sync>> + Send + Sync>,
675);
676
677impl std::fmt::Debug for ElicitationHandlerFn {
678 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
679 f.write_str("<elicitation_handler>")
680 }
681}
682
683#[derive(Debug, Clone, Default, Serialize, Deserialize)]
685#[serde(rename_all = "camelCase")]
686pub struct ResumeSessionConfig {
687 pub session_id: String,
688 #[serde(skip_serializing_if = "Option::is_none")]
689 pub model: Option<String>,
690 #[serde(skip_serializing_if = "Option::is_none")]
691 pub reasoning_effort: Option<ReasoningEffort>,
692 #[serde(skip_serializing_if = "Option::is_none")]
693 pub config_dir: Option<String>,
694 #[serde(skip_serializing_if = "Option::is_none")]
695 pub tools: Option<Vec<ToolDefinition>>,
696 #[serde(skip_serializing_if = "Option::is_none")]
697 pub system_message: Option<SystemMessageConfig>,
698 #[serde(skip_serializing_if = "Option::is_none")]
699 pub available_tools: Option<Vec<String>>,
700 #[serde(skip_serializing_if = "Option::is_none")]
701 pub excluded_tools: Option<Vec<String>>,
702 #[serde(skip_serializing_if = "Option::is_none")]
703 pub provider: Option<ProviderConfig>,
704 #[serde(skip_serializing_if = "Option::is_none")]
705 pub working_directory: Option<String>,
706 #[serde(skip_serializing_if = "Option::is_none")]
707 pub streaming: Option<bool>,
708 #[serde(skip_serializing_if = "Option::is_none")]
710 pub include_sub_agent_streaming_events: Option<bool>,
711 #[serde(skip_serializing_if = "Option::is_none")]
712 pub mcp_servers: Option<HashMap<String, McpServerConfig>>,
713 #[serde(skip_serializing_if = "Option::is_none")]
714 pub custom_agents: Option<Vec<CustomAgentConfig>>,
715 #[serde(skip_serializing_if = "Option::is_none")]
716 pub skill_directories: Option<Vec<String>>,
717 #[serde(skip_serializing_if = "Option::is_none")]
718 pub disabled_skills: Option<Vec<String>>,
719 #[serde(skip_serializing_if = "Option::is_none")]
720 pub infinite_sessions: Option<InfiniteSessionConfig>,
721 #[serde(skip_serializing_if = "Option::is_none")]
723 pub model_capabilities: Option<HashMap<String, serde_json::Value>>,
724 #[serde(skip_serializing_if = "Option::is_none")]
726 pub enable_config_discovery: Option<bool>,
727 #[serde(skip_serializing_if = "Option::is_none")]
729 pub github_token: Option<String>,
730 #[serde(skip_serializing_if = "Option::is_none")]
731 pub disable_resume: Option<bool>,
732 #[serde(skip_serializing_if = "Option::is_none")]
733 pub request_permission: Option<bool>,
734 #[serde(skip_serializing_if = "Option::is_none")]
735 pub request_user_input: Option<bool>,
736 #[serde(skip_serializing_if = "Option::is_none")]
737 pub hooks: Option<bool>,
738}
739
740#[derive(Debug, Clone, Serialize, Deserialize)]
746#[serde(rename_all = "camelCase")]
747pub struct FileAttachment {
748 pub path: String,
749 #[serde(skip_serializing_if = "Option::is_none")]
750 pub display_name: Option<String>,
751}
752
753#[derive(Debug, Clone, Serialize, Deserialize)]
755#[serde(rename_all = "camelCase")]
756pub struct DirectoryAttachment {
757 pub path: String,
758 #[serde(skip_serializing_if = "Option::is_none")]
759 pub display_name: Option<String>,
760}
761
762#[derive(Debug, Clone, Serialize, Deserialize)]
764pub struct SelectionRange {
765 pub start: Position,
766 pub end: Position,
767}
768
769#[derive(Debug, Clone, Serialize, Deserialize)]
771pub struct Position {
772 pub line: u32,
773 pub character: u32,
774}
775
776#[derive(Debug, Clone, Serialize, Deserialize)]
778#[serde(rename_all = "camelCase")]
779pub struct SelectionAttachment {
780 pub file_path: String,
781 pub display_name: String,
782 #[serde(skip_serializing_if = "Option::is_none")]
783 pub selection: Option<SelectionRange>,
784 #[serde(skip_serializing_if = "Option::is_none")]
785 pub text: Option<String>,
786}
787
788#[derive(Debug, Clone, Serialize, Deserialize)]
790#[serde(tag = "type", rename_all = "camelCase")]
791pub enum Attachment {
792 File(FileAttachment),
793 Directory(DirectoryAttachment),
794 Selection(SelectionAttachment),
795}
796
797#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
799pub enum ResponseFormat {
800 #[serde(rename = "text")]
801 Text,
802 #[serde(rename = "image")]
803 Image,
804 #[serde(rename = "json_object")]
805 JsonObject,
806}
807
808#[derive(Debug, Clone, Serialize, Deserialize)]
810#[serde(rename_all = "camelCase")]
811pub struct ImageOptions {
812 #[serde(skip_serializing_if = "Option::is_none")]
813 pub size: Option<String>,
814 #[serde(skip_serializing_if = "Option::is_none")]
815 pub quality: Option<String>,
816 #[serde(skip_serializing_if = "Option::is_none")]
817 pub style: Option<String>,
818}
819
820#[derive(Debug, Clone, Serialize, Deserialize)]
822#[serde(rename_all = "camelCase")]
823pub struct AssistantImageData {
824 pub format: String,
825 pub base64: String,
826 #[serde(skip_serializing_if = "Option::is_none")]
827 pub url: Option<String>,
828 #[serde(skip_serializing_if = "Option::is_none")]
829 pub revised_prompt: Option<String>,
830 pub width: u32,
831 pub height: u32,
832}
833
834#[derive(Debug, Clone, Serialize, Deserialize)]
836#[serde(tag = "type", rename_all = "camelCase")]
837pub enum ContentBlock {
838 #[serde(rename = "text")]
839 Text { text: String },
840 #[serde(rename = "image")]
841 Image { image: AssistantImageData },
842}
843
844#[derive(Debug, Clone, Serialize, Deserialize)]
846#[serde(rename_all = "camelCase")]
847pub struct MessageOptions {
848 pub prompt: String,
849 #[serde(skip_serializing_if = "Option::is_none")]
850 pub attachments: Option<Vec<Attachment>>,
851 #[serde(skip_serializing_if = "Option::is_none")]
852 pub mode: Option<String>,
853 #[serde(skip_serializing_if = "Option::is_none")]
854 pub response_format: Option<ResponseFormat>,
855 #[serde(skip_serializing_if = "Option::is_none")]
856 pub image_options: Option<ImageOptions>,
857 #[serde(skip_serializing_if = "Option::is_none")]
859 pub request_headers: Option<HashMap<String, String>>,
860}
861
862#[derive(Debug, Clone, Serialize, Deserialize)]
871pub struct SessionEvent {
872 pub id: String,
873 pub timestamp: String,
874 #[serde(rename = "parentId")]
875 pub parent_id: Option<String>,
876 #[serde(default)]
877 pub ephemeral: bool,
878 #[serde(rename = "type")]
879 pub event_type: String,
880 pub data: serde_json::Value,
883}
884
885impl SessionEvent {
886 pub fn is_assistant_message(&self) -> bool {
888 self.event_type == "assistant.message"
889 }
890
891 pub fn is_session_idle(&self) -> bool {
893 self.event_type == "session.idle"
894 }
895
896 pub fn is_session_error(&self) -> bool {
898 self.event_type == "session.error"
899 }
900
901 pub fn assistant_message_content(&self) -> Option<&str> {
904 if self.is_assistant_message() {
905 self.data.get("content").and_then(|v| v.as_str())
906 } else {
907 None
908 }
909 }
910
911 pub fn error_message(&self) -> Option<&str> {
913 if self.is_session_error() {
914 self.data.get("message").and_then(|v| v.as_str())
915 } else {
916 None
917 }
918 }
919
920 pub fn error_stack(&self) -> Option<&str> {
922 if self.is_session_error() {
923 self.data.get("stack").and_then(|v| v.as_str())
924 } else {
925 None
926 }
927 }
928}
929
930#[derive(Debug, Clone, Serialize, Deserialize)]
936#[serde(rename_all = "camelCase")]
937pub struct PingResponse {
938 pub message: String,
939 pub timestamp: f64,
940 #[serde(skip_serializing_if = "Option::is_none")]
941 pub protocol_version: Option<u32>,
942}
943
944#[derive(Debug, Clone, Serialize, Deserialize)]
950#[serde(rename_all = "camelCase")]
951pub struct GetStatusResponse {
952 pub version: String,
953 pub protocol_version: u32,
954}
955
956#[derive(Debug, Clone, Serialize, Deserialize)]
958#[serde(rename_all = "camelCase")]
959pub struct GetAuthStatusResponse {
960 pub is_authenticated: bool,
961 #[serde(skip_serializing_if = "Option::is_none")]
962 pub auth_type: Option<String>,
963 #[serde(skip_serializing_if = "Option::is_none")]
964 pub host: Option<String>,
965 #[serde(skip_serializing_if = "Option::is_none")]
966 pub login: Option<String>,
967 #[serde(skip_serializing_if = "Option::is_none")]
968 pub status_message: Option<String>,
969}
970
971#[derive(Debug, Clone, Serialize, Deserialize)]
977#[serde(rename_all = "camelCase")]
978pub struct VisionLimits {
979 pub supported_media_types: Vec<String>,
980 pub max_prompt_images: u32,
981 pub max_prompt_image_size: u64,
982}
983
984#[derive(Debug, Clone, Serialize, Deserialize)]
986#[serde(rename_all = "camelCase")]
987pub struct ModelLimits {
988 #[serde(skip_serializing_if = "Option::is_none")]
989 pub max_prompt_tokens: Option<u64>,
990 pub max_context_window_tokens: u64,
991 #[serde(skip_serializing_if = "Option::is_none")]
992 pub vision: Option<VisionLimits>,
993}
994
995#[derive(Debug, Clone, Serialize, Deserialize)]
997#[serde(rename_all = "camelCase")]
998pub struct ModelSupports {
999 pub vision: bool,
1000 pub reasoning_effort: bool,
1001}
1002
1003#[derive(Debug, Clone, Serialize, Deserialize)]
1005pub struct ModelCapabilities {
1006 pub supports: ModelSupports,
1007 pub limits: ModelLimits,
1008}
1009
1010#[derive(Debug, Clone, Serialize, Deserialize)]
1012pub struct ModelPolicy {
1013 pub state: String,
1014 pub terms: String,
1015}
1016
1017#[derive(Debug, Clone, Serialize, Deserialize)]
1019pub struct ModelBilling {
1020 pub multiplier: f64,
1021}
1022
1023#[derive(Debug, Clone, Serialize, Deserialize)]
1025#[serde(rename_all = "camelCase")]
1026pub struct ModelInfo {
1027 pub id: String,
1028 pub name: String,
1029 pub capabilities: ModelCapabilities,
1030 #[serde(skip_serializing_if = "Option::is_none")]
1031 pub policy: Option<ModelPolicy>,
1032 #[serde(skip_serializing_if = "Option::is_none")]
1033 pub billing: Option<ModelBilling>,
1034 #[serde(skip_serializing_if = "Option::is_none")]
1035 pub supported_reasoning_efforts: Option<Vec<ReasoningEffort>>,
1036 #[serde(skip_serializing_if = "Option::is_none")]
1037 pub default_reasoning_effort: Option<ReasoningEffort>,
1038}
1039
1040#[derive(Debug, Clone, Serialize, Deserialize)]
1046#[serde(rename_all = "camelCase")]
1047pub struct SessionMetadata {
1048 pub session_id: String,
1049 pub start_time: String,
1050 pub modified_time: String,
1051 #[serde(skip_serializing_if = "Option::is_none")]
1052 pub summary: Option<String>,
1053 pub is_remote: bool,
1054}
1055
1056#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
1062pub enum SessionLifecycleEventType {
1063 #[serde(rename = "session.created")]
1064 SessionCreated,
1065 #[serde(rename = "session.deleted")]
1066 SessionDeleted,
1067 #[serde(rename = "session.updated")]
1068 SessionUpdated,
1069 #[serde(rename = "session.foreground")]
1070 SessionForeground,
1071 #[serde(rename = "session.background")]
1072 SessionBackground,
1073}
1074
1075#[derive(Debug, Clone, Serialize, Deserialize)]
1077#[serde(rename_all = "camelCase")]
1078pub struct LifecycleMetadata {
1079 pub start_time: String,
1080 pub modified_time: String,
1081 #[serde(skip_serializing_if = "Option::is_none")]
1082 pub summary: Option<String>,
1083}
1084
1085#[derive(Debug, Clone, Serialize, Deserialize)]
1087#[serde(rename_all = "camelCase")]
1088pub struct SessionLifecycleEvent {
1089 #[serde(rename = "type")]
1090 pub event_type: SessionLifecycleEventType,
1091 pub session_id: String,
1092 #[serde(skip_serializing_if = "Option::is_none")]
1093 pub metadata: Option<LifecycleMetadata>,
1094}
1095
1096#[derive(Debug, Clone, Serialize, Deserialize)]
1102#[serde(rename_all = "camelCase")]
1103pub struct ForegroundSessionInfo {
1104 #[serde(skip_serializing_if = "Option::is_none")]
1105 pub session_id: Option<String>,
1106 #[serde(skip_serializing_if = "Option::is_none")]
1107 pub workspace_path: Option<String>,
1108}
1109
1110#[derive(Debug, Clone, Serialize, Deserialize)]
1116#[serde(rename_all = "camelCase")]
1117pub struct SessionFsConfig {
1118 pub initial_cwd: String,
1119 pub session_state_path: String,
1120 pub conventions: String,
1121}
1122
1123#[derive(Debug, Clone, Serialize, Deserialize)]
1125#[serde(rename_all = "camelCase")]
1126pub struct SessionFsFileInfo {
1127 pub name: String,
1128 pub size: i64,
1129 pub is_directory: bool,
1130 pub is_file: bool,
1131 #[serde(skip_serializing_if = "Option::is_none")]
1132 pub created_at: Option<String>,
1133 #[serde(skip_serializing_if = "Option::is_none")]
1134 pub modified_at: Option<String>,
1135}
1136
1137pub trait SessionFsProvider: Send + Sync {
1142 fn read_file(&self, session_id: &str, path: &str) -> Result<String, Box<dyn std::error::Error + Send + Sync>>;
1143 fn write_file(&self, session_id: &str, path: &str, content: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
1144 fn append_file(&self, session_id: &str, path: &str, content: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
1145 fn exists(&self, session_id: &str, path: &str) -> Result<bool, Box<dyn std::error::Error + Send + Sync>>;
1146 fn stat(&self, session_id: &str, path: &str) -> Result<SessionFsFileInfo, Box<dyn std::error::Error + Send + Sync>>;
1147 fn mkdir(&self, session_id: &str, path: &str, recursive: bool) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
1148 fn readdir(&self, session_id: &str, path: &str) -> Result<Vec<String>, Box<dyn std::error::Error + Send + Sync>>;
1149 fn readdir_with_types(&self, session_id: &str, path: &str) -> Result<Vec<SessionFsFileInfo>, Box<dyn std::error::Error + Send + Sync>>;
1150 fn rm(&self, session_id: &str, path: &str, recursive: bool) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
1151 fn rename(&self, session_id: &str, old_path: &str, new_path: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
1152}
1153
1154#[derive(Debug, Clone)]
1160pub struct CopilotClientOptions {
1161 pub cli_path: Option<String>,
1163 pub cli_args: Vec<String>,
1165 pub cwd: Option<String>,
1167 pub port: u16,
1169 pub use_stdio: bool,
1171 pub cli_url: Option<String>,
1173 pub log_level: String,
1175 pub auto_start: bool,
1177 pub auto_restart: bool,
1179 pub env: Option<HashMap<String, String>>,
1181 pub github_token: Option<String>,
1183 pub use_logged_in_user: Option<bool>,
1185 pub session_idle_timeout_seconds: Option<u64>,
1187 pub session_fs: Option<SessionFsConfig>,
1189}
1190
1191impl Default for CopilotClientOptions {
1192 fn default() -> Self {
1193 Self {
1194 cli_path: None,
1195 cli_args: Vec::new(),
1196 cwd: None,
1197 port: 0,
1198 use_stdio: true,
1199 cli_url: None,
1200 log_level: "info".to_string(),
1201 auto_start: true,
1202 auto_restart: true,
1203 env: None,
1204 github_token: None,
1205 use_logged_in_user: None,
1206 session_idle_timeout_seconds: None,
1207 session_fs: None,
1208 }
1209 }
1210}