Adds the opt-in bundled GitHub Copilot agent runtime, pinned SDK install path, docs/inventory, SDK/tool/sandbox/auth wiring, and replay/tool-safety fixes.
Verification:
- Local: git diff --check; fnm exec --using 24.15.0 pnpm tsgo:extensions; fnm exec --using 24.15.0 pnpm check:test-types; fnm exec --using 24.15.0 pnpm build.
- Autoreview local: clean for the replay-safety fix; branch autoreview engine returned empty output twice, so local autoreview plus local/Crabbox/CI proof was used.
- Crabbox focused Copilot: run_2c0db9f48a4a, 19 files / 485 tests passed.
- Crabbox additional boundary shard: run_26a246a1aa24, prompt snapshots and plugin SDK boundary/export checks passed.
- Crabbox live Copilot: run_d128e4048b4e, real gpt-4.1 turn with live_echo phase-1-green and clean session-file check.
- GitHub checks: green on head 7cc8657e0d, including Dependency Guard after exact-head approval.
Co-authored-by: Ramraj Balasubramanian <ramrajba@microsoft.com>
48 KiB
Copilot SDK capability inventory (@github/copilot-sdk@1.0.0-beta.4)
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.
1. Package metadata
- Package name:
@github/copilot-sdk. - Version:
1.0.0-beta.4. - Export map:
.-> 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.
- Primary type barrel
dist/index.d.tsre-exportsCopilotClient,CopilotSession,AssistantMessageEvent, helpers likedefineTool/approveAll, and the full public type surface fromdist/types.d.ts. - Declared runtime deps:
@github/copilot^1.0.46(bundled CLI/runtime dependency)vscode-jsonrpc^8.2.1zod^4.3.6
Sources: package.json (on-disk install): 2-32, 58-62; dist/index.d.ts (sdk-inventory.txt:1033-1042).
2. Lifecycle methods on CopilotClient
Public 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).
3. Lifecycle methods on CopilotSession
Public 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).
4. Event types
4.1 Harness-relevant event types with inspected payloads
Streaming deltas / assistant turn
| 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 |
Tool execution
| 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 |
Interactivity / permissions / user prompts
| 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 |
Lifecycle / error / compaction
| 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 |
4.2 Full SessionEvent union members
The 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.
5. Tool contract
- Public tool shape:
name: stringdescription?: stringparameters?: ZodSchema<TArgs> | Record<string, unknown>handler: ToolHandler<TArgs>overridesBuiltInTool?: booleanskipPermission?: boolean
ToolHandler<TArgs>signature:(args: TArgs, invocation: ToolInvocation) => Promise<unknown> | unknown.ToolInvocationcarries{ sessionId, toolCallId, toolName, arguments, traceparent?, tracestate? }.- Return values:
- A plain
string - A
ToolResultObjectwith{ textResultForLlm, binaryResultsForLlm?, resultType, error?, sessionLog?, toolTelemetry? } - README/examples also state any JSON-serializable handler return is accepted and auto-wrapped; extension docs add that
undefinedbecomes an empty success and throwing becomes a failure/error message.
- A plain
ToolResultTypeis"success" | "failure" | "rejected" | "denied" | "timeout".- Built-in tool override semantics: using a built-in tool name without
overridesBuiltInTool: truethrows. - Permission bypass semantics:
skipPermission: truesuppresses permission prompts for that custom tool. - Helper:
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).
6. Permission contract (onPermissionRequest)
- Session config requires
onPermissionRequest: PermissionHandlerfor bothcreateSessionandresumeSession. - Declared handler type in
dist/types.d.ts:type PermissionHandler = (request: PermissionRequest, invocation: { sessionId: string }) => Promise<PermissionRequestResult> | PermissionRequestResultPermissionRequestis typed only as{ kind: "shell" | "write" | "mcp" | "read" | "url" | "custom-tool" | "memory" | "hook"; toolCallId?: string }PermissionRequestResultisPermissionDecisionRequest["result"] | { kind: "no-result" }
- README claims the runtime supplies richer fields such as
toolName,fileName, andfullCommandTextto custom handlers; the generatedpermission.requestedevent 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?- plus extension-specific
extension-managementandextension-permission-accessvariants in the event schema.
- Result kinds explicitly documented in README:
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. - Protocol-v2 caveat:
NO_RESULT_PERMISSION_V2_ERROR = "Permission handlers cannot return 'no-result' when connected to a protocol v2 server." - Timeout behavior: not documented in the public types/docs inspected.
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.
7. User-input contract (onUserInputRequest)
- Session config field:
onUserInputRequest?: UserInputHandler. - Declared handler type:
(request: UserInputRequest, invocation: { sessionId: string }) => Promise<UserInputResponse> | UserInputResponse. UserInputRequestfields:question: stringchoices?: string[]allowFreeform?: boolean(defaulttrue)
UserInputResponsefields:answer: stringwasFreeform: boolean
- README says providing the handler enables the
ask_usertool. - The event stream adds request/response correlation fields not present in the handler type:
user_input.requestedincludesrequestIdand optionaltoolCallIduser_input.completedincludesrequestId, optionalanswer, optionalwasFreeform
- Timeout behavior is not documented in the inspected public surface.
Sources: 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.
8. Infinite sessions
SessionConfig.infiniteSessions?: InfiniteSessionConfigcontrols the feature.InfiniteSessionConfigfields:enabled?: boolean(defaulttrue)backgroundCompactionThreshold?: number(default0.80)bufferExhaustionThreshold?: number(default0.95)
- README says infinite sessions are the default, automatically manage context limits, and persist state to a workspace directory.
CopilotSession.workspacePathis populated only when infinite sessions are enabled.- The workspace is explicitly documented as containing
checkpoints/,plan.md, andfiles/. - README example shows the default location as
~/.copilot/session-state/{sessionId}/. - Auto-compaction trigger semantics:
- background compaction starts at the configured
backgroundCompactionThreshold - the session blocks at
bufferExhaustionThresholduntil compaction finishes - events emitted:
session.compaction_startandsession.compaction_complete
- background compaction starts at the configured
- Compaction result payload includes checkpoint metadata (
checkpointNumber,checkpointPath), summary text (summaryContent), before/after token counts, messages removed, tokens removed, and nestedcompactionTokensUsedusage 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.
9. Reasoning effort
- Declared enum/type:
type ReasoningEffort = "low" | "medium" | "high" | "xhigh". - Session config field:
reasoningEffort?: ReasoningEffort. - It is only valid when
ModelCapabilities.supports.reasoningEffortistrue. - Discovery/model metadata surface:
ModelInfo.supportedReasoningEfforts?: ReasoningEffort[]ModelInfo.defaultReasoningEffort?: ReasoningEffort
- The README repeatedly points callers to
listModels()to discover support/defaults rather than assuming a global SDK default. - Runtime/event reflection:
session.start/session.resumemetadata may includereasoningEffort?: stringassistant.usagemay also includereasoningEffort?: stringplusreasoningTokens?
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.
10. Telemetry
TelemetryConfigshape:otlpEndpoint?: stringfilePath?: stringexporterType?: string("otlp-http"or"file"in README)sourceName?: stringcaptureContent?: boolean
CopilotClientOptions.telemetry?: TelemetryConfigconfigures CLI-process telemetry by setting environment variables on the spawned CLI.TraceContextProvidersignature:() => TraceContext | Promise<TraceContext>.TraceContextshape:{ traceparent?: string; tracestate?: string }.CopilotClientOptions.onGetTraceContext?: TraceContextProvideris called beforesession.create,session.resume, andsession.sendRPCs to inject distributed trace headers.- Tool handlers receive inbound trace context on
ToolInvocation.traceparentandToolInvocation.tracestate. dist/telemetry.d.tsexportsgetTraceContext(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).
11. Auth modes
Client-level auth/config
gitHubToken?: string: explicit GitHub token; takes priority over other auth methods.useLoggedInUser?: boolean: defaulttrue, but defaults tofalsewhengitHubTokenis 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.useLoggedInUsercannot be used withcliUrl;copilotHomeis ignored withcliUrl.getAuthStatus()returns{ isAuthenticated, authType?, host?, login?, statusMessage? }, whereauthTypecan beuser,env,gh-cli,hmac,api-key, ortoken.
Session-level auth/BYOK
SessionConfig.gitHubToken?: stringis 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?: ProviderConfigswitches the session to a custom API provider (openai,azure, oranthropic) withbaseUrl, optionalapiKey, optionalbearerToken(takes precedence overapiKey), optionalwireApi, optionalazure.apiVersion, optionalheaders,modelId,wireModel,maxInputTokens,maxOutputTokens.- README explicitly says
modelis required when usingprovider. enableSessionTelemetryis always disabled when a customprovideris configured.
Legality / unresolved combinations
- Explicitly documented illegal/mutually exclusive combos:
cliUrlwithuseLoggedInUser- constructor rejects mutually exclusive options such as
cliUrlwithuseStdioorcliPath
- The inspected inventory does not explicitly document whether
providermay 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).
12. copilotHome
What is explicit in the inventory:
copilotHomeis the base directory for Copilot data: "session state, config, etc."; it setsCOPILOT_HOMEon the spawned CLI process.- If omitted, the CLI defaults to
~/.copilot. workspacePathexamples place per-session state under~/.copilot/session-state/{sessionId}/, withcheckpoints/,plan.md, andfiles/inside that session directory.
What is not explicit in the inventory:
- Exact full directory tree under
copilotHome - File/lock semantics for multiple
CopilotClientinstances sharing the samecopilotHome - Whether same-process sharing is safe under concurrent session creation/resume/delete
OpenClaw 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).
13. Replay / resume
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 includingsessionId,startTime,modifiedTime,summary?,isRemote,context?.getSessionMetadata(sessionId)is a targeted metadata lookup.getLastSessionId()returns the most recently updated session id.- Resume-specific semantics in
ResumeSessionConfig:disableResume?: booleanskips emittingsession.resumecontinuePendingWork?: booleanresumes in-flight permissions/tool work; otherwise pending work is treated as interrupted and permissions are re-emitted aspermission.requested
- Resume event metadata distinguishes hot vs cold attach:
sessionWasActive?: booleanmeans the runtime already had the session in memoryfalse/missing means a cold resume reconstructed from persisted event log
Sources: 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.
14. Models advertised
Explicit model ids mentioned in the inspected inventory:
gpt-5gpt-4gpt-4.1claude-sonnet-4.5claude-sonnet-4.6- example BYOK/Ollama model:
deepseek-coder-v2:16b
Discovery API:
client.listModels(): Promise<ModelInfo[]>is the authoritative discovery path.ModelInfocarriesid,name,capabilities, optionalpolicy, optionalbilling, optionalsupportedReasoningEfforts, optionaldefaultReasoningEffort.CopilotClientOptions.onListModelscan override discovery entirely (useful for BYOK mode).
What is not in the inspected inventory:
- A static canonical built-in model catalog beyond the handful of examples above.
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).
15. Error surface
Public methods
- Public methods generally document
@throws Error; the SDK does not expose a rich public exception-class hierarchy in the inspected.d.tsfiles. stop()is unusual: instead of throwing cleanup failures, it resolves toError[].- Constructor may throw on mutually exclusive options.
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.Toolregistration can throw for built-in name collisions unlessoverridesBuiltInTool: trueis set.- README says missing
modelwith customproviderthrows. - Protocol-v2 permission adapter throws the exported
NO_RESULT_PERMISSION_V2_ERRORif a handler returnsno-result.
Event / telemetry error reporting
session.errorcarries{ errorType, message, errorCode?, statusCode?, providerCallId?, stack?, url?, eligibleForAutoSwitch? }.model.call_failurecarries failed model-call telemetry (source,model?,statusCode?,durationMs?,providerCallId?,errorMessage?).tool.execution_complete.errorcarries{ code?, message }.- Hook APIs expose explicit recovery output:
onErrorOccurredmay returnerrorHandling: "retry" | "skip" | "abort"plusretryCount?.
Retryability
- Explicitly retry-like signals in the inspected surface:
session.error.eligibleForAutoSwitchfor rate-limit flowsauto_mode_switch.requested/auto_mode_switch.completedeventsonErrorOccurredhook outputerrorHandling: "retry"
- The SDK does not publish a general retryable/non-retryable error enum for all thrown errors. Anything beyond the rate-limit/auto-switch path needs probing.
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).
16. Open SDK questions
Concrete gaps to answer in spike-app before landing a real harness:
- Permission handler typing mismatch: README says
onPermissionRequestreceives rich per-kind fields (toolName,fileName,fullCommandText), butdist/types.d.tstypesPermissionRequestas just{ kind, toolCallId? }. What object shape does runtime actually deliver to JS/TS handlers? - Permission timeouts: what happens if
onPermissionRequestnever resolves? Is there a default timeout, cancellation, or session hang? - User-input timeouts/cancellation: same question for
onUserInputRequest. copilotHomeconcurrency: can multipleCopilotClientinstances in one process safely share onecopilotHome, or are there lock/race hazards aroundsession-state/and config files?- Exact
copilotHomelayout: beyondsession-state/<id>/{checkpoints,plan.md,files}, what other top-level files/directories are created, and which are session-global versus client-global? - Provider/auth combination matrix: what combinations of client-level
gitHubToken, session-levelgitHubToken,useLoggedInUser, andproviderare accepted or rejected in practice? - Resume behavior for encrypted reasoning fields:
assistant.messagenotesencryptedContent/reasoningOpaqueare session-bound and stripped on resume. What survives after process restart versus live reconnect? - Event coverage needed by OpenClaw: do we need additional exact-string handling for non-core events like
ToolsUpdatedEvent,SkillsLoadedEvent,McpServersLoadedEvent,ExtensionsLoadedEvent, or is the harness safe to ignore them? - Cold-resume pending work: with
continuePendingWork: true, what concrete low-level RPCs are required to finish previously pending external tool calls in an SDK-only consumer? - Model discovery under BYOK: when
provideris set withoutonListModels, what doeslistModels()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.