@github/copilot-sdk 0.2.2 → 0.3.0-preview.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -5,5 +5,5 @@
5
5
  */
6
6
  export { CopilotClient } from "./client.js";
7
7
  export { CopilotSession, type AssistantMessageEvent } from "./session.js";
8
- export { defineTool, approveAll, SYSTEM_PROMPT_SECTIONS } from "./types.js";
9
- export type { CommandContext, CommandDefinition, CommandHandler, ConnectionState, CopilotClientOptions, CustomAgentConfig, ElicitationFieldValue, ElicitationHandler, ElicitationParams, ElicitationContext, ElicitationResult, ElicitationSchema, ElicitationSchemaField, ForegroundSessionInfo, GetAuthStatusResponse, GetStatusResponse, InfiniteSessionConfig, InputOptions, MCPLocalServerConfig, MCPRemoteServerConfig, MCPServerConfig, MessageOptions, ModelBilling, ModelCapabilities, ModelCapabilitiesOverride, ModelInfo, ModelPolicy, PermissionHandler, PermissionRequest, PermissionRequestResult, ResumeSessionConfig, SectionOverride, SectionOverrideAction, SectionTransformFn, SessionCapabilities, SessionConfig, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionLifecycleEvent, SessionLifecycleEventType, SessionLifecycleHandler, SessionContext, SessionListFilter, SessionMetadata, SessionUiApi, SessionFsConfig, SessionFsHandler, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageCustomizeConfig, SystemMessageReplaceConfig, SystemPromptSection, TelemetryConfig, TraceContext, TraceContextProvider, Tool, ToolHandler, ToolInvocation, ToolResultObject, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, } from "./types.js";
8
+ export { defineTool, approveAll, convertMcpCallToolResult, createSessionFsAdapter, SYSTEM_PROMPT_SECTIONS, } from "./types.js";
9
+ export type { CommandContext, CommandDefinition, CommandHandler, ConnectionState, CopilotClientOptions, CustomAgentConfig, ElicitationFieldValue, ElicitationHandler, ElicitationParams, ElicitationContext, ElicitationResult, ElicitationSchema, ElicitationSchemaField, ForegroundSessionInfo, GetAuthStatusResponse, GetStatusResponse, InfiniteSessionConfig, InputOptions, MCPStdioServerConfig, MCPHTTPServerConfig, MCPServerConfig, DefaultAgentConfig, MessageOptions, ModelBilling, ModelCapabilities, ModelCapabilitiesOverride, ModelInfo, ModelPolicy, PermissionHandler, PermissionRequest, PermissionRequestResult, ProviderConfig, ResumeSessionConfig, SectionOverride, SectionOverrideAction, SectionTransformFn, SessionCapabilities, SessionConfig, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionLifecycleEvent, SessionLifecycleEventType, SessionLifecycleHandler, SessionContext, SessionListFilter, SessionMetadata, SessionUiApi, SessionFsConfig, SessionFsProvider, SessionFsFileInfo, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageCustomizeConfig, SystemMessageReplaceConfig, SystemPromptSection, TelemetryConfig, TraceContext, TraceContextProvider, Tool, ToolHandler, ToolInvocation, ToolResultObject, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, } from "./types.js";
package/dist/index.js CHANGED
@@ -1,10 +1,18 @@
1
1
  import { CopilotClient } from "./client.js";
2
2
  import { CopilotSession } from "./session.js";
3
- import { defineTool, approveAll, SYSTEM_PROMPT_SECTIONS } from "./types.js";
3
+ import {
4
+ defineTool,
5
+ approveAll,
6
+ convertMcpCallToolResult,
7
+ createSessionFsAdapter,
8
+ SYSTEM_PROMPT_SECTIONS
9
+ } from "./types.js";
4
10
  export {
5
11
  CopilotClient,
6
12
  CopilotSession,
7
13
  SYSTEM_PROMPT_SECTIONS,
8
14
  approveAll,
15
+ convertMcpCallToolResult,
16
+ createSessionFsAdapter,
9
17
  defineTool
10
18
  };
