/** * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ /** * Control protocol (bidirectional CLI ↔ SDK requests outside the agentic * loop): permission prompts, model switches, MCP management, hooks, etc. * * Wire envelope is `control_request` / `control_response` / * `control_cancel_request` / `control_cancel`. Inner request payloads are * discriminated by `type` (with some legacy `subtype` variants). */ import type { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js'; import type { HookEvent, HookInput } from './hooks.js'; import type { McpServerStatus, McpSetServersResult, McpServerConfigForCliTransport, McpToolRuntimeOverride, OAuthToken } from './mcp.js'; import type { PermissionMode, PermissionUpdate } from './permissions.js'; import type { SDKMessage } from './messages.js'; import type { AgentDefinition, AgentInfo } from './agents.js'; import type { AccountInfo, FastModeState, ModelInfo, SessionCreditsUsage, SlashCommand, SdkPluginConfig, UsageInfo } from './common.js'; import type { PluginDetails } from '../types/plugins.js'; import type { ModelPromptPatches } from './model-prompt-patches.js'; import type { EffectiveMemoryConfig, MemoryGenerationGateInput, SerializableMemoryConfig } from './memory.js'; export type SDKControlRequest = { type: 'control_request'; request_id: string; request: SDKControlRequestInner; }; type ControlSuccessResponse = { subtype: 'success'; request_id: string; response?: Record; }; type ControlErrorResponse = { subtype: 'error'; request_id: string; error: string; code?: string; pending_permission_requests?: SDKControlRequest[]; }; export type SDKControlResponse = { type: 'control_response'; response: ControlSuccessResponse | ControlErrorResponse; }; export type SDKControlCancelRequest = { type: 'control_cancel_request' | 'control_cancel'; request_id: string; }; export type SDKControlInterruptRequest = { type: 'interrupt'; /** * Cancel queued main-thread commands together with the active turn. * * This field requires the CLI capability * `interrupt_cancel_queued_v1`. */ cancel_queued?: boolean; }; export type SDKControlInterruptResponse = { /** * UUIDs of queued messages that survive the interrupt and may still run. */ still_queued: string[]; /** * UUIDs cancelled by an interrupt request with `cancel_queued: true`. */ cancelled?: string[]; }; export type SDKControlPermissionDecisionReasonType = 'rule' | 'mode' | 'subcommandResults' | 'permissionPromptTool' | 'hook' | 'asyncAgent' | 'workingDir' | 'safetyCheck' | 'classifier' | 'other'; export type SDKControlPermissionRequest = { subtype: 'can_use_tool'; tool_name: string; input: Record; permission_suggestions?: PermissionUpdate[]; blocked_path?: string; decision_reason?: string; decision_reason_type?: SDKControlPermissionDecisionReasonType; classifier_approvable?: boolean; title?: string; display_name?: string; description?: string; tool_use_id: string; agent_id?: string; }; /** * Wire form of MCP server config sent by SDK in `initialize` and * `mcp_set_servers` requests. Excludes the in-process variant * (`McpSdkServerConfigWithInstance`) because that carries a runtime * `McpServer` instance — the SDK substitutes a `McpSdkServerConfig` * (just `{ type: 'sdk', name }`) on the wire and registers the instance * locally. */ export type ControlMcpServerConfig = McpServerConfigForCliTransport; export type SDKControlInitializeRequest = { type: 'initialize'; model?: string; cwd?: string; allowedTools?: string[]; disallowedTools?: string[]; mcpServers?: Record; agents?: Record; skills?: string[]; plugins?: SdkPluginConfig[]; systemPrompt?: string; appendSystemPrompt?: string; modelRequestPatches?: ModelPromptPatches; excludeDynamicSections?: boolean; permissionMode?: PermissionMode; maxThinkingTokens?: number; enableFileCheckpointing?: boolean; sdkMcpServers?: string[]; sdkMcpToolOverrides?: Record>; promptSuggestions?: boolean; supportsCatalogReadyInitialize?: boolean; initializeTimeoutMs?: number; agentProgressSummaries?: boolean; memory?: SerializableMemoryConfig; hooks?: Partial>>; /** * Scene identifier for model filtering (e.g. 'quest', 'assistant'). * @deprecated The SDK no longer sends this field; scene is now driven by * the `QODER_SCENE` environment variable at CLI process boot. Kept for * backward compatibility with older SDK versions. */ scene?: string; }; export type SDKControlMemoryShouldGenerateRequest = { type: 'memory_should_generate'; callbackId: string; input: MemoryGenerationGateInput; }; export type SDKControlFlushMemoryRequest = { type: 'flush_memory'; }; export type SDKControlRefreshMemoryRequest = { type: 'refresh_memory'; }; export type SDKControlSetPermissionModeRequest = { type: 'set_permission_mode'; mode: PermissionMode; }; export type SDKControlSetModelRequest = { type: 'set_model'; model: string; }; export type SDKControlSetProxyRequest = { type: 'set_proxy'; proxy: string | null; }; export type SDKControlGenerateSessionTitleRequest = { type: 'generate_session_title'; description: string; persist?: boolean; }; export type SDKControlGenerateSessionTitleResponse = { title: string | null; }; /** One completed side-question exchange that may be reused as local context. */ export type SideQuestionHistoryEntry = { question: string; response: string; /** Optional notice explaining that a fallback model produced the response. */ fallback_notice?: string; }; /** Options for a side question that does not interrupt the main agent turn. */ export type AskSideQuestionOptions = { /** Cancels only this side question. The main agent turn continues running. */ signal?: AbortSignal; /** Previous side-question exchanges to include as local context. */ history?: readonly SideQuestionHistoryEntry[]; }; export type SideQuestionRefusalFallback = { originalModel: string; fallbackModel: string; content: string; }; /** Public result returned by {@link Query.askSideQuestion}. */ export type SideQuestionResult = { response: string; synthetic: boolean; refusalFallback?: SideQuestionRefusalFallback; }; export type SDKControlSideQuestionRequest = { subtype: 'side_question'; question: string; history?: SideQuestionHistoryEntry[]; }; export type SDKControlSideQuestionResponse = { response: string | null; synthetic?: boolean; refusal_fallback?: { original_model: string; fallback_model: string; content: string; }; }; export type SDKControlAddDirectoriesRequest = { type: 'add_directories'; directories: string[]; }; export type SDKControlAddDirectoriesResponse = { added: string[]; failed: Array<{ path: string; error: string; }>; directories: string[]; }; export declare const QoderModelPurpose: { /** 主对话 LLM 调用 */ readonly Main: "main"; /** 规划阶段调用 */ readonly Plan: "plan"; /** 子任务执行 */ readonly Task: "task"; /** 上下文压缩/摘要 */ readonly Compact: "compact"; /** 标题生成 */ readonly Title: "title"; /** 提示建议生成 */ readonly Suggestion: "suggestion"; /** 独立生成(非对话模式) */ readonly Generate: "generate"; /** Hook prompt 执行 */ readonly HookPrompt: "hook_prompt"; /** 子代理(subagent)调用 */ readonly Subagent: "subagent"; /** WebFetch 工具触发的 LLM 调用 */ readonly WebFetch: "web_fetch"; /** ImageGen 工具触发的 LLM 调用 */ readonly ImageGen: "image_gen"; /** 上下文压缩触发的 LLM 调用 */ readonly Compression: "compression"; /** 辅助性调用(兜底) */ readonly Utility: "utility"; }; export type QoderModelPurpose = (typeof QoderModelPurpose)[keyof typeof QoderModelPurpose]; /** * CLI sends this before each LLM request to ask the SDK which model to use. * The SDK delegates to the host's `resolveModel` callback. */ export type SDKControlGetModelPolicyRequest = { type: 'get_model_policy'; /** The purpose of this LLM request. */ purpose: QoderModelPurpose; /** Current session ID. */ sessionId: string; /** Current conversation turn index. */ turnIndex: number; /** Current agent ID (for subagent scenarios). */ agentId?: string; /** Context window usage ratio (0~1). */ contextUsage?: number; /** Estimated input token count for this prompt. */ estimatedInputTokens?: number; /** Estimated output token count for this prompt. */ estimatedOutputTokens?: number; /** Retry information when retrying after a failure. */ retry?: { attempt: number; lastError: string; lastModelId: string; }; /** Currently available models. Provided by CLI on each request. */ models?: ModelInfo[]; }; /** * SDK responds with the model the CLI should use for this request. */ export type SDKControlGetModelPolicyResponse = { type: 'get_model_policy'; /** The model to use for this request. */ model: string; /** Optional per-request model policy parameters (contextWindow, reasoningEffort). */ parameters?: Record; /** * Optional per-call BYOK credential payload. When present, the CLI * dispatches the LLM request through the third-party provider using * the supplied API key instead of the default upstream. */ custom_model?: CustomModel; /** * Optional routing scene label the CLI forwards as the inference request * body `task_id`. */ task_id?: string; /** * Optional business sub-task label the CLI forwards as `business.sub_task` * on the inference request (billing/analytics). */ sub_task?: string; }; export type SDKControlSetMaxThinkingTokensRequest = { type: 'set_max_thinking_tokens'; max_thinking_tokens: number | null; }; export type SDKControlMcpStatusRequest = { type: 'mcp_status'; }; export type SDKControlGetContextUsageRequest = { type: 'get_context_usage'; }; export type SDKControlGetUsageInfoRequest = { type: 'get_usage_info'; }; export type SDKControlGetUsageInfoResponse = { usage: UsageInfo | null; /** Session-local credits, independent from account quota availability. */ session?: SessionCreditsUsage; /** Account quota lookup failure; session credits may still be available. */ usage_error?: string; }; export type SDKControlAccountInfoRequest = { type: 'account_info'; }; export type SDKHookCallbackRequest = { subtype: 'hook_callback'; callback_id: string; input: HookInput; tool_use_id?: string; } | { type: 'hook_callback'; hook_id: string; hook_event: HookEvent; input: HookInput; tool_use_id?: string; }; export type SDKControlMcpMessageRequest = { subtype: 'mcp_message'; server_name: string; message: JSONRPCMessage; } | { type: 'mcp_message'; server_name: string; message: JSONRPCMessage; }; export type SDKControlRewindFilesRequest = { type: 'rewind_files'; user_message_id: string; dry_run?: boolean; }; export type SDKControlRewindRequest = { type: 'rewind'; user_message_id: string; scope?: 'conversation' | 'files' | 'both'; dry_run?: boolean; }; export type SDKControlCancelAsyncMessageRequest = { subtype: 'cancel_async_message'; message_uuid: string; }; export type SDKControlSeedReadStateRequest = { type: 'seed_read_state'; path: string; mtime: number; }; export type SDKControlMcpSetServersRequest = { type: 'mcp_set_servers'; servers: Record; }; export type SDKControlReloadPluginsRequest = { type: 'reload_plugins'; }; export type SDKControlMcpReconnectRequest = { type: 'mcp_reconnect'; serverName: string; }; export type SDKControlMcpToggleRequest = { type: 'mcp_toggle'; serverName: string; enabled: boolean; }; export type SDKControlApplyFlagSettingsRequest = { type: 'apply_flag_settings'; settings: Record; }; export type SDKControlGetSettingsRequest = { type: 'get_settings'; }; export type SDKControlElicitationRequest = { subtype: 'elicitation'; mcp_server_name: string; message: string; mode?: 'form' | 'url'; url?: string; elicitation_id?: string; requested_schema?: Record; title?: string; display_name?: string; description?: string; } | { type: 'elicitation_response'; elicitation_id: string; prompt: string; options?: string[]; tool_use_id?: string; }; export type SDKControlEndSessionRequest = { type: 'end_session'; reason?: string; }; export type SDKControlChannelEnableRequest = { type: 'channel_enable'; channel: string; enabled: boolean; }; /** * SDK requests the CLI's BYOK (Bring Your Own Key) configuration. * The CLI responds with the server-side provider/model catalog. */ export type SDKControlGetByokConfigRequest = { type: 'get_byok_config'; }; /** * Response to `get_byok_config`. Contains the BYOK provider catalog * from the server. */ export type SDKControlGetByokConfigResponse = { providers: BYOKProviderInfo[]; }; /** * User-supplied BYOK model credentials to validate through the CLI. */ export type BYOKModelValidationInput = { /** BYOK provider identifier, e.g. "openai", "deepseek", "kimi". */ provider: string; /** Third-party model identifier to validate. */ model: string; /** User-provided third-party API key. */ api_key: string; /** Optional provider base URL override. */ url?: string; /** Provider wire format, e.g. "openai". */ style?: string; }; /** * SDK asks the CLI to validate a BYOK provider/model/API-key combination. * The CLI delegates to the Qoder server-side BYOK check endpoint. */ export type SDKControlValidateByokModelRequest = BYOKModelValidationInput & { type: 'validate_byok_model'; }; /** Response to `validate_byok_model`. */ export type SDKControlValidateByokModelResponse = { success: boolean; }; /** A third-party LLM provider in the BYOK catalog. */ export type BYOKProviderInfo = { /** Provider identifier, e.g. "openai", "deepseek" */ key: string; /** Display name (may be localized object or plain string) */ display_name: string; /** URL where the user can obtain an API key */ api_key_url: string; /** Base URL for inference requests */ url: string; /** Fields the user must fill in */ fields: BYOKFieldInfo[]; /** Model groups offered by this provider */ types: BYOKModelTypeInfo[]; }; /** A required field for a BYOK provider (e.g. "api_key"). */ export type BYOKFieldInfo = { key: string; display_name: string; type: string; /** Whether the user must fill this field. */ mandatory?: boolean; }; /** A model group within a provider (e.g. "Chat", "Reasoning"). */ export type BYOKModelTypeInfo = { /** Group identifier, e.g. "cp" (coding plan), "tp" (token plan), "pg" (pay-as-you-go). */ key?: string; display_name: string; models: BYOKModelInfo[]; }; /** A specific model offered by a BYOK provider. */ export type BYOKModelInfo = { key: string; display_name: string; is_vl: boolean; is_reasoning: boolean; format: string; max_input_tokens: number; /** Explicit reasoning effort levels supported. */ efforts?: string[]; /** Whether this model supports disabling thinking explicitly. */ supports_disabled?: boolean; }; /** * Per-call BYOK credential payload returned by `resolveModel`. * * Defined in the SDK protocol module so public npm builds do not depend on * internal protocol packages. When the host attaches * `custom_model` to a `ModelPolicyResult`, the SDK forwards it to the CLI * on the wire so the CLI dispatches the LLM call through the third-party * provider with the supplied API key. * * NOTE: `style` defaults to `"openai"` — the SDK fills the default before * forwarding to the CLI, so the CLI always receives an explicit value. */ export type CustomModel = { /** BYOK provider identifier, e.g. "openai", "deepseek", "kimi". */ provider: string; /** User-provided third-party API key. */ api_key: string; /** Third-party model identifier, typically matching the outer model value. */ model?: string; /** Optional provider base URL override. */ url?: string; /** Provider wire format. The SDK defaults this to "openai" before forwarding. */ style?: string; }; export type SDKControlMcpInjectTokenRequest = { type: 'mcp_inject_token'; serverName: string; token: OAuthToken; }; export type SDKControlMcpAuthenticateRequest = { type: 'mcp_authenticate'; serverName: string; redirectUri?: string; }; export type SDKControlMcpOAuthCallbackUrlRequest = { type: 'mcp_oauth_callback_url'; serverName: string; callbackUrl: string; }; export type SDKControlMcpClearAuthRequest = { type: 'mcp_clear_auth'; serverName: string; }; export type SDKControlListPluginsRequest = { type: 'list_plugins'; }; export type SDKControlListPluginsResponse = { plugins: PluginDetails[]; }; /** Stop one running task by its stable public task ID. */ export type SDKControlStopTaskRequest = { subtype: 'stop_task'; task_id: string; }; /** * Move foreground Bash/Agent executions into the background. With a tool use * ID only the matching execution is targeted; without it all eligible * foreground executions are targeted. */ export type SDKControlBackgroundTasksRequest = { subtype: 'background_tasks'; tool_use_id?: string; }; export type SDKControlBackgroundTasksResponse = { /** Present for a targeted tool use. Bulk backgrounding may omit the body. */ backgrounded?: boolean; }; /** Lifecycle status of a goal (aligned with the CLI goal state machine). */ export type SDKGoalStatus = 'active' | 'paused' | 'blocked' | 'usage_limited' | 'budget_limited' | 'complete'; /** Structured snapshot of the current goal. */ export type SDKGoalSnapshot = { id: string; objective: string; status: SDKGoalStatus; turns_used: number; max_turns?: number; time_used_seconds: number; credits_budget?: number; credits_used?: number; created_at: number; updated_at: number; }; /** * Create, redirect, transition, or re-budget the session goal. Omitted fields * are left unchanged; `credits_budget: null` explicitly clears the budget. * Setting `status: 'active'` while the session is idle starts the goal loop. */ export type SDKControlSetGoalRequest = { subtype: 'set_goal'; objective?: string; status?: SDKGoalStatus; credits_budget?: number | null; }; export type SDKControlSetGoalResponse = { goal: SDKGoalSnapshot | null; }; export type SDKControlGetGoalRequest = { subtype: 'get_goal'; }; export type SDKControlGetGoalResponse = { goal: SDKGoalSnapshot | null; }; export type SDKControlClearGoalRequest = { subtype: 'clear_goal'; }; export type SDKControlClearGoalResponse = { cleared: boolean; }; export type SDKControlRequestInner = SDKControlInterruptRequest | SDKControlPermissionRequest | SDKControlInitializeRequest | SDKControlSetPermissionModeRequest | SDKControlSetModelRequest | SDKControlSetProxyRequest | SDKControlGenerateSessionTitleRequest | SDKControlSideQuestionRequest | SDKControlAddDirectoriesRequest | SDKControlSetMaxThinkingTokensRequest | SDKControlMcpStatusRequest | SDKControlGetContextUsageRequest | SDKControlGetUsageInfoRequest | SDKControlGetModelPolicyRequest | SDKControlAccountInfoRequest | SDKHookCallbackRequest | SDKControlMcpMessageRequest | SDKControlRewindFilesRequest | SDKControlRewindRequest | SDKControlCancelAsyncMessageRequest | SDKControlSeedReadStateRequest | SDKControlMcpSetServersRequest | SDKControlReloadPluginsRequest | SDKControlMcpReconnectRequest | SDKControlMcpToggleRequest | SDKControlApplyFlagSettingsRequest | SDKControlGetSettingsRequest | SDKControlElicitationRequest | SDKControlEndSessionRequest | SDKControlChannelEnableRequest | SDKControlMcpInjectTokenRequest | SDKControlMcpAuthenticateRequest | SDKControlMcpOAuthCallbackUrlRequest | SDKControlMcpClearAuthRequest | SDKControlGetByokConfigRequest | SDKControlValidateByokModelRequest | SDKControlListPluginsRequest | SDKControlStopTaskRequest | SDKControlBackgroundTasksRequest | SDKControlMemoryShouldGenerateRequest | SDKControlFlushMemoryRequest | SDKControlRefreshMemoryRequest | SDKControlSetGoalRequest | SDKControlGetGoalRequest | SDKControlClearGoalRequest; export type SDKControlInitializeResponse = { commands: SlashCommand[]; agents: AgentInfo[]; skills?: Array<{ name: string; description?: string; source?: string; }>; output_style: string; available_output_styles: string[]; models: ModelInfo[]; account: AccountInfo; fast_mode_state?: FastModeState; /** Optional features implemented by the connected CLI control channel. */ capabilities?: string[]; memory?: EffectiveMemoryConfig; }; export type SDKControlGetContextUsageResponse = { model: string; contextWindow: { /** Context occupancy as a percentage from 0 to 100. */ usedPercentage: number; }; /** Local estimates in the same order and category model as `/context`. */ categories: Array<{ type: 'system_prompt' | 'system_tools' | 'skills' | 'messages' | 'other' | 'free_space' | 'auto_compact'; percentage: number; }>; autoCompact: { enabled: boolean; thresholdPercentage: number; }; skills: { count: number; /** Aggregate skill frontmatter as a percentage of the full context. */ percentageOfContext: number; items: Array<{ name: string; source: 'project' | 'user' | 'built-in' | 'plugin'; /** This skill's frontmatter as a percentage of the full context. */ percentageOfContext: number; }>; }; duplicateFileReads: Array<{ path: string; count: number; }>; session: { messageCount: number; promptCount: number; toolCalls: { total: number; succeeded: number; failed: number; }; linesChanged: { added: number; removed: number; }; }; }; export type SDKControlReloadPluginsResponse = { commands: SlashCommand[]; agents: AgentInfo[]; plugins: Array<{ name: string; path: string; source?: string; }>; mcpServers: McpServerStatus[]; error_count: number; }; export type SDKControlMcpStatusResponse = { servers: McpServerStatus[]; }; export type SDKControlMcpSetServersResponse = McpSetServersResult; export type SDKControlMcpAuthenticateResponse = { authUrl?: string; requiresUserAction: boolean; }; export type SDKKeepAliveMessage = { type: 'keep_alive'; }; /** SDK-internal post-commit transcript frame emitted by local runtimes. */ export type TranscriptMirrorMessage = { type: 'transcript_mirror'; filePath: string; entries: Array<{ type: string; [key: string]: unknown; }>; }; export type StdoutMessage = SDKMessage | SDKControlResponse | SDKControlRequest | SDKControlCancelRequest | SDKKeepAliveMessage | TranscriptMirrorMessage; export {};