/** * QueryRunner — The core runtime class that implements the Query interface. * * QueryRunner is an AsyncGenerator that the consumer * iterates via `for await (const msg of query)`. Internally it: * * 1. Runs a background message routing loop (readMessages) that reads * from the Transport and dispatches messages: * - control_response → resolves pending request Promises * - control_request → dispatches to handlers (permissions, hooks, MCP, etc.) * - control_cancel → aborts pending handler via AbortController * - keepalive / streamlined summaries → silently skipped * - result → recorded, optionally closes stdin for single-turn * - everything else → enqueued to the consumer's PushQueue * * 2. Manages the bidirectional control protocol: * - request(payload) sends a control request and returns a Promise * that resolves when the CLI responds with a matching request_id * - handleControlRequest() dispatches inbound requests from the CLI * * 3. Implements all Query interface methods for the consumer. */ import type { DiagnosticsSink } from '../core/sdk-diagnostics.js'; import type { ModelPromptPatches } from '../protocol/model-prompt-patches.js'; import type { Transport } from '../core/transport.js'; import type { SDKMessage, SDKUserMessage } from '../types/messages.js'; import type { InternalQuery, OnElicitation } from '../types/options.js'; import type { FetchJobToken, FetchServiceAccountToken } from '../types/auth.js'; import type { SDKGoalSnapshot, SDKGoalStatus, SDKControlInterruptResponse, SDKControlInitializeResponse, SDKControlGetContextUsageResponse, SDKControlGenerateSessionTitleResponse, AskSideQuestionOptions, SideQuestionResult, SDKControlAddDirectoriesResponse, SDKControlReloadPluginsResponse } from '../types/control.js'; import type { PermissionMode, CanUseTool } from '../types/permissions.js'; import type { HookCallbackMatcher } from '../types/hooks.js'; import type { HookEvent as InternalHookEvent } from '../protocol/index.js'; import type { McpServerConfig, McpServerStatus, McpSetServersResult, OAuthToken } from '../types/mcp.js'; import type { McpToolRuntimeOverride } from '../protocol/mcp.js'; import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import type { SdkMcpTransport } from '../mcp/sdk-mcp-transport.js'; import { type PendingMcpResponse } from '../mcp/mcp-handler.js'; import type { AgentDefinition, AgentInfo } from '../types/agents.js'; import type { SessionStore, SessionStoreFlush } from '../session/session-store.js'; import type { PluginDetails } from '../types/plugins.js'; import type { ModelInfo, SlashCommand, AccountInfo, UsageInfo } from '../types/common.js'; import type { ModelPolicyProvider } from '../types/model-policy-provider.js'; import type { MemoryRuntimeCallbacks, SerializableMemoryConfig } from '../types/memory.js'; import type { BYOKModelValidationInput, BYOKProviderInfo } from '../types/byok.js'; /** Init config passed to the initialize control request. */ type InitConfig = { systemPrompt?: string; appendSystemPrompt?: string; modelRequestPatches?: ModelPromptPatches; agents?: Record; skills?: string[]; promptSuggestions?: boolean; enableFileCheckpointing?: boolean; memory?: SerializableMemoryConfig; customContext?: Record; }; export declare class QueryRunner implements InternalQuery { private static readonly CUSTOM_CONTEXT_CAPABILITY; private static readonly INITIALIZE_TIMEOUT_MS; private static readonly BACKGROUND_TASKS_CAPABILITY; private static readonly SIDE_QUESTION_CAPABILITY; private static readonly GOAL_CAPABILITY; private readonly transport; private readonly inputStream; private readonly pendingRequests; private readonly pendingInboundRequests; private readonly hooks; private readonly hookCallbacks; private nextHookCallbackId; private readonly sdkMcpServers; private readonly sdkMcpTransports; private readonly pendingMcpResponses; private readonly sdkMcpToolOverrides; private readonly isSingleTurn; private readonly canUseTool?; private readonly abortController?; private readonly initConfig; private readonly onElicitation?; private readonly onAuthExpired?; private readonly fetchJobToken?; private readonly fetchServiceAccountToken?; private readonly diagnostics?; private readonly controlRequestTimeoutMs; private readonly resolveModel?; private readonly resolveModelTimeoutMs; private readonly transcriptMirrorBatcher?; private readonly memoryCallbacks?; private initResponse?; private initializationPromise?; private resultMessage?; private readLoopPromise?; private closed; private authExpiredFired; private protocolHandshakeValidated; private cliCapabilities?; private customContextCapabilityWarningEmitted; private firstResultReceived; private firstResultReceivedResolve?; private memoryFlushPromise?; private memoryEndInputPromise?; private closePromise?; constructor(transport: Transport, isSingleTurn: boolean, canUseTool?: CanUseTool, hooks?: Partial>, abortController?: AbortController, sdkMcpServers?: Map, initConfig?: InitConfig, onElicitation?: OnElicitation, diagnostics?: DiagnosticsSink, onAuthExpired?: () => void, controlRequestTimeoutMs?: number, sdkMcpTransports?: Map, pendingMcpResponses?: Map, fetchJobToken?: FetchJobToken, resolveModel?: ModelPolicyProvider, resolveModelTimeoutMs?: number, sessionStore?: SessionStore, sessionStoreFlush?: SessionStoreFlush, sdkMcpToolOverrides?: Record>, fetchServiceAccountToken?: FetchServiceAccountToken, memoryCallbacks?: MemoryRuntimeCallbacks); private getRecord; private normalizeLogPreview; private extractMessagePreview; private getMessagePreviewSuffix; private getMessageType; private getMessageSubtype; private getMessageUuid; private recordInboundSessionMessage; private recordOutboundSessionMessage; [Symbol.asyncIterator](): AsyncGenerator; next(): Promise>; return(): Promise>; throw(e?: unknown): Promise>; /** * Reads messages from the transport and routes them. * * This runs as a background task for the lifetime of the query. * When the transport's readMessages generator completes (process exited), * this method finishes and signals the consumer queue. */ private readMessages; private notifyAuthExpiredIfNeeded; private dispatchMemoryCallbacks; private flushMemoryBeforeEndInput; private performFlushMemoryBeforeEndInput; /** * Send a control request to the CLI and wait for the response. * * Enforces an upper-bound `controlRequestTimeoutMs` so a stuck cli * can't wedge consumers indefinitely — on timeout the pending Promise * rejects AND a `control_cancel_request` is written to let the cli * clean up. Pass `timeoutMs: 0` to opt a specific call out of the * timeout (useful for long-running operations like bulk restarts). * * @param payload - The inner request payload * @param opts.timeoutMs - Override the default timeout (0 disables) * @returns The response data from the CLI * @throws Error if the CLI responds with an error, the transport * closes, or the timeout elapses. */ private request; /** * Handle an inbound control response from the CLI. * * Resolves or rejects the pending Promise associated with the request_id. */ private handleControlResponse; private processPendingPermissionRequests; /** * Handle an inbound control request from the CLI. * * The CLI sends control requests for: * - Permission prompts * - Hook callbacks * - MCP message routing * - Elicitation requests */ private handleControlRequest; /** * Cancel a pending inbound control request. * * The CLI sends this when it no longer needs a response (e.g., user * interrupted while a permission prompt was pending). */ private handleControlCancelRequest; private throwIfAborted; /** * Validate the wire-protocol version handshake against the * `system/init` message. * * Throws ProtocolVersionMismatchError on cross-major mismatch. Logs a * warning when the CLI is older than the SDK's minor version (some new * fields may be missing) or when the field is absent (older CLI build * predating the handshake). */ private validateProtocolHandshake; private awaitAbortable; /** * Dispatch an inbound control request to the appropriate handler. * * @param req - The control request from the CLI * @param signal - AbortSignal for cancellation * @returns The response data to send back */ private processControlRequest; /** * Send the initialize control request and wait for the response. * * This must be called before iterating messages. It sends the * initialization configuration (system prompt, agents, etc.) to the * CLI and waits for the system init message. */ initialize(): Promise; private performInitialize; private invokeRegisteredHookCallback; /** * Get the cached initialization response. * * Returns a Promise that resolves when the initialization response * is available, matching the Query interface contract. */ initializationResult(): Promise; /** * Stream user messages into the session. * * Consumes an async iterable of user messages and writes each one * to the transport as JSONL. This is used for multi-turn conversations * where the caller provides messages dynamically. */ streamInput(stream: AsyncIterable): Promise; /** * Interrupt the current operation. */ interrupt(): Promise; /** * Drop a UUID-stamped async user message while it is still queued. */ cancelAsyncMessage(messageUuid: string): Promise; /** Stop one task without aborting the active main-session turn. */ stopTask(taskId: string): Promise; /** Move one or all eligible foreground tasks into the background. */ backgroundTasks(toolUseId?: string): Promise; /** * Create, redirect, transition, or re-budget the session goal. * * Omitted fields are left unchanged; `creditsBudget: null` explicitly * clears the credits budget. Setting `status: 'active'` while the session * is idle starts the goal loop. Returns the goal snapshot after the change * (null only if no goal exists afterwards). */ setGoal(params: { objective?: string; status?: SDKGoalStatus; creditsBudget?: number | null; }): Promise; /** Read the current goal, or null when the session has none. */ getGoal(): Promise; /** Clear the session goal. Returns whether a goal was actually cleared. */ clearGoal(): Promise; private requireCliCapability; /** * Set the permission mode. */ setPermissionMode(mode: PermissionMode): Promise; private waitForFirstResult; /** * Set the model. */ setModel(model?: string): Promise; setProxy(proxy?: string | null): Promise; /** * Generate a concise display title for the current session. */ generateSessionTitle(description: string, options?: { persist?: boolean; }): Promise; askSideQuestion(question: string, options?: AskSideQuestionOptions): Promise; /** * Add directories to the running session workspace. */ addDirectories(directories: string[]): Promise; /** * Apply flag settings. */ applyFlagSettings(settings: import('../types/settings.js').Settings): Promise; /** * Get supported slash commands. */ supportedCommands(): Promise; /** * Fetch available models from the CLI in real-time. * Sends a `get_models` control request; the CLI responds with the * current model catalog filtered by the catalog's default scene * (set at CLI process boot via the `QODER_SCENE` env var). */ getAvailableModels(options?: { fetchStrategy?: 'live' | 'cache'; uid?: string; }): Promise; /** * List the available BYOK (Bring Your Own Key) providers and their supported models. * The CLI in turn queries the server-side BYOK provider catalog (cached for 5 min). * * Returns `null` if BYOK is disabled or the CLI does not support this request. */ listByokProviders(): Promise; /** * Validate a BYOK provider/model/API-key combination through the CLI. */ validateByokModel(input: BYOKModelValidationInput): Promise; /** * Get supported agents. */ supportedAgents(): Promise; /** * Get account info. * * Always re-queries the CLI so callers see the freshest fields — the CLI * fills in `email` / `organization` asynchronously after device-flow login, * and a stale init-time snapshot can leave the SDK with only `userId`. * Falls back to the initialization snapshot when the CLI is older and does * not implement the `account_info` control request. */ accountInfo(): Promise; /** * Get MCP server status. */ mcpServerStatus(): Promise; /** * Get context usage information. */ getContextUsage(): Promise; /** * Get account quota and usage information. */ getUsageInfo(): Promise; /** * Reload plugins. */ reloadPlugins(): Promise; listPlugins(): Promise; /** * Rewind files to a previous user message. */ rewindFiles(userMessageId: string, options?: { dryRun?: boolean; }): Promise; /** * Rewind the active conversation branch, its file checkpoints, or both. */ rewind(userMessageId: string, options?: { scope?: import('../types/session.js').RewindScope; dryRun?: boolean; }): Promise; /** * Seed read state for a file. */ seedReadState(path: string, mtime: number): Promise; flushMemory(): Promise; private performMemoryFlush; refreshMemory(): Promise; private requireSdkMemoryEnabled; /** * Reconnect an MCP server. */ reconnectMcpServer(name: string): Promise; /** * Toggle an MCP server on/off. */ toggleMcpServer(name: string, enabled: boolean): Promise; /** * Set MCP servers configuration. */ setMcpServers(servers: Record): Promise; /** * Inject an OAuth token for an MCP server. **InternalQuery-only.** * * Skips the standard OAuth flow and writes a host-supplied token straight * into the cli's token store, then reconnects the server. The host is * fully responsible for token validity (scope, expiry, refresh). Public * code should use {@link mcpAuthenticate} + {@link mcpSubmitOAuthCallbackUrl} * instead. */ injectMcpToken(name: string, token: OAuthToken): Promise; /** * Initiate an OAuth flow for an MCP server and let the host drive the * user-agent step. * * Two outcomes: * - `{ requiresUserAction: false }` — cli completed silently via cached * client + valid refresh token. The host should NOT show any UI. * - `{ authUrl, requiresUserAction: true }` — host needs to open the URL * (browser, Electron window, manual paste) and then call * {@link mcpSubmitOAuthCallbackUrl} once the redirect is captured. * * `redirectUri` is optional and overrides the OAuth redirect target * (Electron custom protocol, enterprise callback host, etc.). */ mcpAuthenticate(serverName: string, redirectUri?: string): Promise<{ authUrl?: string; requiresUserAction: boolean; }>; /** * Submit a pasted-back OAuth callback URL for a flow previously started * with {@link mcpAuthenticate}. The cli extracts the authorization code, * validates the state parameter, completes token exchange, and reconnects * the server. */ mcpSubmitOAuthCallbackUrl(serverName: string, callbackUrl: string): Promise; /** * Delete any stored OAuth credentials for a server and force a reconnect. * Use to "sign out" of an MCP server — the next tool call will re-trigger * auth. */ mcpClearAuth(serverName: string): Promise; /** * Close the query session. * * Closes the transport, rejects pending requests, and signals the * consumer queue that no more messages will arrive. */ close(): Promise; private performClose; /** * Async dispose support. * * Allows using the QueryRunner with `await using`: * ```ts * await using query = createQuery(...); * for await (const msg of query) { ... } * ``` */ [Symbol.asyncDispose](): Promise; } export {};