package/dist/session.js CHANGED
@@ -100,7 +100,8 @@ class CopilotSession {
100
100
  sessionId: this.sessionId,
101
101
  prompt: options.prompt,
102
102
  attachments: options.attachments,
103
- mode: options.mode
103
+ mode: options.mode,
104
+ requestHeaders: options.requestHeaders
104
105
  });
105
106
  return response.messageId;
106
107
  }
@@ -324,7 +325,7 @@ class CopilotSession {
324
325
  await this.rpc.permissions.handlePendingPermissionRequest({
325
326
  requestId,
326
327
  result: {
327
- kind: "denied-no-approval-rule-and-could-not-request-from-user"
328
+ kind: "user-not-available"
328
329
  }
329
330
  });
330
331
  } catch (rpcError) {
@@ -602,7 +603,7 @@ class CopilotSession {
602
603
  */
603
604
  async _handlePermissionRequestV2(request) {
604
605
  if (!this.permissionHandler) {
605
- return { kind: "denied-no-approval-rule-and-could-not-request-from-user" };
606
+ return { kind: "user-not-available" };
606
607
  }
607
608
  try {
608
609
  const result = await this.permissionHandler(request, {
@@ -616,7 +617,7 @@ class CopilotSession {
616
617
  if (error instanceof Error && error.message === NO_RESULT_PERMISSION_V2_ERROR) {
617
618
  throw error;
618
619
  }
619
- return { kind: "denied-no-approval-rule-and-could-not-request-from-user" };
620
+ return { kind: "user-not-available" };
620
621
  }
621
622
  }
622
623
  /**
@@ -0,0 +1,44 @@
1
+ import type { SessionFsHandler, SessionFsStatResult, SessionFsReaddirWithTypesEntry } from "./generated/rpc.js";
2
+ /**
3
+ * File metadata returned by {@link SessionFsProvider.stat}.
4
+ * Same shape as the generated {@link SessionFsStatResult} but without the
5
+ * `error` field, since providers signal errors by throwing.
6
+ */
7
+ export type SessionFsFileInfo = Omit<SessionFsStatResult, "error">;
8
+ /**
9
+ * Interface for session filesystem providers. Implementors use idiomatic
10
+ * TypeScript patterns: throw on error, return values directly. Use
11
+ * {@link createSessionFsAdapter} to convert a provider into the
12
+ * {@link SessionFsHandler} expected by the SDK.
13
+ *
14
+ * Errors with a `code` property of `"ENOENT"` are mapped to the ENOENT
15
+ * error code; all others map to UNKNOWN.
16
+ */
17
+ export interface SessionFsProvider {
18
+ /** Reads the full content of a file. Throw if the file does not exist. */
19
+ readFile(path: string): Promise<string>;
20
+ /** Writes content to a file, creating parent directories if needed. */
21
+ writeFile(path: string, content: string, mode?: number): Promise<void>;
22
+ /** Appends content to a file, creating parent directories if needed. */
23
+ appendFile(path: string, content: string, mode?: number): Promise<void>;
24
+ /** Checks whether a path exists. */
25
+ exists(path: string): Promise<boolean>;
26
+ /** Gets metadata about a file or directory. Throw if it does not exist. */
27
+ stat(path: string): Promise<SessionFsFileInfo>;
28
+ /** Creates a directory. If recursive is true, creates parents as needed. */
29
+ mkdir(path: string, recursive: boolean, mode?: number): Promise<void>;
30
+ /** Lists entry names in a directory. Throw if it does not exist. */
31
+ readdir(path: string): Promise<string[]>;
32
+ /** Lists entries with type info. Throw if the directory does not exist. */
33
+ readdirWithTypes(path: string): Promise<SessionFsReaddirWithTypesEntry[]>;
34
+ /** Removes a file or directory. If force is true, do not throw on ENOENT. */
35
+ rm(path: string, recursive: boolean, force: boolean): Promise<void>;
36
+ /** Renames/moves a file or directory. */
37
+ rename(src: string, dest: string): Promise<void>;
38
+ }
39
+ /**
40
+ * Wraps a {@link SessionFsProvider} into the {@link SessionFsHandler}
41
+ * interface expected by the SDK, converting thrown errors into
42
+ * {@link SessionFsError} results.
43
+ */
44
+ export declare function createSessionFsAdapter(provider: SessionFsProvider): SessionFsHandler;
@@ -0,0 +1,97 @@
1
+ function createSessionFsAdapter(provider) {
2
+ return {
3
+ readFile: async ({ path }) => {
4
+ try {
5
+ const content = await provider.readFile(path);
6
+ return { content };
7
+ } catch (err) {
8
+ return { content: "", error: toSessionFsError(err) };
9
+ }
10
+ },
11
+ writeFile: async ({ path, content, mode }) => {
12
+ try {
13
+ await provider.writeFile(path, content, mode);
14
+ return void 0;
15
+ } catch (err) {
16
+ return toSessionFsError(err);
17
+ }
18
+ },
19
+ appendFile: async ({ path, content, mode }) => {
20
+ try {
21
+ await provider.appendFile(path, content, mode);
22
+ return void 0;
23
+ } catch (err) {
24
+ return toSessionFsError(err);
25
+ }
26
+ },
27
+ exists: async ({ path }) => {
28
+ try {
29
+ return { exists: await provider.exists(path) };
30
+ } catch {
31
+ return { exists: false };
32
+ }
33
+ },
34
+ stat: async ({ path }) => {
35
+ try {
36
+ return await provider.stat(path);
37
+ } catch (err) {
38
+ return {
39
+ isFile: false,
40
+ isDirectory: false,
41
+ size: 0,
42
+ mtime: (/* @__PURE__ */ new Date()).toISOString(),
43
+ birthtime: (/* @__PURE__ */ new Date()).toISOString(),
44
+ error: toSessionFsError(err)
45
+ };
46
+ }
47
+ },
48
+ mkdir: async ({ path, recursive, mode }) => {
49
+ try {
50
+ await provider.mkdir(path, recursive ?? false, mode);
51
+ return void 0;
52
+ } catch (err) {
53
+ return toSessionFsError(err);
54
+ }
55
+ },
56
+ readdir: async ({ path }) => {
57
+ try {
58
+ const entries = await provider.readdir(path);
59
+ return { entries };
60
+ } catch (err) {
61
+ return { entries: [], error: toSessionFsError(err) };
62
+ }
63
+ },
64
+ readdirWithTypes: async ({ path }) => {
65
+ try {
66
+ const entries = await provider.readdirWithTypes(path);
67
+ return { entries };
68
+ } catch (err) {
69
+ return { entries: [], error: toSessionFsError(err) };
70
+ }
71
+ },
72
+ rm: async ({ path, recursive, force }) => {
73
+ try {
74
+ await provider.rm(path, recursive ?? false, force ?? false);
75
+ return void 0;
76
+ } catch (err) {
77
+ return toSessionFsError(err);
78
+ }
79
+ },
80
+ rename: async ({ src, dest }) => {
81
+ try {
82
+ await provider.rename(src, dest);
83
+ return void 0;
84
+ } catch (err) {
85
+ return toSessionFsError(err);
86
+ }
87
+ }
88
+ };
89
+ }
90
+ function toSessionFsError(err) {
91
+ const e = err;
92
+ const code = e.code === "ENOENT" ? "ENOENT" : "UNKNOWN";
93
+ return { code, message: e.message ?? String(err) };
94
+ }
95
+ export {
96
+ createSessionFsAdapter
97
+ };
package/dist/types.d.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * Type definitions for the Copilot SDK
3
3
  */
4
- import type { SessionFsHandler } from "./generated/rpc.js";
4
+ import type { SessionFsProvider } from "./sessionFsProvider.js";
5
5
  import type { SessionEvent as GeneratedSessionEvent } from "./generated/session-events.js";
6
6
  import type { CopilotSession } from "./session.js";
7
7
  export type SessionEvent = GeneratedSessionEvent;
8
- export type { SessionFsHandler } from "./generated/rpc.js";
8
+ export type { SessionFsProvider } from "./sessionFsProvider.js";
9
+ export { createSessionFsAdapter } from "./sessionFsProvider.js";
10
+ export type { SessionFsFileInfo } from "./sessionFsProvider.js";
9
11
  /**
10
12
  * Options for creating a CopilotClient
11
13
  */
@@ -103,12 +105,12 @@ export interface CopilotClientOptions {
103
105
  * When provided, the token is passed to the CLI server via environment variable.
104
106
  * This takes priority over other authentication methods.
105
107
  */
106
- githubToken?: string;
108
+ gitHubToken?: string;
107
109
  /**
108
110
  * Whether to use the logged-in user for authentication.
109
111
  * When true, the CLI server will attempt to use stored OAuth tokens or gh CLI auth.
110
- * When false, only explicit tokens (githubToken or environment variables) are used.
111
- * @default true (but defaults to false when githubToken is provided)
112
+ * When false, only explicit tokens (gitHubToken or environment variables) are used.
113
+ * @default true (but defaults to false when gitHubToken is provided)
112
114
  */
113
115
  useLoggedInUser?: boolean;
114
116
  /**
@@ -156,6 +158,15 @@ export interface CopilotClientOptions {
156
158
  * instead of the server's default local filesystem storage.
157
159
  */
158
160
  sessionFs?: SessionFsConfig;
161
+ /**
162
+ * Server-wide idle timeout for sessions in seconds.
163
+ * Sessions without activity for this duration are automatically cleaned up.
164
+ * Set to 0 or omit to disable (sessions live indefinitely).
165
+ * This option is only used when the SDK spawns the CLI process; it is ignored
166
+ * when connecting to an external server via {@link cliUrl}.
167
+ * @default undefined (disabled)
168
+ */
169
+ sessionIdleTimeoutSeconds?: number;
159
170
  }
160
171
  /**
161
172
  * Configuration for creating a session
@@ -176,6 +187,40 @@ export type ToolResultObject = {
176
187
  toolTelemetry?: Record<string, unknown>;
177
188
  };
178
189
  export type ToolResult = string | ToolResultObject;
190
+ /**
191
+ * Content block types within an MCP CallToolResult.
192
+ */
193
+ type McpCallToolResultTextContent = {
194
+ type: "text";
195
+ text: string;
196
+ };
197
+ type McpCallToolResultImageContent = {
198
+ type: "image";
199
+ data: string;
200
+ mimeType: string;
201
+ };
202
+ type McpCallToolResultResourceContent = {
203
+ type: "resource";
204
+ resource: {
205
+ uri: string;
206
+ mimeType?: string;
207
+ text?: string;
208
+ blob?: string;
209
+ };
210
+ };
211
+ type McpCallToolResultContent = McpCallToolResultTextContent | McpCallToolResultImageContent | McpCallToolResultResourceContent;
212
+ /**
213
+ * MCP-compatible CallToolResult type. Can be passed to
214
+ * {@link convertMcpCallToolResult} to produce a {@link ToolResultObject}.
215
+ */
216
+ type McpCallToolResult = {
217
+ content: McpCallToolResultContent[];
218
+ isError?: boolean;
219
+ };
220
+ /**
221
+ * Converts an MCP CallToolResult into the SDK's ToolResultObject format.
222
+ */
223
+ export declare function convertMcpCallToolResult(callResult: McpCallToolResult): ToolResultObject;
179
224
  export interface ToolInvocation {
180
225
  sessionId: string;
181
226
  toolCallId: string;
@@ -532,18 +577,18 @@ export type SystemMessageConfig = SystemMessageAppendConfig | SystemMessageRepla
532
577
  * Permission request types from the server
533
578
  */
534
579
  export interface PermissionRequest {
535
- kind: "shell" | "write" | "mcp" | "read" | "url" | "custom-tool";
580
+ kind: "shell" | "write" | "mcp" | "read" | "url" | "custom-tool" | "memory" | "hook";
536
581
  toolCallId?: string;
537
- [key: string]: unknown;
538
582
  }
539
- import type { SessionPermissionsHandlePendingPermissionRequestParams } from "./generated/rpc.js";
540
- export type PermissionRequestResult = SessionPermissionsHandlePendingPermissionRequestParams["result"] | {
583
+ import type { PermissionDecisionRequest } from "./generated/rpc.js";
584
+ export type PermissionRequestResult = PermissionDecisionRequest["result"] | {
541
585
  kind: "no-result";
542
586
  };
543
587
  export type PermissionHandler = (request: PermissionRequest, invocation: {
544
588
  sessionId: string;
545
589
  }) => Promise<PermissionRequestResult> | PermissionRequestResult;
546
590
  export declare const approveAll: PermissionHandler;
591
+ export declare const defaultJoinSessionPermissionHandler: PermissionHandler;
547
592
  /**
548
593
  * Request for user input from the agent (enables ask_user tool)
549
594
  */
@@ -756,8 +801,8 @@ interface MCPServerConfigBase {
756
801
  */
757
802
  tools: string[];
758
803
  /**
759
- * Indicates "remote" or "local" server type.
760
- * If not specified, defaults to "local".
804
+ * Indicates the server type: "stdio" for local/subprocess servers, "http"/"sse" for remote servers.
805
+ * If not specified, defaults to "stdio".
761
806
  */
762
807
  type?: string;
763
808
  /**
@@ -768,7 +813,7 @@ interface MCPServerConfigBase {
768
813
  /**
769
814
  * Configuration for a local/stdio MCP server.
770
815
  */
771
- export interface MCPLocalServerConfig extends MCPServerConfigBase {
816
+ export interface MCPStdioServerConfig extends MCPServerConfigBase {
772
817
  type?: "local" | "stdio";
773
818
  command: string;
774
819
  args: string[];
@@ -781,7 +826,7 @@ export interface MCPLocalServerConfig extends MCPServerConfigBase {
781
826
  /**
782
827
  * Configuration for a remote MCP server (HTTP or SSE).
783
828
  */
784
- export interface MCPRemoteServerConfig extends MCPServerConfigBase {
829
+ export interface MCPHTTPServerConfig extends MCPServerConfigBase {
785
830
  type: "http" | "sse";
786
831
  /**
787
832
  * URL of the remote server.
@@ -795,7 +840,7 @@ export interface MCPRemoteServerConfig extends MCPServerConfigBase {
795
840
  /**
796
841
  * Union type for MCP server configurations.
797
842
  */
798
- export type MCPServerConfig = MCPLocalServerConfig | MCPRemoteServerConfig;
843
+ export type MCPServerConfig = MCPStdioServerConfig | MCPHTTPServerConfig;
799
844
  /**
800
845
  * Configuration for a custom agent.
801
846
  */
@@ -830,6 +875,28 @@ export interface CustomAgentConfig {
830
875
  * @default true
831
876
  */
832
877
  infer?: boolean;
878
+ /**
879
+ * List of skill names to preload into this agent's context.
880
+ * When set, the full content of each listed skill is eagerly injected into
881
+ * the agent's context at startup. Skills are resolved by name from the
882
+ * session's configured skill directories (`skillDirectories`).
883
+ * When omitted, no skills are injected (opt-in model).
884
+ */
885
+ skills?: string[];
886
+ }
887
+ /**
888
+ * Configuration for the default agent (the built-in agent that handles
889
+ * turns when no custom agent is selected).
890
+ * Use this to control tool visibility for the default agent independently of custom sub-agents.
891
+ */
892
+ export interface DefaultAgentConfig {
893
+ /**
894
+ * List of tool names to exclude from the default agent.
895
+ * These tools remain available to custom sub-agents that reference them in their `tools` array.
896
+ * Use this to register tools that should only be accessed via delegation to sub-agents,
897
+ * keeping the default agent's context clean.
898
+ */
899
+ excludedTools?: string[];
833
900
  }
834
901
  /**
835
902
  * Configuration for infinite sessions with automatic context compaction and workspace persistence.
@@ -956,6 +1023,16 @@ export interface SessionConfig {
956
1023
  */
957
1024
  workingDirectory?: string;
958
1025
  streaming?: boolean;
1026
+ /**
1027
+ * Include sub-agent streaming events in the event stream. When true, streaming
1028
+ * delta events from sub-agents (e.g., `assistant.message_delta`,
1029
+ * `assistant.reasoning_delta`, `assistant.streaming_delta` with `agentId` set)
1030
+ * are forwarded to this connection. When false, only non-streaming sub-agent
1031
+ * events and `subagent.*` lifecycle events are forwarded; streaming deltas from
1032
+ * sub-agents are suppressed.
1033
+ * @default true
1034
+ */
1035
+ includeSubAgentStreamingEvents?: boolean;
959
1036
  /**
960
1037
  * MCP server configurations for the session.
961
1038
  * Keys are server names, values are server configurations.
@@ -965,6 +1042,13 @@ export interface SessionConfig {
965
1042
  * Custom agent configurations for the session.
966
1043
  */
967
1044
  customAgents?: CustomAgentConfig[];
1045
+ /**
1046
+ * Configuration for the default agent (the built-in agent that handles
1047
+ * turns when no custom agent is selected).
1048
+ * Use `excludedTools` to hide specific tools from the default agent while keeping
1049
+ * them available to custom sub-agents.
1050
+ */
1051
+ defaultAgent?: DefaultAgentConfig;
968
1052
  /**
969
1053
  * Name of the custom agent to activate when the session starts.
970
1054
  * Must match the `name` of one of the agents in `customAgents`.
@@ -985,6 +1069,17 @@ export interface SessionConfig {
985
1069
  * Set to `{ enabled: false }` to disable.
986
1070
  */
987
1071
  infiniteSessions?: InfiniteSessionConfig;
1072
+ /**
1073
+ * GitHub token for per-session authentication.
1074
+ * When provided, the runtime resolves this token into a full GitHub identity
1075
+ * (login, Copilot plan, endpoints) and stores it on the session. This enables
1076
+ * multitenancy — different sessions can have different GitHub identities.
1077
+ *
1078
+ * This is independent of the client-level `gitHubToken` in {@link CopilotClientOptions},
1079
+ * which authenticates the CLI process itself. The session-level token determines
1080
+ * the identity used for content exclusion, model routing, and quota checks.
1081
+ */
1082
+ gitHubToken?: string;
988
1083
  /**
989
1084
  * Optional event handler that is registered on the session before the
990
1085
  * session.create RPC is issued. This guarantees that early events emitted
@@ -999,12 +1094,12 @@ export interface SessionConfig {
999
1094
  * Supplies a handler for session filesystem operations. This takes effect
1000
1095
  * only if {@link CopilotClientOptions.sessionFs} is configured.
1001
1096
  */
1002
- createSessionFsHandler?: (session: CopilotSession) => SessionFsHandler;
1097
+ createSessionFsHandler?: (session: CopilotSession) => SessionFsProvider;
1003
1098
  }
1004
1099
  /**
1005
1100
  * Configuration for resuming a session
1006
1101
  */
1007
- export type ResumeSessionConfig = Pick<SessionConfig, "clientName" | "model" | "tools" | "commands" | "systemMessage" | "availableTools" | "excludedTools" | "provider" | "modelCapabilities" | "streaming" | "reasoningEffort" | "onPermissionRequest" | "onUserInputRequest" | "onElicitationRequest" | "hooks" | "workingDirectory" | "configDir" | "enableConfigDiscovery" | "mcpServers" | "customAgents" | "agent" | "skillDirectories" | "disabledSkills" | "infiniteSessions" | "onEvent" | "createSessionFsHandler"> & {
1102
+ export type ResumeSessionConfig = Pick<SessionConfig, "clientName" | "model" | "tools" | "commands" | "systemMessage" | "availableTools" | "excludedTools" | "provider" | "modelCapabilities" | "streaming" | "includeSubAgentStreamingEvents" | "reasoningEffort" | "onPermissionRequest" | "onUserInputRequest" | "onElicitationRequest" | "hooks" | "workingDirectory" | "configDir" | "enableConfigDiscovery" | "mcpServers" | "customAgents" | "defaultAgent" | "agent" | "skillDirectories" | "disabledSkills" | "infiniteSessions" | "gitHubToken" | "onEvent" | "createSessionFsHandler"> & {
1008
1103
  /**
1009
1104
  * When true, skips emitting the session.resume event.
1010
1105
  * Useful for reconnecting to a session without triggering resume-related side effects.
@@ -1047,6 +1142,10 @@ export interface ProviderConfig {
1047
1142
  */
1048
1143
  apiVersion?: string;
1049
1144
  };
1145
+ /**
1146
+ * Custom HTTP headers to include in outbound provider requests.
1147
+ */
1148
+ headers?: Record<string, string>;
1050
1149
  }
1051
1150
  /**
1052
1151
  * Options for sending a message to a session
@@ -1094,6 +1193,10 @@ export interface MessageOptions {
1094
1193
  * - "immediate": Send immediately
1095
1194
  */
1096
1195
  mode?: "enqueue" | "immediate";
1196
+ /**
1197
+ * Custom HTTP headers to include in outbound model requests for this turn.
1198
+ */
1199
+ requestHeaders?: Record<string, string>;
1097
1200
  }
1098
1201
  /**
1099
1202
  * All possible event type strings from SessionEvent
package/dist/types.js CHANGED
@@ -1,3 +1,45 @@
1
+ import { createSessionFsAdapter } from "./sessionFsProvider.js";
2
+ function convertMcpCallToolResult(callResult) {
3
+ const textParts = [];
4
+ const binaryResults = [];
5
+ for (const block of callResult.content) {
6
+ switch (block.type) {
7
+ case "text":
8
+ if (typeof block.text === "string") {
9
+ textParts.push(block.text);
10
+ }
11
+ break;
12
+ case "image":
13
+ if (typeof block.data === "string" && block.data && typeof block.mimeType === "string") {
14
+ binaryResults.push({
15
+ data: block.data,
16
+ mimeType: block.mimeType,
17
+ type: "image"
18
+ });
19
+ }
20
+ break;
21
+ case "resource": {
22
+ if (block.resource?.text) {
23
+ textParts.push(block.resource.text);
24
+ }
25
+ if (block.resource?.blob) {
26
+ binaryResults.push({
27
+ data: block.resource.blob,
28
+ mimeType: block.resource.mimeType ?? "application/octet-stream",
29
+ type: "resource",
30
+ description: block.resource.uri
31
+ });
32
+ }
33
+ break;
34
+ }
35
+ }
36
+ }
37
+ return {
38
+ textResultForLlm: textParts.join("\n"),
39
+ resultType: callResult.isError ? "failure" : "success",
40
+ ...binaryResults.length > 0 ? { binaryResultsForLlm: binaryResults } : {}
41
+ };
42
+ }
1
43
  function defineTool(name, config) {
2
44
  return { name, ...config };
3
45
  }
@@ -15,9 +57,15 @@ const SYSTEM_PROMPT_SECTIONS = {
15
57
  description: "End-of-prompt instructions: parallel tool calling, persistence, task completion"
16
58
  }
17
59
  };
18
- const approveAll = () => ({ kind: "approved" });
60
+ const approveAll = () => ({ kind: "approve-once" });
61
+ const defaultJoinSessionPermissionHandler = () => ({
62
+ kind: "no-result"
63
+ });
19
64
  export {
20
65
  SYSTEM_PROMPT_SECTIONS,
21
66
  approveAll,
67
+ convertMcpCallToolResult,
68
+ createSessionFsAdapter,
69
+ defaultJoinSessionPermissionHandler,
22
70
  defineTool
23
71
  };
@@ -18,6 +18,7 @@ For user-scoped extensions (persist across all repos), add `location: "user"`.
18
18
  ### Step 2: Edit the extension file
19
19
 
20
20
  Modify the generated `extension.mjs` using `edit` or `create` tools. The file must:
21
+
21
22
  - Be named `extension.mjs` (only `.mjs` is supported)
22
23
  - Use ES module syntax (`import`/`export`)
23
24
  - Call `joinSession({ ... })`
@@ -48,6 +49,7 @@ Check that the extension loaded successfully and isn't marked as "failed".
48
49
  ```
49
50
 
50
51
  Discovery rules:
52
+
51
53
  - The CLI scans `.github/extensions/` relative to the git root
52
54
  - It also scans the user's copilot config extensions directory
53
55
  - Only immediate subdirectories are checked (not recursive)
@@ -62,8 +64,8 @@ Discovery rules:
62
64
  import { joinSession } from "@github/copilot-sdk/extension";
63
65
 
64
66
  await joinSession({
65
- tools: [], // Optional — custom tools
66
- hooks: {}, // Optional — lifecycle hooks
67
+ tools: [], // Optional — custom tools
68
+ hooks: {}, // Optional — lifecycle hooks
67
69
  });
68
70
  ```
69
71
 
@@ -74,9 +76,10 @@ await joinSession({
74
76
  ```js
75
77
  tools: [
76
78
  {
77
- name: "tool_name", // Required. Must be globally unique across all extensions.
79
+ name: "tool_name", // Required. Must be globally unique across all extensions.
78
80
  description: "What it does", // Required. Shown to the agent in tool descriptions.
79
- parameters: { // Optional. JSON Schema for the arguments.
81
+ parameters: {
82
+ // Optional. JSON Schema for the arguments.
80
83
  type: "object",
81
84
  properties: {
82
85
  arg1: { type: "string", description: "..." },
@@ -96,10 +99,11 @@ tools: [
96
99
  return `Result: ${args.arg1}`;
97
100
  },
98
101
  },
99
- ]
102
+ ];
100
103
  ```
101
104
 
102
105
  **Constraints:**
106
+
103
107
  - Tool names must be unique across ALL loaded extensions. Collisions cause the second extension to fail to load.
104
108
  - Handler must return a string or `{ textResultForLlm: string, resultType?: string }`.
105
109
  - Handler receives `(args, invocation)` — the second argument has `sessionId`, `toolCallId`, `toolName`.
@@ -195,6 +199,7 @@ After `joinSession()`, the returned `session` provides:
195
199
  ### session.send(options)
196
200
 
197
201
  Send a message programmatically:
202
+
198
203
  ```js
199
204
  await session.send({ prompt: "Analyze the test results." });
200
205
  await session.send({
@@ -206,6 +211,7 @@ await session.send({
206
211
  ### session.sendAndWait(options, timeout?)
207
212
 
208
213
  Send and block until the agent finishes (resolves on `session.idle`):
214
+
209
215
  ```js
210
216
  const response = await session.sendAndWait({ prompt: "What is 2+2?" });
211
217
  // response?.data.content contains the agent's reply
@@ -214,6 +220,7 @@ const response = await session.sendAndWait({ prompt: "What is 2+2?" });
214
220
  ### session.log(message, options?)
215
221
 
216
222
  Log to the CLI timeline:
223
+
217
224
  ```js
218
225
  await session.log("Extension ready");
219
226
  await session.log("Rate limit approaching", { level: "warning" });
@@ -224,6 +231,7 @@ await session.log("Processing...", { ephemeral: true }); // transient, not persi
224
231
  ### session.on(eventType, handler)
225
232
 
226
233
  Subscribe to session events. Returns an unsubscribe function.
234
+
227
235
  ```js
228
236
  const unsub = session.on("tool.execution_complete", (event) => {
229
237
  // event.data.toolName, event.data.success, event.data.result
@@ -232,16 +240,16 @@ const unsub = session.on("tool.execution_complete", (event) => {
232
240
 
233
241
  ### Key Event Types
234
242
 
235
- | Event | Key Data Fields |
236
- |-------|----------------|
237
- | `assistant.message` | `content`, `messageId` |
238
- | `tool.execution_start` | `toolCallId`, `toolName`, `arguments` |
243
+ | Event | Key Data Fields |
244
+ | ------------------------- | ------------------------------------------------------ |
245
+ | `assistant.message` | `content`, `messageId` |
246
+ | `tool.execution_start` | `toolCallId`, `toolName`, `arguments` |
239
247
  | `tool.execution_complete` | `toolCallId`, `toolName`, `success`, `result`, `error` |
240
- | `user.message` | `content`, `attachments`, `source` |
241
- | `session.idle` | `backgroundTasks` |
242
- | `session.error` | `errorType`, `message`, `stack` |
243
- | `permission.requested` | `requestId`, `permissionRequest.kind` |
244
- | `session.shutdown` | `shutdownType`, `totalPremiumRequests` |
248
+ | `user.message` | `content`, `attachments`, `source` |
249
+ | `session.idle` | `backgroundTasks` |
250
+ | `session.error` | `errorType`, `message`, `stack` |
251
+ | `permission.requested` | `requestId`, `permissionRequest.kind` |
252
+ | `session.shutdown` | `shutdownType`, `totalPremiumRequests` |
245
253
 
246
254
  ### session.workspacePath
247
255