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