1use crate::jsonrpc::RequestId;
27use crate::protocol::{
28 methods, AccountLoginCompletedNotification, AccountRateLimitsUpdatedNotification,
29 AccountUpdatedNotification, AgentMessageDeltaNotification, AppListUpdatedNotification,
30 CommandExecOutputDeltaNotification, CommandExecutionOutputDeltaNotification,
31 CommandExecutionRequestApprovalParams, ConfigWarningNotification, ContextCompactedNotification,
32 DeprecationNoticeNotification, ErrorNotification,
33 ExternalAgentConfigImportCompletedNotification, FileChangeOutputDeltaNotification,
34 FileChangePatchUpdatedNotification, FileChangeRequestApprovalParams, FsChangedNotification,
35 FuzzyFileSearchSessionCompletedNotification, FuzzyFileSearchSessionUpdatedNotification,
36 GuardianWarningNotification, HookCompletedNotification, HookStartedNotification,
37 ItemCompletedNotification, ItemGuardianApprovalReviewCompletedNotification,
38 ItemGuardianApprovalReviewStartedNotification, ItemStartedNotification,
39 McpServerOauthLoginCompletedNotification, McpServerStatusUpdatedNotification,
40 McpToolCallProgressNotification, ModelReroutedNotification, ModelVerificationNotification,
41 PlanDeltaNotification, ProcessExitedNotification, ProcessOutputDeltaNotification,
42 ReasoningSummaryPartAddedNotification, ReasoningSummaryTextDeltaNotification,
43 ReasoningTextDeltaNotification, RemoteControlStatusChangedNotification,
44 ServerRequestResolvedNotification, SkillsChangedNotification, TerminalInteractionNotification,
45 ThreadArchivedNotification, ThreadClosedNotification, ThreadDeletedNotification,
46 ThreadGoalClearedNotification, ThreadGoalUpdatedNotification, ThreadNameUpdatedNotification,
47 ThreadRealtimeClosedNotification, ThreadRealtimeErrorNotification,
48 ThreadRealtimeItemAddedNotification, ThreadRealtimeOutputAudioDeltaNotification,
49 ThreadRealtimeSdpNotification, ThreadRealtimeStartedNotification,
50 ThreadRealtimeTranscriptDeltaNotification, ThreadRealtimeTranscriptDoneNotification,
51 ThreadSettingsUpdatedNotification, ThreadStartedNotification, ThreadStatusChangedNotification,
52 ThreadTokenUsageUpdatedNotification, ThreadUnarchivedNotification, TurnCompletedNotification,
53 TurnDiffUpdatedNotification, TurnModerationMetadataNotification, TurnPlanUpdatedNotification,
54 TurnStartedNotification, WarningNotification, WindowsSandboxSetupCompletedNotification,
55 WindowsWorldWritableWarningNotification,
56};
57use serde::{Deserialize, Deserializer, Serialize, Serializer};
58use serde_json::Value;
59
60#[derive(Debug, Clone)]
66pub enum Notification {
67 ThreadStarted(ThreadStartedNotification),
69 ThreadStatusChanged(ThreadStatusChangedNotification),
71 ThreadTokenUsageUpdated(ThreadTokenUsageUpdatedNotification),
73 TurnStarted(TurnStartedNotification),
75 TurnCompleted(TurnCompletedNotification),
77 ItemStarted(ItemStartedNotification),
79 ItemCompleted(ItemCompletedNotification),
81 AgentMessageDelta(AgentMessageDeltaNotification),
83 CmdOutputDelta(CommandExecutionOutputDeltaNotification),
85 FileChangeOutputDelta(FileChangeOutputDeltaNotification),
87 ReasoningDelta(ReasoningSummaryTextDeltaNotification),
89 Error(ErrorNotification),
91 AccountRateLimitsUpdated(AccountRateLimitsUpdatedNotification),
93 McpServerStartupStatusUpdated(McpServerStatusUpdatedNotification),
95 RemoteControlStatusChanged(RemoteControlStatusChangedNotification),
97 McpServerOauthLoginCompleted(McpServerOauthLoginCompletedNotification),
99 FileChangePatchUpdated(FileChangePatchUpdatedNotification),
101 PlanDelta(PlanDeltaNotification),
103 TurnPlanUpdated(TurnPlanUpdatedNotification),
105 TurnDiffUpdated(TurnDiffUpdatedNotification),
107 ReasoningSummaryPartAdded(ReasoningSummaryPartAddedNotification),
109 ReasoningTextDelta(ReasoningTextDeltaNotification),
111 AccountLoginCompleted(AccountLoginCompletedNotification),
113 DeprecationNotice(DeprecationNoticeNotification),
115 GuardianWarning(GuardianWarningNotification),
117 Warning(WarningNotification),
119 ThreadArchived(ThreadArchivedNotification),
121 ThreadClosed(ThreadClosedNotification),
123 ThreadDeleted(ThreadDeletedNotification),
125 ThreadUnarchived(ThreadUnarchivedNotification),
127 ThreadGoalCleared(ThreadGoalClearedNotification),
129 ThreadNameUpdated(ThreadNameUpdatedNotification),
131 SkillsChanged(SkillsChangedNotification),
133 FsChanged(FsChangedNotification),
135 ConfigWarning(ConfigWarningNotification),
137 AccountUpdated(AccountUpdatedNotification),
139 AppListUpdated(AppListUpdatedNotification),
141 CommandExecOutputDelta(CommandExecOutputDeltaNotification),
143 ExternalAgentConfigImportCompleted(ExternalAgentConfigImportCompletedNotification),
145 FuzzyFileSearchSessionCompleted(FuzzyFileSearchSessionCompletedNotification),
147 FuzzyFileSearchSessionUpdated(FuzzyFileSearchSessionUpdatedNotification),
149 HookCompleted(HookCompletedNotification),
151 HookStarted(HookStartedNotification),
153 ItemGuardianApprovalReviewCompleted(ItemGuardianApprovalReviewCompletedNotification),
155 ItemGuardianApprovalReviewStarted(ItemGuardianApprovalReviewStartedNotification),
157 TerminalInteraction(TerminalInteractionNotification),
159 McpToolCallProgress(McpToolCallProgressNotification),
161 ModelRerouted(ModelReroutedNotification),
163 ModelVerification(ModelVerificationNotification),
165 ProcessExited(ProcessExitedNotification),
167 ProcessOutputDelta(ProcessOutputDeltaNotification),
169 ServerRequestResolved(ServerRequestResolvedNotification),
171 ContextCompacted(ContextCompactedNotification),
173 ThreadGoalUpdated(ThreadGoalUpdatedNotification),
175 ThreadRealtimeClosed(ThreadRealtimeClosedNotification),
177 ThreadRealtimeError(ThreadRealtimeErrorNotification),
179 ThreadRealtimeItemAdded(ThreadRealtimeItemAddedNotification),
181 ThreadRealtimeOutputAudioDelta(ThreadRealtimeOutputAudioDeltaNotification),
183 ThreadRealtimeSdp(ThreadRealtimeSdpNotification),
185 ThreadRealtimeStarted(ThreadRealtimeStartedNotification),
187 ThreadRealtimeTranscriptDelta(ThreadRealtimeTranscriptDeltaNotification),
189 ThreadRealtimeTranscriptDone(ThreadRealtimeTranscriptDoneNotification),
191 WindowsWorldWritableWarning(WindowsWorldWritableWarningNotification),
193 WindowsSandboxSetupCompleted(WindowsSandboxSetupCompletedNotification),
195 ThreadSettingsUpdated(ThreadSettingsUpdatedNotification),
197 TurnModerationMetadata(TurnModerationMetadataNotification),
199 Unknown {
203 method: String,
204 params: Option<Value>,
205 },
206}
207
208impl Notification {
209 pub fn method(&self) -> &str {
211 match self {
212 Self::ThreadStarted(_) => methods::THREAD_STARTED,
213 Self::ThreadStatusChanged(_) => methods::THREAD_STATUS_CHANGED,
214 Self::ThreadTokenUsageUpdated(_) => methods::THREAD_TOKEN_USAGE_UPDATED,
215 Self::TurnStarted(_) => methods::TURN_STARTED,
216 Self::TurnCompleted(_) => methods::TURN_COMPLETED,
217 Self::ItemStarted(_) => methods::ITEM_STARTED,
218 Self::ItemCompleted(_) => methods::ITEM_COMPLETED,
219 Self::AgentMessageDelta(_) => methods::AGENT_MESSAGE_DELTA,
220 Self::CmdOutputDelta(_) => methods::CMD_OUTPUT_DELTA,
221 Self::FileChangeOutputDelta(_) => methods::FILE_CHANGE_OUTPUT_DELTA,
222 Self::ReasoningDelta(_) => methods::REASONING_DELTA,
223 Self::Error(_) => methods::ERROR,
224 Self::AccountRateLimitsUpdated(_) => methods::ACCOUNT_RATE_LIMITS_UPDATED,
225 Self::McpServerStartupStatusUpdated(_) => methods::MCP_SERVER_STARTUP_STATUS_UPDATED,
226 Self::RemoteControlStatusChanged(_) => methods::REMOTE_CONTROL_STATUS_CHANGED,
227 Self::McpServerOauthLoginCompleted(_) => methods::MCP_SERVER_OAUTH_LOGIN_COMPLETED,
228 Self::FileChangePatchUpdated(_) => methods::FILE_CHANGE_PATCH_UPDATED,
229 Self::PlanDelta(_) => methods::PLAN_DELTA,
230 Self::TurnPlanUpdated(_) => methods::TURN_PLAN_UPDATED,
231 Self::TurnDiffUpdated(_) => methods::TURN_DIFF_UPDATED,
232 Self::ReasoningSummaryPartAdded(_) => methods::REASONING_SUMMARY_PART_ADDED,
233 Self::ReasoningTextDelta(_) => methods::REASONING_TEXT_DELTA,
234 Self::AccountLoginCompleted(_) => methods::ACCOUNT_LOGIN_COMPLETED,
235 Self::DeprecationNotice(_) => methods::DEPRECATION_NOTICE,
236 Self::GuardianWarning(_) => methods::GUARDIAN_WARNING,
237 Self::Warning(_) => methods::WARNING,
238 Self::ThreadArchived(_) => methods::THREAD_ARCHIVED,
239 Self::ThreadClosed(_) => methods::THREAD_CLOSED,
240 Self::ThreadDeleted(_) => methods::THREAD_DELETED,
241 Self::ThreadUnarchived(_) => methods::THREAD_UNARCHIVED,
242 Self::ThreadGoalCleared(_) => methods::THREAD_GOAL_CLEARED,
243 Self::ThreadNameUpdated(_) => methods::THREAD_NAME_UPDATED,
244 Self::SkillsChanged(_) => methods::SKILLS_CHANGED,
245 Self::FsChanged(_) => methods::FS_CHANGED,
246 Self::ConfigWarning(_) => methods::CONFIG_WARNING,
247 Self::AccountUpdated(_) => methods::ACCOUNT_UPDATED,
248 Self::AppListUpdated(_) => methods::APP_LIST_UPDATED,
249 Self::CommandExecOutputDelta(_) => methods::COMMAND_EXEC_OUTPUT_DELTA,
250 Self::ExternalAgentConfigImportCompleted(_) => {
251 methods::EXTERNAL_AGENT_CONFIG_IMPORT_COMPLETED
252 }
253 Self::FuzzyFileSearchSessionCompleted(_) => {
254 methods::FUZZY_FILE_SEARCH_SESSION_COMPLETED
255 }
256 Self::FuzzyFileSearchSessionUpdated(_) => methods::FUZZY_FILE_SEARCH_SESSION_UPDATED,
257 Self::HookCompleted(_) => methods::HOOK_COMPLETED,
258 Self::HookStarted(_) => methods::HOOK_STARTED,
259 Self::ItemGuardianApprovalReviewCompleted(_) => {
260 methods::ITEM_AUTO_APPROVAL_REVIEW_COMPLETED
261 }
262 Self::ItemGuardianApprovalReviewStarted(_) => {
263 methods::ITEM_AUTO_APPROVAL_REVIEW_STARTED
264 }
265 Self::TerminalInteraction(_) => methods::ITEM_COMMAND_EXEC_TERMINAL_INTERACTION,
266 Self::McpToolCallProgress(_) => methods::ITEM_MCP_TOOL_CALL_PROGRESS,
267 Self::ModelRerouted(_) => methods::MODEL_REROUTED,
268 Self::ModelVerification(_) => methods::MODEL_VERIFICATION,
269 Self::ProcessExited(_) => methods::PROCESS_EXITED,
270 Self::ProcessOutputDelta(_) => methods::PROCESS_OUTPUT_DELTA,
271 Self::ServerRequestResolved(_) => methods::SERVER_REQUEST_RESOLVED,
272 Self::ContextCompacted(_) => methods::THREAD_COMPACTED,
273 Self::ThreadGoalUpdated(_) => methods::THREAD_GOAL_UPDATED,
274 Self::ThreadRealtimeClosed(_) => methods::THREAD_REALTIME_CLOSED,
275 Self::ThreadRealtimeError(_) => methods::THREAD_REALTIME_ERROR,
276 Self::ThreadRealtimeItemAdded(_) => methods::THREAD_REALTIME_ITEM_ADDED,
277 Self::ThreadRealtimeOutputAudioDelta(_) => methods::THREAD_REALTIME_OUTPUT_AUDIO_DELTA,
278 Self::ThreadRealtimeSdp(_) => methods::THREAD_REALTIME_SDP,
279 Self::ThreadRealtimeStarted(_) => methods::THREAD_REALTIME_STARTED,
280 Self::ThreadRealtimeTranscriptDelta(_) => methods::THREAD_REALTIME_TRANSCRIPT_DELTA,
281 Self::ThreadRealtimeTranscriptDone(_) => methods::THREAD_REALTIME_TRANSCRIPT_DONE,
282 Self::WindowsWorldWritableWarning(_) => methods::WINDOWS_WORLD_WRITABLE_WARNING,
283 Self::WindowsSandboxSetupCompleted(_) => methods::WINDOWS_SANDBOX_SETUP_COMPLETED,
284 Self::ThreadSettingsUpdated(_) => methods::THREAD_SETTINGS_UPDATED,
285 Self::TurnModerationMetadata(_) => methods::TURN_MODERATION_METADATA,
286 Self::Unknown { method, .. } => method,
287 }
288 }
289
290 pub fn is_unknown(&self) -> bool {
292 matches!(self, Self::Unknown { .. })
293 }
294
295 pub fn from_envelope(method: &str, params: Option<Value>) -> Result<Self, serde_json::Error> {
301 let params_value = params.clone().unwrap_or(Value::Null);
302 match method {
303 methods::THREAD_STARTED => {
304 serde_json::from_value(params_value).map(Self::ThreadStarted)
305 }
306 methods::THREAD_STATUS_CHANGED => {
307 serde_json::from_value(params_value).map(Self::ThreadStatusChanged)
308 }
309 methods::THREAD_TOKEN_USAGE_UPDATED => {
310 serde_json::from_value(params_value).map(Self::ThreadTokenUsageUpdated)
311 }
312 methods::TURN_STARTED => serde_json::from_value(params_value).map(Self::TurnStarted),
313 methods::TURN_COMPLETED => {
314 serde_json::from_value(params_value).map(Self::TurnCompleted)
315 }
316 methods::ITEM_STARTED => serde_json::from_value(params_value).map(Self::ItemStarted),
317 methods::ITEM_COMPLETED => {
318 serde_json::from_value(params_value).map(Self::ItemCompleted)
319 }
320 methods::AGENT_MESSAGE_DELTA => {
321 serde_json::from_value(params_value).map(Self::AgentMessageDelta)
322 }
323 methods::CMD_OUTPUT_DELTA => {
324 serde_json::from_value(params_value).map(Self::CmdOutputDelta)
325 }
326 methods::FILE_CHANGE_OUTPUT_DELTA => {
327 serde_json::from_value(params_value).map(Self::FileChangeOutputDelta)
328 }
329 methods::REASONING_DELTA => {
330 serde_json::from_value(params_value).map(Self::ReasoningDelta)
331 }
332 methods::ERROR => serde_json::from_value(params_value).map(Self::Error),
333 methods::ACCOUNT_RATE_LIMITS_UPDATED => {
334 serde_json::from_value(params_value).map(Self::AccountRateLimitsUpdated)
335 }
336 methods::MCP_SERVER_STARTUP_STATUS_UPDATED => {
337 serde_json::from_value(params_value).map(Self::McpServerStartupStatusUpdated)
338 }
339 methods::REMOTE_CONTROL_STATUS_CHANGED => {
340 serde_json::from_value(params_value).map(Self::RemoteControlStatusChanged)
341 }
342 methods::MCP_SERVER_OAUTH_LOGIN_COMPLETED => {
343 serde_json::from_value(params_value).map(Self::McpServerOauthLoginCompleted)
344 }
345 methods::FILE_CHANGE_PATCH_UPDATED => {
346 serde_json::from_value(params_value).map(Self::FileChangePatchUpdated)
347 }
348 methods::PLAN_DELTA => serde_json::from_value(params_value).map(Self::PlanDelta),
349 methods::TURN_PLAN_UPDATED => {
350 serde_json::from_value(params_value).map(Self::TurnPlanUpdated)
351 }
352 methods::TURN_DIFF_UPDATED => {
353 serde_json::from_value(params_value).map(Self::TurnDiffUpdated)
354 }
355 methods::REASONING_SUMMARY_PART_ADDED => {
356 serde_json::from_value(params_value).map(Self::ReasoningSummaryPartAdded)
357 }
358 methods::REASONING_TEXT_DELTA => {
359 serde_json::from_value(params_value).map(Self::ReasoningTextDelta)
360 }
361 methods::ACCOUNT_LOGIN_COMPLETED => {
362 serde_json::from_value(params_value).map(Self::AccountLoginCompleted)
363 }
364 methods::DEPRECATION_NOTICE => {
365 serde_json::from_value(params_value).map(Self::DeprecationNotice)
366 }
367 methods::GUARDIAN_WARNING => {
368 serde_json::from_value(params_value).map(Self::GuardianWarning)
369 }
370 methods::WARNING => serde_json::from_value(params_value).map(Self::Warning),
371 methods::THREAD_ARCHIVED => {
372 serde_json::from_value(params_value).map(Self::ThreadArchived)
373 }
374 methods::THREAD_CLOSED => serde_json::from_value(params_value).map(Self::ThreadClosed),
375 methods::THREAD_DELETED => {
376 serde_json::from_value(params_value).map(Self::ThreadDeleted)
377 }
378 methods::THREAD_UNARCHIVED => {
379 serde_json::from_value(params_value).map(Self::ThreadUnarchived)
380 }
381 methods::THREAD_GOAL_CLEARED => {
382 serde_json::from_value(params_value).map(Self::ThreadGoalCleared)
383 }
384 methods::THREAD_NAME_UPDATED => {
385 serde_json::from_value(params_value).map(Self::ThreadNameUpdated)
386 }
387 methods::SKILLS_CHANGED => {
388 serde_json::from_value(params_value).map(Self::SkillsChanged)
389 }
390 methods::FS_CHANGED => serde_json::from_value(params_value).map(Self::FsChanged),
391 methods::CONFIG_WARNING => {
392 serde_json::from_value(params_value).map(Self::ConfigWarning)
393 }
394 methods::ACCOUNT_UPDATED => {
395 serde_json::from_value(params_value).map(Self::AccountUpdated)
396 }
397 methods::APP_LIST_UPDATED => {
398 serde_json::from_value(params_value).map(Self::AppListUpdated)
399 }
400 methods::COMMAND_EXEC_OUTPUT_DELTA => {
401 serde_json::from_value(params_value).map(Self::CommandExecOutputDelta)
402 }
403 methods::EXTERNAL_AGENT_CONFIG_IMPORT_COMPLETED => {
404 serde_json::from_value(params_value).map(Self::ExternalAgentConfigImportCompleted)
405 }
406 methods::FUZZY_FILE_SEARCH_SESSION_COMPLETED => {
407 serde_json::from_value(params_value).map(Self::FuzzyFileSearchSessionCompleted)
408 }
409 methods::FUZZY_FILE_SEARCH_SESSION_UPDATED => {
410 serde_json::from_value(params_value).map(Self::FuzzyFileSearchSessionUpdated)
411 }
412 methods::HOOK_COMPLETED => {
413 serde_json::from_value(params_value).map(Self::HookCompleted)
414 }
415 methods::HOOK_STARTED => serde_json::from_value(params_value).map(Self::HookStarted),
416 methods::ITEM_AUTO_APPROVAL_REVIEW_COMPLETED => {
417 serde_json::from_value(params_value).map(Self::ItemGuardianApprovalReviewCompleted)
418 }
419 methods::ITEM_AUTO_APPROVAL_REVIEW_STARTED => {
420 serde_json::from_value(params_value).map(Self::ItemGuardianApprovalReviewStarted)
421 }
422 methods::ITEM_COMMAND_EXEC_TERMINAL_INTERACTION => {
423 serde_json::from_value(params_value).map(Self::TerminalInteraction)
424 }
425 methods::ITEM_MCP_TOOL_CALL_PROGRESS => {
426 serde_json::from_value(params_value).map(Self::McpToolCallProgress)
427 }
428 methods::MODEL_REROUTED => {
429 serde_json::from_value(params_value).map(Self::ModelRerouted)
430 }
431 methods::MODEL_VERIFICATION => {
432 serde_json::from_value(params_value).map(Self::ModelVerification)
433 }
434 methods::PROCESS_EXITED => {
435 serde_json::from_value(params_value).map(Self::ProcessExited)
436 }
437 methods::PROCESS_OUTPUT_DELTA => {
438 serde_json::from_value(params_value).map(Self::ProcessOutputDelta)
439 }
440 methods::SERVER_REQUEST_RESOLVED => {
441 serde_json::from_value(params_value).map(Self::ServerRequestResolved)
442 }
443 methods::THREAD_COMPACTED => {
444 serde_json::from_value(params_value).map(Self::ContextCompacted)
445 }
446 methods::THREAD_GOAL_UPDATED => {
447 serde_json::from_value(params_value).map(Self::ThreadGoalUpdated)
448 }
449 methods::THREAD_REALTIME_CLOSED => {
450 serde_json::from_value(params_value).map(Self::ThreadRealtimeClosed)
451 }
452 methods::THREAD_REALTIME_ERROR => {
453 serde_json::from_value(params_value).map(Self::ThreadRealtimeError)
454 }
455 methods::THREAD_REALTIME_ITEM_ADDED => {
456 serde_json::from_value(params_value).map(Self::ThreadRealtimeItemAdded)
457 }
458 methods::THREAD_REALTIME_OUTPUT_AUDIO_DELTA => {
459 serde_json::from_value(params_value).map(Self::ThreadRealtimeOutputAudioDelta)
460 }
461 methods::THREAD_REALTIME_SDP => {
462 serde_json::from_value(params_value).map(Self::ThreadRealtimeSdp)
463 }
464 methods::THREAD_REALTIME_STARTED => {
465 serde_json::from_value(params_value).map(Self::ThreadRealtimeStarted)
466 }
467 methods::THREAD_REALTIME_TRANSCRIPT_DELTA => {
468 serde_json::from_value(params_value).map(Self::ThreadRealtimeTranscriptDelta)
469 }
470 methods::THREAD_REALTIME_TRANSCRIPT_DONE => {
471 serde_json::from_value(params_value).map(Self::ThreadRealtimeTranscriptDone)
472 }
473 methods::WINDOWS_WORLD_WRITABLE_WARNING => {
474 serde_json::from_value(params_value).map(Self::WindowsWorldWritableWarning)
475 }
476 methods::WINDOWS_SANDBOX_SETUP_COMPLETED => {
477 serde_json::from_value(params_value).map(Self::WindowsSandboxSetupCompleted)
478 }
479 methods::THREAD_SETTINGS_UPDATED => {
480 serde_json::from_value(params_value).map(Self::ThreadSettingsUpdated)
481 }
482 methods::TURN_MODERATION_METADATA => {
483 serde_json::from_value(params_value).map(Self::TurnModerationMetadata)
484 }
485 _ => Ok(Self::Unknown {
486 method: method.to_string(),
487 params,
488 }),
489 }
490 }
491
492 pub fn into_envelope(self) -> Result<(String, Option<Value>), serde_json::Error> {
494 fn pack<T: Serialize>(
495 method: &str,
496 v: &T,
497 ) -> Result<(String, Option<Value>), serde_json::Error> {
498 Ok((method.to_string(), Some(serde_json::to_value(v)?)))
499 }
500 match &self {
501 Self::ThreadStarted(v) => pack(methods::THREAD_STARTED, v),
502 Self::ThreadStatusChanged(v) => pack(methods::THREAD_STATUS_CHANGED, v),
503 Self::ThreadTokenUsageUpdated(v) => pack(methods::THREAD_TOKEN_USAGE_UPDATED, v),
504 Self::TurnStarted(v) => pack(methods::TURN_STARTED, v),
505 Self::TurnCompleted(v) => pack(methods::TURN_COMPLETED, v),
506 Self::ItemStarted(v) => pack(methods::ITEM_STARTED, v),
507 Self::ItemCompleted(v) => pack(methods::ITEM_COMPLETED, v),
508 Self::AgentMessageDelta(v) => pack(methods::AGENT_MESSAGE_DELTA, v),
509 Self::CmdOutputDelta(v) => pack(methods::CMD_OUTPUT_DELTA, v),
510 Self::FileChangeOutputDelta(v) => pack(methods::FILE_CHANGE_OUTPUT_DELTA, v),
511 Self::ReasoningDelta(v) => pack(methods::REASONING_DELTA, v),
512 Self::Error(v) => pack(methods::ERROR, v),
513 Self::AccountRateLimitsUpdated(v) => pack(methods::ACCOUNT_RATE_LIMITS_UPDATED, v),
514 Self::McpServerStartupStatusUpdated(v) => {
515 pack(methods::MCP_SERVER_STARTUP_STATUS_UPDATED, v)
516 }
517 Self::RemoteControlStatusChanged(v) => pack(methods::REMOTE_CONTROL_STATUS_CHANGED, v),
518 Self::McpServerOauthLoginCompleted(v) => {
519 pack(methods::MCP_SERVER_OAUTH_LOGIN_COMPLETED, v)
520 }
521 Self::FileChangePatchUpdated(v) => pack(methods::FILE_CHANGE_PATCH_UPDATED, v),
522 Self::PlanDelta(v) => pack(methods::PLAN_DELTA, v),
523 Self::TurnPlanUpdated(v) => pack(methods::TURN_PLAN_UPDATED, v),
524 Self::TurnDiffUpdated(v) => pack(methods::TURN_DIFF_UPDATED, v),
525 Self::ReasoningSummaryPartAdded(v) => pack(methods::REASONING_SUMMARY_PART_ADDED, v),
526 Self::ReasoningTextDelta(v) => pack(methods::REASONING_TEXT_DELTA, v),
527 Self::AccountLoginCompleted(v) => pack(methods::ACCOUNT_LOGIN_COMPLETED, v),
528 Self::DeprecationNotice(v) => pack(methods::DEPRECATION_NOTICE, v),
529 Self::GuardianWarning(v) => pack(methods::GUARDIAN_WARNING, v),
530 Self::Warning(v) => pack(methods::WARNING, v),
531 Self::ThreadArchived(v) => pack(methods::THREAD_ARCHIVED, v),
532 Self::ThreadClosed(v) => pack(methods::THREAD_CLOSED, v),
533 Self::ThreadDeleted(v) => pack(methods::THREAD_DELETED, v),
534 Self::ThreadUnarchived(v) => pack(methods::THREAD_UNARCHIVED, v),
535 Self::ThreadGoalCleared(v) => pack(methods::THREAD_GOAL_CLEARED, v),
536 Self::ThreadNameUpdated(v) => pack(methods::THREAD_NAME_UPDATED, v),
537 Self::SkillsChanged(v) => pack(methods::SKILLS_CHANGED, v),
538 Self::FsChanged(v) => pack(methods::FS_CHANGED, v),
539 Self::ConfigWarning(v) => pack(methods::CONFIG_WARNING, v),
540 Self::AccountUpdated(v) => pack(methods::ACCOUNT_UPDATED, v),
541 Self::AppListUpdated(v) => pack(methods::APP_LIST_UPDATED, v),
542 Self::CommandExecOutputDelta(v) => pack(methods::COMMAND_EXEC_OUTPUT_DELTA, v),
543 Self::ExternalAgentConfigImportCompleted(v) => {
544 pack(methods::EXTERNAL_AGENT_CONFIG_IMPORT_COMPLETED, v)
545 }
546 Self::FuzzyFileSearchSessionCompleted(v) => {
547 pack(methods::FUZZY_FILE_SEARCH_SESSION_COMPLETED, v)
548 }
549 Self::FuzzyFileSearchSessionUpdated(v) => {
550 pack(methods::FUZZY_FILE_SEARCH_SESSION_UPDATED, v)
551 }
552 Self::HookCompleted(v) => pack(methods::HOOK_COMPLETED, v),
553 Self::HookStarted(v) => pack(methods::HOOK_STARTED, v),
554 Self::ItemGuardianApprovalReviewCompleted(v) => {
555 pack(methods::ITEM_AUTO_APPROVAL_REVIEW_COMPLETED, v)
556 }
557 Self::ItemGuardianApprovalReviewStarted(v) => {
558 pack(methods::ITEM_AUTO_APPROVAL_REVIEW_STARTED, v)
559 }
560 Self::TerminalInteraction(v) => {
561 pack(methods::ITEM_COMMAND_EXEC_TERMINAL_INTERACTION, v)
562 }
563 Self::McpToolCallProgress(v) => pack(methods::ITEM_MCP_TOOL_CALL_PROGRESS, v),
564 Self::ModelRerouted(v) => pack(methods::MODEL_REROUTED, v),
565 Self::ModelVerification(v) => pack(methods::MODEL_VERIFICATION, v),
566 Self::ProcessExited(v) => pack(methods::PROCESS_EXITED, v),
567 Self::ProcessOutputDelta(v) => pack(methods::PROCESS_OUTPUT_DELTA, v),
568 Self::ServerRequestResolved(v) => pack(methods::SERVER_REQUEST_RESOLVED, v),
569 Self::ContextCompacted(v) => pack(methods::THREAD_COMPACTED, v),
570 Self::ThreadGoalUpdated(v) => pack(methods::THREAD_GOAL_UPDATED, v),
571 Self::ThreadRealtimeClosed(v) => pack(methods::THREAD_REALTIME_CLOSED, v),
572 Self::ThreadRealtimeError(v) => pack(methods::THREAD_REALTIME_ERROR, v),
573 Self::ThreadRealtimeItemAdded(v) => pack(methods::THREAD_REALTIME_ITEM_ADDED, v),
574 Self::ThreadRealtimeOutputAudioDelta(v) => {
575 pack(methods::THREAD_REALTIME_OUTPUT_AUDIO_DELTA, v)
576 }
577 Self::ThreadRealtimeSdp(v) => pack(methods::THREAD_REALTIME_SDP, v),
578 Self::ThreadRealtimeStarted(v) => pack(methods::THREAD_REALTIME_STARTED, v),
579 Self::ThreadRealtimeTranscriptDelta(v) => {
580 pack(methods::THREAD_REALTIME_TRANSCRIPT_DELTA, v)
581 }
582 Self::ThreadRealtimeTranscriptDone(v) => {
583 pack(methods::THREAD_REALTIME_TRANSCRIPT_DONE, v)
584 }
585 Self::WindowsWorldWritableWarning(v) => {
586 pack(methods::WINDOWS_WORLD_WRITABLE_WARNING, v)
587 }
588 Self::WindowsSandboxSetupCompleted(v) => {
589 pack(methods::WINDOWS_SANDBOX_SETUP_COMPLETED, v)
590 }
591 Self::ThreadSettingsUpdated(v) => pack(methods::THREAD_SETTINGS_UPDATED, v),
592 Self::TurnModerationMetadata(v) => pack(methods::TURN_MODERATION_METADATA, v),
593 Self::Unknown { method, params } => Ok((method.clone(), params.clone())),
594 }
595 }
596}
597
598impl Serialize for Notification {
599 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
600 let (method, params) = self
601 .clone()
602 .into_envelope()
603 .map_err(serde::ser::Error::custom)?;
604 let mut env = serde_json::Map::new();
605 env.insert("method".to_string(), Value::String(method));
606 if let Some(p) = params {
607 env.insert("params".to_string(), p);
608 }
609 Value::Object(env).serialize(serializer)
610 }
611}
612
613impl<'de> Deserialize<'de> for Notification {
614 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
615 let value = Value::deserialize(deserializer)?;
616 let method = value
617 .get("method")
618 .and_then(|v| v.as_str())
619 .ok_or_else(|| serde::de::Error::missing_field("method"))?
620 .to_string();
621 let params = value.get("params").cloned();
622 Self::from_envelope(&method, params).map_err(serde::de::Error::custom)
623 }
624}
625
626#[derive(Debug, Clone)]
633pub enum ServerRequest {
634 CmdExecApproval(CommandExecutionRequestApprovalParams),
636 FileChangeApproval(FileChangeRequestApprovalParams),
638 ToolRequestUserInput(crate::protocol::ToolRequestUserInputParams),
640 McpServerElicitationRequest(crate::protocol::McpServerElicitationRequestParams),
642 PermissionsRequestApproval(crate::protocol::PermissionsRequestApprovalParams),
644 ItemToolCall(crate::protocol::DynamicToolCallParams),
646 ChatgptAuthTokensRefresh(crate::protocol::ChatgptAuthTokensRefreshParams),
648 AttestationGenerate(crate::protocol::AttestationGenerateParams),
650 ApplyPatchApproval(crate::protocol::ApplyPatchApprovalParams),
652 ExecCommandApproval(crate::protocol::ExecCommandApprovalParams),
654 Unknown {
656 method: String,
657 params: Option<Value>,
658 },
659}
660
661impl ServerRequest {
662 pub fn method(&self) -> &str {
664 match self {
665 Self::CmdExecApproval(_) => methods::CMD_EXEC_APPROVAL,
666 Self::FileChangeApproval(_) => methods::FILE_CHANGE_APPROVAL,
667 Self::ToolRequestUserInput(_) => methods::TOOL_REQUEST_USER_INPUT,
668 Self::McpServerElicitationRequest(_) => methods::MCP_SERVER_ELICITATION_REQUEST,
669 Self::PermissionsRequestApproval(_) => methods::PERMISSIONS_REQUEST_APPROVAL,
670 Self::ItemToolCall(_) => methods::ITEM_TOOL_CALL,
671 Self::ChatgptAuthTokensRefresh(_) => methods::CHATGPT_AUTH_TOKENS_REFRESH,
672 Self::AttestationGenerate(_) => methods::ATTESTATION_GENERATE,
673 Self::ApplyPatchApproval(_) => methods::APPLY_PATCH_APPROVAL,
674 Self::ExecCommandApproval(_) => methods::EXEC_COMMAND_APPROVAL,
675 Self::Unknown { method, .. } => method,
676 }
677 }
678
679 pub fn is_unknown(&self) -> bool {
681 matches!(self, Self::Unknown { .. })
682 }
683
684 pub fn from_envelope(method: &str, params: Option<Value>) -> Result<Self, serde_json::Error> {
686 let params_value = params.clone().unwrap_or(Value::Null);
687 match method {
688 methods::CMD_EXEC_APPROVAL => {
689 serde_json::from_value(params_value).map(Self::CmdExecApproval)
690 }
691 methods::FILE_CHANGE_APPROVAL => {
692 serde_json::from_value(params_value).map(Self::FileChangeApproval)
693 }
694 methods::TOOL_REQUEST_USER_INPUT => {
695 serde_json::from_value(params_value).map(Self::ToolRequestUserInput)
696 }
697 methods::MCP_SERVER_ELICITATION_REQUEST => {
698 serde_json::from_value(params_value).map(Self::McpServerElicitationRequest)
699 }
700 methods::PERMISSIONS_REQUEST_APPROVAL => {
701 serde_json::from_value(params_value).map(Self::PermissionsRequestApproval)
702 }
703 methods::ITEM_TOOL_CALL => serde_json::from_value(params_value).map(Self::ItemToolCall),
704 methods::CHATGPT_AUTH_TOKENS_REFRESH => {
705 serde_json::from_value(params_value).map(Self::ChatgptAuthTokensRefresh)
706 }
707 methods::ATTESTATION_GENERATE => {
708 serde_json::from_value(params_value).map(Self::AttestationGenerate)
709 }
710 methods::APPLY_PATCH_APPROVAL => {
711 serde_json::from_value(params_value).map(Self::ApplyPatchApproval)
712 }
713 methods::EXEC_COMMAND_APPROVAL => {
714 serde_json::from_value(params_value).map(Self::ExecCommandApproval)
715 }
716 _ => Ok(Self::Unknown {
717 method: method.to_string(),
718 params,
719 }),
720 }
721 }
722}
723
724#[derive(Debug, Clone)]
731pub enum ServerMessage {
732 Notification(Notification),
734 Request {
736 id: RequestId,
737 request: ServerRequest,
738 },
739}
740
741impl ServerMessage {
742 pub fn is_unknown(&self) -> bool {
744 match self {
745 Self::Notification(n) => n.is_unknown(),
746 Self::Request { request, .. } => request.is_unknown(),
747 }
748 }
749}
750
751#[cfg(test)]
752mod tests {
753 use super::*;
754
755 #[test]
756 fn test_notification_unknown_method_routes_to_unknown_variant() {
757 let n = Notification::from_envelope("foo/bar", Some(serde_json::json!({"x": 1})))
758 .expect("unknown methods do not error");
759 match n {
760 Notification::Unknown { method, params } => {
761 assert_eq!(method, "foo/bar");
762 assert_eq!(params, Some(serde_json::json!({"x": 1})));
763 }
764 other => panic!("expected Unknown, got {:?}", other),
765 }
766 }
767
768 #[test]
769 fn test_notification_known_method_with_bad_params_errors() {
770 let err = Notification::from_envelope("thread/started", Some(serde_json::json!({})));
772 assert!(err.is_err());
773 }
774
775 #[test]
776 fn test_notification_round_trip_envelope() {
777 let wire = serde_json::json!({
778 "method": "item/agentMessage/delta",
779 "params": {"threadId": "t1", "turnId": "u1", "itemId": "i1", "delta": "hi"},
780 });
781 let n: Notification = serde_json::from_value(wire.clone()).unwrap();
782 assert!(matches!(n, Notification::AgentMessageDelta(_)));
783 let back = serde_json::to_value(&n).unwrap();
784 assert_eq!(back, wire);
785 }
786}