qa/copilot-capabilities.md
@github/[email protected])Public preview audit for the
1.0.0-beta.4pin. Per task contract, treat this as the currentlatestdist-tag snapshot and re-generate this document whenever the pinned SDK version changes.
This inventory documents the shipped TypeScript surface that the bundled copilot plugin pins against, instead of guessing. Every claim below is tied to the installed SDK's .d.ts files and bundled docs; where the inventory is silent, this document says so explicitly.
@github/copilot-sdk.1.0.0-beta.4.. -> ESM ./dist/index.js, CJS ./dist/cjs/index.js, types ./dist/index.d.ts../extension -> ESM ./dist/extension.js, CJS ./dist/cjs/extension.js, types ./dist/extension.d.ts.dist/index.d.ts re-exports CopilotClient, CopilotSession, AssistantMessageEvent, helpers like defineTool/approveAll, and the full public type surface from dist/types.d.ts.@github/copilot ^1.0.46 (bundled CLI/runtime dependency)vscode-jsonrpc ^8.2.1zod ^4.3.6Sources: package.json (on-disk install): 2-32, 58-62; dist/index.d.ts (sdk-inventory.txt:1033-1042).
CopilotClientPublic methods/getters visible in dist/client.d.ts:
| Member | Signature | Return shape | What it does |
| ------------------------ | ------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| rpc | get rpc(): ReturnType<typeof createServerRpc> | typed server RPC facade | Low-level server-scoped RPC surface; throws if not connected. |
| start | start(): Promise<void> | void | Starts/spawns the CLI server and connects. |
| stop | stop(): Promise<Error[]> | cleanup errors array | Graceful shutdown: closes sessions, JSON-RPC connection, then spawned CLI; preserves on-disk session state. |
| forceStop | forceStop(): Promise<void> | void | Force-kills client state/process without graceful cleanup. |
| createSession | createSession(config: SessionConfig): Promise<CopilotSession> | CopilotSession | Creates a new conversation session; auto-starts when enabled. |
| resumeSession | resumeSession(sessionId: string, config: ResumeSessionConfig): Promise<CopilotSession> | CopilotSession | Re-attaches to a persisted session; returns workspacePath when infinite sessions were enabled. |
| getState | getState(): ConnectionState | "disconnected" \| "connecting" \| "connected" \| "error" | Returns client connection state. |
| ping | ping(message?: string): Promise<{ message: string; timestamp: number; protocolVersion?: number; }> | echo payload | Connectivity/protocol sanity check. |
| getStatus | getStatus(): Promise<GetStatusResponse> | { version: string; protocolVersion: number } | Returns CLI package version and negotiated protocol version. |
| getAuthStatus | getAuthStatus(): Promise<GetAuthStatusResponse> | { isAuthenticated, authType?, host?, login?, statusMessage? } | Returns current auth mode/status. |
| listModels | listModels(): Promise<ModelInfo[]> | model metadata array | Lists models; caches first successful result unless overridden by onListModels. |
| getLastSessionId | getLastSessionId(): Promise<string | undefined> | optional session id | Returns most recently updated session id. |
| deleteSession | deleteSession(sessionId: string): Promise<void> | void | Irreversibly deletes persisted session data from disk. |
| listSessions | listSessions(filter?: SessionListFilter): Promise<SessionMetadata[]> | session metadata array | Lists persisted sessions, optionally filtered by cwd/git context. |
| getSessionMetadata | getSessionMetadata(sessionId: string): Promise<SessionMetadata | undefined> | optional metadata | O(1)-style lookup for one session's metadata. |
| getForegroundSessionId | getForegroundSessionId(): Promise<string | undefined> | optional session id | TUI+server-only: returns current foreground session. |
| setForegroundSessionId | setForegroundSessionId(sessionId: string): Promise<void> | void | TUI+server-only: asks the TUI to foreground a session. |
| on (typed) | on<K extends SessionLifecycleEventType>(eventType: K, handler: TypedSessionLifecycleHandler<K>): () => void | unsubscribe fn | Subscribes to one lifecycle event type. |
| on (catch-all) | on(handler: SessionLifecycleHandler): () => void | unsubscribe fn | Subscribes to all lifecycle events. |
Lifecycle event types for client.on(...): session.created, session.deleted, session.updated, session.foreground, session.background.
Sources: dist/client.d.ts (sdk-inventory.txt:1081-1518), especially 1112-1477; dist/types.d.ts (sdk-inventory.txt:3421-3528); README API docs (sdk-inventory.txt:96-199).
CopilotSessionPublic properties/getters/methods visible in dist/session.d.ts:
| Member | Signature | Return shape | Notes |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| rpc | get rpc(): ReturnType<typeof createSessionRpc> | typed session RPC facade | Low-level session RPC surface. |
| workspacePath | get workspacePath(): string | undefined | optional path | Present only when infinite sessions are enabled; workspace contains checkpoints/, plan.md, files/. |
| capabilities | get capabilities(): SessionCapabilities | { ui?: { elicitation?: boolean } } | Host capability snapshot; auto-updated on capability change events. |
| ui | get ui(): SessionUiApi | convenience UI API | Exposes elicitation, confirm, select, input; requires capabilities.ui?.elicitation. |
| send | send(options: MessageOptions): Promise<string> | message id | Queues a user prompt and returns immediately. |
| sendAndWait | sendAndWait(options: MessageOptions, timeout?: number): Promise<AssistantMessageEvent | undefined> | final assistant message or undefined | Waits for session.idle; timeout defaults to 60000ms and does not abort in-flight work. |
| on (typed) | on<K extends SessionEventType>(eventType: K, handler: TypedSessionEventHandler<K>): () => void | unsubscribe fn | Subscribes to one event type. |
| on (catch-all) | on(handler: SessionEventHandler): () => void | unsubscribe fn | Subscribes to all session events. |
| getMessages | getMessages(): Promise<SessionEvent[]> | complete event history | Returns the full persisted conversation/event stream. |
| disconnect | disconnect(): Promise<void> | void | Releases in-memory resources but preserves on-disk session state for resume. |
| destroy | destroy(): Promise<void> | void | Deprecated alias for disconnect(). |
| [Symbol.asyncDispose] | [Symbol.asyncDispose](): Promise<void> | void | Enables await using. |
| abort | abort(): Promise<void> | void | Cancels the currently processing message without invalidating the session. |
| setModel | setModel(model: string, options?: { reasoningEffort?: ReasoningEffort; modelCapabilities?: ModelCapabilitiesOverride; }): Promise<void> | void | Switches model for future turns while preserving history. |
| log | log(message: string, options?: { level?: "info" \| "warning" \| "error"; ephemeral?: boolean; }): Promise<void> | void | Writes timeline messages; docs explicitly say to use this instead of console.log(). |
MessageOptions supports prompt, attachments, optional mode (enqueue or immediate), and per-turn requestHeaders.
Sources: dist/session.d.ts (sdk-inventory.txt:1520-2003); dist/types.d.ts (sdk-inventory.txt:3292-3339); docs/examples.md (sdk-inventory.txt:3829-3894).
| Event | Payload shape | Sources |
|---|---|---|
assistant.turn_start | { interactionId?, turnId } | dist/generated/session-events.d.ts: 1633-1668 |
assistant.intent | { intent: string } | dist/generated/session-events.d.ts: 1670-1699 |
assistant.reasoning | { content: string, reasoningId: string } | dist/generated/session-events.d.ts: 1700-1735 |
assistant.reasoning_delta | { deltaContent: string, reasoningId: string } | dist/generated/session-events.d.ts: 1737-1770 |
assistant.streaming_delta | { totalResponseSizeBytes: number } | dist/generated/session-events.d.ts: 1771-1800 |
assistant.message_start | { messageId: string, phase?: string } | dist/generated/session-events.d.ts: 1927-1960 |
assistant.message_delta | { deltaContent: string, messageId: string, parentToolCallId? } | dist/generated/session-events.d.ts: 1961-1999 |
assistant.message | { content, messageId, model?, outputTokens?, toolRequests?, reasoningText?, reasoningOpaque?, encryptedContent?, interactionId?, requestId?, phase?, turnId?, anthropicAdvisorBlocks?, anthropicAdvisorModel?, parentToolCallId? } | dist/generated/session-events.d.ts: 1801-1926 |
assistant.turn_end | { turnId: string } | dist/generated/session-events.d.ts: 2000-2032 |
assistant.usage | usage metrics including { model, inputTokens?, outputTokens?, reasoningTokens?, reasoningEffort?, duration?, cost?, cacheReadTokens?, cacheWriteTokens?, ttftMs?, interTokenLatencyMs?, quotaSnapshots?, copilotUsage? } | dist/generated/session-events.d.ts: 2033-2215 |
| Event | Payload shape | Sources |
|---|---|---|
tool.execution_start | { toolCallId, toolName, arguments?, mcpServerName?, mcpToolName?, parentToolCallId?, turnId? } | dist/generated/session-events.d.ts: 2323-2382 |
tool.execution_partial_result | { partialOutput: string, toolCallId: string } | dist/generated/session-events.d.ts: 2383-2416 |
tool.execution_progress | { progressMessage: string, toolCallId: string } | dist/generated/session-events.d.ts: 2417-2450 |
tool.execution_complete | { success: boolean, toolCallId: string, result?, error?, model?, interactionId?, isUserRequested?, toolTelemetry?, turnId?, parentToolCallId? }; result is { content, contents?, detailedContent? }; error is { code?, message } | dist/generated/session-events.d.ts: 2451-2665 |
| Event | Payload shape | Sources |
|---|---|---|
permission.requested | { requestId: string, permissionRequest, promptRequest?, resolvedByHook? }; permissionRequest is a rich union, not just a bare kind | dist/generated/session-events.d.ts: 3293-3628 |
permission.completed | { requestId: string, result: PermissionResult, toolCallId? } where result kinds include approved, approved-for-session, approved-for-location, cancelled, denied-by-rules, denied-no-approval-rule-and-could-not-request-from-user, denied-interactively-by-user, denied-by-content-exclusion-policy, denied-by-permission-request-hook | dist/generated/session-events.d.ts: 3909-4120 |
user_input.requested | { question: string, choices?, allowFreeform?, requestId: string, toolCallId? } | dist/generated/session-events.d.ts: 4121-4166 |
user_input.completed | { answer?, requestId: string, wasFreeform? } | dist/generated/session-events.d.ts: 4167-4204 |
elicitation.requested | { message: string, requestId: string, elicitationSource?, mode?, requestedSchema?, toolCallId?, url? } | dist/generated/session-events.d.ts: 4205-4257 |
elicitation.completed | { requestId: string, action?, content? } | dist/generated/session-events.d.ts: 4273-4308 |
command.execute | { commandName, command, args, requestId } | dist/generated/session-events.d.ts: 4588-4629 |
commands.changed | { commands: Array<{ name: string, description?: string }> } | dist/generated/session-events.d.ts: 4732-4765 |
capabilities.changed | { ui?: { elicitation?: boolean } } | dist/generated/session-events.d.ts: 4766-4801 |
| Event | Payload shape | Sources |
|---|---|---|
session.start | session bootstrap metadata including { sessionId, startTime, copilotVersion, producer, selectedModel?, reasoningEffort?, remoteSteerable?, context? } | dist/generated/session-events.d.ts: 135-238 |
session.resume | { eventCount, resumeTime, selectedModel?, reasoningEffort?, continuePendingWork?, sessionWasActive?, context? } | dist/generated/session-events.d.ts: 239-300 |
session.error | { errorType: string, message: string, errorCode?, eligibleForAutoSwitch?, providerCallId?, stack?, statusCode?, url? } | dist/generated/session-events.d.ts: 334-394 |
session.idle | { aborted?: boolean } | dist/generated/session-events.d.ts: 395-424 |
session.usage_info | { currentTokens, tokenLimit, messagesLength, conversationTokens?, systemTokens?, toolDefinitionsTokens?, isInitial? } | dist/generated/session-events.d.ts: 1116-1169 |
session.compaction_start | { conversationTokens?, systemTokens?, toolDefinitionsTokens? } | dist/generated/session-events.d.ts: 1170-1210 |
session.compaction_complete | { success, checkpointNumber?, checkpointPath?, summaryContent?, messagesRemoved?, preCompactionTokens?, postCompactionTokens?, tokensRemoved?, compactionTokensUsed?, error?, requestId? } | dist/generated/session-events.d.ts: 1211-1308 |
model.call_failure | { source, model?, statusCode?, durationMs?, apiCallId?, providerCallId?, errorMessage?, initiator? } | dist/generated/session-events.d.ts: 2195-2249 |
abort | { reason: "user_initiated" | "remote_command" | "user_abort" } | dist/generated/session-events.d.ts: 2250-2279 |
SessionEvent union membersThe generated SessionEvent union is authoritative and currently includes all of these members:
StartEvent, ResumeEvent, RemoteSteerableChangedEvent, ErrorEvent, IdleEvent, TitleChangedEvent, ScheduleCreatedEvent, ScheduleCancelledEvent, InfoEvent, WarningEvent, ModelChangeEvent, ModeChangedEvent, PlanChangedEvent, WorkspaceFileChangedEvent, HandoffEvent, TruncationEvent, SnapshotRewindEvent, ShutdownEvent, ContextChangedEvent, UsageInfoEvent, CompactionStartEvent, CompactionCompleteEvent, TaskCompleteEvent, UserMessageEvent, PendingMessagesModifiedEvent, AssistantTurnStartEvent, AssistantIntentEvent, AssistantReasoningEvent, AssistantReasoningDeltaEvent, AssistantStreamingDeltaEvent, AssistantMessageEvent, AssistantMessageStartEvent, AssistantMessageDeltaEvent, AssistantTurnEndEvent, AssistantUsageEvent, ModelCallFailureEvent, AbortEvent, ToolUserRequestedEvent, ToolExecutionStartEvent, ToolExecutionPartialResultEvent, ToolExecutionProgressEvent, ToolExecutionCompleteEvent, SkillInvokedEvent, SubagentStartedEvent, SubagentCompletedEvent, SubagentFailedEvent, SubagentSelectedEvent, SubagentDeselectedEvent, HookStartEvent, HookEndEvent, SystemMessageEvent, SystemNotificationEvent, PermissionRequestedEvent, PermissionCompletedEvent, UserInputRequestedEvent, UserInputCompletedEvent, ElicitationRequestedEvent, ElicitationCompletedEvent, SamplingRequestedEvent, SamplingCompletedEvent, McpOauthRequiredEvent, McpOauthCompletedEvent, ExternalToolRequestedEvent, ExternalToolCompletedEvent, CommandQueuedEvent, CommandExecuteEvent, CommandCompletedEvent, AutoModeSwitchRequestedEvent, AutoModeSwitchCompletedEvent, CommandsChangedEvent, CapabilitiesChangedEvent, ExitPlanModeRequestedEvent, ExitPlanModeCompletedEvent, ToolsUpdatedEvent, BackgroundTasksChangedEvent, SkillsLoadedEvent, CustomAgentsUpdatedEvent, McpServersLoadedEvent, McpServerStatusChangedEvent, ExtensionsLoadedEvent.For OpenClaw harness work, the inspected payloads above are the important ones; the remaining union members exist in the shipped schema but are not otherwise documented in the README.
Source: dist/generated/session-events.d.ts: 5.
name: stringdescription?: stringparameters?: ZodSchema<TArgs> | Record<string, unknown>handler: ToolHandler<TArgs>overridesBuiltInTool?: booleanskipPermission?: booleanToolHandler<TArgs> signature: (args: TArgs, invocation: ToolInvocation) => Promise<unknown> | unknown.ToolInvocation carries { sessionId, toolCallId, toolName, arguments, traceparent?, tracestate? }.stringToolResultObject with { textResultForLlm, binaryResultsForLlm?, resultType, error?, sessionLog?, toolTelemetry? }undefined becomes an empty success and throwing becomes a failure/error message.ToolResultType is "success" | "failure" | "rejected" | "denied" | "timeout".overridesBuiltInTool: true throws.skipPermission: true suppresses permission prompts for that custom tool.defineTool(name, config) exists purely to preserve type inference from Zod schemas.Sources: dist/types.d.ts (sdk-inventory.txt:2203-2304); README tools section (sdk-inventory.txt:430-485); docs/agent-author.md (sdk-inventory.txt:3708-3745, 3905).
onPermissionRequest)onPermissionRequest: PermissionHandler for both createSession and resumeSession.dist/types.d.ts:
type PermissionHandler = (request: PermissionRequest, invocation: { sessionId: string }) => Promise<PermissionRequestResult> | PermissionRequestResultPermissionRequest is typed only as { kind: "shell" | "write" | "mcp" | "read" | "url" | "custom-tool" | "memory" | "hook"; toolCallId?: string }PermissionRequestResult is PermissionDecisionRequest["result"] | { kind: "no-result" }toolName, fileName, and fullCommandText to custom handlers; the generated permission.requested event schema confirms a richer union exists with per-kind payloads:
shell: fullCommandText, commands[], possiblePaths[], possibleUrls[], hasWriteFileRedirection, intention, warning, canOfferSessionApprovalwrite: fileName, diff, newFileContents?, intention, canOfferSessionApprovalread: path, intentionmcp: serverName, toolName, toolTitle, args?, readOnlyurl: url, intentionmemory: action?, fact, subject?, citations?, direction?, reason?custom-tool: toolName, toolDescription, args?hook: toolName, toolArgs?, hookMessage?extension-management and extension-permission-access variants in the event schema.approved, denied-interactively-by-user, denied-no-approval-rule-and-could-not-request-from-user, denied-by-rules, denied-by-content-exclusion-policy, no-result.NO_RESULT_PERMISSION_V2_ERROR = "Permission handlers cannot return 'no-result' when connected to a protocol v2 server."Sources: dist/types.d.ts (sdk-inventory.txt:2608-2619); README permission handling (sdk-inventory.txt:804-879); dist/session.d.ts (sdk-inventory.txt:1529, 1813-1822, 1866-1873); dist/generated/session-events.d.ts: 3293-3628, 3909-4120.
onUserInputRequest)onUserInputRequest?: UserInputHandler.(request: UserInputRequest, invocation: { sessionId: string }) => Promise<UserInputResponse> | UserInputResponse.UserInputRequest fields:
question: stringchoices?: string[]allowFreeform?: boolean (default true)UserInputResponse fields:
answer: stringwasFreeform: booleanask_user tool.user_input.requested includes requestId and optional toolCallIduser_input.completed includes requestId, optional answer, optional wasFreeformSources: dist/types.d.ts (sdk-inventory.txt:2624-2657, 3091-3095); README user-input section (sdk-inventory.txt:881-905); dist/generated/session-events.d.ts: 4121-4204.
SessionConfig.infiniteSessions?: InfiniteSessionConfig controls the feature.InfiniteSessionConfig fields:
enabled?: boolean (default true)backgroundCompactionThreshold?: number (default 0.80)bufferExhaustionThreshold?: number (default 0.95)CopilotSession.workspacePath is populated only when infinite sessions are enabled.checkpoints/, plan.md, and files/.~/.copilot/session-state/{sessionId}/.backgroundCompactionThresholdbufferExhaustionThreshold until compaction finishessession.compaction_start and session.compaction_completecheckpointNumber, checkpointPath), summary text (summaryContent), before/after token counts, messages removed, tokens removed, and nested compactionTokensUsed usage breakdown.Sources: README infinite sessions section (sdk-inventory.txt:627-660); dist/session.d.ts (sdk-inventory.txt:1594-1598); dist/types.d.ts (sdk-inventory.txt:2980-3006, 3168-3172); docs/examples.md (sdk-inventory.txt:4330-4346); dist/generated/session-events.d.ts: 1170-1308.
type ReasoningEffort = "low" | "medium" | "high" | "xhigh".reasoningEffort?: ReasoningEffort.ModelCapabilities.supports.reasoningEffort is true.ModelInfo.supportedReasoningEfforts?: ReasoningEffort[]ModelInfo.defaultReasoningEffort?: ReasoningEffortlistModels() to discover support/defaults rather than assuming a global SDK default.session.start / session.resume metadata may include reasoningEffort?: stringassistant.usage may also include reasoningEffort?: string plus reasoningTokens?Sources: README API docs (sdk-inventory.txt:116-123, 118); dist/types.d.ts (sdk-inventory.txt:3003-3006, 3023-3027, 3445-3498); dist/generated/session-events.d.ts: 181-183, 281-283, 2115-2121.
TelemetryConfig shape:
otlpEndpoint?: stringfilePath?: stringexporterType?: string ("otlp-http" or "file" in README)sourceName?: stringcaptureContent?: booleanCopilotClientOptions.telemetry?: TelemetryConfig configures CLI-process telemetry by setting environment variables on the spawned CLI.TraceContextProvider signature: () => TraceContext | Promise<TraceContext>.TraceContext shape: { traceparent?: string; tracestate?: string }.CopilotClientOptions.onGetTraceContext?: TraceContextProvider is called before session.create, session.resume, and session.send RPCs to inject distributed trace headers.ToolInvocation.traceparent and ToolInvocation.tracestate.dist/telemetry.d.ts exports getTraceContext(provider?) as a helper that returns {} when no provider is configured.Sources: README telemetry section (sdk-inventory.txt:759-803); dist/types.d.ts (sdk-inventory.txt:2020-2049, 2137-2167, 2253-2262); dist/telemetry.d.ts (sdk-inventory.txt:3560-3574).
gitHubToken?: string: explicit GitHub token; takes priority over other auth methods.useLoggedInUser?: boolean: default true, but defaults to false when gitHubToken is provided.copilotHome?: string: base directory for Copilot data; only used when the SDK spawns the CLI process.cliUrl?: string: connect to an existing server instead of spawning the CLI.useLoggedInUser cannot be used with cliUrl; copilotHome is ignored with cliUrl.getAuthStatus() returns { isAuthenticated, authType?, host?, login?, statusMessage? }, where authType can be user, env, gh-cli, hmac, api-key, or token.SessionConfig.gitHubToken?: string is separate from client auth. The docs say it is resolved into a full GitHub identity used for content exclusion, model routing, and quota checks, enabling multitenant sessions.SessionConfig.provider?: ProviderConfig switches the session to a custom API provider (openai, azure, or anthropic) with baseUrl, optional apiKey, optional bearerToken (takes precedence over apiKey), optional wireApi, optional azure.apiVersion, optional headers, modelId, wireModel, maxInputTokens, maxOutputTokens.model is required when using provider.enableSessionTelemetry is always disabled when a custom provider is configured.cliUrl with useLoggedInUsercliUrl with useStdio or cliPathprovider may be combined with client-level/session-level GitHub auth, so treat that as an open probe.Sources: README options/custom-provider docs (sdk-inventory.txt:83-94, 116-123, 696-757); dist/client.d.ts (sdk-inventory.txt:1121-1123, 1304-1308); dist/types.d.ts (sdk-inventory.txt:2051-2167, 3077-3085, 3174-3183, 3223-3288, 3430-3441).
copilotHomeWhat is explicit in the inventory:
copilotHome is the base directory for Copilot data: "session state, config, etc."; it sets COPILOT_HOME on the spawned CLI process.~/.copilot.workspacePath examples place per-session state under ~/.copilot/session-state/{sessionId}/, with checkpoints/, plan.md, and files/ inside that session directory.What is not explicit in the inventory:
copilotHomeCopilotClient instances sharing the same copilotHomeOpenClaw implication: the docs are not strong enough to justify shared copilotHome pools. Q5's per-agent-pool decision should therefore keep isolated copilotHome directories until spike-app proves concurrency safety.
Sources: README options/infinite-session docs (sdk-inventory.txt:90-94, 627-660); dist/types.d.ts (sdk-inventory.txt:2067-2073); dist/session.d.ts (sdk-inventory.txt:1594-1598).
resumeSession(sessionId, config) re-attaches to a previous session and keeps conversation history.disconnect() preserves on-disk session state; stop() also preserves it; deleteSession() is the destructive operation.getMessages() returns the complete session event history (SessionEvent[]).listSessions(filter?) returns persisted session metadata including sessionId, startTime, modifiedTime, summary?, isRemote, context?.getSessionMetadata(sessionId) is a targeted metadata lookup.getLastSessionId() returns the most recently updated session id.ResumeSessionConfig:
disableResume?: boolean skips emitting session.resumecontinuePendingWork?: boolean resumes in-flight permissions/tool work; otherwise pending work is treated as interrupted and permissions are re-emitted as permission.requestedsessionWasActive?: boolean means the runtime already had the session in memoryfalse/missing means a cold resume reconstructed from persisted event logSources: README API docs (sdk-inventory.txt:128-170, 281-287, 867-875); dist/client.d.ts (sdk-inventory.txt:1246-1395); dist/session.d.ts (sdk-inventory.txt:1892-1944); dist/types.d.ts (sdk-inventory.txt:3200-3221, 3409-3417); dist/generated/session-events.d.ts: 266-299.
Explicit model ids mentioned in the inspected inventory:
gpt-5gpt-4gpt-4.1claude-sonnet-4.5claude-sonnet-4.6deepseek-coder-v2:16bDiscovery API:
client.listModels(): Promise<ModelInfo[]> is the authoritative discovery path.ModelInfo carries id, name, capabilities, optional policy, optional billing, optional supportedReasoningEfforts, optional defaultReasoningEffort.CopilotClientOptions.onListModels can override discovery entirely (useful for BYOK mode).What is not in the inspected inventory:
Sources: README/examples (sdk-inventory.txt:38, 65, 117-118, 633-665, 713-749); dist/client.d.ts (sdk-inventory.txt:1310-1320); dist/types.d.ts (sdk-inventory.txt:2130-2135, 3483-3498); dist/session.d.ts (sdk-inventory.txt:1975-1982).
@throws Error; the SDK does not expose a rich public exception-class hierarchy in the inspected .d.ts files.stop() is unusual: instead of throwing cleanup failures, it resolves to Error[].createSession() can throw if auto-start is disabled and the client is disconnected.resumeSession() can throw if the session does not exist or the client is not connected.sendAndWait() throws on timeout or connection/disconnect failure.Tool registration can throw for built-in name collisions unless overridesBuiltInTool: true is set.model with custom provider throws.NO_RESULT_PERMISSION_V2_ERROR if a handler returns no-result.session.error carries { errorType, message, errorCode?, statusCode?, providerCallId?, stack?, url?, eligibleForAutoSwitch? }.model.call_failure carries failed model-call telemetry (source, model?, statusCode?, durationMs?, providerCallId?, errorMessage?).tool.execution_complete.error carries { code?, message }.onErrorOccurred may return errorHandling: "retry" | "skip" | "abort" plus retryCount?.session.error.eligibleForAutoSwitch for rate-limit flowsauto_mode_switch.requested / auto_mode_switch.completed eventsonErrorOccurred hook output errorHandling: "retry"Sources: README/tool/provider/error docs (sdk-inventory.txt:459-480, 753-757, 1013-1021); dist/client.d.ts (sdk-inventory.txt:1119-1123, 1147-1214, 1222-1225, 1252-1255, 1284-1288, 1346-1355); dist/session.d.ts (sdk-inventory.txt:1529, 1645-1650, 1813-1822, 1866-1889); dist/generated/session-events.d.ts: 361-393, 2195-2279, 2478-2529; dist/types.d.ts (sdk-inventory.txt:2822-2871).
Concrete gaps to answer in spike-app before landing a real harness:
onPermissionRequest receives rich per-kind fields (toolName, fileName, fullCommandText), but dist/types.d.ts types PermissionRequest as just { kind, toolCallId? }. What object shape does runtime actually deliver to JS/TS handlers?onPermissionRequest never resolves? Is there a default timeout, cancellation, or session hang?onUserInputRequest.copilotHome concurrency: can multiple CopilotClient instances in one process safely share one copilotHome, or are there lock/race hazards around session-state/ and config files?copilotHome layout: beyond session-state/<id>/{checkpoints,plan.md,files}, what other top-level files/directories are created, and which are session-global versus client-global?gitHubToken, session-level gitHubToken, useLoggedInUser, and provider are accepted or rejected in practice?assistant.message notes encryptedContent/reasoningOpaque are session-bound and stripped on resume. What survives after process restart versus live reconnect?ToolsUpdatedEvent, SkillsLoadedEvent, McpServersLoadedEvent, ExtensionsLoadedEvent, or is the harness safe to ignore them?continuePendingWork: true, what concrete low-level RPCs are required to finish previously pending external tool calls in an SDK-only consumer?provider is set without onListModels, what does listModels() return, if anything?Sources: dist/types.d.ts (sdk-inventory.txt:2608-2619, 2624-2657, 3203-3221, 3174-3183, 3226-3288); README permission/user-input/provider docs (sdk-inventory.txt:823-845, 883-905, 696-757); dist/generated/session-events.d.ts: 266-299, 1828-1889, 3293-3628.