@github/copilot-sdk
Advanced tools
+92
-2
| import { CopilotSession } from "./session.js"; | ||
| import type { ConnectionState, CopilotClientOptions, GetAuthStatusResponse, GetStatusResponse, ModelInfo, ResumeSessionConfig, SessionConfig, SessionMetadata } from "./types.js"; | ||
| import type { ConnectionState, CopilotClientOptions, GetAuthStatusResponse, GetStatusResponse, ModelInfo, ResumeSessionConfig, SessionConfig, SessionLifecycleEventType, SessionLifecycleHandler, SessionMetadata, TypedSessionLifecycleHandler } from "./types.js"; | ||
| /** | ||
@@ -47,2 +47,6 @@ * Main client for interacting with the Copilot CLI. | ||
| private forceStopping; | ||
| private modelsCache; | ||
| private modelsCacheLock; | ||
| private sessionLifecycleHandlers; | ||
| private typedLifecycleHandlers; | ||
| /** | ||
@@ -233,3 +237,7 @@ * Creates a new CopilotClient instance. | ||
| /** | ||
| * List available models with their metadata | ||
| * List available models with their metadata. | ||
| * | ||
| * Results are cached after the first successful call to avoid rate limiting. | ||
| * The cache is cleared when the client disconnects. | ||
| * | ||
| * @throws Error if not authenticated | ||
@@ -294,2 +302,83 @@ */ | ||
| /** | ||
| * Gets the foreground session ID in TUI+server mode. | ||
| * | ||
| * This returns the ID of the session currently displayed in the TUI. | ||
| * Only available when connecting to a server running in TUI+server mode (--ui-server). | ||
| * | ||
| * @returns A promise that resolves with the foreground session ID, or undefined if none | ||
| * @throws Error if the client is not connected | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const sessionId = await client.getForegroundSessionId(); | ||
| * if (sessionId) { | ||
| * console.log(`TUI is displaying session: ${sessionId}`); | ||
| * } | ||
| * ``` | ||
| */ | ||
| getForegroundSessionId(): Promise<string | undefined>; | ||
| /** | ||
| * Sets the foreground session in TUI+server mode. | ||
| * | ||
| * This requests the TUI to switch to displaying the specified session. | ||
| * Only available when connecting to a server running in TUI+server mode (--ui-server). | ||
| * | ||
| * @param sessionId - The ID of the session to display in the TUI | ||
| * @returns A promise that resolves when the session is switched | ||
| * @throws Error if the client is not connected or if the operation fails | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Switch the TUI to display a specific session | ||
| * await client.setForegroundSessionId("session-123"); | ||
| * ``` | ||
| */ | ||
| setForegroundSessionId(sessionId: string): Promise<void>; | ||
| /** | ||
| * Subscribes to a specific session lifecycle event type. | ||
| * | ||
| * Lifecycle events are emitted when sessions are created, deleted, updated, | ||
| * or change foreground/background state (in TUI+server mode). | ||
| * | ||
| * @param eventType - The specific event type to listen for | ||
| * @param handler - A callback function that receives events of the specified type | ||
| * @returns A function that, when called, unsubscribes the handler | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Listen for when a session becomes foreground in TUI | ||
| * const unsubscribe = client.on("session.foreground", (event) => { | ||
| * console.log(`Session ${event.sessionId} is now displayed in TUI`); | ||
| * }); | ||
| * | ||
| * // Later, to stop receiving events: | ||
| * unsubscribe(); | ||
| * ``` | ||
| */ | ||
| on<K extends SessionLifecycleEventType>(eventType: K, handler: TypedSessionLifecycleHandler<K>): () => void; | ||
| /** | ||
| * Subscribes to all session lifecycle events. | ||
| * | ||
| * @param handler - A callback function that receives all lifecycle events | ||
| * @returns A function that, when called, unsubscribes the handler | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const unsubscribe = client.on((event) => { | ||
| * switch (event.type) { | ||
| * case "session.foreground": | ||
| * console.log(`Session ${event.sessionId} is now in foreground`); | ||
| * break; | ||
| * case "session.created": | ||
| * console.log(`New session created: ${event.sessionId}`); | ||
| * break; | ||
| * } | ||
| * }); | ||
| * | ||
| * // Later, to stop receiving events: | ||
| * unsubscribe(); | ||
| * ``` | ||
| */ | ||
| on(handler: SessionLifecycleHandler): () => void; | ||
| /** | ||
| * Start the CLI server process | ||
@@ -312,2 +401,3 @@ */ | ||
| private handleSessionEventNotification; | ||
| private handleSessionLifecycleNotification; | ||
| private handleToolCallRequest; | ||
@@ -314,0 +404,0 @@ private executeToolCall; |
+126
-5
@@ -31,2 +31,6 @@ import { spawn } from "node:child_process"; | ||
| forceStopping = false; | ||
| modelsCache = null; | ||
| modelsCacheLock = Promise.resolve(); | ||
| sessionLifecycleHandlers = /* @__PURE__ */ new Set(); | ||
| typedLifecycleHandlers = /* @__PURE__ */ new Map(); | ||
| /** | ||
@@ -200,2 +204,3 @@ * Creates a new CopilotClient instance. | ||
| } | ||
| this.modelsCache = null; | ||
| if (this.socket) { | ||
@@ -264,2 +269,3 @@ try { | ||
| } | ||
| this.modelsCache = null; | ||
| if (this.socket) { | ||
@@ -321,2 +327,3 @@ try { | ||
| sessionId: config.sessionId, | ||
| reasoningEffort: config.reasoningEffort, | ||
| tools: config.tools?.map((tool) => ({ | ||
@@ -391,2 +398,3 @@ name: tool.name, | ||
| sessionId, | ||
| reasoningEffort: config.reasoningEffort, | ||
| tools: config.tools?.map((tool) => ({ | ||
@@ -480,3 +488,7 @@ name: tool.name, | ||
| /** | ||
| * List available models with their metadata | ||
| * List available models with their metadata. | ||
| * | ||
| * Results are cached after the first successful call to avoid rate limiting. | ||
| * The cache is cleared when the client disconnects. | ||
| * | ||
| * @throws Error if not authenticated | ||
@@ -488,5 +500,19 @@ */ | ||
| } | ||
| const result = await this.connection.sendRequest("models.list", {}); | ||
| const response = result; | ||
| return response.models; | ||
| await this.modelsCacheLock; | ||
| let resolveLock; | ||
| this.modelsCacheLock = new Promise((resolve) => { | ||
| resolveLock = resolve; | ||
| }); | ||
| try { | ||
| if (this.modelsCache !== null) { | ||
| return [...this.modelsCache]; | ||
| } | ||
| const result = await this.connection.sendRequest("models.list", {}); | ||
| const response = result; | ||
| const models = response.models; | ||
| this.modelsCache = models; | ||
| return [...models]; | ||
| } finally { | ||
| resolveLock(); | ||
| } | ||
| } | ||
@@ -594,2 +620,73 @@ /** | ||
| /** | ||
| * Gets the foreground session ID in TUI+server mode. | ||
| * | ||
| * This returns the ID of the session currently displayed in the TUI. | ||
| * Only available when connecting to a server running in TUI+server mode (--ui-server). | ||
| * | ||
| * @returns A promise that resolves with the foreground session ID, or undefined if none | ||
| * @throws Error if the client is not connected | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const sessionId = await client.getForegroundSessionId(); | ||
| * if (sessionId) { | ||
| * console.log(`TUI is displaying session: ${sessionId}`); | ||
| * } | ||
| * ``` | ||
| */ | ||
| async getForegroundSessionId() { | ||
| if (!this.connection) { | ||
| throw new Error("Client not connected"); | ||
| } | ||
| const response = await this.connection.sendRequest("session.getForeground", {}); | ||
| return response.sessionId; | ||
| } | ||
| /** | ||
| * Sets the foreground session in TUI+server mode. | ||
| * | ||
| * This requests the TUI to switch to displaying the specified session. | ||
| * Only available when connecting to a server running in TUI+server mode (--ui-server). | ||
| * | ||
| * @param sessionId - The ID of the session to display in the TUI | ||
| * @returns A promise that resolves when the session is switched | ||
| * @throws Error if the client is not connected or if the operation fails | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Switch the TUI to display a specific session | ||
| * await client.setForegroundSessionId("session-123"); | ||
| * ``` | ||
| */ | ||
| async setForegroundSessionId(sessionId) { | ||
| if (!this.connection) { | ||
| throw new Error("Client not connected"); | ||
| } | ||
| const response = await this.connection.sendRequest("session.setForeground", { sessionId }); | ||
| const result = response; | ||
| if (!result.success) { | ||
| throw new Error(result.error || "Failed to set foreground session"); | ||
| } | ||
| } | ||
| on(eventTypeOrHandler, handler) { | ||
| if (typeof eventTypeOrHandler === "string" && handler) { | ||
| const eventType = eventTypeOrHandler; | ||
| if (!this.typedLifecycleHandlers.has(eventType)) { | ||
| this.typedLifecycleHandlers.set(eventType, /* @__PURE__ */ new Set()); | ||
| } | ||
| const storedHandler = handler; | ||
| this.typedLifecycleHandlers.get(eventType).add(storedHandler); | ||
| return () => { | ||
| const handlers = this.typedLifecycleHandlers.get(eventType); | ||
| if (handlers) { | ||
| handlers.delete(storedHandler); | ||
| } | ||
| }; | ||
| } | ||
| const wildcardHandler = eventTypeOrHandler; | ||
| this.sessionLifecycleHandlers.add(wildcardHandler); | ||
| return () => { | ||
| this.sessionLifecycleHandlers.delete(wildcardHandler); | ||
| }; | ||
| } | ||
| /** | ||
| * Start the CLI server process | ||
@@ -601,3 +698,3 @@ */ | ||
| ...this.options.cliArgs, | ||
| "--server", | ||
| "--headless", | ||
| "--log-level", | ||
@@ -747,2 +844,5 @@ this.options.logLevel | ||
| }); | ||
| this.connection.onNotification("session.lifecycle", (notification) => { | ||
| this.handleSessionLifecycleNotification(notification); | ||
| }); | ||
| this.connection.onRequest( | ||
@@ -781,2 +881,23 @@ "tool.call", | ||
| } | ||
| handleSessionLifecycleNotification(notification) { | ||
| if (typeof notification !== "object" || !notification || !("type" in notification) || typeof notification.type !== "string" || !("sessionId" in notification) || typeof notification.sessionId !== "string") { | ||
| return; | ||
| } | ||
| const event = notification; | ||
| const typedHandlers = this.typedLifecycleHandlers.get(event.type); | ||
| if (typedHandlers) { | ||
| for (const handler of typedHandlers) { | ||
| try { | ||
| handler(event); | ||
| } catch { | ||
| } | ||
| } | ||
| } | ||
| for (const handler of this.sessionLifecycleHandlers) { | ||
| try { | ||
| handler(event); | ||
| } catch { | ||
| } | ||
| } | ||
| } | ||
| async handleToolCallRequest(params) { | ||
@@ -783,0 +904,0 @@ if (!params || typeof params.sessionId !== "string" || typeof params.toolCallId !== "string" || typeof params.toolName !== "string") { |
@@ -6,3 +6,3 @@ /** | ||
| * Generated by: scripts/generate-session-types.ts | ||
| * Generated at: 2026-01-26T18:08:33.710Z | ||
| * Generated at: 2026-02-03T20:40:49.167Z | ||
| * | ||
@@ -59,2 +59,4 @@ * To update these types: | ||
| stack?: string; | ||
| statusCode?: number; | ||
| providerCallId?: string; | ||
| }; | ||
@@ -137,2 +139,35 @@ } | { | ||
| ephemeral: true; | ||
| type: "session.shutdown"; | ||
| data: { | ||
| shutdownType: "routine" | "error"; | ||
| errorReason?: string; | ||
| totalPremiumRequests: number; | ||
| totalApiDurationMs: number; | ||
| sessionStartTime: number; | ||
| codeChanges: { | ||
| linesAdded: number; | ||
| linesRemoved: number; | ||
| filesModified: string[]; | ||
| }; | ||
| modelMetrics: { | ||
| [k: string]: { | ||
| requests: { | ||
| count: number; | ||
| cost: number; | ||
| }; | ||
| usage: { | ||
| inputTokens: number; | ||
| outputTokens: number; | ||
| cacheReadTokens: number; | ||
| cacheWriteTokens: number; | ||
| }; | ||
| }; | ||
| }; | ||
| currentModel?: string; | ||
| }; | ||
| } | { | ||
| id: string; | ||
| timestamp: string; | ||
| parentId: string | null; | ||
| ephemeral: true; | ||
| type: "session.usage_info"; | ||
@@ -166,2 +201,4 @@ data: { | ||
| summaryContent?: string; | ||
| checkpointNumber?: number; | ||
| checkpointPath?: string; | ||
| compactionTokensUsed?: { | ||
@@ -268,2 +305,5 @@ input: number; | ||
| }[]; | ||
| reasoningOpaque?: string; | ||
| reasoningText?: string; | ||
| encryptedContent?: string; | ||
| parentToolCallId?: string; | ||
@@ -299,3 +339,3 @@ }; | ||
| data: { | ||
| model?: string; | ||
| model: string; | ||
| inputTokens?: number; | ||
@@ -310,2 +350,3 @@ outputTokens?: number; | ||
| providerCallId?: string; | ||
| parentToolCallId?: string; | ||
| quotaSnapshots?: { | ||
@@ -406,2 +447,14 @@ [k: string]: { | ||
| ephemeral?: boolean; | ||
| type: "skill.invoked"; | ||
| data: { | ||
| name: string; | ||
| path: string; | ||
| content: string; | ||
| allowedTools?: string[]; | ||
| }; | ||
| } | { | ||
| id: string; | ||
| timestamp: string; | ||
| parentId: string | null; | ||
| ephemeral?: boolean; | ||
| type: "subagent.started"; | ||
@@ -408,0 +461,0 @@ data: { |
+1
-1
@@ -9,2 +9,2 @@ /** | ||
| export { defineTool } from "./types.js"; | ||
| export type { ConnectionState, CopilotClientOptions, CustomAgentConfig, GetAuthStatusResponse, GetStatusResponse, InfiniteSessionConfig, MCPLocalServerConfig, MCPRemoteServerConfig, MCPServerConfig, MessageOptions, ModelBilling, ModelCapabilities, ModelInfo, ModelPolicy, PermissionHandler, PermissionRequest, PermissionRequestResult, ResumeSessionConfig, SessionConfig, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionMetadata, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageReplaceConfig, Tool, ToolHandler, ToolInvocation, ToolResultObject, TypedSessionEventHandler, ZodSchema, } from "./types.js"; | ||
| export type { ConnectionState, CopilotClientOptions, CustomAgentConfig, ForegroundSessionInfo, GetAuthStatusResponse, GetStatusResponse, InfiniteSessionConfig, MCPLocalServerConfig, MCPRemoteServerConfig, MCPServerConfig, MessageOptions, ModelBilling, ModelCapabilities, ModelInfo, ModelPolicy, PermissionHandler, PermissionRequest, PermissionRequestResult, ResumeSessionConfig, SessionConfig, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionLifecycleEvent, SessionLifecycleEventType, SessionLifecycleHandler, SessionMetadata, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageReplaceConfig, Tool, ToolHandler, ToolInvocation, ToolResultObject, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, } from "./types.js"; |
+56
-1
@@ -493,2 +493,6 @@ /** | ||
| } | ||
| /** | ||
| * Valid reasoning effort levels for models that support it. | ||
| */ | ||
| export type ReasoningEffort = "low" | "medium" | "high" | "xhigh"; | ||
| export interface SessionConfig { | ||
@@ -505,2 +509,8 @@ /** | ||
| /** | ||
| * Reasoning effort level for models that support it. | ||
| * Only valid for models where capabilities.supports.reasoningEffort is true. | ||
| * Use client.listModels() to check supported values for each model. | ||
| */ | ||
| reasoningEffort?: ReasoningEffort; | ||
| /** | ||
| * Override the default configuration directory location. | ||
@@ -582,3 +592,3 @@ * When specified, the session will use this directory for storing config and state. | ||
| */ | ||
| export type ResumeSessionConfig = Pick<SessionConfig, "tools" | "provider" | "streaming" | "onPermissionRequest" | "onUserInputRequest" | "hooks" | "workingDirectory" | "mcpServers" | "customAgents" | "skillDirectories" | "disabledSkills"> & { | ||
| export type ResumeSessionConfig = Pick<SessionConfig, "tools" | "provider" | "streaming" | "reasoningEffort" | "onPermissionRequest" | "onUserInputRequest" | "hooks" | "workingDirectory" | "mcpServers" | "customAgents" | "skillDirectories" | "disabledSkills"> & { | ||
| /** | ||
@@ -712,2 +722,4 @@ * When true, skips emitting the session.resume event. | ||
| vision: boolean; | ||
| /** Whether this model supports reasoning effort configuration */ | ||
| reasoningEffort: boolean; | ||
| }; | ||
@@ -751,3 +763,46 @@ limits: { | ||
| billing?: ModelBilling; | ||
| /** Supported reasoning effort levels (only present if model supports reasoning effort) */ | ||
| supportedReasoningEfforts?: ReasoningEffort[]; | ||
| /** Default reasoning effort level (only present if model supports reasoning effort) */ | ||
| defaultReasoningEffort?: ReasoningEffort; | ||
| } | ||
| /** | ||
| * Types of session lifecycle events | ||
| */ | ||
| export type SessionLifecycleEventType = "session.created" | "session.deleted" | "session.updated" | "session.foreground" | "session.background"; | ||
| /** | ||
| * Session lifecycle event notification | ||
| * Sent when sessions are created, deleted, updated, or change foreground/background state | ||
| */ | ||
| export interface SessionLifecycleEvent { | ||
| /** Type of lifecycle event */ | ||
| type: SessionLifecycleEventType; | ||
| /** ID of the session this event relates to */ | ||
| sessionId: string; | ||
| /** Session metadata (not included for deleted sessions) */ | ||
| metadata?: { | ||
| startTime: string; | ||
| modifiedTime: string; | ||
| summary?: string; | ||
| }; | ||
| } | ||
| /** | ||
| * Handler for session lifecycle events | ||
| */ | ||
| export type SessionLifecycleHandler = (event: SessionLifecycleEvent) => void; | ||
| /** | ||
| * Typed handler for specific session lifecycle event types | ||
| */ | ||
| export type TypedSessionLifecycleHandler<K extends SessionLifecycleEventType> = (event: SessionLifecycleEvent & { | ||
| type: K; | ||
| }) => void; | ||
| /** | ||
| * Information about the foreground session in TUI+server mode | ||
| */ | ||
| export interface ForegroundSessionInfo { | ||
| /** ID of the foreground session, or undefined if none */ | ||
| sessionId?: string; | ||
| /** Workspace path of the foreground session */ | ||
| workspacePath?: string; | ||
| } | ||
| export {}; |
+7
-7
@@ -7,3 +7,3 @@ { | ||
| }, | ||
| "version": "0.1.20", | ||
| "version": "0.1.21", | ||
| "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", | ||
@@ -44,3 +44,3 @@ "main": "./dist/index.js", | ||
| "dependencies": { | ||
| "@github/copilot": "^0.0.399", | ||
| "@github/copilot": "^0.0.402", | ||
| "vscode-jsonrpc": "^8.2.1", | ||
@@ -50,6 +50,6 @@ "zod": "^4.3.5" | ||
| "devDependencies": { | ||
| "@types/node": "^22.19.6", | ||
| "@typescript-eslint/eslint-plugin": "^8.0.0", | ||
| "@typescript-eslint/parser": "^8.0.0", | ||
| "esbuild": "^0.27.0", | ||
| "@types/node": "^25.2.0", | ||
| "@typescript-eslint/eslint-plugin": "^8.54.0", | ||
| "@typescript-eslint/parser": "^8.54.0", | ||
| "esbuild": "^0.27.2", | ||
| "eslint": "^9.0.0", | ||
@@ -65,3 +65,3 @@ "glob": "^11.0.0", | ||
| "typescript": "^5.0.0", | ||
| "vitest": "^4.0.16" | ||
| "vitest": "^4.0.18" | ||
| }, | ||
@@ -68,0 +68,0 @@ "engines": { |
+44
-8
@@ -89,4 +89,5 @@ # Copilot SDK for Node.js/TypeScript | ||
| - `sessionId?: string` - Custom session ID | ||
| - `sessionId?: string` - Custom session ID. | ||
| - `model?: string` - Model to use ("gpt-5", "claude-sonnet-4.5", etc.). **Required when using custom provider.** | ||
| - `reasoningEffort?: "low" | "medium" | "high" | "xhigh"` - Reasoning effort level for models that support it. Use `listModels()` to check which models support this option. | ||
| - `tools?: Tool[]` - Custom tools exposed to the CLI | ||
@@ -119,2 +120,37 @@ - `systemMessage?: SystemMessageConfig` - System message customization (see below) | ||
| ##### `getForegroundSessionId(): Promise<string | undefined>` | ||
| Get the ID of the session currently displayed in the TUI. Only available when connecting to a server running in TUI+server mode (`--ui-server`). | ||
| ##### `setForegroundSessionId(sessionId: string): Promise<void>` | ||
| Request the TUI to switch to displaying the specified session. Only available in TUI+server mode. | ||
| ##### `on(eventType: SessionLifecycleEventType, handler): () => void` | ||
| Subscribe to a specific session lifecycle event type. Returns an unsubscribe function. | ||
| ```typescript | ||
| const unsubscribe = client.on("session.foreground", (event) => { | ||
| console.log(`Session ${event.sessionId} is now in foreground`); | ||
| }); | ||
| ``` | ||
| ##### `on(handler: SessionLifecycleHandler): () => void` | ||
| Subscribe to all session lifecycle events. Returns an unsubscribe function. | ||
| ```typescript | ||
| const unsubscribe = client.on((event) => { | ||
| console.log(`${event.type}: ${event.sessionId}`); | ||
| }); | ||
| ``` | ||
| **Lifecycle Event Types:** | ||
| - `session.created` - A new session was created | ||
| - `session.deleted` - A session was deleted | ||
| - `session.updated` - A session was updated (e.g., new messages) | ||
| - `session.foreground` - A session became the foreground session in TUI | ||
| - `session.background` - A session is no longer the foreground session | ||
| --- | ||
@@ -516,3 +552,3 @@ | ||
| // request.allowFreeform - Whether freeform input is allowed (default: true) | ||
| console.log(`Agent asks: ${request.question}`); | ||
@@ -522,3 +558,3 @@ if (request.choices) { | ||
| } | ||
| // Return the user's response | ||
@@ -551,3 +587,3 @@ return { | ||
| }, | ||
| // Called after each tool execution | ||
@@ -561,3 +597,3 @@ onPostToolUse: async (input, invocation) => { | ||
| }, | ||
| // Called when user submits a prompt | ||
@@ -570,3 +606,3 @@ onUserPromptSubmitted: async (input, invocation) => { | ||
| }, | ||
| // Called when session starts | ||
@@ -579,3 +615,3 @@ onSessionStart: async (input, invocation) => { | ||
| }, | ||
| // Called when session ends | ||
@@ -585,3 +621,3 @@ onSessionEnd: async (input, invocation) => { | ||
| }, | ||
| // Called when an error occurs | ||
@@ -588,0 +624,0 @@ onErrorOccurred: async (input, invocation) => { |
131712
10.69%3472
10.12%653
5.83%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated