source dump of claude code
at main 663 lines 20 kB view raw
1/** 2 * SDK Control Schemas - Zod schemas for the control protocol. 3 * 4 * These schemas define the control protocol between SDK implementations and the CLI. 5 * Used by SDK builders (e.g., Python SDK) to communicate with the CLI process. 6 * 7 * SDK consumers should use coreSchemas.ts instead. 8 */ 9 10import { z } from 'zod/v4' 11import { lazySchema } from '../../utils/lazySchema.js' 12import { 13 AccountInfoSchema, 14 AgentDefinitionSchema, 15 AgentInfoSchema, 16 FastModeStateSchema, 17 HookEventSchema, 18 HookInputSchema, 19 McpServerConfigForProcessTransportSchema, 20 McpServerStatusSchema, 21 ModelInfoSchema, 22 PermissionModeSchema, 23 PermissionUpdateSchema, 24 SDKMessageSchema, 25 SDKPostTurnSummaryMessageSchema, 26 SDKStreamlinedTextMessageSchema, 27 SDKStreamlinedToolUseSummaryMessageSchema, 28 SDKUserMessageSchema, 29 SlashCommandSchema, 30} from './coreSchemas.js' 31 32// ============================================================================ 33// External Type Placeholders 34// ============================================================================ 35 36// JSONRPCMessage from @modelcontextprotocol/sdk - treat as unknown 37export const JSONRPCMessagePlaceholder = lazySchema(() => z.unknown()) 38 39// ============================================================================ 40// Hook Callback Types 41// ============================================================================ 42 43export const SDKHookCallbackMatcherSchema = lazySchema(() => 44 z 45 .object({ 46 matcher: z.string().optional(), 47 hookCallbackIds: z.array(z.string()), 48 timeout: z.number().optional(), 49 }) 50 .describe('Configuration for matching and routing hook callbacks.'), 51) 52 53// ============================================================================ 54// Control Request Types 55// ============================================================================ 56 57export const SDKControlInitializeRequestSchema = lazySchema(() => 58 z 59 .object({ 60 subtype: z.literal('initialize'), 61 hooks: z 62 .record(HookEventSchema(), z.array(SDKHookCallbackMatcherSchema())) 63 .optional(), 64 sdkMcpServers: z.array(z.string()).optional(), 65 jsonSchema: z.record(z.string(), z.unknown()).optional(), 66 systemPrompt: z.string().optional(), 67 appendSystemPrompt: z.string().optional(), 68 agents: z.record(z.string(), AgentDefinitionSchema()).optional(), 69 promptSuggestions: z.boolean().optional(), 70 agentProgressSummaries: z.boolean().optional(), 71 }) 72 .describe( 73 'Initializes the SDK session with hooks, MCP servers, and agent configuration.', 74 ), 75) 76 77export const SDKControlInitializeResponseSchema = lazySchema(() => 78 z 79 .object({ 80 commands: z.array(SlashCommandSchema()), 81 agents: z.array(AgentInfoSchema()), 82 output_style: z.string(), 83 available_output_styles: z.array(z.string()), 84 models: z.array(ModelInfoSchema()), 85 account: AccountInfoSchema(), 86 pid: z 87 .number() 88 .optional() 89 .describe('@internal CLI process PID for tmux socket isolation'), 90 fast_mode_state: FastModeStateSchema().optional(), 91 }) 92 .describe( 93 'Response from session initialization with available commands, models, and account info.', 94 ), 95) 96 97export const SDKControlInterruptRequestSchema = lazySchema(() => 98 z 99 .object({ 100 subtype: z.literal('interrupt'), 101 }) 102 .describe('Interrupts the currently running conversation turn.'), 103) 104 105 106export const SDKControlPermissionRequestSchema = lazySchema(() => 107 z 108 .object({ 109 subtype: z.literal('can_use_tool'), 110 tool_name: z.string(), 111 input: z.record(z.string(), z.unknown()), 112 permission_suggestions: z.array(PermissionUpdateSchema()).optional(), 113 blocked_path: z.string().optional(), 114 decision_reason: z.string().optional(), 115 title: z.string().optional(), 116 display_name: z.string().optional(), 117 tool_use_id: z.string(), 118 agent_id: z.string().optional(), 119 description: z.string().optional(), 120 }) 121 .describe('Requests permission to use a tool with the given input.'), 122) 123 124export const SDKControlSetPermissionModeRequestSchema = lazySchema(() => 125 z 126 .object({ 127 subtype: z.literal('set_permission_mode'), 128 mode: PermissionModeSchema(), 129 ultraplan: z 130 .boolean() 131 .optional() 132 .describe('@internal CCR ultraplan session marker.'), 133 }) 134 .describe('Sets the permission mode for tool execution handling.'), 135) 136 137export const SDKControlSetModelRequestSchema = lazySchema(() => 138 z 139 .object({ 140 subtype: z.literal('set_model'), 141 model: z.string().optional(), 142 }) 143 .describe('Sets the model to use for subsequent conversation turns.'), 144) 145 146export const SDKControlSetMaxThinkingTokensRequestSchema = lazySchema(() => 147 z 148 .object({ 149 subtype: z.literal('set_max_thinking_tokens'), 150 max_thinking_tokens: z.number().nullable(), 151 }) 152 .describe( 153 'Sets the maximum number of thinking tokens for extended thinking.', 154 ), 155) 156 157export const SDKControlMcpStatusRequestSchema = lazySchema(() => 158 z 159 .object({ 160 subtype: z.literal('mcp_status'), 161 }) 162 .describe('Requests the current status of all MCP server connections.'), 163) 164 165export const SDKControlMcpStatusResponseSchema = lazySchema(() => 166 z 167 .object({ 168 mcpServers: z.array(McpServerStatusSchema()), 169 }) 170 .describe( 171 'Response containing the current status of all MCP server connections.', 172 ), 173) 174 175export const SDKControlGetContextUsageRequestSchema = lazySchema(() => 176 z 177 .object({ 178 subtype: z.literal('get_context_usage'), 179 }) 180 .describe( 181 'Requests a breakdown of current context window usage by category.', 182 ), 183) 184 185const ContextCategorySchema = lazySchema(() => 186 z.object({ 187 name: z.string(), 188 tokens: z.number(), 189 color: z.string(), 190 isDeferred: z.boolean().optional(), 191 }), 192) 193 194const ContextGridSquareSchema = lazySchema(() => 195 z.object({ 196 color: z.string(), 197 isFilled: z.boolean(), 198 categoryName: z.string(), 199 tokens: z.number(), 200 percentage: z.number(), 201 squareFullness: z.number(), 202 }), 203) 204 205export const SDKControlGetContextUsageResponseSchema = lazySchema(() => 206 z 207 .object({ 208 categories: z.array(ContextCategorySchema()), 209 totalTokens: z.number(), 210 maxTokens: z.number(), 211 rawMaxTokens: z.number(), 212 percentage: z.number(), 213 gridRows: z.array(z.array(ContextGridSquareSchema())), 214 model: z.string(), 215 memoryFiles: z.array( 216 z.object({ 217 path: z.string(), 218 type: z.string(), 219 tokens: z.number(), 220 }), 221 ), 222 mcpTools: z.array( 223 z.object({ 224 name: z.string(), 225 serverName: z.string(), 226 tokens: z.number(), 227 isLoaded: z.boolean().optional(), 228 }), 229 ), 230 deferredBuiltinTools: z 231 .array( 232 z.object({ 233 name: z.string(), 234 tokens: z.number(), 235 isLoaded: z.boolean(), 236 }), 237 ) 238 .optional(), 239 systemTools: z 240 .array(z.object({ name: z.string(), tokens: z.number() })) 241 .optional(), 242 systemPromptSections: z 243 .array(z.object({ name: z.string(), tokens: z.number() })) 244 .optional(), 245 agents: z.array( 246 z.object({ 247 agentType: z.string(), 248 source: z.string(), 249 tokens: z.number(), 250 }), 251 ), 252 slashCommands: z 253 .object({ 254 totalCommands: z.number(), 255 includedCommands: z.number(), 256 tokens: z.number(), 257 }) 258 .optional(), 259 skills: z 260 .object({ 261 totalSkills: z.number(), 262 includedSkills: z.number(), 263 tokens: z.number(), 264 skillFrontmatter: z.array( 265 z.object({ 266 name: z.string(), 267 source: z.string(), 268 tokens: z.number(), 269 }), 270 ), 271 }) 272 .optional(), 273 autoCompactThreshold: z.number().optional(), 274 isAutoCompactEnabled: z.boolean(), 275 messageBreakdown: z 276 .object({ 277 toolCallTokens: z.number(), 278 toolResultTokens: z.number(), 279 attachmentTokens: z.number(), 280 assistantMessageTokens: z.number(), 281 userMessageTokens: z.number(), 282 toolCallsByType: z.array( 283 z.object({ 284 name: z.string(), 285 callTokens: z.number(), 286 resultTokens: z.number(), 287 }), 288 ), 289 attachmentsByType: z.array( 290 z.object({ name: z.string(), tokens: z.number() }), 291 ), 292 }) 293 .optional(), 294 apiUsage: z 295 .object({ 296 input_tokens: z.number(), 297 output_tokens: z.number(), 298 cache_creation_input_tokens: z.number(), 299 cache_read_input_tokens: z.number(), 300 }) 301 .nullable(), 302 }) 303 .describe( 304 'Breakdown of current context window usage by category (system prompt, tools, messages, etc.).', 305 ), 306) 307 308export const SDKControlRewindFilesRequestSchema = lazySchema(() => 309 z 310 .object({ 311 subtype: z.literal('rewind_files'), 312 user_message_id: z.string(), 313 dry_run: z.boolean().optional(), 314 }) 315 .describe('Rewinds file changes made since a specific user message.'), 316) 317 318export const SDKControlRewindFilesResponseSchema = lazySchema(() => 319 z 320 .object({ 321 canRewind: z.boolean(), 322 error: z.string().optional(), 323 filesChanged: z.array(z.string()).optional(), 324 insertions: z.number().optional(), 325 deletions: z.number().optional(), 326 }) 327 .describe('Result of a rewindFiles operation.'), 328) 329 330export const SDKControlCancelAsyncMessageRequestSchema = lazySchema(() => 331 z 332 .object({ 333 subtype: z.literal('cancel_async_message'), 334 message_uuid: z.string(), 335 }) 336 .describe( 337 'Drops a pending async user message from the command queue by uuid. No-op if already dequeued for execution.', 338 ), 339) 340 341export const SDKControlCancelAsyncMessageResponseSchema = lazySchema(() => 342 z 343 .object({ 344 cancelled: z.boolean(), 345 }) 346 .describe( 347 'Result of a cancel_async_message operation. cancelled=false means the message was not in the queue (already dequeued or never enqueued).', 348 ), 349) 350 351export const SDKControlSeedReadStateRequestSchema = lazySchema(() => 352 z 353 .object({ 354 subtype: z.literal('seed_read_state'), 355 path: z.string(), 356 mtime: z.number(), 357 }) 358 .describe( 359 'Seeds the readFileState cache with a path+mtime entry. Use when a prior Read was removed from context (e.g. by snip) so Edit validation would fail despite the client having observed the Read. The mtime lets the CLI detect if the file changed since the seeded Read — same staleness check as the normal path.', 360 ), 361) 362 363export const SDKHookCallbackRequestSchema = lazySchema(() => 364 z 365 .object({ 366 subtype: z.literal('hook_callback'), 367 callback_id: z.string(), 368 input: HookInputSchema(), 369 tool_use_id: z.string().optional(), 370 }) 371 .describe('Delivers a hook callback with its input data.'), 372) 373 374export const SDKControlMcpMessageRequestSchema = lazySchema(() => 375 z 376 .object({ 377 subtype: z.literal('mcp_message'), 378 server_name: z.string(), 379 message: JSONRPCMessagePlaceholder(), 380 }) 381 .describe('Sends a JSON-RPC message to a specific MCP server.'), 382) 383 384export const SDKControlMcpSetServersRequestSchema = lazySchema(() => 385 z 386 .object({ 387 subtype: z.literal('mcp_set_servers'), 388 servers: z.record(z.string(), McpServerConfigForProcessTransportSchema()), 389 }) 390 .describe('Replaces the set of dynamically managed MCP servers.'), 391) 392 393export const SDKControlMcpSetServersResponseSchema = lazySchema(() => 394 z 395 .object({ 396 added: z.array(z.string()), 397 removed: z.array(z.string()), 398 errors: z.record(z.string(), z.string()), 399 }) 400 .describe( 401 'Result of replacing the set of dynamically managed MCP servers.', 402 ), 403) 404 405export const SDKControlReloadPluginsRequestSchema = lazySchema(() => 406 z 407 .object({ 408 subtype: z.literal('reload_plugins'), 409 }) 410 .describe( 411 'Reloads plugins from disk and returns the refreshed session components.', 412 ), 413) 414 415export const SDKControlReloadPluginsResponseSchema = lazySchema(() => 416 z 417 .object({ 418 commands: z.array(SlashCommandSchema()), 419 agents: z.array(AgentInfoSchema()), 420 plugins: z.array( 421 z.object({ 422 name: z.string(), 423 path: z.string(), 424 source: z.string().optional(), 425 }), 426 ), 427 mcpServers: z.array(McpServerStatusSchema()), 428 error_count: z.number(), 429 }) 430 .describe( 431 'Refreshed commands, agents, plugins, and MCP server status after reload.', 432 ), 433) 434 435export const SDKControlMcpReconnectRequestSchema = lazySchema(() => 436 z 437 .object({ 438 subtype: z.literal('mcp_reconnect'), 439 serverName: z.string(), 440 }) 441 .describe('Reconnects a disconnected or failed MCP server.'), 442) 443 444export const SDKControlMcpToggleRequestSchema = lazySchema(() => 445 z 446 .object({ 447 subtype: z.literal('mcp_toggle'), 448 serverName: z.string(), 449 enabled: z.boolean(), 450 }) 451 .describe('Enables or disables an MCP server.'), 452) 453 454 455export const SDKControlStopTaskRequestSchema = lazySchema(() => 456 z 457 .object({ 458 subtype: z.literal('stop_task'), 459 task_id: z.string(), 460 }) 461 .describe('Stops a running task.'), 462) 463 464export const SDKControlApplyFlagSettingsRequestSchema = lazySchema(() => 465 z 466 .object({ 467 subtype: z.literal('apply_flag_settings'), 468 settings: z.record(z.string(), z.unknown()), 469 }) 470 .describe( 471 'Merges the provided settings into the flag settings layer, updating the active configuration.', 472 ), 473) 474 475export const SDKControlGetSettingsRequestSchema = lazySchema(() => 476 z 477 .object({ 478 subtype: z.literal('get_settings'), 479 }) 480 .describe( 481 'Returns the effective merged settings and the raw per-source settings.', 482 ), 483) 484 485export const SDKControlGetSettingsResponseSchema = lazySchema(() => 486 z 487 .object({ 488 effective: z.record(z.string(), z.unknown()), 489 sources: z 490 .array( 491 z.object({ 492 source: z.enum([ 493 'userSettings', 494 'projectSettings', 495 'localSettings', 496 'flagSettings', 497 'policySettings', 498 ]), 499 settings: z.record(z.string(), z.unknown()), 500 }), 501 ) 502 .describe( 503 'Ordered low-to-high priority — later entries override earlier ones.', 504 ), 505 applied: z 506 .object({ 507 model: z.string(), 508 // String levels only — numeric effort is ant-only and the 509 // Zod→proto generator can't emit enum∪number unions. 510 effort: z.enum(['low', 'medium', 'high', 'max']).nullable(), 511 }) 512 .optional() 513 .describe( 514 'Runtime-resolved values after env overrides, session state, and model-specific defaults are applied. Unlike `effective` (disk merge), these reflect what will actually be sent to the API.', 515 ), 516 }) 517 .describe( 518 'Effective merged settings plus raw per-source settings in merge order.', 519 ), 520) 521 522export const SDKControlElicitationRequestSchema = lazySchema(() => 523 z 524 .object({ 525 subtype: z.literal('elicitation'), 526 mcp_server_name: z.string(), 527 message: z.string(), 528 mode: z.enum(['form', 'url']).optional(), 529 url: z.string().optional(), 530 elicitation_id: z.string().optional(), 531 requested_schema: z.record(z.string(), z.unknown()).optional(), 532 }) 533 .describe( 534 'Requests the SDK consumer to handle an MCP elicitation (user input request).', 535 ), 536) 537 538export const SDKControlElicitationResponseSchema = lazySchema(() => 539 z 540 .object({ 541 action: z.enum(['accept', 'decline', 'cancel']), 542 content: z.record(z.string(), z.unknown()).optional(), 543 }) 544 .describe('Response from the SDK consumer for an elicitation request.'), 545) 546 547 548// ============================================================================ 549// Control Request/Response Wrappers 550// ============================================================================ 551 552export const SDKControlRequestInnerSchema = lazySchema(() => 553 z.union([ 554 SDKControlInterruptRequestSchema(), 555 SDKControlPermissionRequestSchema(), 556 SDKControlInitializeRequestSchema(), 557 SDKControlSetPermissionModeRequestSchema(), 558 SDKControlSetModelRequestSchema(), 559 SDKControlSetMaxThinkingTokensRequestSchema(), 560 SDKControlMcpStatusRequestSchema(), 561 SDKControlGetContextUsageRequestSchema(), 562 SDKHookCallbackRequestSchema(), 563 SDKControlMcpMessageRequestSchema(), 564 SDKControlRewindFilesRequestSchema(), 565 SDKControlCancelAsyncMessageRequestSchema(), 566 SDKControlSeedReadStateRequestSchema(), 567 SDKControlMcpSetServersRequestSchema(), 568 SDKControlReloadPluginsRequestSchema(), 569 SDKControlMcpReconnectRequestSchema(), 570 SDKControlMcpToggleRequestSchema(), 571 SDKControlStopTaskRequestSchema(), 572 SDKControlApplyFlagSettingsRequestSchema(), 573 SDKControlGetSettingsRequestSchema(), 574 SDKControlElicitationRequestSchema(), 575 ]), 576) 577 578export const SDKControlRequestSchema = lazySchema(() => 579 z.object({ 580 type: z.literal('control_request'), 581 request_id: z.string(), 582 request: SDKControlRequestInnerSchema(), 583 }), 584) 585 586export const ControlResponseSchema = lazySchema(() => 587 z.object({ 588 subtype: z.literal('success'), 589 request_id: z.string(), 590 response: z.record(z.string(), z.unknown()).optional(), 591 }), 592) 593 594export const ControlErrorResponseSchema = lazySchema(() => 595 z.object({ 596 subtype: z.literal('error'), 597 request_id: z.string(), 598 error: z.string(), 599 pending_permission_requests: z 600 .array(z.lazy(() => SDKControlRequestSchema())) 601 .optional(), 602 }), 603) 604 605export const SDKControlResponseSchema = lazySchema(() => 606 z.object({ 607 type: z.literal('control_response'), 608 response: z.union([ControlResponseSchema(), ControlErrorResponseSchema()]), 609 }), 610) 611 612export const SDKControlCancelRequestSchema = lazySchema(() => 613 z 614 .object({ 615 type: z.literal('control_cancel_request'), 616 request_id: z.string(), 617 }) 618 .describe('Cancels a currently open control request.'), 619) 620 621export const SDKKeepAliveMessageSchema = lazySchema(() => 622 z 623 .object({ 624 type: z.literal('keep_alive'), 625 }) 626 .describe('Keep-alive message to maintain WebSocket connection.'), 627) 628 629export const SDKUpdateEnvironmentVariablesMessageSchema = lazySchema(() => 630 z 631 .object({ 632 type: z.literal('update_environment_variables'), 633 variables: z.record(z.string(), z.string()), 634 }) 635 .describe('Updates environment variables at runtime.'), 636) 637 638// ============================================================================ 639// Aggregate Message Types 640// ============================================================================ 641 642export const StdoutMessageSchema = lazySchema(() => 643 z.union([ 644 SDKMessageSchema(), 645 SDKStreamlinedTextMessageSchema(), 646 SDKStreamlinedToolUseSummaryMessageSchema(), 647 SDKPostTurnSummaryMessageSchema(), 648 SDKControlResponseSchema(), 649 SDKControlRequestSchema(), 650 SDKControlCancelRequestSchema(), 651 SDKKeepAliveMessageSchema(), 652 ]), 653) 654 655export const StdinMessageSchema = lazySchema(() => 656 z.union([ 657 SDKUserMessageSchema(), 658 SDKControlRequestSchema(), 659 SDKControlResponseSchema(), 660 SDKKeepAliveMessageSchema(), 661 SDKUpdateEnvironmentVariablesMessageSchema(), 662 ]), 663)