1use crate::io::items::ThreadItem;
34use serde::{Deserialize, Serialize};
35use serde_json::Value;
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
53#[serde(tag = "type", rename_all = "camelCase")]
54pub enum UserInput {
55 Text { text: String },
57 Image { data: String },
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
69#[serde(rename_all = "camelCase")]
70pub struct ClientInfo {
71 pub name: String,
73 pub version: String,
75 #[serde(skip_serializing_if = "Option::is_none")]
77 pub title: Option<String>,
78}
79
80#[derive(Debug, Clone, Default, Serialize, Deserialize)]
82#[serde(rename_all = "camelCase")]
83pub struct InitializeCapabilities {
84 #[serde(default)]
86 pub experimental_api: bool,
87 #[serde(skip_serializing_if = "Option::is_none")]
89 pub opt_out_notification_methods: Option<Vec<String>>,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
96#[serde(rename_all = "camelCase")]
97pub struct InitializeParams {
98 pub client_info: ClientInfo,
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub capabilities: Option<InitializeCapabilities>,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107#[serde(rename_all = "camelCase")]
108pub struct InitializeResponse {
109 pub user_agent: String,
111}
112
113#[derive(Debug, Clone, Default, Serialize, Deserialize)]
121#[serde(rename_all = "camelCase")]
122pub struct ThreadStartParams {
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub instructions: Option<String>,
126 #[serde(skip_serializing_if = "Option::is_none")]
128 pub tools: Option<Vec<Value>>,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
133#[serde(rename_all = "camelCase")]
134pub struct ThreadInfo {
135 pub id: String,
137 #[serde(flatten)]
139 pub extra: Value,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
144#[serde(rename_all = "camelCase")]
145pub struct ThreadStartResponse {
146 pub thread: ThreadInfo,
148 #[serde(default)]
150 pub model: Option<String>,
151 #[serde(flatten)]
153 pub extra: Value,
154}
155
156impl ThreadStartResponse {
157 pub fn thread_id(&self) -> &str {
159 &self.thread.id
160 }
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
165#[serde(rename_all = "camelCase")]
166pub struct ThreadArchiveParams {
167 pub thread_id: String,
168}
169
170#[derive(Debug, Clone, Default, Serialize, Deserialize)]
172#[serde(rename_all = "camelCase")]
173pub struct ThreadArchiveResponse {}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
184#[serde(rename_all = "camelCase")]
185pub struct TurnStartParams {
186 pub thread_id: String,
188 pub input: Vec<UserInput>,
190 #[serde(skip_serializing_if = "Option::is_none")]
192 pub model: Option<String>,
193 #[serde(skip_serializing_if = "Option::is_none")]
195 pub reasoning_effort: Option<String>,
196 #[serde(skip_serializing_if = "Option::is_none")]
198 pub sandbox_policy: Option<Value>,
199}
200
201#[derive(Debug, Clone, Default, Serialize, Deserialize)]
203#[serde(rename_all = "camelCase")]
204pub struct TurnStartResponse {}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
208#[serde(rename_all = "camelCase")]
209pub struct TurnInterruptParams {
210 pub thread_id: String,
211}
212
213#[derive(Debug, Clone, Default, Serialize, Deserialize)]
215#[serde(rename_all = "camelCase")]
216pub struct TurnInterruptResponse {}
217
218#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
224#[serde(rename_all = "camelCase")]
225pub enum TurnStatus {
226 Completed,
228 Interrupted,
230 Failed,
232 InProgress,
234}
235
236#[derive(Debug, Clone, Serialize, Deserialize)]
238#[serde(rename_all = "camelCase")]
239pub struct TurnError {
240 pub message: String,
241 #[serde(skip_serializing_if = "Option::is_none")]
242 pub codex_error_info: Option<Value>,
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize)]
249#[serde(rename_all = "camelCase")]
250pub struct Turn {
251 pub id: String,
253 #[serde(default)]
255 pub items: Vec<ThreadItem>,
256 pub status: TurnStatus,
258 #[serde(skip_serializing_if = "Option::is_none")]
260 pub error: Option<TurnError>,
261}
262
263#[derive(Debug, Clone, Default, Serialize, Deserialize)]
270#[serde(rename_all = "camelCase")]
271pub struct TokenCounts {
272 #[serde(default)]
274 pub input_tokens: u64,
275 #[serde(default)]
277 pub output_tokens: u64,
278 #[serde(default)]
280 pub cached_input_tokens: u64,
281 #[serde(default)]
283 pub reasoning_output_tokens: u64,
284 #[serde(default)]
286 pub total_tokens: u64,
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize)]
295#[serde(rename_all = "camelCase")]
296pub struct TokenUsage {
297 pub last: TokenCounts,
299 pub total: TokenCounts,
301 pub model_context_window: u64,
303}
304
305#[derive(Debug, Clone, Serialize, Deserialize)]
314#[serde(tag = "type", rename_all = "camelCase")]
315pub enum ThreadStatus {
316 NotLoaded,
318 Idle,
320 Active {
322 #[serde(default, skip_serializing_if = "Vec::is_empty")]
325 active_flags: Vec<Value>,
326 },
327 SystemError,
329}
330
331#[derive(Debug, Clone, Serialize, Deserialize)]
340#[serde(rename_all = "camelCase")]
341pub struct ThreadStartedNotification {
342 pub thread: ThreadInfo,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize)]
347#[serde(rename_all = "camelCase")]
348pub struct ThreadStatusChangedNotification {
349 pub thread_id: String,
350 pub status: ThreadStatus,
351}
352
353#[derive(Debug, Clone, Serialize, Deserialize)]
357#[serde(rename_all = "camelCase")]
358pub struct TurnStartedNotification {
359 pub thread_id: String,
360 pub turn: Turn,
361}
362
363#[derive(Debug, Clone, Serialize, Deserialize)]
367#[serde(rename_all = "camelCase")]
368pub struct TurnCompletedNotification {
369 pub thread_id: String,
370 pub turn: Turn,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize)]
375#[serde(rename_all = "camelCase")]
376pub struct ItemStartedNotification {
377 pub thread_id: String,
378 pub turn_id: String,
379 #[serde(default, skip_serializing_if = "Option::is_none")]
382 pub started_at_ms: Option<i64>,
383 pub item: ThreadItem,
384}
385
386#[derive(Debug, Clone, Serialize, Deserialize)]
388#[serde(rename_all = "camelCase")]
389pub struct ItemCompletedNotification {
390 pub thread_id: String,
391 pub turn_id: String,
392 #[serde(default, skip_serializing_if = "Option::is_none")]
395 pub completed_at_ms: Option<i64>,
396 pub item: ThreadItem,
397}
398
399#[derive(Debug, Clone, Serialize, Deserialize)]
401#[serde(rename_all = "camelCase")]
402pub struct AgentMessageDeltaNotification {
403 pub thread_id: String,
404 pub item_id: String,
405 pub delta: String,
406}
407
408#[derive(Debug, Clone, Serialize, Deserialize)]
410#[serde(rename_all = "camelCase")]
411pub struct CmdOutputDeltaNotification {
412 pub thread_id: String,
413 pub item_id: String,
414 pub delta: String,
415}
416
417#[derive(Debug, Clone, Serialize, Deserialize)]
419#[serde(rename_all = "camelCase")]
420pub struct FileChangeOutputDeltaNotification {
421 pub thread_id: String,
422 pub item_id: String,
423 pub delta: String,
424}
425
426#[derive(Debug, Clone, Serialize, Deserialize)]
428#[serde(rename_all = "camelCase")]
429pub struct ReasoningDeltaNotification {
430 pub thread_id: String,
431 pub item_id: String,
432 pub delta: String,
433}
434
435#[derive(Debug, Clone, Serialize, Deserialize)]
437#[serde(rename_all = "camelCase")]
438pub struct ErrorNotification {
439 pub error: String,
440 #[serde(skip_serializing_if = "Option::is_none")]
441 pub thread_id: Option<String>,
442 #[serde(skip_serializing_if = "Option::is_none")]
443 pub turn_id: Option<String>,
444 #[serde(default)]
445 pub will_retry: bool,
446}
447
448#[derive(Debug, Clone, Serialize, Deserialize)]
452#[serde(rename_all = "camelCase")]
453pub struct ThreadTokenUsageUpdatedNotification {
454 pub thread_id: String,
455 #[serde(default, skip_serializing_if = "Option::is_none")]
458 pub turn_id: Option<String>,
459 pub token_usage: TokenUsage,
460}
461
462#[derive(Debug, Clone, Serialize, Deserialize)]
464#[serde(rename_all = "camelCase")]
465pub struct RateLimitWindow {
466 pub resets_at: i64,
468 pub used_percent: i32,
470 pub window_duration_mins: i64,
472}
473
474#[derive(Debug, Clone, Serialize, Deserialize)]
476#[serde(rename_all = "camelCase")]
477pub struct RateLimits {
478 #[serde(default, skip_serializing_if = "Option::is_none")]
481 pub credits: Option<Value>,
482 pub limit_id: String,
484 #[serde(default, skip_serializing_if = "Option::is_none")]
486 pub limit_name: Option<String>,
487 pub plan_type: String,
489 #[serde(default, skip_serializing_if = "Option::is_none")]
491 pub primary: Option<RateLimitWindow>,
492 #[serde(default, skip_serializing_if = "Option::is_none")]
494 pub secondary: Option<RateLimitWindow>,
495 #[serde(default, skip_serializing_if = "Option::is_none")]
497 pub rate_limit_reached_type: Option<String>,
498}
499
500#[derive(Debug, Clone, Serialize, Deserialize)]
502#[serde(rename_all = "camelCase")]
503pub struct AccountRateLimitsUpdatedNotification {
504 pub rate_limits: RateLimits,
505}
506
507#[derive(Debug, Clone, Serialize, Deserialize)]
512#[serde(rename_all = "camelCase")]
513pub struct McpServerStartupStatusUpdatedNotification {
514 pub name: String,
516 pub status: String,
519 #[serde(default, skip_serializing_if = "Option::is_none")]
521 pub error: Option<String>,
522}
523
524#[derive(Debug, Clone, Serialize, Deserialize)]
526#[serde(rename_all = "camelCase")]
527pub struct RemoteControlStatusChangedNotification {
528 pub status: String,
530 #[serde(default, skip_serializing_if = "Option::is_none")]
532 pub environment_id: Option<String>,
533}
534
535#[derive(Debug, Clone, Serialize, Deserialize)]
540#[serde(rename_all = "camelCase")]
541pub struct FileChangePatchUpdatedNotification {
542 pub thread_id: String,
543 pub turn_id: String,
544 pub item_id: String,
545 pub changes: Vec<crate::FileUpdateChange>,
546}
547
548#[derive(Debug, Clone, Serialize, Deserialize)]
553#[serde(rename_all = "camelCase")]
554pub struct PlanDeltaNotification {
555 pub thread_id: String,
556 pub turn_id: String,
557 pub item_id: String,
558 pub delta: String,
559}
560
561#[derive(Debug, Clone, Serialize, Deserialize)]
563#[serde(rename_all = "camelCase")]
564pub struct TurnPlanStep {
565 pub step: String,
566 pub status: TurnPlanStepStatus,
567}
568
569#[derive(Debug, Clone, Serialize, Deserialize)]
571#[serde(rename_all = "camelCase")]
572pub enum TurnPlanStepStatus {
573 Pending,
574 InProgress,
575 Completed,
576}
577
578#[derive(Debug, Clone, Serialize, Deserialize)]
583#[serde(rename_all = "camelCase")]
584pub struct TurnPlanUpdatedNotification {
585 pub thread_id: String,
586 pub turn_id: String,
587 pub plan: Vec<TurnPlanStep>,
588 #[serde(default, skip_serializing_if = "Option::is_none")]
589 pub explanation: Option<String>,
590}
591
592#[derive(Debug, Clone, Serialize, Deserialize)]
597#[serde(rename_all = "camelCase")]
598pub struct TurnDiffUpdatedNotification {
599 pub thread_id: String,
600 pub turn_id: String,
601 pub diff: String,
602}
603
604#[derive(Debug, Clone, Serialize, Deserialize)]
609#[serde(rename_all = "camelCase")]
610pub struct ReasoningSummaryPartAddedNotification {
611 pub thread_id: String,
612 pub turn_id: String,
613 pub item_id: String,
614 pub summary_index: i64,
615}
616
617#[derive(Debug, Clone, Serialize, Deserialize)]
622#[serde(rename_all = "camelCase")]
623pub struct ReasoningTextDeltaNotification {
624 pub thread_id: String,
625 pub turn_id: String,
626 pub item_id: String,
627 pub content_index: i64,
628 pub delta: String,
629}
630
631#[derive(Debug, Clone, Serialize, Deserialize)]
635#[serde(rename_all = "camelCase")]
636pub struct McpServerOauthLoginCompletedNotification {
637 pub name: String,
638 pub success: bool,
639 #[serde(default, skip_serializing_if = "Option::is_none")]
640 pub error: Option<String>,
641}
642
643#[derive(Debug, Clone, Serialize, Deserialize)]
645#[serde(rename_all = "camelCase")]
646pub struct AccountLoginCompletedNotification {
647 pub success: bool,
648 #[serde(default, skip_serializing_if = "Option::is_none")]
649 pub login_id: Option<String>,
650 #[serde(default, skip_serializing_if = "Option::is_none")]
651 pub error: Option<String>,
652}
653
654#[derive(Debug, Clone, Serialize, Deserialize)]
656#[serde(rename_all = "camelCase")]
657pub struct DeprecationNoticeNotification {
658 pub summary: String,
659 #[serde(default, skip_serializing_if = "Option::is_none")]
660 pub details: Option<String>,
661}
662
663#[derive(Debug, Clone, Serialize, Deserialize)]
665#[serde(rename_all = "camelCase")]
666pub struct GuardianWarningNotification {
667 pub thread_id: String,
668 pub message: String,
669}
670
671#[derive(Debug, Clone, Serialize, Deserialize)]
673#[serde(rename_all = "camelCase")]
674pub struct WarningNotification {
675 pub message: String,
676 #[serde(default, skip_serializing_if = "Option::is_none")]
677 pub thread_id: Option<String>,
678}
679
680#[derive(Debug, Clone, Serialize, Deserialize)]
682#[serde(rename_all = "camelCase")]
683pub struct ThreadArchivedNotification {
684 pub thread_id: String,
685}
686
687#[derive(Debug, Clone, Serialize, Deserialize)]
689#[serde(rename_all = "camelCase")]
690pub struct ThreadClosedNotification {
691 pub thread_id: String,
692}
693
694#[derive(Debug, Clone, Serialize, Deserialize)]
696#[serde(rename_all = "camelCase")]
697pub struct ThreadUnarchivedNotification {
698 pub thread_id: String,
699}
700
701#[derive(Debug, Clone, Serialize, Deserialize)]
703#[serde(rename_all = "camelCase")]
704pub struct ThreadGoalClearedNotification {
705 pub thread_id: String,
706}
707
708#[derive(Debug, Clone, Serialize, Deserialize)]
710#[serde(rename_all = "camelCase")]
711pub struct ThreadNameUpdatedNotification {
712 pub thread_id: String,
713 #[serde(default, skip_serializing_if = "Option::is_none")]
714 pub thread_name: Option<String>,
715}
716
717#[derive(Debug, Clone, Default, Serialize, Deserialize)]
719#[serde(rename_all = "camelCase")]
720pub struct SkillsChangedNotification {}
721
722#[derive(Debug, Clone, Serialize, Deserialize)]
724#[serde(rename_all = "camelCase")]
725pub struct FsChangedNotification {
726 pub watch_id: String,
727 pub changed_paths: Vec<String>,
728}
729
730#[derive(Debug, Clone, Serialize, Deserialize)]
735#[serde(rename_all = "camelCase")]
736pub struct ConfigWarningNotification {
737 pub summary: String,
738 #[serde(default, skip_serializing_if = "Option::is_none")]
739 pub path: Option<String>,
740 #[serde(default, skip_serializing_if = "Option::is_none")]
741 pub details: Option<String>,
742 #[serde(default, skip_serializing_if = "Option::is_none")]
743 pub range: Option<Value>,
744}
745
746#[derive(Debug, Clone, Serialize, Deserialize, Default)]
755#[serde(transparent)]
756pub struct AccountUpdatedNotification(pub Value);
757
758#[derive(Debug, Clone, Serialize, Deserialize, Default)]
760#[serde(transparent)]
761pub struct AppListUpdatedNotification(pub Value);
762
763#[derive(Debug, Clone, Serialize, Deserialize, Default)]
765#[serde(transparent)]
766pub struct CommandExecOutputDeltaNotification(pub Value);
767
768#[derive(Debug, Clone, Serialize, Deserialize, Default)]
770#[serde(transparent)]
771pub struct ExternalAgentConfigImportCompletedNotification(pub Value);
772
773#[derive(Debug, Clone, Serialize, Deserialize, Default)]
775#[serde(transparent)]
776pub struct FuzzyFileSearchSessionCompletedNotification(pub Value);
777
778#[derive(Debug, Clone, Serialize, Deserialize, Default)]
780#[serde(transparent)]
781pub struct FuzzyFileSearchSessionUpdatedNotification(pub Value);
782
783#[derive(Debug, Clone, Serialize, Deserialize, Default)]
785#[serde(transparent)]
786pub struct HookCompletedNotification(pub Value);
787
788#[derive(Debug, Clone, Serialize, Deserialize, Default)]
790#[serde(transparent)]
791pub struct HookStartedNotification(pub Value);
792
793#[derive(Debug, Clone, Serialize, Deserialize, Default)]
795#[serde(transparent)]
796pub struct ItemGuardianApprovalReviewCompletedNotification(pub Value);
797
798#[derive(Debug, Clone, Serialize, Deserialize, Default)]
800#[serde(transparent)]
801pub struct ItemGuardianApprovalReviewStartedNotification(pub Value);
802
803#[derive(Debug, Clone, Serialize, Deserialize, Default)]
805#[serde(transparent)]
806pub struct TerminalInteractionNotification(pub Value);
807
808#[derive(Debug, Clone, Serialize, Deserialize, Default)]
810#[serde(transparent)]
811pub struct McpToolCallProgressNotification(pub Value);
812
813#[derive(Debug, Clone, Serialize, Deserialize, Default)]
815#[serde(transparent)]
816pub struct ModelReroutedNotification(pub Value);
817
818#[derive(Debug, Clone, Serialize, Deserialize, Default)]
820#[serde(transparent)]
821pub struct ModelVerificationNotification(pub Value);
822
823#[derive(Debug, Clone, Serialize, Deserialize, Default)]
825#[serde(transparent)]
826pub struct ProcessExitedNotification(pub Value);
827
828#[derive(Debug, Clone, Serialize, Deserialize, Default)]
830#[serde(transparent)]
831pub struct ProcessOutputDeltaNotification(pub Value);
832
833#[derive(Debug, Clone, Serialize, Deserialize, Default)]
835#[serde(transparent)]
836pub struct ServerRequestResolvedNotification(pub Value);
837
838#[derive(Debug, Clone, Serialize, Deserialize, Default)]
840#[serde(transparent)]
841pub struct ContextCompactedNotification(pub Value);
842
843#[derive(Debug, Clone, Serialize, Deserialize, Default)]
845#[serde(transparent)]
846pub struct ThreadGoalUpdatedNotification(pub Value);
847
848#[derive(Debug, Clone, Serialize, Deserialize, Default)]
850#[serde(transparent)]
851pub struct ThreadRealtimeClosedNotification(pub Value);
852
853#[derive(Debug, Clone, Serialize, Deserialize, Default)]
855#[serde(transparent)]
856pub struct ThreadRealtimeErrorNotification(pub Value);
857
858#[derive(Debug, Clone, Serialize, Deserialize, Default)]
860#[serde(transparent)]
861pub struct ThreadRealtimeItemAddedNotification(pub Value);
862
863#[derive(Debug, Clone, Serialize, Deserialize, Default)]
865#[serde(transparent)]
866pub struct ThreadRealtimeOutputAudioDeltaNotification(pub Value);
867
868#[derive(Debug, Clone, Serialize, Deserialize, Default)]
870#[serde(transparent)]
871pub struct ThreadRealtimeSdpNotification(pub Value);
872
873#[derive(Debug, Clone, Serialize, Deserialize, Default)]
875#[serde(transparent)]
876pub struct ThreadRealtimeStartedNotification(pub Value);
877
878#[derive(Debug, Clone, Serialize, Deserialize, Default)]
880#[serde(transparent)]
881pub struct ThreadRealtimeTranscriptDeltaNotification(pub Value);
882
883#[derive(Debug, Clone, Serialize, Deserialize, Default)]
885#[serde(transparent)]
886pub struct ThreadRealtimeTranscriptDoneNotification(pub Value);
887
888#[derive(Debug, Clone, Serialize, Deserialize, Default)]
890#[serde(transparent)]
891pub struct WindowsWorldWritableWarningNotification(pub Value);
892
893#[derive(Debug, Clone, Serialize, Deserialize, Default)]
895#[serde(transparent)]
896pub struct WindowsSandboxSetupCompletedNotification(pub Value);
897
898#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
907#[serde(rename_all = "camelCase")]
908pub enum CommandApprovalDecision {
909 Accept,
911 AcceptForSession,
913 Decline,
915 Cancel,
917}
918
919#[derive(Debug, Clone, Serialize, Deserialize)]
925#[serde(rename_all = "camelCase")]
926pub struct CommandExecutionApprovalParams {
927 pub thread_id: String,
928 pub turn_id: String,
929 pub call_id: String,
931 pub command: String,
933 pub cwd: String,
935 #[serde(skip_serializing_if = "Option::is_none")]
937 pub reason: Option<String>,
938}
939
940#[derive(Debug, Clone, Serialize, Deserialize)]
942#[serde(rename_all = "camelCase")]
943pub struct CommandExecutionApprovalResponse {
944 pub decision: CommandApprovalDecision,
945}
946
947#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
952#[serde(rename_all = "camelCase")]
953pub enum FileChangeApprovalDecision {
954 Accept,
956 AcceptForSession,
958 Decline,
960 Cancel,
962}
963
964#[derive(Debug, Clone, Serialize, Deserialize)]
970#[serde(rename_all = "camelCase")]
971pub struct FileChangeApprovalParams {
972 pub thread_id: String,
973 pub turn_id: String,
974 pub call_id: String,
976 pub changes: Value,
978 #[serde(skip_serializing_if = "Option::is_none")]
980 pub reason: Option<String>,
981}
982
983#[derive(Debug, Clone, Serialize, Deserialize)]
985#[serde(rename_all = "camelCase")]
986pub struct FileChangeApprovalResponse {
987 pub decision: FileChangeApprovalDecision,
988}
989
990pub mod methods {
1003 pub const INITIALIZE: &str = "initialize";
1005 pub const INITIALIZED: &str = "initialized";
1006 pub const THREAD_START: &str = "thread/start";
1007 pub const THREAD_ARCHIVE: &str = "thread/archive";
1008 pub const TURN_START: &str = "turn/start";
1009 pub const TURN_INTERRUPT: &str = "turn/interrupt";
1010 pub const TURN_STEER: &str = "turn/steer";
1011 pub const THREAD_RESUME: &str = "thread/resume";
1014 pub const THREAD_FORK: &str = "thread/fork";
1015 pub const THREAD_UNSUBSCRIBE: &str = "thread/unsubscribe";
1016 pub const THREAD_NAME_SET: &str = "thread/name/set";
1017 pub const THREAD_METADATA_UPDATE: &str = "thread/metadata/update";
1018 pub const THREAD_UNARCHIVE: &str = "thread/unarchive";
1019 pub const THREAD_COMPACT_START: &str = "thread/compact/start";
1020 pub const THREAD_SHELLCOMMAND: &str = "thread/shellCommand";
1021 pub const THREAD_APPROVEGUARDIANDENIEDACTION: &str = "thread/approveGuardianDeniedAction";
1022 pub const THREAD_ROLLBACK: &str = "thread/rollback";
1023 pub const THREAD_LIST: &str = "thread/list";
1024 pub const THREAD_LOADED_LIST: &str = "thread/loaded/list";
1025 pub const THREAD_READ: &str = "thread/read";
1026 pub const THREAD_INJECT_ITEMS: &str = "thread/inject_items";
1027 pub const SKILLS_LIST: &str = "skills/list";
1028 pub const HOOKS_LIST: &str = "hooks/list";
1029 pub const MARKETPLACE_ADD: &str = "marketplace/add";
1030 pub const MARKETPLACE_REMOVE: &str = "marketplace/remove";
1031 pub const MARKETPLACE_UPGRADE: &str = "marketplace/upgrade";
1032 pub const PLUGIN_LIST: &str = "plugin/list";
1033 pub const PLUGIN_READ: &str = "plugin/read";
1034 pub const PLUGIN_SKILL_READ: &str = "plugin/skill/read";
1035 pub const PLUGIN_SHARE_SAVE: &str = "plugin/share/save";
1036 pub const PLUGIN_SHARE_UPDATETARGETS: &str = "plugin/share/updateTargets";
1037 pub const PLUGIN_SHARE_LIST: &str = "plugin/share/list";
1038 pub const PLUGIN_SHARE_CHECKOUT: &str = "plugin/share/checkout";
1039 pub const PLUGIN_SHARE_DELETE: &str = "plugin/share/delete";
1040 pub const APP_LIST: &str = "app/list";
1041 pub const FS_READFILE: &str = "fs/readFile";
1042 pub const FS_WRITEFILE: &str = "fs/writeFile";
1043 pub const FS_CREATEDIRECTORY: &str = "fs/createDirectory";
1044 pub const FS_GETMETADATA: &str = "fs/getMetadata";
1045 pub const FS_READDIRECTORY: &str = "fs/readDirectory";
1046 pub const FS_REMOVE: &str = "fs/remove";
1047 pub const FS_COPY: &str = "fs/copy";
1048 pub const FS_WATCH: &str = "fs/watch";
1049 pub const FS_UNWATCH: &str = "fs/unwatch";
1050 pub const SKILLS_CONFIG_WRITE: &str = "skills/config/write";
1051 pub const PLUGIN_INSTALL: &str = "plugin/install";
1052 pub const PLUGIN_UNINSTALL: &str = "plugin/uninstall";
1053 pub const REVIEW_START: &str = "review/start";
1054 pub const MODEL_LIST: &str = "model/list";
1055 pub const MODELPROVIDER_CAPABILITIES_READ: &str = "modelProvider/capabilities/read";
1056 pub const EXPERIMENTALFEATURE_LIST: &str = "experimentalFeature/list";
1057 pub const EXPERIMENTALFEATURE_ENABLEMENT_SET: &str = "experimentalFeature/enablement/set";
1058 pub const MCPSERVER_OAUTH_LOGIN: &str = "mcpServer/oauth/login";
1059 pub const CONFIG_MCPSERVER_RELOAD: &str = "config/mcpServer/reload";
1060 pub const MCPSERVERSTATUS_LIST: &str = "mcpServerStatus/list";
1061 pub const MCPSERVER_RESOURCE_READ: &str = "mcpServer/resource/read";
1062 pub const MCPSERVER_TOOL_CALL: &str = "mcpServer/tool/call";
1063 pub const WINDOWSSANDBOX_SETUPSTART: &str = "windowsSandbox/setupStart";
1064 pub const WINDOWSSANDBOX_READINESS: &str = "windowsSandbox/readiness";
1065 pub const ACCOUNT_LOGIN_START: &str = "account/login/start";
1066 pub const ACCOUNT_LOGIN_CANCEL: &str = "account/login/cancel";
1067 pub const ACCOUNT_LOGOUT: &str = "account/logout";
1068 pub const ACCOUNT_RATELIMITS_READ: &str = "account/rateLimits/read";
1069 pub const ACCOUNT_SENDADDCREDITSNUDGEEMAIL: &str = "account/sendAddCreditsNudgeEmail";
1070 pub const FEEDBACK_UPLOAD: &str = "feedback/upload";
1071 pub const COMMAND_EXEC: &str = "command/exec";
1072 pub const COMMAND_EXEC_WRITE: &str = "command/exec/write";
1073 pub const COMMAND_EXEC_TERMINATE: &str = "command/exec/terminate";
1074 pub const COMMAND_EXEC_RESIZE: &str = "command/exec/resize";
1075 pub const CONFIG_READ: &str = "config/read";
1076 pub const EXTERNALAGENTCONFIG_DETECT: &str = "externalAgentConfig/detect";
1077 pub const EXTERNALAGENTCONFIG_IMPORT: &str = "externalAgentConfig/import";
1078 pub const CONFIG_VALUE_WRITE: &str = "config/value/write";
1079 pub const CONFIG_BATCHWRITE: &str = "config/batchWrite";
1080 pub const CONFIGREQUIREMENTS_READ: &str = "configRequirements/read";
1081 pub const ACCOUNT_READ: &str = "account/read";
1082 pub const FUZZYFILESEARCH: &str = "fuzzyFileSearch";
1083
1084 pub const THREAD_STARTED: &str = "thread/started";
1086 pub const THREAD_STATUS_CHANGED: &str = "thread/status/changed";
1087 pub const THREAD_TOKEN_USAGE_UPDATED: &str = "thread/tokenUsage/updated";
1088 pub const TURN_STARTED: &str = "turn/started";
1089 pub const TURN_COMPLETED: &str = "turn/completed";
1090 pub const ITEM_STARTED: &str = "item/started";
1091 pub const ITEM_COMPLETED: &str = "item/completed";
1092 pub const AGENT_MESSAGE_DELTA: &str = "item/agentMessage/delta";
1093 pub const CMD_OUTPUT_DELTA: &str = "item/commandExecution/outputDelta";
1094 pub const FILE_CHANGE_OUTPUT_DELTA: &str = "item/fileChange/outputDelta";
1095 pub const REASONING_DELTA: &str = "item/reasoning/summaryTextDelta";
1096 pub const ERROR: &str = "error";
1097 pub const ACCOUNT_RATE_LIMITS_UPDATED: &str = "account/rateLimits/updated";
1098 pub const MCP_SERVER_STARTUP_STATUS_UPDATED: &str = "mcpServer/startupStatus/updated";
1099 pub const MCP_SERVER_OAUTH_LOGIN_COMPLETED: &str = "mcpServer/oauthLogin/completed";
1100 pub const REMOTE_CONTROL_STATUS_CHANGED: &str = "remoteControl/status/changed";
1101 pub const FILE_CHANGE_PATCH_UPDATED: &str = "item/fileChange/patchUpdated";
1102 pub const PLAN_DELTA: &str = "item/plan/delta";
1103 pub const TURN_PLAN_UPDATED: &str = "turn/plan/updated";
1104 pub const TURN_DIFF_UPDATED: &str = "turn/diff/updated";
1105 pub const REASONING_SUMMARY_PART_ADDED: &str = "item/reasoning/summaryPartAdded";
1106 pub const REASONING_TEXT_DELTA: &str = "item/reasoning/textDelta";
1107 pub const ACCOUNT_LOGIN_COMPLETED: &str = "account/login/completed";
1108 pub const DEPRECATION_NOTICE: &str = "deprecationNotice";
1109 pub const GUARDIAN_WARNING: &str = "guardianWarning";
1110 pub const WARNING: &str = "warning";
1111 pub const THREAD_ARCHIVED: &str = "thread/archived";
1112 pub const THREAD_CLOSED: &str = "thread/closed";
1113 pub const THREAD_UNARCHIVED: &str = "thread/unarchived";
1114 pub const THREAD_GOAL_CLEARED: &str = "thread/goal/cleared";
1115 pub const THREAD_NAME_UPDATED: &str = "thread/name/updated";
1116 pub const SKILLS_CHANGED: &str = "skills/changed";
1117 pub const FS_CHANGED: &str = "fs/changed";
1118 pub const CONFIG_WARNING: &str = "configWarning";
1119 pub const ACCOUNT_UPDATED: &str = "account/updated";
1120 pub const APP_LIST_UPDATED: &str = "app/list/updated";
1121 pub const COMMAND_EXEC_OUTPUT_DELTA: &str = "command/exec/outputDelta";
1122 pub const EXTERNAL_AGENT_CONFIG_IMPORT_COMPLETED: &str = "externalAgentConfig/import/completed";
1123 pub const FUZZY_FILE_SEARCH_SESSION_COMPLETED: &str = "fuzzyFileSearch/sessionCompleted";
1124 pub const FUZZY_FILE_SEARCH_SESSION_UPDATED: &str = "fuzzyFileSearch/sessionUpdated";
1125 pub const HOOK_COMPLETED: &str = "hook/completed";
1126 pub const HOOK_STARTED: &str = "hook/started";
1127 pub const ITEM_AUTO_APPROVAL_REVIEW_COMPLETED: &str = "item/autoApprovalReview/completed";
1128 pub const ITEM_AUTO_APPROVAL_REVIEW_STARTED: &str = "item/autoApprovalReview/started";
1129 pub const ITEM_COMMAND_EXEC_TERMINAL_INTERACTION: &str =
1130 "item/commandExecution/terminalInteraction";
1131 pub const ITEM_MCP_TOOL_CALL_PROGRESS: &str = "item/mcpToolCall/progress";
1132 pub const MODEL_REROUTED: &str = "model/rerouted";
1133 pub const MODEL_VERIFICATION: &str = "model/verification";
1134 pub const PROCESS_EXITED: &str = "process/exited";
1135 pub const PROCESS_OUTPUT_DELTA: &str = "process/outputDelta";
1136 pub const SERVER_REQUEST_RESOLVED: &str = "serverRequest/resolved";
1137 pub const THREAD_COMPACTED: &str = "thread/compacted";
1138 pub const THREAD_GOAL_UPDATED: &str = "thread/goal/updated";
1139 pub const THREAD_REALTIME_CLOSED: &str = "thread/realtime/closed";
1140 pub const THREAD_REALTIME_ERROR: &str = "thread/realtime/error";
1141 pub const THREAD_REALTIME_ITEM_ADDED: &str = "thread/realtime/itemAdded";
1142 pub const THREAD_REALTIME_OUTPUT_AUDIO_DELTA: &str = "thread/realtime/outputAudio/delta";
1143 pub const THREAD_REALTIME_SDP: &str = "thread/realtime/sdp";
1144 pub const THREAD_REALTIME_STARTED: &str = "thread/realtime/started";
1145 pub const THREAD_REALTIME_TRANSCRIPT_DELTA: &str = "thread/realtime/transcript/delta";
1146 pub const THREAD_REALTIME_TRANSCRIPT_DONE: &str = "thread/realtime/transcript/done";
1147 pub const WINDOWS_WORLD_WRITABLE_WARNING: &str = "windows/worldWritableWarning";
1148 pub const WINDOWS_SANDBOX_SETUP_COMPLETED: &str = "windowsSandbox/setupCompleted";
1149
1150 pub const CMD_EXEC_APPROVAL: &str = "item/commandExecution/requestApproval";
1152 pub const FILE_CHANGE_APPROVAL: &str = "item/fileChange/requestApproval";
1153}
1154
1155#[cfg(test)]
1156mod tests {
1157 use super::*;
1158
1159 #[test]
1160 fn test_initialize_params() {
1161 let params = InitializeParams {
1162 client_info: ClientInfo {
1163 name: "my-app".to_string(),
1164 version: "1.0.0".to_string(),
1165 title: Some("My App".to_string()),
1166 },
1167 capabilities: None,
1168 };
1169 let json = serde_json::to_string(¶ms).unwrap();
1170 assert!(json.contains("clientInfo"));
1171 assert!(json.contains("my-app"));
1172 assert!(!json.contains("capabilities"));
1173 }
1174
1175 #[test]
1176 fn test_initialize_response() {
1177 let json = r#"{"userAgent":"codex-cli/0.104.0"}"#;
1178 let resp: InitializeResponse = serde_json::from_str(json).unwrap();
1179 assert_eq!(resp.user_agent, "codex-cli/0.104.0");
1180 }
1181
1182 #[test]
1183 fn test_initialize_capabilities() {
1184 let params = InitializeParams {
1185 client_info: ClientInfo {
1186 name: "test".to_string(),
1187 version: "0.1.0".to_string(),
1188 title: None,
1189 },
1190 capabilities: Some(InitializeCapabilities {
1191 experimental_api: true,
1192 opt_out_notification_methods: Some(vec!["thread/started".to_string()]),
1193 }),
1194 };
1195 let json = serde_json::to_string(¶ms).unwrap();
1196 assert!(json.contains("experimentalApi"));
1197 assert!(json.contains("optOutNotificationMethods"));
1198 }
1199
1200 #[test]
1201 fn test_user_input_text() {
1202 let input = UserInput::Text {
1203 text: "Hello".to_string(),
1204 };
1205 let json = serde_json::to_string(&input).unwrap();
1206 assert!(json.contains(r#""type":"text""#));
1207 let parsed: UserInput = serde_json::from_str(&json).unwrap();
1208 assert!(matches!(parsed, UserInput::Text { text } if text == "Hello"));
1209 }
1210
1211 #[test]
1212 fn test_thread_start_params() {
1213 let params = ThreadStartParams {
1214 instructions: Some("Be helpful".to_string()),
1215 tools: None,
1216 };
1217 let json = serde_json::to_string(¶ms).unwrap();
1218 assert!(json.contains("instructions"));
1219 assert!(!json.contains("tools"));
1220 }
1221
1222 #[test]
1223 fn test_thread_start_response() {
1224 let json = r#"{"thread":{"id":"th_abc123"},"model":"gpt-4","approvalPolicy":"never","cwd":"/tmp","modelProvider":"openai","sandbox":{}}"#;
1225 let resp: ThreadStartResponse = serde_json::from_str(json).unwrap();
1226 assert_eq!(resp.thread_id(), "th_abc123");
1227 assert_eq!(resp.model.as_deref(), Some("gpt-4"));
1228 }
1229
1230 #[test]
1231 fn test_turn_start_params() {
1232 let params = TurnStartParams {
1233 thread_id: "th_1".to_string(),
1234 input: vec![UserInput::Text {
1235 text: "What is 2+2?".to_string(),
1236 }],
1237 model: None,
1238 reasoning_effort: None,
1239 sandbox_policy: None,
1240 };
1241 let json = serde_json::to_string(¶ms).unwrap();
1242 assert!(json.contains("threadId"));
1243 assert!(json.contains("input"));
1244 }
1245
1246 #[test]
1247 fn test_turn_status() {
1248 let json = r#""completed""#;
1249 let status: TurnStatus = serde_json::from_str(json).unwrap();
1250 assert_eq!(status, TurnStatus::Completed);
1251 }
1252
1253 #[test]
1254 fn test_turn_completed_notification() {
1255 let json = r#"{
1256 "threadId": "th_1",
1257 "turnId": "t_1",
1258 "turn": {
1259 "id": "t_1",
1260 "items": [],
1261 "status": "completed"
1262 }
1263 }"#;
1264 let notif: TurnCompletedNotification = serde_json::from_str(json).unwrap();
1265 assert_eq!(notif.thread_id, "th_1");
1266 assert_eq!(notif.turn.status, TurnStatus::Completed);
1267 }
1268
1269 #[test]
1270 fn test_agent_message_delta() {
1271 let json = r#"{"threadId":"th_1","itemId":"msg_1","delta":"Hello "}"#;
1272 let notif: AgentMessageDeltaNotification = serde_json::from_str(json).unwrap();
1273 assert_eq!(notif.delta, "Hello ");
1274 }
1275
1276 #[test]
1277 fn test_command_approval_decision() {
1278 let json = r#""accept""#;
1279 let decision: CommandApprovalDecision = serde_json::from_str(json).unwrap();
1280 assert_eq!(decision, CommandApprovalDecision::Accept);
1281
1282 let json = r#""acceptForSession""#;
1283 let decision: CommandApprovalDecision = serde_json::from_str(json).unwrap();
1284 assert_eq!(decision, CommandApprovalDecision::AcceptForSession);
1285 }
1286
1287 #[test]
1288 fn test_command_approval_params() {
1289 let json = r#"{
1290 "threadId": "th_1",
1291 "turnId": "t_1",
1292 "callId": "call_1",
1293 "command": "rm -rf /tmp/test",
1294 "cwd": "/home/user"
1295 }"#;
1296 let params: CommandExecutionApprovalParams = serde_json::from_str(json).unwrap();
1297 assert_eq!(params.command, "rm -rf /tmp/test");
1298 }
1299
1300 #[test]
1301 fn test_error_notification() {
1302 let json = r#"{"error":"something failed","willRetry":true}"#;
1303 let notif: ErrorNotification = serde_json::from_str(json).unwrap();
1304 assert_eq!(notif.error, "something failed");
1305 assert!(notif.will_retry);
1306 }
1307
1308 #[test]
1309 fn test_thread_status_idle() {
1310 let json = r#"{"type":"idle"}"#;
1311 let status: ThreadStatus = serde_json::from_str(json).unwrap();
1312 assert!(matches!(status, ThreadStatus::Idle));
1313 }
1314
1315 #[test]
1316 fn test_thread_status_active_with_flags() {
1317 let json = r#"{"type":"active","activeFlags":[]}"#;
1318 let status: ThreadStatus = serde_json::from_str(json).unwrap();
1319 match status {
1320 ThreadStatus::Active { active_flags } => assert!(active_flags.is_empty()),
1321 other => panic!("expected Active, got {:?}", other),
1322 }
1323 }
1324
1325 #[test]
1326 fn test_token_usage() {
1327 let json = r#"{
1328 "last":{"inputTokens":100,"outputTokens":200,"cachedInputTokens":50,"reasoningOutputTokens":0,"totalTokens":300},
1329 "total":{"inputTokens":1000,"outputTokens":2000,"cachedInputTokens":500,"reasoningOutputTokens":10,"totalTokens":3000},
1330 "modelContextWindow":200000
1331 }"#;
1332 let usage: TokenUsage = serde_json::from_str(json).unwrap();
1333 assert_eq!(usage.last.input_tokens, 100);
1334 assert_eq!(usage.last.output_tokens, 200);
1335 assert_eq!(usage.last.cached_input_tokens, 50);
1336 assert_eq!(usage.total.input_tokens, 1000);
1337 assert_eq!(usage.model_context_window, 200000);
1338 }
1339}