🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@github/copilot-sdk

Package Overview
Dependencies
Maintainers
20
Versions
71
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@github/copilot-sdk - npm Package Compare versions

Comparing version
0.1.10-preview.1
to
0.1.10
+306
dist/nodejs/src/client.d.ts
import { CopilotSession } from "./session.js";
import type { ConnectionState, CopilotClientOptions, ResumeSessionConfig, SessionConfig, SessionMetadata } from "./types.js";
/**
* Main client for interacting with the Copilot CLI.
*
* The CopilotClient manages the connection to the Copilot CLI server and provides
* methods to create and manage conversation sessions. It can either spawn a CLI
* server process or connect to an existing server.
*
* @example
* ```typescript
* import { CopilotClient } from "@github/copilot-sdk";
*
* // Create a client with default options (spawns CLI server)
* const client = new CopilotClient();
*
* // Or connect to an existing server
* const client = new CopilotClient({ cliUrl: "localhost:3000" });
*
* // Create a session
* const session = await client.createSession({ model: "gpt-4" });
*
* // Send messages and handle responses
* session.on((event) => {
* if (event.type === "assistant.message") {
* console.log(event.data.content);
* }
* });
* await session.send({ prompt: "Hello!" });
*
* // Clean up
* await session.destroy();
* await client.stop();
* ```
*/
export declare class CopilotClient {
private cliProcess;
private connection;
private socket;
private actualPort;
private actualHost;
private state;
private sessions;
private options;
private isExternalServer;
private forceStopping;
/**
* Creates a new CopilotClient instance.
*
* @param options - Configuration options for the client
* @throws Error if mutually exclusive options are provided (e.g., cliUrl with useStdio or cliPath)
*
* @example
* ```typescript
* // Default options - spawns CLI server using stdio
* const client = new CopilotClient();
*
* // Connect to an existing server
* const client = new CopilotClient({ cliUrl: "localhost:3000" });
*
* // Custom CLI path with specific log level
* const client = new CopilotClient({
* cliPath: "/usr/local/bin/copilot",
* logLevel: "debug"
* });
* ```
*/
constructor(options?: CopilotClientOptions);
/**
* Parse CLI URL into host and port
* Supports formats: "host:port", "http://host:port", "https://host:port", or just "port"
*/
private parseCliUrl;
/**
* Starts the CLI server and establishes a connection.
*
* If connecting to an external server (via cliUrl), only establishes the connection.
* Otherwise, spawns the CLI server process and then connects.
*
* This method is called automatically when creating a session if `autoStart` is true (default).
*
* @returns A promise that resolves when the connection is established
* @throws Error if the server fails to start or the connection fails
*
* @example
* ```typescript
* const client = new CopilotClient({ autoStart: false });
* await client.start();
* // Now ready to create sessions
* ```
*/
start(): Promise<void>;
/**
* Stops the CLI server and closes all active sessions.
*
* This method performs graceful cleanup:
* 1. Destroys all active sessions with retry logic
* 2. Closes the JSON-RPC connection
* 3. Terminates the CLI server process (if spawned by this client)
*
* @returns A promise that resolves with an array of errors encountered during cleanup.
* An empty array indicates all cleanup succeeded.
*
* @example
* ```typescript
* const errors = await client.stop();
* if (errors.length > 0) {
* console.error("Cleanup errors:", errors);
* }
* ```
*/
stop(): Promise<Error[]>;
/**
* Forcefully stops the CLI server without graceful cleanup.
*
* Use this when {@link stop} fails or takes too long. This method:
* - Clears all sessions immediately without destroying them
* - Force closes the connection
* - Sends SIGKILL to the CLI process (if spawned by this client)
*
* @returns A promise that resolves when the force stop is complete
*
* @example
* ```typescript
* // If normal stop hangs, force stop
* const stopPromise = client.stop();
* const timeout = new Promise((_, reject) =>
* setTimeout(() => reject(new Error("Timeout")), 5000)
* );
*
* try {
* await Promise.race([stopPromise, timeout]);
* } catch {
* await client.forceStop();
* }
* ```
*/
forceStop(): Promise<void>;
/**
* Creates a new conversation session with the Copilot CLI.
*
* Sessions maintain conversation state, handle events, and manage tool execution.
* If the client is not connected and `autoStart` is enabled, this will automatically
* start the connection.
*
* @param config - Optional configuration for the session
* @returns A promise that resolves with the created session
* @throws Error if the client is not connected and autoStart is disabled
*
* @example
* ```typescript
* // Basic session
* const session = await client.createSession();
*
* // Session with model and tools
* const session = await client.createSession({
* model: "gpt-4",
* tools: [{
* name: "get_weather",
* description: "Get weather for a location",
* parameters: { type: "object", properties: { location: { type: "string" } } },
* handler: async (args) => ({ temperature: 72 })
* }]
* });
* ```
*/
createSession(config?: SessionConfig): Promise<CopilotSession>;
/**
* Resumes an existing conversation session by its ID.
*
* This allows you to continue a previous conversation, maintaining all
* conversation history. The session must have been previously created
* and not deleted.
*
* @param sessionId - The ID of the session to resume
* @param config - Optional configuration for the resumed session
* @returns A promise that resolves with the resumed session
* @throws Error if the session does not exist or the client is not connected
*
* @example
* ```typescript
* // Resume a previous session
* const session = await client.resumeSession("session-123");
*
* // Resume with new tools
* const session = await client.resumeSession("session-123", {
* tools: [myNewTool]
* });
* ```
*/
resumeSession(sessionId: string, config?: ResumeSessionConfig): Promise<CopilotSession>;
/**
* Gets the current connection state of the client.
*
* @returns The current connection state: "disconnected", "connecting", "connected", or "error"
*
* @example
* ```typescript
* if (client.getState() === "connected") {
* const session = await client.createSession();
* }
* ```
*/
getState(): ConnectionState;
/**
* Sends a ping request to the server to verify connectivity.
*
* @param message - Optional message to include in the ping
* @returns A promise that resolves with the ping response containing the message and timestamp
* @throws Error if the client is not connected
*
* @example
* ```typescript
* const response = await client.ping("health check");
* console.log(`Server responded at ${new Date(response.timestamp)}`);
* ```
*/
ping(message?: string): Promise<{
message: string;
timestamp: number;
protocolVersion?: number;
}>;
/**
* Verify that the server's protocol version matches the SDK's expected version
*/
private verifyProtocolVersion;
/**
* Gets the ID of the most recently updated session.
*
* This is useful for resuming the last conversation when the session ID
* was not stored.
*
* @returns A promise that resolves with the session ID, or undefined if no sessions exist
* @throws Error if the client is not connected
*
* @example
* ```typescript
* const lastId = await client.getLastSessionId();
* if (lastId) {
* const session = await client.resumeSession(lastId);
* }
* ```
*/
getLastSessionId(): Promise<string | undefined>;
/**
* Deletes a session and its data from disk.
*
* This permanently removes the session and all its conversation history.
* The session cannot be resumed after deletion.
*
* @param sessionId - The ID of the session to delete
* @returns A promise that resolves when the session is deleted
* @throws Error if the session does not exist or deletion fails
*
* @example
* ```typescript
* await client.deleteSession("session-123");
* ```
*/
deleteSession(sessionId: string): Promise<void>;
/**
* Lists all available sessions known to the server.
*
* Returns metadata about each session including ID, timestamps, and summary.
*
* @returns A promise that resolves with an array of session metadata
* @throws Error if the client is not connected
*
* @example
* ```typescript
* const sessions = await client.listSessions();
* for (const session of sessions) {
* console.log(`${session.sessionId}: ${session.summary}`);
* }
* ```
*/
listSessions(): Promise<SessionMetadata[]>;
/**
* Start the CLI server process
*/
private startCLIServer;
/**
* Connect to the CLI server (via socket or stdio)
*/
private connectToServer;
/**
* Connect via stdio pipes
*/
private connectViaStdio;
/**
* Connect to the CLI server via TCP socket
*/
private connectViaTcp;
private attachConnectionHandlers;
private handleSessionEventNotification;
private handleToolCallRequest;
private executeToolCall;
private handlePermissionRequest;
private normalizeToolResult;
private isToolResultObject;
private buildUnsupportedToolResult;
/**
* Attempt to reconnect to the server
*/
private reconnect;
}
/**
* AUTO-GENERATED FILE - DO NOT EDIT
*
* Generated from: @github/copilot/session-events.schema.json
* Generated by: scripts/generate-session-types.ts
* Generated at: 2026-01-13T00:08:20.716Z
*
* To update these types:
* 1. Update the schema in copilot-agent-runtime
* 2. Run: npm run generate:session-types
*/
export type SessionEvent = {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.start";
data: {
sessionId: string;
version: number;
producer: string;
copilotVersion: string;
startTime: string;
selectedModel?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.resume";
data: {
resumeTime: string;
eventCount: number;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.error";
data: {
errorType: string;
message: string;
stack?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral: true;
type: "session.idle";
data: {};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.info";
data: {
infoType: string;
message: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.model_change";
data: {
previousModel?: string;
newModel: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.handoff";
data: {
handoffTime: string;
sourceType: "remote" | "local";
repository?: {
owner: string;
name: string;
branch?: string;
};
context?: string;
summary?: string;
remoteSessionId?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.truncation";
data: {
tokenLimit: number;
preTruncationTokensInMessages: number;
preTruncationMessagesLength: number;
postTruncationTokensInMessages: number;
postTruncationMessagesLength: number;
tokensRemovedDuringTruncation: number;
messagesRemovedDuringTruncation: number;
performedBy: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "user.message";
data: {
content: string;
transformedContent?: string;
attachments?: {
type: "file" | "directory";
path: string;
displayName: string;
}[];
source?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral: true;
type: "pending_messages.modified";
data: {};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "assistant.turn_start";
data: {
turnId: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral: true;
type: "assistant.intent";
data: {
intent: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "assistant.reasoning";
data: {
reasoningId: string;
content: string;
chunkContent?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: true;
type: "assistant.reasoning_delta";
data: {
reasoningId: string;
deltaContent: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "assistant.message";
data: {
messageId: string;
content: string;
chunkContent?: string;
totalResponseSizeBytes?: number;
toolRequests?: {
toolCallId: string;
name: string;
arguments?: unknown;
}[];
parentToolCallId?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: true;
type: "assistant.message_delta";
data: {
messageId: string;
deltaContent: string;
totalResponseSizeBytes?: number;
parentToolCallId?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "assistant.turn_end";
data: {
turnId: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral: true;
type: "assistant.usage";
data: {
model?: string;
inputTokens?: number;
outputTokens?: number;
cacheReadTokens?: number;
cacheWriteTokens?: number;
cost?: number;
duration?: number;
initiator?: string;
apiCallId?: string;
providerCallId?: string;
quotaSnapshots?: {
[k: string]: {
isUnlimitedEntitlement: boolean;
entitlementRequests: number;
usedRequests: number;
usageAllowedWithExhaustedQuota: boolean;
overage: number;
overageAllowedWithExhaustedQuota: boolean;
remainingPercentage: number;
resetDate?: string;
};
};
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "abort";
data: {
reason: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "tool.user_requested";
data: {
toolCallId: string;
toolName: string;
arguments?: unknown;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "tool.execution_start";
data: {
toolCallId: string;
toolName: string;
arguments?: unknown;
parentToolCallId?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral: true;
type: "tool.execution_partial_result";
data: {
toolCallId: string;
partialOutput: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "tool.execution_complete";
data: {
toolCallId: string;
success: boolean;
isUserRequested?: boolean;
result?: {
content: string;
};
error?: {
message: string;
code?: string;
};
toolTelemetry?: {
[k: string]: unknown;
};
parentToolCallId?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "custom_agent.started";
data: {
toolCallId: string;
agentName: string;
agentDisplayName: string;
agentDescription: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "custom_agent.completed";
data: {
toolCallId: string;
agentName: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "custom_agent.failed";
data: {
toolCallId: string;
agentName: string;
error: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "custom_agent.selected";
data: {
agentName: string;
agentDisplayName: string;
tools: string[] | null;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "hook.start";
data: {
hookInvocationId: string;
hookType: string;
input?: unknown;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "hook.end";
data: {
hookInvocationId: string;
hookType: string;
output?: unknown;
success: boolean;
error?: {
message: string;
stack?: string;
};
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "system.message";
data: {
content: string;
role: "system" | "developer";
name?: string;
metadata?: {
promptVersion?: string;
variables?: {
[k: string]: unknown;
};
};
};
};
/**
* Copilot SDK - TypeScript/Node.js Client
*
* JSON-RPC based SDK for programmatic control of GitHub Copilot CLI
*/
export { CopilotClient } from "./client.js";
export { CopilotSession } from "./session.js";
export { defineTool } from "./types.js";
export type { ConnectionState, CopilotClientOptions, CustomAgentConfig, MCPLocalServerConfig, MCPRemoteServerConfig, MCPServerConfig, MessageOptions, PermissionHandler, PermissionRequest, PermissionRequestResult, ResumeSessionConfig, SessionConfig, SessionEvent, SessionEventHandler, SessionMetadata, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageReplaceConfig, Tool, ToolHandler, ToolInvocation, ToolResultObject, ZodSchema, } from "./types.js";
/**
* Gets the SDK protocol version from sdk-protocol-version.json.
* @returns The protocol version number
*/
export declare function getSdkProtocolVersion(): number;
/**
* Copilot Session - represents a single conversation session with the Copilot CLI.
* @module session
*/
import type { MessageConnection } from "vscode-jsonrpc/node";
import type { MessageOptions, PermissionHandler, PermissionRequestResult, SessionEvent, SessionEventHandler, Tool, ToolHandler } from "./types.js";
/**
* Represents a single conversation session with the Copilot CLI.
*
* A session maintains conversation state, handles events, and manages tool execution.
* Sessions are created via {@link CopilotClient.createSession} or resumed via
* {@link CopilotClient.resumeSession}.
*
* @example
* ```typescript
* const session = await client.createSession({ model: "gpt-4" });
*
* // Subscribe to events
* const unsubscribe = session.on((event) => {
* if (event.type === "assistant.message") {
* console.log(event.data.content);
* }
* });
*
* // Send a message
* await session.send({ prompt: "Hello, world!" });
*
* // Clean up
* unsubscribe();
* await session.destroy();
* ```
*/
export declare class CopilotSession {
readonly sessionId: string;
private connection;
private eventHandlers;
private toolHandlers;
private permissionHandler?;
/**
* Creates a new CopilotSession instance.
*
* @param sessionId - The unique identifier for this session
* @param connection - The JSON-RPC message connection to the Copilot CLI
* @internal This constructor is internal. Use {@link CopilotClient.createSession} to create sessions.
*/
constructor(sessionId: string, connection: MessageConnection);
/**
* Sends a message to this session and waits for the response.
*
* The message is processed asynchronously. Subscribe to events via {@link on}
* to receive streaming responses and other session events.
*
* @param options - The message options including the prompt and optional attachments
* @returns A promise that resolves with the message ID of the response
* @throws Error if the session has been destroyed or the connection fails
*
* @example
* ```typescript
* const messageId = await session.send({
* prompt: "Explain this code",
* attachments: [{ type: "file", path: "./src/index.ts" }]
* });
* ```
*/
send(options: MessageOptions): Promise<string>;
/**
* Subscribes to events from this session.
*
* Events include assistant messages, tool executions, errors, and session state changes.
* Multiple handlers can be registered and will all receive events.
*
* @param handler - A callback function that receives session events
* @returns A function that, when called, unsubscribes the handler
*
* @example
* ```typescript
* const unsubscribe = session.on((event) => {
* switch (event.type) {
* case "assistant.message":
* console.log("Assistant:", event.data.content);
* break;
* case "session.error":
* console.error("Error:", event.data.message);
* break;
* }
* });
*
* // Later, to stop receiving events:
* unsubscribe();
* ```
*/
on(handler: SessionEventHandler): () => void;
/**
* Dispatches an event to all registered handlers.
*
* @param event - The session event to dispatch
* @internal This method is for internal use by the SDK.
*/
_dispatchEvent(event: SessionEvent): void;
/**
* Registers custom tool handlers for this session.
*
* Tools allow the assistant to execute custom functions. When the assistant
* invokes a tool, the corresponding handler is called with the tool arguments.
*
* @param tools - An array of tool definitions with their handlers, or undefined to clear all tools
* @internal This method is typically called internally when creating a session with tools.
*/
registerTools(tools?: Tool[]): void;
/**
* Retrieves a registered tool handler by name.
*
* @param name - The name of the tool to retrieve
* @returns The tool handler if found, or undefined
* @internal This method is for internal use by the SDK.
*/
getToolHandler(name: string): ToolHandler | undefined;
/**
* Registers a handler for permission requests.
*
* When the assistant needs permission to perform certain actions (e.g., file operations),
* this handler is called to approve or deny the request.
*
* @param handler - The permission handler function, or undefined to remove the handler
* @internal This method is typically called internally when creating a session.
*/
registerPermissionHandler(handler?: PermissionHandler): void;
/**
* Handles a permission request from the Copilot CLI.
*
* @param request - The permission request data from the CLI
* @returns A promise that resolves with the permission decision
* @internal This method is for internal use by the SDK.
*/
_handlePermissionRequest(request: unknown): Promise<PermissionRequestResult>;
/**
* Retrieves all events and messages from this session's history.
*
* This returns the complete conversation history including user messages,
* assistant responses, tool executions, and other session events.
*
* @returns A promise that resolves with an array of all session events
* @throws Error if the session has been destroyed or the connection fails
*
* @example
* ```typescript
* const events = await session.getMessages();
* for (const event of events) {
* if (event.type === "assistant.message") {
* console.log("Assistant:", event.data.content);
* }
* }
* ```
*/
getMessages(): Promise<SessionEvent[]>;
/**
* Destroys this session and releases all associated resources.
*
* After calling this method, the session can no longer be used. All event
* handlers and tool handlers are cleared. To continue the conversation,
* use {@link CopilotClient.resumeSession} with the session ID.
*
* @returns A promise that resolves when the session is destroyed
* @throws Error if the connection fails
*
* @example
* ```typescript
* // Clean up when done
* await session.destroy();
* ```
*/
destroy(): Promise<void>;
/**
* Aborts the currently processing message in this session.
*
* Use this to cancel a long-running request. The session remains valid
* and can continue to be used for new messages.
*
* @returns A promise that resolves when the abort request is acknowledged
* @throws Error if the session has been destroyed or the connection fails
*
* @example
* ```typescript
* // Start a long-running request
* const messagePromise = session.send({ prompt: "Write a very long story..." });
*
* // Abort after 5 seconds
* setTimeout(async () => {
* await session.abort();
* }, 5000);
* ```
*/
abort(): Promise<void>;
}
/**
* Type definitions for the Copilot SDK
*/
import type { SessionEvent as GeneratedSessionEvent } from "./generated/session-events.js";
export type SessionEvent = GeneratedSessionEvent;
/**
* Options for creating a CopilotClient
*/
export interface CopilotClientOptions {
/**
* Path to the Copilot CLI executable
* @default "copilot" (searches PATH)
*/
cliPath?: string;
/**
* Extra arguments to pass to the CLI executable (inserted before SDK-managed args)
*/
cliArgs?: string[];
/**
* Working directory for the CLI process
* If not set, inherits the current process's working directory
*/
cwd?: string;
/**
* Port for the CLI server (TCP mode only)
* @default 0 (random available port)
*/
port?: number;
/**
* Use stdio transport instead of TCP
* When true, communicates with CLI via stdin/stdout pipes
* @default true
*/
useStdio?: boolean;
/**
* URL of an existing Copilot CLI server to connect to over TCP
* When provided, the client will not spawn a CLI process
* Format: "host:port" or "http://host:port" or just "port" (defaults to localhost)
* Examples: "localhost:8080", "http://127.0.0.1:9000", "8080"
* Mutually exclusive with cliPath, useStdio
*/
cliUrl?: string;
/**
* Log level for the CLI server
*/
logLevel?: "none" | "error" | "warning" | "info" | "debug" | "all";
/**
* Auto-start the CLI server on first use
* @default true
*/
autoStart?: boolean;
/**
* Auto-restart the CLI server if it crashes
* @default true
*/
autoRestart?: boolean;
/**
* Environment variables to pass to the CLI process. If not set, inherits process.env.
*/
env?: Record<string, string | undefined>;
}
/**
* Configuration for creating a session
*/
export type ToolResultType = "success" | "failure" | "rejected" | "denied";
export type ToolBinaryResult = {
data: string;
mimeType: string;
type: string;
description?: string;
};
export type ToolResultObject = {
textResultForLlm: string;
binaryResultsForLlm?: ToolBinaryResult[];
resultType: ToolResultType;
error?: string;
sessionLog?: string;
toolTelemetry?: Record<string, unknown>;
};
export type ToolResult = string | ToolResultObject;
export interface ToolInvocation {
sessionId: string;
toolCallId: string;
toolName: string;
arguments: unknown;
}
export type ToolHandler<TArgs = unknown> = (args: TArgs, invocation: ToolInvocation) => Promise<unknown> | unknown;
/**
* Zod-like schema interface for type inference.
* Any object with `toJSONSchema()` method is treated as a Zod schema.
*/
export interface ZodSchema<T = unknown> {
_output: T;
toJSONSchema(): Record<string, unknown>;
}
/**
* Tool definition. Parameters can be either:
* - A Zod schema (provides type inference for handler)
* - A raw JSON schema object
* - Omitted (no parameters)
*/
export interface Tool<TArgs = unknown> {
name: string;
description?: string;
parameters?: ZodSchema<TArgs> | Record<string, unknown>;
handler: ToolHandler<TArgs>;
}
/**
* Helper to define a tool with Zod schema and get type inference for the handler.
* Without this helper, TypeScript cannot infer handler argument types from Zod schemas.
*/
export declare function defineTool<T = unknown>(name: string, config: {
description?: string;
parameters?: ZodSchema<T> | Record<string, unknown>;
handler: ToolHandler<T>;
}): Tool<T>;
export interface ToolCallRequestPayload {
sessionId: string;
toolCallId: string;
toolName: string;
arguments: unknown;
}
export interface ToolCallResponsePayload {
result: ToolResult;
}
/**
* Append mode: Use CLI foundation with optional appended content (default).
*/
export interface SystemMessageAppendConfig {
mode?: "append";
/**
* Additional instructions appended after SDK-managed sections.
*/
content?: string;
}
/**
* Replace mode: Use caller-provided system message entirely.
* Removes all SDK guardrails including security restrictions.
*/
export interface SystemMessageReplaceConfig {
mode: "replace";
/**
* Complete system message content.
* Replaces the entire SDK-managed system message.
*/
content: string;
}
/**
* System message configuration for session creation.
* - Append mode (default): SDK foundation + optional custom content
* - Replace mode: Full control, caller provides entire system message
*/
export type SystemMessageConfig = SystemMessageAppendConfig | SystemMessageReplaceConfig;
/**
* Permission request types from the server
*/
export interface PermissionRequest {
kind: "shell" | "write" | "mcp" | "read" | "url";
toolCallId?: string;
[key: string]: unknown;
}
export interface PermissionRequestResult {
kind: "approved" | "denied-by-rules" | "denied-no-approval-rule-and-could-not-request-from-user" | "denied-interactively-by-user";
rules?: unknown[];
}
export type PermissionHandler = (request: PermissionRequest, invocation: {
sessionId: string;
}) => Promise<PermissionRequestResult> | PermissionRequestResult;
/**
* Base interface for MCP server configuration.
*/
interface MCPServerConfigBase {
/**
* List of tools to include from this server. [] means none. "*" means all.
*/
tools: string[];
/**
* Indicates "remote" or "local" server type.
* If not specified, defaults to "local".
*/
type?: string;
/**
* Optional timeout in milliseconds for tool calls to this server.
*/
timeout?: number;
}
/**
* Configuration for a local/stdio MCP server.
*/
export interface MCPLocalServerConfig extends MCPServerConfigBase {
type?: "local" | "stdio";
command: string;
args: string[];
/**
* Environment variables to pass to the server.
*/
env?: Record<string, string>;
cwd?: string;
}
/**
* Configuration for a remote MCP server (HTTP or SSE).
*/
export interface MCPRemoteServerConfig extends MCPServerConfigBase {
type: "http" | "sse";
/**
* URL of the remote server.
*/
url: string;
/**
* Optional HTTP headers to include in requests.
*/
headers?: Record<string, string>;
}
/**
* Union type for MCP server configurations.
*/
export type MCPServerConfig = MCPLocalServerConfig | MCPRemoteServerConfig;
/**
* Configuration for a custom agent.
*/
export interface CustomAgentConfig {
/**
* Unique name of the custom agent.
*/
name: string;
/**
* Display name for UI purposes.
*/
displayName?: string;
/**
* Description of what the agent does.
*/
description?: string;
/**
* List of tool names the agent can use.
* Use null or undefined for all tools.
*/
tools?: string[] | null;
/**
* The prompt content for the agent.
*/
prompt: string;
/**
* MCP servers specific to this agent.
*/
mcpServers?: Record<string, MCPServerConfig>;
/**
* Whether the agent should be available for model inference.
* @default true
*/
infer?: boolean;
}
export interface SessionConfig {
/**
* Optional custom session ID
* If not provided, server will generate one
*/
sessionId?: string;
/**
* Model to use for this session
*/
model?: string;
/**
* Tools exposed to the CLI server
*/
tools?: Tool<any>[];
/**
* System message configuration
* Controls how the system prompt is constructed
*/
systemMessage?: SystemMessageConfig;
/**
* List of tool names to allow. When specified, only these tools will be available.
* Takes precedence over excludedTools.
*/
availableTools?: string[];
/**
* List of tool names to disable. All other tools remain available.
* Ignored if availableTools is specified.
*/
excludedTools?: string[];
/**
* Custom provider configuration (BYOK - Bring Your Own Key).
* When specified, uses the provided API endpoint instead of the Copilot API.
*/
provider?: ProviderConfig;
/**
* Handler for permission requests from the server.
* When provided, the server will call this handler to request permission for operations.
*/
onPermissionRequest?: PermissionHandler;
streaming?: boolean;
/**
* MCP server configurations for the session.
* Keys are server names, values are server configurations.
*/
mcpServers?: Record<string, MCPServerConfig>;
/**
* Custom agent configurations for the session.
*/
customAgents?: CustomAgentConfig[];
}
/**
* Configuration for resuming a session
*/
export type ResumeSessionConfig = Pick<SessionConfig, "tools" | "provider" | "streaming" | "onPermissionRequest" | "mcpServers" | "customAgents">;
/**
* Configuration for a custom API provider.
*/
export interface ProviderConfig {
/**
* Provider type. Defaults to "openai" for generic OpenAI-compatible APIs.
*/
type?: "openai" | "azure" | "anthropic";
/**
* API format (openai/azure only). Defaults to "completions".
*/
wireApi?: "completions" | "responses";
/**
* API endpoint URL
*/
baseUrl: string;
/**
* API key. Optional for local providers like Ollama.
*/
apiKey?: string;
/**
* Bearer token for authentication. Sets the Authorization header directly.
* Use this for services requiring bearer token auth instead of API key.
* Takes precedence over apiKey when both are set.
*/
bearerToken?: string;
/**
* Azure-specific options
*/
azure?: {
/**
* API version. Defaults to "2024-10-21".
*/
apiVersion?: string;
};
}
/**
* Options for sending a message to a session
*/
export interface MessageOptions {
/**
* The prompt/message to send
*/
prompt: string;
/**
* File or directory attachments
*/
attachments?: Array<{
type: "file" | "directory";
path: string;
displayName?: string;
}>;
/**
* Message delivery mode
* - "enqueue": Add to queue (default)
* - "immediate": Send immediately
*/
mode?: "enqueue" | "immediate";
}
/**
* Event handler callback type
*/
export type SessionEventHandler = (event: SessionEvent) => void;
/**
* Connection state
*/
export type ConnectionState = "disconnected" | "connecting" | "connected" | "error";
/**
* Metadata about a session
*/
export interface SessionMetadata {
sessionId: string;
startTime: Date;
modifiedTime: Date;
summary?: string;
isRemote: boolean;
}
export {};
import sdkProtocolVersion from "../../sdk-protocol-version.json";
function getSdkProtocolVersion() {
return sdkProtocolVersion.version;
}
export {
getSdkProtocolVersion
};
+213
-17

@@ -9,2 +9,3 @@ import { spawn } from "node:child_process";

import { CopilotSession } from "./session.js";
import { getSdkProtocolVersion } from "./sdkProtocolVersion.js";
function isZodSchema(value) {

@@ -31,2 +32,23 @@ return value != null && typeof value === "object" && "toJSONSchema" in value && typeof value.toJSONSchema === "function";

forceStopping = false;
/**
* Creates a new CopilotClient instance.
*
* @param options - Configuration options for the client
* @throws Error if mutually exclusive options are provided (e.g., cliUrl with useStdio or cliPath)
*
* @example
* ```typescript
* // Default options - spawns CLI server using stdio
* const client = new CopilotClient();
*
* // Connect to an existing server
* const client = new CopilotClient({ cliUrl: "localhost:3000" });
*
* // Custom CLI path with specific log level
* const client = new CopilotClient({
* cliPath: "/usr/local/bin/copilot",
* logLevel: "debug"
* });
* ```
*/
constructor(options = {}) {

@@ -79,3 +101,18 @@ if (options.cliUrl && (options.useStdio === true || options.cliPath)) {

/**
* Start the CLI server and establish connection
* Starts the CLI server and establishes a connection.
*
* If connecting to an external server (via cliUrl), only establishes the connection.
* Otherwise, spawns the CLI server process and then connects.
*
* This method is called automatically when creating a session if `autoStart` is true (default).
*
* @returns A promise that resolves when the connection is established
* @throws Error if the server fails to start or the connection fails
*
* @example
* ```typescript
* const client = new CopilotClient({ autoStart: false });
* await client.start();
* // Now ready to create sessions
* ```
*/

@@ -92,2 +129,3 @@ async start() {

await this.connectToServer();
await this.verifyProtocolVersion();
this.state = "connected";

@@ -100,4 +138,19 @@ } catch (error) {

/**
* Stop the CLI server and close all sessions
* Returns array of errors encountered during cleanup (empty if all succeeded)
* Stops the CLI server and closes all active sessions.
*
* This method performs graceful cleanup:
* 1. Destroys all active sessions with retry logic
* 2. Closes the JSON-RPC connection
* 3. Terminates the CLI server process (if spawned by this client)
*
* @returns A promise that resolves with an array of errors encountered during cleanup.
* An empty array indicates all cleanup succeeded.
*
* @example
* ```typescript
* const errors = await client.stop();
* if (errors.length > 0) {
* console.error("Cleanup errors:", errors);
* }
* ```
*/

@@ -172,4 +225,25 @@ async stop() {

/**
* Force stop the CLI server without graceful cleanup
* Use when normal stop() fails or takes too long
* Forcefully stops the CLI server without graceful cleanup.
*
* Use this when {@link stop} fails or takes too long. This method:
* - Clears all sessions immediately without destroying them
* - Force closes the connection
* - Sends SIGKILL to the CLI process (if spawned by this client)
*
* @returns A promise that resolves when the force stop is complete
*
* @example
* ```typescript
* // If normal stop hangs, force stop
* const stopPromise = client.stop();
* const timeout = new Promise((_, reject) =>
* setTimeout(() => reject(new Error("Timeout")), 5000)
* );
*
* try {
* await Promise.race([stopPromise, timeout]);
* } catch {
* await client.forceStop();
* }
* ```
*/

@@ -204,3 +278,28 @@ async forceStop() {

/**
* Create a new session
* Creates a new conversation session with the Copilot CLI.
*
* Sessions maintain conversation state, handle events, and manage tool execution.
* If the client is not connected and `autoStart` is enabled, this will automatically
* start the connection.
*
* @param config - Optional configuration for the session
* @returns A promise that resolves with the created session
* @throws Error if the client is not connected and autoStart is disabled
*
* @example
* ```typescript
* // Basic session
* const session = await client.createSession();
*
* // Session with model and tools
* const session = await client.createSession({
* model: "gpt-4",
* tools: [{
* name: "get_weather",
* description: "Get weather for a location",
* parameters: { type: "object", properties: { location: { type: "string" } } },
* handler: async (args) => ({ temperature: 72 })
* }]
* });
* ```
*/

@@ -228,3 +327,5 @@ async createSession(config = {}) {

requestPermission: !!config.onPermissionRequest,
streaming: config.streaming
streaming: config.streaming,
mcpServers: config.mcpServers,
customAgents: config.customAgents
});

@@ -241,3 +342,23 @@ const sessionId = response.sessionId;

/**
* Resume an existing session
* Resumes an existing conversation session by its ID.
*
* This allows you to continue a previous conversation, maintaining all
* conversation history. The session must have been previously created
* and not deleted.
*
* @param sessionId - The ID of the session to resume
* @param config - Optional configuration for the resumed session
* @returns A promise that resolves with the resumed session
* @throws Error if the session does not exist or the client is not connected
*
* @example
* ```typescript
* // Resume a previous session
* const session = await client.resumeSession("session-123");
*
* // Resume with new tools
* const session = await client.resumeSession("session-123", {
* tools: [myNewTool]
* });
* ```
*/

@@ -261,3 +382,5 @@ async resumeSession(sessionId, config = {}) {

requestPermission: !!config.onPermissionRequest,
streaming: config.streaming
streaming: config.streaming,
mcpServers: config.mcpServers,
customAgents: config.customAgents
});

@@ -274,3 +397,12 @@ const resumedSessionId = response.sessionId;

/**
* Get connection state
* Gets the current connection state of the client.
*
* @returns The current connection state: "disconnected", "connecting", "connected", or "error"
*
* @example
* ```typescript
* if (client.getState() === "connected") {
* const session = await client.createSession();
* }
* ```
*/

@@ -281,3 +413,13 @@ getState() {

/**
* Ping the server
* Sends a ping request to the server to verify connectivity.
*
* @param message - Optional message to include in the ping
* @returns A promise that resolves with the ping response containing the message and timestamp
* @throws Error if the client is not connected
*
* @example
* ```typescript
* const response = await client.ping("health check");
* console.log(`Server responded at ${new Date(response.timestamp)}`);
* ```
*/

@@ -292,5 +434,36 @@ async ping(message) {

/**
* Get the ID of the most recently updated session
* @returns The session ID, or undefined if no sessions exist
* Verify that the server's protocol version matches the SDK's expected version
*/
async verifyProtocolVersion() {
const expectedVersion = getSdkProtocolVersion();
const pingResult = await this.ping();
const serverVersion = pingResult.protocolVersion;
if (serverVersion === void 0) {
throw new Error(
`SDK protocol version mismatch: SDK expects version ${expectedVersion}, but server does not report a protocol version. Please update your server to ensure compatibility.`
);
}
if (serverVersion !== expectedVersion) {
throw new Error(
`SDK protocol version mismatch: SDK expects version ${expectedVersion}, but server reports version ${serverVersion}. Please update your SDK or server to ensure compatibility.`
);
}
}
/**
* Gets the ID of the most recently updated session.
*
* This is useful for resuming the last conversation when the session ID
* was not stored.
*
* @returns A promise that resolves with the session ID, or undefined if no sessions exist
* @throws Error if the client is not connected
*
* @example
* ```typescript
* const lastId = await client.getLastSessionId();
* if (lastId) {
* const session = await client.resumeSession(lastId);
* }
* ```
*/
async getLastSessionId() {

@@ -304,4 +477,15 @@ if (!this.connection) {

/**
* Delete a session and its data from disk
* @param sessionId The ID of the session to delete
* Deletes a session and its data from disk.
*
* This permanently removes the session and all its conversation history.
* The session cannot be resumed after deletion.
*
* @param sessionId - The ID of the session to delete
* @returns A promise that resolves when the session is deleted
* @throws Error if the session does not exist or deletion fails
*
* @example
* ```typescript
* await client.deleteSession("session-123");
* ```
*/

@@ -322,4 +506,16 @@ async deleteSession(sessionId) {

/**
* List all available sessions
* @returns Array of session metadata
* Lists all available sessions known to the server.
*
* Returns metadata about each session including ID, timestamps, and summary.
*
* @returns A promise that resolves with an array of session metadata
* @throws Error if the client is not connected
*
* @example
* ```typescript
* const sessions = await client.listSessions();
* for (const session of sessions) {
* console.log(`${session.sessionId}: ${session.summary}`);
* }
* ```
*/

@@ -326,0 +522,0 @@ async listSessions() {

class CopilotSession {
/**
* Creates a new CopilotSession instance.
*
* @param sessionId - The unique identifier for this session
* @param connection - The JSON-RPC message connection to the Copilot CLI
* @internal This constructor is internal. Use {@link CopilotClient.createSession} to create sessions.
*/
constructor(sessionId, connection) {

@@ -10,3 +17,18 @@ this.sessionId = sessionId;

/**
* Send a message to this session
* Sends a message to this session and waits for the response.
*
* The message is processed asynchronously. Subscribe to events via {@link on}
* to receive streaming responses and other session events.
*
* @param options - The message options including the prompt and optional attachments
* @returns A promise that resolves with the message ID of the response
* @throws Error if the session has been destroyed or the connection fails
*
* @example
* ```typescript
* const messageId = await session.send({
* prompt: "Explain this code",
* attachments: [{ type: "file", path: "./src/index.ts" }]
* });
* ```
*/

@@ -23,4 +45,26 @@ async send(options) {

/**
* Subscribe to events from this session
* @returns Unsubscribe function
* Subscribes to events from this session.
*
* Events include assistant messages, tool executions, errors, and session state changes.
* Multiple handlers can be registered and will all receive events.
*
* @param handler - A callback function that receives session events
* @returns A function that, when called, unsubscribes the handler
*
* @example
* ```typescript
* const unsubscribe = session.on((event) => {
* switch (event.type) {
* case "assistant.message":
* console.log("Assistant:", event.data.content);
* break;
* case "session.error":
* console.error("Error:", event.data.message);
* break;
* }
* });
*
* // Later, to stop receiving events:
* unsubscribe();
* ```
*/

@@ -34,3 +78,6 @@ on(handler) {

/**
* Internal: dispatch an event to all handlers
* Dispatches an event to all registered handlers.
*
* @param event - The session event to dispatch
* @internal This method is for internal use by the SDK.
*/

@@ -45,2 +92,11 @@ _dispatchEvent(event) {

}
/**
* Registers custom tool handlers for this session.
*
* Tools allow the assistant to execute custom functions. When the assistant
* invokes a tool, the corresponding handler is called with the tool arguments.
*
* @param tools - An array of tool definitions with their handlers, or undefined to clear all tools
* @internal This method is typically called internally when creating a session with tools.
*/
registerTools(tools) {

@@ -55,8 +111,31 @@ this.toolHandlers.clear();

}
/**
* Retrieves a registered tool handler by name.
*
* @param name - The name of the tool to retrieve
* @returns The tool handler if found, or undefined
* @internal This method is for internal use by the SDK.
*/
getToolHandler(name) {
return this.toolHandlers.get(name);
}
/**
* Registers a handler for permission requests.
*
* When the assistant needs permission to perform certain actions (e.g., file operations),
* this handler is called to approve or deny the request.
*
* @param handler - The permission handler function, or undefined to remove the handler
* @internal This method is typically called internally when creating a session.
*/
registerPermissionHandler(handler) {
this.permissionHandler = handler;
}
/**
* Handles a permission request from the Copilot CLI.
*
* @param request - The permission request data from the CLI
* @returns A promise that resolves with the permission decision
* @internal This method is for internal use by the SDK.
*/
async _handlePermissionRequest(request) {

@@ -76,3 +155,19 @@ if (!this.permissionHandler) {

/**
* Get all events/messages from this session
* Retrieves all events and messages from this session's history.
*
* This returns the complete conversation history including user messages,
* assistant responses, tool executions, and other session events.
*
* @returns A promise that resolves with an array of all session events
* @throws Error if the session has been destroyed or the connection fails
*
* @example
* ```typescript
* const events = await session.getMessages();
* for (const event of events) {
* if (event.type === "assistant.message") {
* console.log("Assistant:", event.data.content);
* }
* }
* ```
*/

@@ -86,3 +181,16 @@ async getMessages() {

/**
* Destroy this session and free resources
* Destroys this session and releases all associated resources.
*
* After calling this method, the session can no longer be used. All event
* handlers and tool handlers are cleared. To continue the conversation,
* use {@link CopilotClient.resumeSession} with the session ID.
*
* @returns A promise that resolves when the session is destroyed
* @throws Error if the connection fails
*
* @example
* ```typescript
* // Clean up when done
* await session.destroy();
* ```
*/

@@ -98,3 +206,20 @@ async destroy() {

/**
* Abort the currently processing message in this session
* Aborts the currently processing message in this session.
*
* Use this to cancel a long-running request. The session remains valid
* and can continue to be used for new messages.
*
* @returns A promise that resolves when the abort request is acknowledged
* @throws Error if the session has been destroyed or the connection fails
*
* @example
* ```typescript
* // Start a long-running request
* const messagePromise = session.send({ prompt: "Write a very long story..." });
*
* // Abort after 5 seconds
* setTimeout(async () => {
* await session.abort();
* }, 5000);
* ```
*/

@@ -101,0 +226,0 @@ async abort() {

+4
-3

@@ -7,3 +7,3 @@ {

},
"version": "0.1.10-preview.1",
"version": "0.1.10",
"description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC",

@@ -30,2 +30,3 @@ "main": "./dist/index.js",

"generate:session-types": "tsx scripts/generate-session-types.ts",
"update:protocol-version": "tsx scripts/generate-protocol-version.ts",
"prepublishOnly": "npm run build",

@@ -44,3 +45,3 @@ "package": "npm run clean && npm run build && node scripts/set-version.js && npm pack && npm version 0.1.0 --no-git-tag-version --allow-same-version"

"dependencies": {
"@github/copilot": "^0.0.378-0",
"@github/copilot": "^0.0.382-0",
"vscode-jsonrpc": "^8.2.1",

@@ -50,3 +51,3 @@ "zod": "^4.3.5"

"devDependencies": {
"@types/node": "^22.0.0",
"@types/node": "^22.19.6",
"@typescript-eslint/eslint-plugin": "^8.0.0",

@@ -53,0 +54,0 @@ "@typescript-eslint/parser": "^8.0.0",

import { CopilotSession } from "./session.js";
import type { ConnectionState, CopilotClientOptions, ResumeSessionConfig, SessionConfig, SessionMetadata } from "./types.js";
export declare class CopilotClient {
private cliProcess;
private connection;
private socket;
private actualPort;
private actualHost;
private state;
private sessions;
private options;
private isExternalServer;
private forceStopping;
constructor(options?: CopilotClientOptions);
/**
* Parse CLI URL into host and port
* Supports formats: "host:port", "http://host:port", "https://host:port", or just "port"
*/
private parseCliUrl;
/**
* Start the CLI server and establish connection
*/
start(): Promise<void>;
/**
* Stop the CLI server and close all sessions
* Returns array of errors encountered during cleanup (empty if all succeeded)
*/
stop(): Promise<Error[]>;
/**
* Force stop the CLI server without graceful cleanup
* Use when normal stop() fails or takes too long
*/
forceStop(): Promise<void>;
/**
* Create a new session
*/
createSession(config?: SessionConfig): Promise<CopilotSession>;
/**
* Resume an existing session
*/
resumeSession(sessionId: string, config?: ResumeSessionConfig): Promise<CopilotSession>;
/**
* Get connection state
*/
getState(): ConnectionState;
/**
* Ping the server
*/
ping(message?: string): Promise<{
message: string;
timestamp: number;
}>;
/**
* Get the ID of the most recently updated session
* @returns The session ID, or undefined if no sessions exist
*/
getLastSessionId(): Promise<string | undefined>;
/**
* Delete a session and its data from disk
* @param sessionId The ID of the session to delete
*/
deleteSession(sessionId: string): Promise<void>;
/**
* List all available sessions
* @returns Array of session metadata
*/
listSessions(): Promise<SessionMetadata[]>;
/**
* Start the CLI server process
*/
private startCLIServer;
/**
* Connect to the CLI server (via socket or stdio)
*/
private connectToServer;
/**
* Connect via stdio pipes
*/
private connectViaStdio;
/**
* Connect to the CLI server via TCP socket
*/
private connectViaTcp;
private attachConnectionHandlers;
private handleSessionEventNotification;
private handleToolCallRequest;
private executeToolCall;
private handlePermissionRequest;
private normalizeToolResult;
private isToolResultObject;
private buildUnsupportedToolResult;
/**
* Attempt to reconnect to the server
*/
private reconnect;
}
/**
* AUTO-GENERATED FILE - DO NOT EDIT
*
* Generated from: @github/copilot/session-events.schema.json
* Generated by: scripts/generate-session-types.ts
* Generated at: 2026-01-08T23:59:19.905Z
*
* To update these types:
* 1. Update the schema in copilot-agent-runtime
* 2. Run: npm run generate:session-types
*/
export type SessionEvent = {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.start";
data: {
sessionId: string;
version: number;
producer: string;
copilotVersion: string;
startTime: string;
selectedModel?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.resume";
data: {
resumeTime: string;
eventCount: number;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.error";
data: {
errorType: string;
message: string;
stack?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral: true;
type: "session.idle";
data: {};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.info";
data: {
infoType: string;
message: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.model_change";
data: {
previousModel?: string;
newModel: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.handoff";
data: {
handoffTime: string;
sourceType: "remote" | "local";
repository?: {
owner: string;
name: string;
branch?: string;
};
context?: string;
summary?: string;
remoteSessionId?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "session.truncation";
data: {
tokenLimit: number;
preTruncationTokensInMessages: number;
preTruncationMessagesLength: number;
postTruncationTokensInMessages: number;
postTruncationMessagesLength: number;
tokensRemovedDuringTruncation: number;
messagesRemovedDuringTruncation: number;
performedBy: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "user.message";
data: {
content: string;
transformedContent?: string;
attachments?: {
type: "file" | "directory";
path: string;
displayName: string;
}[];
source?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "assistant.turn_start";
data: {
turnId: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral: true;
type: "assistant.intent";
data: {
intent: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "assistant.reasoning";
data: {
reasoningId: string;
content: string;
chunkContent?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: true;
type: "assistant.reasoning_delta";
data: {
reasoningId: string;
deltaContent: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "assistant.message";
data: {
messageId: string;
content: string;
chunkContent?: string;
totalResponseSizeBytes?: number;
toolRequests?: {
toolCallId: string;
name: string;
arguments?: unknown;
}[];
parentToolCallId?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: true;
type: "assistant.message_delta";
data: {
messageId: string;
deltaContent: string;
totalResponseSizeBytes?: number;
parentToolCallId?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "assistant.turn_end";
data: {
turnId: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral: true;
type: "assistant.usage";
data: {
model?: string;
inputTokens?: number;
outputTokens?: number;
cacheReadTokens?: number;
cacheWriteTokens?: number;
cost?: number;
duration?: number;
initiator?: string;
apiCallId?: string;
providerCallId?: string;
quotaSnapshots?: {
[k: string]: {
isUnlimitedEntitlement: boolean;
entitlementRequests: number;
usedRequests: number;
usageAllowedWithExhaustedQuota: boolean;
overage: number;
overageAllowedWithExhaustedQuota: boolean;
remainingPercentage: number;
resetDate?: string;
};
};
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "abort";
data: {
reason: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "tool.user_requested";
data: {
toolCallId: string;
toolName: string;
arguments?: unknown;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "tool.execution_start";
data: {
toolCallId: string;
toolName: string;
arguments?: unknown;
parentToolCallId?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral: true;
type: "tool.execution_partial_result";
data: {
toolCallId: string;
partialOutput: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "tool.execution_complete";
data: {
toolCallId: string;
success: boolean;
isUserRequested?: boolean;
result?: {
content: string;
};
error?: {
message: string;
code?: string;
};
toolTelemetry?: {
[k: string]: unknown;
};
parentToolCallId?: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "custom_agent.started";
data: {
toolCallId: string;
agentName: string;
agentDisplayName: string;
agentDescription: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "custom_agent.completed";
data: {
toolCallId: string;
agentName: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "custom_agent.failed";
data: {
toolCallId: string;
agentName: string;
error: string;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "custom_agent.selected";
data: {
agentName: string;
agentDisplayName: string;
tools: string[] | null;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "hook.start";
data: {
hookInvocationId: string;
hookType: string;
input?: unknown;
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "hook.end";
data: {
hookInvocationId: string;
hookType: string;
output?: unknown;
success: boolean;
error?: {
message: string;
stack?: string;
};
};
} | {
id: string;
timestamp: string;
parentId: string | null;
ephemeral?: boolean;
type: "system.message";
data: {
content: string;
role: "system" | "developer";
name?: string;
metadata?: {
promptVersion?: string;
variables?: {
[k: string]: unknown;
};
};
};
};
/**
* Copilot SDK - TypeScript/Node.js Client
*
* JSON-RPC based SDK for programmatic control of GitHub Copilot CLI
*/
export { CopilotClient } from "./client.js";
export { CopilotSession } from "./session.js";
export { defineTool } from "./types.js";
export type { ConnectionState, CopilotClientOptions, MessageOptions, PermissionHandler, PermissionRequest, PermissionRequestResult, ResumeSessionConfig, SessionConfig, SessionEvent, SessionEventHandler, SessionMetadata, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageReplaceConfig, Tool, ToolHandler, ToolInvocation, ToolResultObject, ZodSchema, } from "./types.js";
/**
* Copilot Session - represents a single conversation session with the CLI
*/
import type { MessageConnection } from "vscode-jsonrpc/node";
import type { MessageOptions, PermissionHandler, PermissionRequestResult, SessionEvent, SessionEventHandler, Tool, ToolHandler } from "./types.js";
export declare class CopilotSession {
readonly sessionId: string;
private connection;
private eventHandlers;
private toolHandlers;
private permissionHandler?;
constructor(sessionId: string, connection: MessageConnection);
/**
* Send a message to this session
*/
send(options: MessageOptions): Promise<string>;
/**
* Subscribe to events from this session
* @returns Unsubscribe function
*/
on(handler: SessionEventHandler): () => void;
/**
* Internal: dispatch an event to all handlers
*/
_dispatchEvent(event: SessionEvent): void;
registerTools(tools?: Tool[]): void;
getToolHandler(name: string): ToolHandler | undefined;
registerPermissionHandler(handler?: PermissionHandler): void;
_handlePermissionRequest(request: unknown): Promise<PermissionRequestResult>;
/**
* Get all events/messages from this session
*/
getMessages(): Promise<SessionEvent[]>;
/**
* Destroy this session and free resources
*/
destroy(): Promise<void>;
/**
* Abort the currently processing message in this session
*/
abort(): Promise<void>;
}
/**
* Type definitions for the Copilot SDK
*/
import type { SessionEvent as GeneratedSessionEvent } from "./generated/session-events.js";
export type SessionEvent = GeneratedSessionEvent;
/**
* Options for creating a CopilotClient
*/
export interface CopilotClientOptions {
/**
* Path to the Copilot CLI executable
* @default "copilot" (searches PATH)
*/
cliPath?: string;
/**
* Extra arguments to pass to the CLI executable (inserted before SDK-managed args)
*/
cliArgs?: string[];
/**
* Working directory for the CLI process
* If not set, inherits the current process's working directory
*/
cwd?: string;
/**
* Port for the CLI server (TCP mode only)
* @default 0 (random available port)
*/
port?: number;
/**
* Use stdio transport instead of TCP
* When true, communicates with CLI via stdin/stdout pipes
* @default true
*/
useStdio?: boolean;
/**
* URL of an existing Copilot CLI server to connect to over TCP
* When provided, the client will not spawn a CLI process
* Format: "host:port" or "http://host:port" or just "port" (defaults to localhost)
* Examples: "localhost:8080", "http://127.0.0.1:9000", "8080"
* Mutually exclusive with cliPath, useStdio
*/
cliUrl?: string;
/**
* Log level for the CLI server
*/
logLevel?: "none" | "error" | "warning" | "info" | "debug" | "all";
/**
* Auto-start the CLI server on first use
* @default true
*/
autoStart?: boolean;
/**
* Auto-restart the CLI server if it crashes
* @default true
*/
autoRestart?: boolean;
/**
* Environment variables to pass to the CLI process. If not set, inherits process.env.
*/
env?: Record<string, string | undefined>;
}
/**
* Configuration for creating a session
*/
export type ToolResultType = "success" | "failure" | "rejected" | "denied";
export type ToolBinaryResult = {
data: string;
mimeType: string;
type: string;
description?: string;
};
export type ToolResultObject = {
textResultForLlm: string;
binaryResultsForLlm?: ToolBinaryResult[];
resultType: ToolResultType;
error?: string;
sessionLog?: string;
toolTelemetry?: Record<string, unknown>;
};
export type ToolResult = string | ToolResultObject;
export interface ToolInvocation {
sessionId: string;
toolCallId: string;
toolName: string;
arguments: unknown;
}
export type ToolHandler<TArgs = unknown> = (args: TArgs, invocation: ToolInvocation) => Promise<unknown> | unknown;
/**
* Zod-like schema interface for type inference.
* Any object with `toJSONSchema()` method is treated as a Zod schema.
*/
export interface ZodSchema<T = unknown> {
_output: T;
toJSONSchema(): Record<string, unknown>;
}
/**
* Tool definition. Parameters can be either:
* - A Zod schema (provides type inference for handler)
* - A raw JSON schema object
* - Omitted (no parameters)
*/
export interface Tool<TArgs = unknown> {
name: string;
description?: string;
parameters?: ZodSchema<TArgs> | Record<string, unknown>;
handler: ToolHandler<TArgs>;
}
/**
* Helper to define a tool with Zod schema and get type inference for the handler.
* Without this helper, TypeScript cannot infer handler argument types from Zod schemas.
*/
export declare function defineTool<T = unknown>(name: string, config: {
description?: string;
parameters?: ZodSchema<T> | Record<string, unknown>;
handler: ToolHandler<T>;
}): Tool<T>;
export interface ToolCallRequestPayload {
sessionId: string;
toolCallId: string;
toolName: string;
arguments: unknown;
}
export interface ToolCallResponsePayload {
result: ToolResult;
}
/**
* Append mode: Use CLI foundation with optional appended content (default).
*/
export interface SystemMessageAppendConfig {
mode?: "append";
/**
* Additional instructions appended after SDK-managed sections.
*/
content?: string;
}
/**
* Replace mode: Use caller-provided system message entirely.
* Removes all SDK guardrails including security restrictions.
*/
export interface SystemMessageReplaceConfig {
mode: "replace";
/**
* Complete system message content.
* Replaces the entire SDK-managed system message.
*/
content: string;
}
/**
* System message configuration for session creation.
* - Append mode (default): SDK foundation + optional custom content
* - Replace mode: Full control, caller provides entire system message
*/
export type SystemMessageConfig = SystemMessageAppendConfig | SystemMessageReplaceConfig;
/**
* Permission request types from the server
*/
export interface PermissionRequest {
kind: "shell" | "write" | "mcp" | "read" | "url";
toolCallId?: string;
[key: string]: unknown;
}
export interface PermissionRequestResult {
kind: "approved" | "denied-by-rules" | "denied-no-approval-rule-and-could-not-request-from-user" | "denied-interactively-by-user";
rules?: unknown[];
}
export type PermissionHandler = (request: PermissionRequest, invocation: {
sessionId: string;
}) => Promise<PermissionRequestResult> | PermissionRequestResult;
export interface SessionConfig {
/**
* Optional custom session ID
* If not provided, server will generate one
*/
sessionId?: string;
/**
* Model to use for this session
*/
model?: string;
/**
* Tools exposed to the CLI server
*/
tools?: Tool<any>[];
/**
* System message configuration
* Controls how the system prompt is constructed
*/
systemMessage?: SystemMessageConfig;
/**
* List of tool names to allow. When specified, only these tools will be available.
* Takes precedence over excludedTools.
*/
availableTools?: string[];
/**
* List of tool names to disable. All other tools remain available.
* Ignored if availableTools is specified.
*/
excludedTools?: string[];
/**
* Custom provider configuration (BYOK - Bring Your Own Key).
* When specified, uses the provided API endpoint instead of the Copilot API.
*/
provider?: ProviderConfig;
/**
* Handler for permission requests from the server.
* When provided, the server will call this handler to request permission for operations.
*/
onPermissionRequest?: PermissionHandler;
streaming?: boolean;
}
/**
* Configuration for resuming a session
*/
export type ResumeSessionConfig = Pick<SessionConfig, "tools" | "provider" | "streaming" | "onPermissionRequest">;
/**
* Configuration for a custom API provider.
*/
export interface ProviderConfig {
/**
* Provider type. Defaults to "openai" for generic OpenAI-compatible APIs.
*/
type?: "openai" | "azure" | "anthropic";
/**
* API format (openai/azure only). Defaults to "completions".
*/
wireApi?: "completions" | "responses";
/**
* API endpoint URL
*/
baseUrl: string;
/**
* API key. Optional for local providers like Ollama.
*/
apiKey?: string;
/**
* Bearer token for authentication. Sets the Authorization header directly.
* Use this for services requiring bearer token auth instead of API key.
* Takes precedence over apiKey when both are set.
*/
bearerToken?: string;
/**
* Azure-specific options
*/
azure?: {
/**
* API version. Defaults to "2024-10-21".
*/
apiVersion?: string;
};
}
/**
* Options for sending a message to a session
*/
export interface MessageOptions {
/**
* The prompt/message to send
*/
prompt: string;
/**
* File or directory attachments
*/
attachments?: Array<{
type: "file" | "directory";
path: string;
displayName?: string;
}>;
/**
* Message delivery mode
* - "enqueue": Add to queue (default)
* - "immediate": Send immediately
*/
mode?: "enqueue" | "immediate";
}
/**
* Event handler callback type
*/
export type SessionEventHandler = (event: SessionEvent) => void;
/**
* Connection state
*/
export type ConnectionState = "disconnected" | "connecting" | "connected" | "error";
/**
* Metadata about a session
*/
export interface SessionMetadata {
sessionId: string;
startTime: Date;
modifiedTime: Date;
summary?: string;
isRemote: boolean;
}