@github/copilot-sdk 1.0.0-beta.7 → 1.0.0-beta.9
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/README.md +13 -2
- package/dist/canvas.d.ts +10 -70
- package/dist/canvas.js +1 -44
- package/dist/cjs/canvas.js +2 -46
- package/dist/cjs/client.js +155 -45
- package/dist/cjs/generated/rpc.js +51 -3
- package/dist/cjs/index.js +5 -0
- package/dist/cjs/session.js +50 -11
- package/dist/cjs/toolSet.js +107 -0
- package/dist/client.d.ts +17 -27
- package/dist/client.js +155 -47
- package/dist/extension.d.ts +1 -1
- package/dist/generated/rpc.d.ts +766 -25
- package/dist/generated/rpc.js +51 -3
- package/dist/generated/session-events.d.ts +154 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -0
- package/dist/session.js +51 -12
- package/dist/toolSet.d.ts +75 -0
- package/dist/toolSet.js +82 -0
- package/dist/types.d.ts +134 -6
- package/docs/agent-author.md +31 -7
- package/docs/examples.md +20 -13
- package/package.json +2 -2
package/dist/cjs/index.js
CHANGED
|
@@ -18,12 +18,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var index_exports = {};
|
|
20
20
|
__export(index_exports, {
|
|
21
|
+
BuiltInTools: () => import_toolSet.BuiltInTools,
|
|
21
22
|
Canvas: () => import_canvas.Canvas,
|
|
22
23
|
CanvasError: () => import_canvas.CanvasError,
|
|
23
24
|
CopilotClient: () => import_client.CopilotClient,
|
|
24
25
|
CopilotSession: () => import_session.CopilotSession,
|
|
25
26
|
RuntimeConnection: () => import_types.RuntimeConnection,
|
|
26
27
|
SYSTEM_MESSAGE_SECTIONS: () => import_types2.SYSTEM_MESSAGE_SECTIONS,
|
|
28
|
+
ToolSet: () => import_toolSet.ToolSet,
|
|
27
29
|
approveAll: () => import_types2.approveAll,
|
|
28
30
|
convertMcpCallToolResult: () => import_types2.convertMcpCallToolResult,
|
|
29
31
|
createCanvas: () => import_canvas.createCanvas,
|
|
@@ -33,17 +35,20 @@ __export(index_exports, {
|
|
|
33
35
|
module.exports = __toCommonJS(index_exports);
|
|
34
36
|
var import_client = require("./client.js");
|
|
35
37
|
var import_types = require("./types.js");
|
|
38
|
+
var import_toolSet = require("./toolSet.js");
|
|
36
39
|
var import_session = require("./session.js");
|
|
37
40
|
var import_canvas = require("./canvas.js");
|
|
38
41
|
var import_types2 = require("./types.js");
|
|
39
42
|
// Annotate the CommonJS export names for ESM import in node:
|
|
40
43
|
0 && (module.exports = {
|
|
44
|
+
BuiltInTools,
|
|
41
45
|
Canvas,
|
|
42
46
|
CanvasError,
|
|
43
47
|
CopilotClient,
|
|
44
48
|
CopilotSession,
|
|
45
49
|
RuntimeConnection,
|
|
46
50
|
SYSTEM_MESSAGE_SECTIONS,
|
|
51
|
+
ToolSet,
|
|
47
52
|
approveAll,
|
|
48
53
|
convertMcpCallToolResult,
|
|
49
54
|
createCanvas,
|
package/dist/cjs/session.js
CHANGED
|
@@ -23,6 +23,7 @@ __export(session_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(session_exports);
|
|
24
24
|
var import_node = require("vscode-jsonrpc/node.js");
|
|
25
25
|
var import_rpc = require("./generated/rpc.js");
|
|
26
|
+
var import_canvas = require("./canvas.js");
|
|
26
27
|
var import_telemetry = require("./telemetry.js");
|
|
27
28
|
function deserializeHookInput(raw) {
|
|
28
29
|
if (!raw || typeof raw !== "object" || typeof raw.timestamp !== "number") {
|
|
@@ -118,6 +119,7 @@ class CopilotSession {
|
|
|
118
119
|
prompt: options.prompt,
|
|
119
120
|
attachments: options.attachments,
|
|
120
121
|
mode: options.mode,
|
|
122
|
+
agentMode: options.agentMode,
|
|
121
123
|
requestHeaders: options.requestHeaders
|
|
122
124
|
});
|
|
123
125
|
return response.messageId;
|
|
@@ -401,22 +403,52 @@ class CopilotSession {
|
|
|
401
403
|
*/
|
|
402
404
|
registerCanvases(canvases) {
|
|
403
405
|
this.canvases.clear();
|
|
404
|
-
if (!canvases) {
|
|
406
|
+
if (!canvases || canvases.length === 0) {
|
|
407
|
+
delete this.clientSessionApis.canvas;
|
|
405
408
|
return;
|
|
406
409
|
}
|
|
407
410
|
for (const canvas of canvases) {
|
|
408
411
|
this.canvases.set(canvas.declaration.id, canvas);
|
|
409
412
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
413
|
+
const self = this;
|
|
414
|
+
this.clientSessionApis.canvas = {
|
|
415
|
+
async open(params) {
|
|
416
|
+
const canvas = self.canvases.get(params.canvasId);
|
|
417
|
+
if (!canvas) throw new Error(`No canvas registered with id "${params.canvasId}"`);
|
|
418
|
+
try {
|
|
419
|
+
return await canvas.open(params) ?? {};
|
|
420
|
+
} catch (error) {
|
|
421
|
+
throw toCanvasRpcError(error);
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
async close(params) {
|
|
425
|
+
const canvas = self.canvases.get(params.canvasId);
|
|
426
|
+
if (!canvas) throw new Error(`No canvas registered with id "${params.canvasId}"`);
|
|
427
|
+
try {
|
|
428
|
+
if (canvas.onClose) {
|
|
429
|
+
await canvas.onClose(params);
|
|
430
|
+
}
|
|
431
|
+
} catch (error) {
|
|
432
|
+
throw toCanvasRpcError(error);
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
async invokeAction(params) {
|
|
436
|
+
const canvas = self.canvases.get(params.canvasId);
|
|
437
|
+
if (!canvas) throw new Error(`No canvas registered with id "${params.canvasId}"`);
|
|
438
|
+
const handler = canvas.actionHandlers.get(params.actionName);
|
|
439
|
+
if (!handler) {
|
|
440
|
+
throw new import_canvas.CanvasError(
|
|
441
|
+
"canvas_action_no_handler",
|
|
442
|
+
"No handler implemented for this canvas action"
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
try {
|
|
446
|
+
return await handler(params);
|
|
447
|
+
} catch (error) {
|
|
448
|
+
throw toCanvasRpcError(error);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
};
|
|
420
452
|
}
|
|
421
453
|
/**
|
|
422
454
|
* Registers command handlers for this session.
|
|
@@ -708,6 +740,7 @@ class CopilotSession {
|
|
|
708
740
|
preToolUse: this.hooks.onPreToolUse,
|
|
709
741
|
preMcpToolCall: this.hooks.onPreMcpToolCall,
|
|
710
742
|
postToolUse: this.hooks.onPostToolUse,
|
|
743
|
+
postToolUseFailure: this.hooks.onPostToolUseFailure,
|
|
711
744
|
userPromptSubmitted: this.hooks.onUserPromptSubmitted,
|
|
712
745
|
sessionStart: this.hooks.onSessionStart,
|
|
713
746
|
sessionEnd: this.hooks.onSessionEnd,
|
|
@@ -867,6 +900,12 @@ function isToolResultObject(value) {
|
|
|
867
900
|
];
|
|
868
901
|
return allowedResultTypes.includes(value.resultType);
|
|
869
902
|
}
|
|
903
|
+
function toCanvasRpcError(error) {
|
|
904
|
+
if (error instanceof import_node.ResponseError) return error;
|
|
905
|
+
const code = error instanceof import_canvas.CanvasError ? error.code : "canvas_handler_error";
|
|
906
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
907
|
+
return new import_node.ResponseError(import_node.ErrorCodes.InternalError, message, { code, message });
|
|
908
|
+
}
|
|
870
909
|
// Annotate the CommonJS export names for ESM import in node:
|
|
871
910
|
0 && (module.exports = {
|
|
872
911
|
CopilotSession
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var toolSet_exports = {};
|
|
20
|
+
__export(toolSet_exports, {
|
|
21
|
+
BuiltInTools: () => BuiltInTools,
|
|
22
|
+
ToolSet: () => ToolSet
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(toolSet_exports);
|
|
25
|
+
const VALID_TOOL_NAME = /^[a-zA-Z0-9_-]+$/;
|
|
26
|
+
function validateName(kind, name) {
|
|
27
|
+
if (name === "*") {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (!VALID_TOOL_NAME.test(name)) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Invalid ${kind} tool name '${name}': tool names must match /^[a-zA-Z0-9_-]+$/ or be the wildcard '*'.`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
class ToolSet {
|
|
37
|
+
items = [];
|
|
38
|
+
addBuiltIn(nameOrNames) {
|
|
39
|
+
const names = typeof nameOrNames === "string" ? [nameOrNames] : nameOrNames;
|
|
40
|
+
for (const name of names) {
|
|
41
|
+
validateName("builtin", name);
|
|
42
|
+
this.items.push(`builtin:${name}`);
|
|
43
|
+
}
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Adds a custom tool pattern. Matches tools registered via the SDK's
|
|
48
|
+
* `tools` option or via custom agents.
|
|
49
|
+
*
|
|
50
|
+
* @param name A specific custom tool name or `"*"` to match all custom tools.
|
|
51
|
+
*/
|
|
52
|
+
addCustom(name) {
|
|
53
|
+
validateName("custom", name);
|
|
54
|
+
this.items.push(`custom:${name}`);
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Adds an MCP tool pattern. Matches tools advertised by any configured
|
|
59
|
+
* MCP server.
|
|
60
|
+
*
|
|
61
|
+
* @param toolName The runtime's canonical wire name for the MCP tool
|
|
62
|
+
* (e.g. `"github-list_issues"`), or `"*"` to match all MCP tools from
|
|
63
|
+
* any server.
|
|
64
|
+
*/
|
|
65
|
+
addMcp(toolName) {
|
|
66
|
+
validateName("mcp", toolName);
|
|
67
|
+
this.items.push(`mcp:${toolName}`);
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Returns a defensive copy of the accumulated filter strings, suitable for
|
|
72
|
+
* passing as {@link SessionConfigBase.availableTools}.
|
|
73
|
+
*/
|
|
74
|
+
toArray() {
|
|
75
|
+
return [...this.items];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const BuiltInTools = {
|
|
79
|
+
/**
|
|
80
|
+
* Built-in tools that operate only within the bounds of a single session —
|
|
81
|
+
* no host filesystem access outside the session, no cross-session state,
|
|
82
|
+
* no host environment access, no network. Safe to enable in `Mode = "empty"`
|
|
83
|
+
* scenarios (e.g. multi-tenant servers) without leaking host capabilities.
|
|
84
|
+
*
|
|
85
|
+
* **Contract:** tools in this set MUST NOT be extended (even behind options
|
|
86
|
+
* or args) to read or write state outside the session boundary. Adding
|
|
87
|
+
* cross-session or host-state behavior to one of these tools is a
|
|
88
|
+
* breaking change that requires removing it from this set.
|
|
89
|
+
*/
|
|
90
|
+
Isolated: [
|
|
91
|
+
"ask_user",
|
|
92
|
+
"task_complete",
|
|
93
|
+
"exit_plan_mode",
|
|
94
|
+
"task",
|
|
95
|
+
"read_agent",
|
|
96
|
+
"write_agent",
|
|
97
|
+
"list_agents",
|
|
98
|
+
"send_inbox",
|
|
99
|
+
"context_board",
|
|
100
|
+
"skill"
|
|
101
|
+
]
|
|
102
|
+
};
|
|
103
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
104
|
+
0 && (module.exports = {
|
|
105
|
+
BuiltInTools,
|
|
106
|
+
ToolSet
|
|
107
|
+
});
|
package/dist/client.d.ts
CHANGED
|
@@ -190,34 +190,26 @@ export declare class CopilotClient {
|
|
|
190
190
|
* ```
|
|
191
191
|
*/
|
|
192
192
|
forceStop(): Promise<void>;
|
|
193
|
+
/** Mode-specific defaults spread under the caller's config (app values win). */
|
|
194
|
+
private configDefaultsForMode;
|
|
193
195
|
/**
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
*
|
|
205
|
-
* // Basic session
|
|
206
|
-
* const session = await client.createSession({ onPermissionRequest: approveAll });
|
|
196
|
+
* Returns the systemMessage config to use, adjusted for the current mode.
|
|
197
|
+
* In empty mode we ensure the environment_context section is removed
|
|
198
|
+
* unless the app has already taken control of it. `append` (and
|
|
199
|
+
* unspecified) mode is promoted to `customize` so we can also strip
|
|
200
|
+
* environment_context; the caller's `content` is preserved verbatim
|
|
201
|
+
* because the runtime appends it as additional instructions in both
|
|
202
|
+
* customize and append modes.
|
|
203
|
+
*/
|
|
204
|
+
private getSystemMessageConfigForMode;
|
|
205
|
+
/**
|
|
206
|
+
* Mode-specific options applied via session.options.update after create/resume.
|
|
207
207
|
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
* model: "gpt-4",
|
|
212
|
-
* tools: [{
|
|
213
|
-
* name: "get_weather",
|
|
214
|
-
* description: "Get weather for a location",
|
|
215
|
-
* parameters: { type: "object", properties: { location: { type: "string" } } },
|
|
216
|
-
* handler: async (args) => ({ temperature: 72 })
|
|
217
|
-
* }]
|
|
218
|
-
* });
|
|
219
|
-
* ```
|
|
208
|
+
* In empty mode, defaults the four overridable feature flags to safe values
|
|
209
|
+
* (caller values from `config` win). `installedPlugins=[]` is unconditional
|
|
210
|
+
* in empty mode — apps that need custom plugins should switch modes.
|
|
220
211
|
*/
|
|
212
|
+
private updateSessionOptionsForMode;
|
|
221
213
|
createSession(config: SessionConfig): Promise<CopilotSession>;
|
|
222
214
|
/**
|
|
223
215
|
* Resumes an existing conversation session by its ID.
|
|
@@ -467,6 +459,4 @@ export declare class CopilotClient {
|
|
|
467
459
|
private handleAutoModeSwitchRequest;
|
|
468
460
|
private handleHooksInvoke;
|
|
469
461
|
private handleSystemMessageTransform;
|
|
470
|
-
private handleCanvasProviderRequest;
|
|
471
|
-
private handleCanvasActionInvokeRequest;
|
|
472
462
|
}
|
package/dist/client.js
CHANGED
|
@@ -17,13 +17,11 @@ import {
|
|
|
17
17
|
createInternalServerRpc,
|
|
18
18
|
registerClientSessionApiHandlers
|
|
19
19
|
} from "./generated/rpc.js";
|
|
20
|
-
import {
|
|
21
|
-
dispatchCanvasProviderRequest
|
|
22
|
-
} from "./canvas.js";
|
|
23
20
|
import { getSdkProtocolVersion } from "./sdkProtocolVersion.js";
|
|
24
21
|
import { CopilotSession } from "./session.js";
|
|
25
22
|
import { createSessionFsAdapter } from "./sessionFsProvider.js";
|
|
26
23
|
import { getTraceContext } from "./telemetry.js";
|
|
24
|
+
import { ToolSet } from "./toolSet.js";
|
|
27
25
|
import { defaultJoinSessionPermissionHandler } from "./types.js";
|
|
28
26
|
const MIN_PROTOCOL_VERSION = 3;
|
|
29
27
|
function isZodSchema(value) {
|
|
@@ -56,15 +54,23 @@ function toWireCustomAgents(agents) {
|
|
|
56
54
|
return { ...rest, mcpServers: toWireMcpServers(mcpServers) };
|
|
57
55
|
});
|
|
58
56
|
}
|
|
59
|
-
function
|
|
60
|
-
if (
|
|
61
|
-
return
|
|
57
|
+
function toolFilterListToArray(value) {
|
|
58
|
+
if (value === void 0) {
|
|
59
|
+
return void 0;
|
|
62
60
|
}
|
|
63
|
-
|
|
64
|
-
return typeof request.sessionId === "string" && typeof request.extensionId === "string" && typeof request.canvasId === "string" && typeof request.instanceId === "string";
|
|
61
|
+
return value instanceof ToolSet ? value.toArray() : value;
|
|
65
62
|
}
|
|
66
|
-
function
|
|
67
|
-
|
|
63
|
+
function validateToolFilterList(field, list) {
|
|
64
|
+
if (!list) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
for (const entry of list) {
|
|
68
|
+
if (entry === "*") {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`Invalid ${field} entry '*': there is no bare wildcard. Use one or more of \`new ToolSet().addBuiltIn('*')\`, \`.addMcp('*')\`, or \`.addCustom('*')\` to target a specific source.`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
68
74
|
}
|
|
69
75
|
function extractTransformCallbacks(systemMessage) {
|
|
70
76
|
if (!systemMessage || systemMessage.mode !== "customize" || !systemMessage.sections) {
|
|
@@ -248,8 +254,19 @@ class CopilotClient {
|
|
|
248
254
|
telemetry: options.telemetry,
|
|
249
255
|
baseDirectory: options.baseDirectory,
|
|
250
256
|
sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0,
|
|
251
|
-
enableRemoteSessions: options.enableRemoteSessions ?? false
|
|
257
|
+
enableRemoteSessions: options.enableRemoteSessions ?? false,
|
|
258
|
+
mode: options.mode ?? "copilot-cli"
|
|
252
259
|
};
|
|
260
|
+
if (this.options.mode === "empty") {
|
|
261
|
+
const hasPersistence = this.options.baseDirectory !== void 0 || this.sessionFsConfig !== null || // External runtimes manage their own persistence layer; the SDK
|
|
262
|
+
// can't enforce it from here.
|
|
263
|
+
conn.kind === "uri" || conn.kind === "parent-process";
|
|
264
|
+
if (!hasPersistence) {
|
|
265
|
+
throw new Error(
|
|
266
|
+
"CopilotClient was created with mode: 'empty' but neither 'baseDirectory' nor 'sessionFs' was set. Empty mode requires an explicit per-session persistence location; pick one."
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
253
270
|
}
|
|
254
271
|
connectionExtraArgs = [];
|
|
255
272
|
/**
|
|
@@ -559,10 +576,122 @@ class CopilotClient {
|
|
|
559
576
|
* });
|
|
560
577
|
* ```
|
|
561
578
|
*/
|
|
579
|
+
/**
|
|
580
|
+
* Normalizes session-level tool filter options. Converts {@link ToolSet}
|
|
581
|
+
* instances to plain string arrays, rejects misuse (bare `"*"`) and the
|
|
582
|
+
* missing-availableTools case in `mode = "empty"`.
|
|
583
|
+
*
|
|
584
|
+
* The SDK always sends `toolFilterPrecedence: "excluded"` so callers can
|
|
585
|
+
* compose include + exclude lists naturally (e.g. "everything matching X
|
|
586
|
+
* except Y") regardless of mode. Allowlist-precedence is intentionally not
|
|
587
|
+
* exposed — it's available on the runtime side as a CLI-only concession to
|
|
588
|
+
* legacy behavior, but SDK consumers always get the composable semantics.
|
|
589
|
+
*
|
|
590
|
+
* @internal
|
|
591
|
+
*/
|
|
592
|
+
resolveToolFilterOptions(config) {
|
|
593
|
+
const availableTools = toolFilterListToArray(config.availableTools);
|
|
594
|
+
const excludedTools = toolFilterListToArray(config.excludedTools);
|
|
595
|
+
validateToolFilterList("availableTools", availableTools);
|
|
596
|
+
validateToolFilterList("excludedTools", excludedTools);
|
|
597
|
+
if (this.options.mode === "empty") {
|
|
598
|
+
if (availableTools === void 0) {
|
|
599
|
+
throw new Error(
|
|
600
|
+
"CopilotClient is in mode: 'empty' but the session config did not specify 'availableTools'. Empty mode requires every session to explicitly opt into the tools it wants \u2014 e.g. `new ToolSet().addBuiltIn(BuiltInTools.Isolated)`."
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return { availableTools, excludedTools, toolFilterPrecedence: "excluded" };
|
|
605
|
+
}
|
|
606
|
+
/** Mode-specific defaults spread under the caller's config (app values win). */
|
|
607
|
+
configDefaultsForMode() {
|
|
608
|
+
if (this.options.mode === "empty") {
|
|
609
|
+
return { enableSessionTelemetry: false };
|
|
610
|
+
}
|
|
611
|
+
return {};
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Returns the systemMessage config to use, adjusted for the current mode.
|
|
615
|
+
* In empty mode we ensure the environment_context section is removed
|
|
616
|
+
* unless the app has already taken control of it. `append` (and
|
|
617
|
+
* unspecified) mode is promoted to `customize` so we can also strip
|
|
618
|
+
* environment_context; the caller's `content` is preserved verbatim
|
|
619
|
+
* because the runtime appends it as additional instructions in both
|
|
620
|
+
* customize and append modes.
|
|
621
|
+
*/
|
|
622
|
+
getSystemMessageConfigForMode(supplied) {
|
|
623
|
+
if (this.options.mode !== "empty") return supplied;
|
|
624
|
+
if (!supplied) {
|
|
625
|
+
return {
|
|
626
|
+
mode: "customize",
|
|
627
|
+
sections: { environment_context: { action: "remove" } }
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
switch (supplied.mode) {
|
|
631
|
+
case "replace":
|
|
632
|
+
return supplied;
|
|
633
|
+
case "customize":
|
|
634
|
+
if (supplied.sections?.environment_context) return supplied;
|
|
635
|
+
return {
|
|
636
|
+
...supplied,
|
|
637
|
+
sections: {
|
|
638
|
+
...supplied.sections,
|
|
639
|
+
environment_context: { action: "remove" }
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
case "append":
|
|
643
|
+
case void 0:
|
|
644
|
+
return {
|
|
645
|
+
mode: "customize",
|
|
646
|
+
content: supplied.content,
|
|
647
|
+
sections: { environment_context: { action: "remove" } }
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Mode-specific options applied via session.options.update after create/resume.
|
|
653
|
+
*
|
|
654
|
+
* In empty mode, defaults the four overridable feature flags to safe values
|
|
655
|
+
* (caller values from `config` win). `installedPlugins=[]` is unconditional
|
|
656
|
+
* in empty mode — apps that need custom plugins should switch modes.
|
|
657
|
+
*/
|
|
658
|
+
async updateSessionOptionsForMode(session, config) {
|
|
659
|
+
const patch = {};
|
|
660
|
+
if (this.options.mode === "empty") {
|
|
661
|
+
patch.skipCustomInstructions = config.skipCustomInstructions ?? true;
|
|
662
|
+
patch.customAgentsLocalOnly = config.customAgentsLocalOnly ?? true;
|
|
663
|
+
patch.coauthorEnabled = config.coauthorEnabled ?? false;
|
|
664
|
+
patch.manageScheduleEnabled = config.manageScheduleEnabled ?? false;
|
|
665
|
+
patch.installedPlugins = [];
|
|
666
|
+
} else {
|
|
667
|
+
if (config.skipCustomInstructions !== void 0)
|
|
668
|
+
patch.skipCustomInstructions = config.skipCustomInstructions;
|
|
669
|
+
if (config.customAgentsLocalOnly !== void 0)
|
|
670
|
+
patch.customAgentsLocalOnly = config.customAgentsLocalOnly;
|
|
671
|
+
if (config.coauthorEnabled !== void 0)
|
|
672
|
+
patch.coauthorEnabled = config.coauthorEnabled;
|
|
673
|
+
if (config.manageScheduleEnabled !== void 0)
|
|
674
|
+
patch.manageScheduleEnabled = config.manageScheduleEnabled;
|
|
675
|
+
}
|
|
676
|
+
if (Object.keys(patch).length === 0) {
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
try {
|
|
680
|
+
await session.rpc.options.update(patch);
|
|
681
|
+
} catch (e) {
|
|
682
|
+
try {
|
|
683
|
+
await session.disconnect();
|
|
684
|
+
} catch {
|
|
685
|
+
}
|
|
686
|
+
throw e;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
562
689
|
async createSession(config) {
|
|
563
690
|
if (!this.connection) {
|
|
564
691
|
await this.start();
|
|
565
692
|
}
|
|
693
|
+
config = { ...this.configDefaultsForMode(), ...config };
|
|
694
|
+
config.systemMessage = this.getSystemMessageConfigForMode(config.systemMessage);
|
|
566
695
|
const sessionId = config.sessionId ?? randomUUID();
|
|
567
696
|
const session = new CopilotSession(
|
|
568
697
|
sessionId,
|
|
@@ -600,6 +729,7 @@ class CopilotClient {
|
|
|
600
729
|
}
|
|
601
730
|
this.sessions.set(sessionId, session);
|
|
602
731
|
this.setupSessionFs(session, config);
|
|
732
|
+
const toolFilterOptions = this.resolveToolFilterOptions(config);
|
|
603
733
|
try {
|
|
604
734
|
const response = await this.connection.sendRequest("session.create", {
|
|
605
735
|
...await getTraceContext(this.onGetTraceContext),
|
|
@@ -623,8 +753,9 @@ class CopilotClient {
|
|
|
623
753
|
description: cmd.description
|
|
624
754
|
})),
|
|
625
755
|
systemMessage: wireSystemMessage,
|
|
626
|
-
availableTools:
|
|
627
|
-
excludedTools:
|
|
756
|
+
availableTools: toolFilterOptions.availableTools,
|
|
757
|
+
excludedTools: toolFilterOptions.excludedTools,
|
|
758
|
+
toolFilterPrecedence: toolFilterOptions.toolFilterPrecedence,
|
|
628
759
|
provider: config.provider,
|
|
629
760
|
enableSessionTelemetry: config.enableSessionTelemetry,
|
|
630
761
|
modelCapabilities: config.modelCapabilities,
|
|
@@ -655,6 +786,7 @@ class CopilotClient {
|
|
|
655
786
|
const { workspacePath, capabilities } = response;
|
|
656
787
|
session["_workspacePath"] = workspacePath;
|
|
657
788
|
session.setCapabilities(capabilities);
|
|
789
|
+
await this.updateSessionOptionsForMode(session, config);
|
|
658
790
|
} catch (e) {
|
|
659
791
|
this.sessions.delete(sessionId);
|
|
660
792
|
throw e;
|
|
@@ -714,6 +846,8 @@ class CopilotClient {
|
|
|
714
846
|
if (config.hooks) {
|
|
715
847
|
session.registerHooks(config.hooks);
|
|
716
848
|
}
|
|
849
|
+
config = { ...this.configDefaultsForMode(), ...config };
|
|
850
|
+
config.systemMessage = this.getSystemMessageConfigForMode(config.systemMessage);
|
|
717
851
|
const { wirePayload: wireSystemMessage, transformCallbacks } = extractTransformCallbacks(
|
|
718
852
|
config.systemMessage
|
|
719
853
|
);
|
|
@@ -725,6 +859,7 @@ class CopilotClient {
|
|
|
725
859
|
}
|
|
726
860
|
this.sessions.set(sessionId, session);
|
|
727
861
|
this.setupSessionFs(session, config);
|
|
862
|
+
const toolFilterOptions = this.resolveToolFilterOptions(config);
|
|
728
863
|
try {
|
|
729
864
|
const response = await this.connection.sendRequest("session.resume", {
|
|
730
865
|
...await getTraceContext(this.onGetTraceContext),
|
|
@@ -733,8 +868,9 @@ class CopilotClient {
|
|
|
733
868
|
model: config.model,
|
|
734
869
|
reasoningEffort: config.reasoningEffort,
|
|
735
870
|
systemMessage: wireSystemMessage,
|
|
736
|
-
availableTools:
|
|
737
|
-
excludedTools:
|
|
871
|
+
availableTools: toolFilterOptions.availableTools,
|
|
872
|
+
excludedTools: toolFilterOptions.excludedTools,
|
|
873
|
+
toolFilterPrecedence: toolFilterOptions.toolFilterPrecedence,
|
|
738
874
|
enableSessionTelemetry: config.enableSessionTelemetry,
|
|
739
875
|
tools: config.tools?.map((tool) => ({
|
|
740
876
|
name: tool.name,
|
|
@@ -783,6 +919,7 @@ class CopilotClient {
|
|
|
783
919
|
session["_workspacePath"] = workspacePath;
|
|
784
920
|
session.setCapabilities(capabilities);
|
|
785
921
|
session.setOpenCanvases(openCanvases ?? []);
|
|
922
|
+
await this.updateSessionOptionsForMode(session, config);
|
|
786
923
|
} catch (e) {
|
|
787
924
|
this.sessions.delete(sessionId);
|
|
788
925
|
throw e;
|
|
@@ -1161,6 +1298,9 @@ class CopilotClient {
|
|
|
1161
1298
|
if (this.options.baseDirectory) {
|
|
1162
1299
|
envWithoutNodeDebug.COPILOT_HOME = this.options.baseDirectory;
|
|
1163
1300
|
}
|
|
1301
|
+
if (this.options.mode === "empty") {
|
|
1302
|
+
envWithoutNodeDebug.COPILOT_DISABLE_KEYTAR = "1";
|
|
1303
|
+
}
|
|
1164
1304
|
if (!this.resolvedCliPath) {
|
|
1165
1305
|
throw new Error(
|
|
1166
1306
|
"Path to Copilot CLI is required. Please supply it via `RuntimeConnection.forStdio({ path })` or `RuntimeConnection.forTcp({ path })`, set the COPILOT_CLI_PATH environment variable, or use `RuntimeConnection.forUri(...)` to connect to an already-running runtime."
|
|
@@ -1397,18 +1537,6 @@ stderr: ${stderrOutput}`
|
|
|
1397
1537
|
"systemMessage.transform",
|
|
1398
1538
|
async (params) => await this.handleSystemMessageTransform(params)
|
|
1399
1539
|
);
|
|
1400
|
-
this.connection.onRequest(
|
|
1401
|
-
"canvas.open",
|
|
1402
|
-
async (params) => this.handleCanvasProviderRequest("canvas.open", params)
|
|
1403
|
-
);
|
|
1404
|
-
this.connection.onRequest(
|
|
1405
|
-
"canvas.close",
|
|
1406
|
-
async (params) => this.handleCanvasProviderRequest("canvas.close", params)
|
|
1407
|
-
);
|
|
1408
|
-
this.connection.onRequest(
|
|
1409
|
-
"canvas.action.invoke",
|
|
1410
|
-
async (params) => this.handleCanvasActionInvokeRequest(params)
|
|
1411
|
-
);
|
|
1412
1540
|
const sessions = this.sessions;
|
|
1413
1541
|
registerClientSessionApiHandlers(this.connection, (sessionId) => {
|
|
1414
1542
|
const session = sessions.get(sessionId);
|
|
@@ -1530,26 +1658,6 @@ stderr: ${stderrOutput}`
|
|
|
1530
1658
|
}
|
|
1531
1659
|
return await session._handleSystemMessageTransform(params.sections);
|
|
1532
1660
|
}
|
|
1533
|
-
async handleCanvasProviderRequest(actionName, params) {
|
|
1534
|
-
if (!isCanvasProviderRequestParams(params)) {
|
|
1535
|
-
throw new Error("Invalid canvas provider request payload");
|
|
1536
|
-
}
|
|
1537
|
-
const session = this.sessions.get(params.sessionId);
|
|
1538
|
-
if (!session) {
|
|
1539
|
-
throw new Error(`Session not found: ${params.sessionId}`);
|
|
1540
|
-
}
|
|
1541
|
-
const canvas = session.getCanvas(params.canvasId);
|
|
1542
|
-
if (!canvas) {
|
|
1543
|
-
throw new Error(`No canvas registered with id "${params.canvasId}"`);
|
|
1544
|
-
}
|
|
1545
|
-
return dispatchCanvasProviderRequest(canvas, actionName, params);
|
|
1546
|
-
}
|
|
1547
|
-
async handleCanvasActionInvokeRequest(params) {
|
|
1548
|
-
if (!isCanvasActionInvokeParams(params)) {
|
|
1549
|
-
throw new Error("Invalid canvas provider request payload");
|
|
1550
|
-
}
|
|
1551
|
-
return this.handleCanvasProviderRequest(params.actionName, params);
|
|
1552
|
-
}
|
|
1553
1661
|
}
|
|
1554
1662
|
export {
|
|
1555
1663
|
CopilotClient
|
package/dist/extension.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CopilotSession } from "./session.js";
|
|
2
2
|
import { type ExtensionInfo, type PermissionHandler, type ResumeSessionConfig } from "./types.js";
|
|
3
|
-
export { Canvas, CanvasError, createCanvas, type CanvasAction, type
|
|
3
|
+
export { Canvas, CanvasError, createCanvas, type CanvasAction, type CanvasDeclaration, type CanvasHostContext, type CanvasJsonSchema, type CanvasOptions, } from "./canvas.js";
|
|
4
4
|
export type JoinSessionConfig = Omit<ResumeSessionConfig, "onPermissionRequest"> & {
|
|
5
5
|
onPermissionRequest?: PermissionHandler;
|
|
6
6
|
};
|