@github/copilot-sdk 1.0.17-preview.2 → 1.0.17-preview.4
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 +67 -0
- package/dist/canvas.d.ts +6 -1
- package/dist/cjs/cliVersion.js +1 -1
- package/dist/cjs/client.js +25 -2
- package/dist/cjs/generated/rpc.js +128 -15
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/runtimeArtifacts.js +1 -0
- package/dist/cjs/session.js +84 -2
- package/dist/cjs/sessionFsProvider.js +57 -0
- package/dist/cjs/types.js +5 -2
- package/dist/cliVersion.d.ts +1 -1
- package/dist/cliVersion.js +1 -1
- package/dist/client.js +25 -2
- package/dist/generated/rpc.d.ts +1128 -411
- package/dist/generated/rpc.js +128 -15
- package/dist/generated/session-events.d.ts +255 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -0
- package/dist/runtimeArtifacts.js +1 -0
- package/dist/session.d.ts +45 -1
- package/dist/session.js +84 -2
- package/dist/sessionFsProvider.d.ts +9 -1
- package/dist/sessionFsProvider.js +56 -0
- package/dist/types.d.ts +83 -2
- package/dist/types.js +4 -2
- package/docs/agent-author.md +29 -2
- package/package.json +13 -12
package/README.md
CHANGED
|
@@ -270,6 +270,19 @@ new CopilotClient(options?: CopilotClientOptions)
|
|
|
270
270
|
- `telemetry?: TelemetryConfig` - OpenTelemetry configuration for the runtime process. Providing this object enables telemetry — no separate flag needed. See [Telemetry](#telemetry) below.
|
|
271
271
|
- `onGetTraceContext?: TraceContextProvider` - Advanced: callback for linking your application's own OpenTelemetry spans into the same distributed trace as the runtime's spans. Not needed for normal telemetry collection. See [Telemetry](#telemetry) below.
|
|
272
272
|
- `sessionFs?: SessionFsConfig` - Custom session filesystem provider.
|
|
273
|
+
|
|
274
|
+
For a custom provider to serve images to the `view` tool, declare
|
|
275
|
+
`sessionFs.capabilities.binary: true` and implement
|
|
276
|
+
`readFileBytes(path): Promise<Uint8Array>` and
|
|
277
|
+
`writeFileBytes(path, content: Uint8Array, mode?: number): Promise<void>` on each session's provider. The
|
|
278
|
+
adapter transmits exact bytes as standard base64; text-only providers still
|
|
279
|
+
support text operations, but image reads fail rather than falling back to the
|
|
280
|
+
runtime machine's filesystem. A missing binary implementation is rejected
|
|
281
|
+
when a session is created.
|
|
282
|
+
|
|
283
|
+
Binary reads and writes are limited to 50,330,880 raw bytes (approximately 48 MiB);
|
|
284
|
+
larger results return a filesystem error before encoding or decoding.
|
|
285
|
+
|
|
273
286
|
- `sessionIdleTimeoutSeconds?: number` - Server-wide idle timeout for sessions in seconds. Ignored when connecting via `RuntimeConnection.forUri`.
|
|
274
287
|
- `enableRemoteSessions?: boolean` - Enable Mission Control remote session support. Ignored when connecting via `RuntimeConnection.forUri`.
|
|
275
288
|
|
|
@@ -644,6 +657,24 @@ if (result.status === "pending") {
|
|
|
644
657
|
|
|
645
658
|
See [Auto tier persistence](../docs/features/session-persistence.md#auto-tier-persistence) for the full lifecycle rules.
|
|
646
659
|
|
|
660
|
+
##### `setTools(tools: Tool[]): Promise<void>`
|
|
661
|
+
|
|
662
|
+
Replace the tools this client supplies to the session, together with the handlers that serve them (experimental). `tools` takes the same definitions as `createSession` and becomes this client's complete tool set; pass `[]` to remove all of this client's tools. Built-in, MCP, and plugin tools, and tools other connected clients supply, are unaffected.
|
|
663
|
+
|
|
664
|
+
Once the runtime accepts the replacement, every tool call this session dispatches uses the new handlers; calls already running finish on their original handlers. If the runtime rejects it, the promise rejects and the previous tools and handlers stay in place. Concurrent calls are applied one at a time, in call order.
|
|
665
|
+
|
|
666
|
+
```typescript
|
|
667
|
+
await session.setTools([
|
|
668
|
+
defineTool("search_issues", {
|
|
669
|
+
description: "Search the issues shown on the current page",
|
|
670
|
+
parameters: z.object({ query: z.string() }),
|
|
671
|
+
handler: async ({ query }) => searchIssues(query),
|
|
672
|
+
}),
|
|
673
|
+
]);
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
The agent sees the new tools from its next model request, which can fall within a turn in progress, so a model request already in flight can still call a tool you removed. See [Changing tools during a session](../docs/features/changing-tools.md) for the details.
|
|
677
|
+
|
|
647
678
|
##### `abort(): Promise<void>`
|
|
648
679
|
|
|
649
680
|
Abort the currently processing message in this session.
|
|
@@ -839,6 +870,22 @@ defineTool("edit_file", {
|
|
|
839
870
|
});
|
|
840
871
|
```
|
|
841
872
|
|
|
873
|
+
An `apply_patch` override can declare a string schema. The model sees a required
|
|
874
|
+
`input` property, but the runtime restores the declared scalar shape before
|
|
875
|
+
dispatching to any SDK. Both a Zod-inferred Node handler and
|
|
876
|
+
`invocation.arguments` receive the patch text as a string:
|
|
877
|
+
|
|
878
|
+
```ts
|
|
879
|
+
defineTool("apply_patch", {
|
|
880
|
+
parameters: z.string(),
|
|
881
|
+
overridesBuiltInTool: true,
|
|
882
|
+
handler: (patch) => patch.trim(),
|
|
883
|
+
});
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
String-schema `apply_patch` overrides cannot contain JSON Schema references;
|
|
887
|
+
use an object schema if references are needed.
|
|
888
|
+
|
|
842
889
|
#### Skipping Permission Prompts
|
|
843
890
|
|
|
844
891
|
Set `skipPermission: true` on a tool definition to allow it to execute without triggering a permission prompt:
|
|
@@ -988,6 +1035,8 @@ Available section IDs: `preamble`, `identity`, `tone`, `tool_efficiency`, `envir
|
|
|
988
1035
|
|
|
989
1036
|
`identity` and `tool_instructions` are section _groups_ that target a collection of related sub-sections as a unit. Use `preamble` to target just the identity preamble without affecting its sibling sub-sections.
|
|
990
1037
|
|
|
1038
|
+
`last_instructions` includes configured subagent-model guidance when the `task` tool is available. Removing or replacing this section also removes that guidance; a transform callback receives the complete section, including the guidance, and its returned content is authoritative. Append, prepend, and preserve retain their usual section semantics. These overrides change prompt prose only, not configured subagent models, tool availability, or runtime dispatch policy. `runtime_instructions` is a separate section: removing it does not remove `last_instructions`.
|
|
1039
|
+
|
|
991
1040
|
Each section override supports five actions:
|
|
992
1041
|
|
|
993
1042
|
- **`replace`** — Replace the section content entirely
|
|
@@ -996,6 +1045,8 @@ Each section override supports five actions:
|
|
|
996
1045
|
- **`prepend`** — Add content before the existing section
|
|
997
1046
|
- **`preserve`** — No-op that opts an individually-addressable section out of a group-level `remove`
|
|
998
1047
|
|
|
1048
|
+
An `action` can also be a callback that receives the current section content and returns the replacement content, synchronously or asynchronously.
|
|
1049
|
+
|
|
999
1050
|
Unknown section IDs are handled gracefully: content from `replace`/`append`/`prepend` overrides is appended to additional instructions, and `remove` overrides are silently ignored.
|
|
1000
1051
|
|
|
1001
1052
|
#### Replace Mode
|
|
@@ -1443,6 +1494,20 @@ const session = await client.createSession({
|
|
|
1443
1494
|
};
|
|
1444
1495
|
}
|
|
1445
1496
|
},
|
|
1497
|
+
|
|
1498
|
+
// Called before a sub-agent's first turn (the input identifies the parent session)
|
|
1499
|
+
onSubagentStart: (input, invocation) => {
|
|
1500
|
+
console.log(`Starting ${input.agentDisplayName ?? input.agentName}`);
|
|
1501
|
+
return { additionalContext: "Check the requested file before reporting back." };
|
|
1502
|
+
},
|
|
1503
|
+
|
|
1504
|
+
// Called when a sub-agent completes a turn
|
|
1505
|
+
onSubagentStop: (input, invocation) => {
|
|
1506
|
+
console.log(`${input.agentName} replied: ${input.response}`);
|
|
1507
|
+
// Return { decision: "block", reason: "Continue checking the file." }
|
|
1508
|
+
// to request another child turn instead.
|
|
1509
|
+
return { modifiedResponse: `Reviewed: ${input.response}` };
|
|
1510
|
+
},
|
|
1446
1511
|
},
|
|
1447
1512
|
});
|
|
1448
1513
|
```
|
|
@@ -1457,6 +1522,8 @@ const session = await client.createSession({
|
|
|
1457
1522
|
- `onSessionEnd` - Cleanup or logging when session ends.
|
|
1458
1523
|
- `onErrorOccurred` - Handle errors with retry/skip/abort strategies.
|
|
1459
1524
|
- `onAgentStop` - Observe natural top-level agent completion. Return `{ decision: "block", reason }` to request another turn; use `stopHookActive` to avoid repeated blocks.
|
|
1525
|
+
- `onSubagentStart` - Observe a sub-agent before its first turn and prepend `additionalContext` to the child's prompt.
|
|
1526
|
+
- `onSubagentStop` - Observe a sub-agent's final response. Return `{ decision: "block", reason }` to request another child turn, or `{ modifiedResponse }` to replace the response reported to the parent.
|
|
1460
1527
|
|
|
1461
1528
|
## Error Handling
|
|
1462
1529
|
|
package/dist/canvas.d.ts
CHANGED
|
@@ -32,7 +32,12 @@ export interface CanvasAction {
|
|
|
32
32
|
description?: string;
|
|
33
33
|
/** Optional JSON Schema for the action's `input` payload. */
|
|
34
34
|
inputSchema?: CanvasJsonSchema;
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Required per-action dispatch handler. The returned value becomes the
|
|
37
|
+
* `invoke_canvas_action` tool result. Return a `ToolResultObject`
|
|
38
|
+
* (with `binaryResultsForLlm`) to send text and images to the model, as a
|
|
39
|
+
* tool handler would; any other value is rendered to the model as JSON text.
|
|
40
|
+
*/
|
|
36
41
|
handler: (ctx: CanvasProviderInvokeActionRequest) => Promise<unknown> | unknown;
|
|
37
42
|
}
|
|
38
43
|
/**
|
package/dist/cjs/cliVersion.js
CHANGED
|
@@ -22,7 +22,7 @@ __export(cliVersion_exports, {
|
|
|
22
22
|
COPILOT_CLI_VERSION: () => COPILOT_CLI_VERSION
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(cliVersion_exports);
|
|
25
|
-
const COPILOT_CLI_VERSION = "1.0.92-
|
|
25
|
+
const COPILOT_CLI_VERSION = "1.0.92-4";
|
|
26
26
|
const COPILOT_CLI_USE_NPM_PACKAGE = false;
|
|
27
27
|
// Annotate the CommonJS export names for ESM import in node:
|
|
28
28
|
0 && (module.exports = {
|
package/dist/cjs/client.js
CHANGED
|
@@ -52,6 +52,7 @@ var import_toolSet = require("./toolSet.js");
|
|
|
52
52
|
var import_types = require("./types.js");
|
|
53
53
|
const MIN_PROTOCOL_VERSION = 3;
|
|
54
54
|
const RUNTIME_SHUTDOWN_TIMEOUT_MS = 1e4;
|
|
55
|
+
const CLOUD_SESSION_CLEANUP_TIMEOUT_MS = 1e4;
|
|
55
56
|
function createMessageConnection(reader, writer) {
|
|
56
57
|
let dispatch;
|
|
57
58
|
let finishDrain;
|
|
@@ -580,6 +581,11 @@ class CopilotClient {
|
|
|
580
581
|
"SessionFsConfig declares capabilities.sqlite but the provider does not implement sqlite."
|
|
581
582
|
);
|
|
582
583
|
}
|
|
584
|
+
if (this.sessionFsConfig.capabilities?.binary && (!provider.readFileBytes || !provider.writeFileBytes)) {
|
|
585
|
+
throw new Error(
|
|
586
|
+
"SessionFsConfig declares capabilities.binary but the provider does not implement readFileBytes and writeFileBytes."
|
|
587
|
+
);
|
|
588
|
+
}
|
|
583
589
|
session.clientSessionApis.sessionFs = (0, import_sessionFsProvider.createSessionFsAdapter)(provider);
|
|
584
590
|
}
|
|
585
591
|
setupClientGlobalHandlers() {
|
|
@@ -1263,12 +1269,13 @@ class CopilotClient {
|
|
|
1263
1269
|
if (config.onEvent) {
|
|
1264
1270
|
s.on(config.onEvent);
|
|
1265
1271
|
}
|
|
1266
|
-
this.sessions.set(sessionId, s);
|
|
1267
1272
|
this.setupSessionFs(s, config);
|
|
1273
|
+
this.sessions.set(sessionId, s);
|
|
1268
1274
|
return s;
|
|
1269
1275
|
};
|
|
1270
1276
|
let session;
|
|
1271
1277
|
let registeredId;
|
|
1278
|
+
let uninitializedCloudSessionId;
|
|
1272
1279
|
if (localSessionId !== void 0) {
|
|
1273
1280
|
try {
|
|
1274
1281
|
session = initializeSession(localSessionId);
|
|
@@ -1391,7 +1398,9 @@ class CopilotClient {
|
|
|
1391
1398
|
);
|
|
1392
1399
|
}
|
|
1393
1400
|
if (session === void 0) {
|
|
1401
|
+
uninitializedCloudSessionId = returnedSessionId;
|
|
1394
1402
|
session = initializeSession(returnedSessionId);
|
|
1403
|
+
uninitializedCloudSessionId = void 0;
|
|
1395
1404
|
registeredId = returnedSessionId;
|
|
1396
1405
|
}
|
|
1397
1406
|
this.assignGitHubTokenProvider(gitHubTokenProviderRegistrationId, returnedSessionId);
|
|
@@ -1413,6 +1422,20 @@ class CopilotClient {
|
|
|
1413
1422
|
if (gitHubTokenProviderRegistrationId !== void 0) {
|
|
1414
1423
|
this.githubTokenProviders.delete(gitHubTokenProviderRegistrationId);
|
|
1415
1424
|
}
|
|
1425
|
+
if (uninitializedCloudSessionId !== void 0) {
|
|
1426
|
+
try {
|
|
1427
|
+
await withTimeout(
|
|
1428
|
+
this.deleteSession(uninitializedCloudSessionId),
|
|
1429
|
+
CLOUD_SESSION_CLEANUP_TIMEOUT_MS,
|
|
1430
|
+
`session.delete timed out after ${CLOUD_SESSION_CLEANUP_TIMEOUT_MS}ms`
|
|
1431
|
+
);
|
|
1432
|
+
} catch (cleanupError) {
|
|
1433
|
+
throw new AggregateError(
|
|
1434
|
+
[e, cleanupError],
|
|
1435
|
+
"Failed to initialize and delete cloud session"
|
|
1436
|
+
);
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1416
1439
|
throw e;
|
|
1417
1440
|
}
|
|
1418
1441
|
for (const entry of this.hostHandoffs.values()) {
|
|
@@ -1512,8 +1535,8 @@ class CopilotClient {
|
|
|
1512
1535
|
if (config.onEvent) {
|
|
1513
1536
|
session.on(config.onEvent);
|
|
1514
1537
|
}
|
|
1515
|
-
this.sessions.set(sessionId, session);
|
|
1516
1538
|
this.setupSessionFs(session, config);
|
|
1539
|
+
this.sessions.set(sessionId, session);
|
|
1517
1540
|
const toolFilterOptions = this.resolveToolFilterOptions(config);
|
|
1518
1541
|
const gitHubTokenProviderRegistrationId = this.registerGitHubTokenProvider(
|
|
1519
1542
|
config.gitHubTokenProvider,
|
|
@@ -127,7 +127,48 @@ function createServerRpc(connection) {
|
|
|
127
127
|
*
|
|
128
128
|
* @returns Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package.
|
|
129
129
|
*/
|
|
130
|
-
getHostSupport: async () => connection.sendRequest("sandbox.getHostSupport", {})
|
|
130
|
+
getHostSupport: async () => connection.sendRequest("sandbox.getHostSupport", {}),
|
|
131
|
+
/** @experimental */
|
|
132
|
+
proxyCa: {
|
|
133
|
+
/**
|
|
134
|
+
* Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing.
|
|
135
|
+
*
|
|
136
|
+
* @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.
|
|
137
|
+
*
|
|
138
|
+
* @returns Status of the persistent certificate authority of the sandbox credential proxy.
|
|
139
|
+
*/
|
|
140
|
+
getStatus: async (params) => connection.sendRequest("sandbox.proxyCa.getStatus", params),
|
|
141
|
+
/**
|
|
142
|
+
* Creates the persistent certificate authority of the sandbox credential proxy if none is stored, without changing OS trust, and returns the path of its public certificate. Keeps an existing certificate authority, even one that must be rotated. Fails where OS trust is unsupported. Trust it with sandbox.proxyCa.trust: the CLI trusts only the hosts in the saved user settings, so it refuses a certificate authority that also covers hosts from sandboxConfig.
|
|
143
|
+
*
|
|
144
|
+
* @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.
|
|
145
|
+
*
|
|
146
|
+
* @returns Result of creating the persistent certificate authority of the sandbox credential proxy.
|
|
147
|
+
*/
|
|
148
|
+
create: async (params) => connection.sendRequest("sandbox.proxyCa.create", params),
|
|
149
|
+
/**
|
|
150
|
+
* Replaces the persistent certificate authority of the sandbox credential proxy with a new one for the current credential hosts. If OS trust included the old one, removes it and trusts the new one, which can show an OS authentication prompt. Running sandboxed tools keep the old certificate authority until they restart.
|
|
151
|
+
*
|
|
152
|
+
* @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.
|
|
153
|
+
*
|
|
154
|
+
* @returns Status of the persistent certificate authority of the sandbox credential proxy.
|
|
155
|
+
*/
|
|
156
|
+
rotate: async (params) => connection.sendRequest("sandbox.proxyCa.rotate", params),
|
|
157
|
+
/**
|
|
158
|
+
* Adds the persistent certificate authority of the sandbox credential proxy to OS trust, so sandboxed clients that read only OS trust accept the proxy. Call create first. Refuses a certificate authority that is not constrained to the current credential hosts. Can show an OS authentication prompt.
|
|
159
|
+
*
|
|
160
|
+
* @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.
|
|
161
|
+
*
|
|
162
|
+
* @returns Status of the persistent certificate authority of the sandbox credential proxy.
|
|
163
|
+
*/
|
|
164
|
+
trust: async (params) => connection.sendRequest("sandbox.proxyCa.trust", params),
|
|
165
|
+
/**
|
|
166
|
+
* Removes the persistent certificate authority of the sandbox credential proxy from OS trust. Keeps the stored certificate authority. Can show an OS authentication prompt. Sandboxed clients that read only OS trust then reject the proxy; clients that read the per-process certificate bundle continue to work.
|
|
167
|
+
*
|
|
168
|
+
* @returns Status of the persistent certificate authority of the sandbox credential proxy.
|
|
169
|
+
*/
|
|
170
|
+
remove: async () => connection.sendRequest("sandbox.proxyCa.remove", {})
|
|
171
|
+
}
|
|
131
172
|
},
|
|
132
173
|
/** @experimental */
|
|
133
174
|
tools: {
|
|
@@ -1047,22 +1088,55 @@ function createInternalServerRpc(connection) {
|
|
|
1047
1088
|
* @param params Params to attach or detach an in-process ExtensionController delegate.
|
|
1048
1089
|
*/
|
|
1049
1090
|
configureSessionExtensions: async (params) => connection.sendRequest("sessions.configureSessionExtensions", params)
|
|
1050
|
-
},
|
|
1051
|
-
/** @experimental */
|
|
1052
|
-
accounts: {
|
|
1053
|
-
/**
|
|
1054
|
-
* Acquire a Microsoft Entra access token through the runtime's OneAuth broker. Account-scoped because it uses the same native broker as the account stack: a trusted host application mints a scoped Entra token for its own use, most notably to authenticate to a remote MCP server whose authorization server is Entra ID (in place of the generic browser-OAuth flow).
|
|
1055
|
-
*
|
|
1056
|
-
* @param params OneAuth token request supplied by a trusted host application.
|
|
1057
|
-
*
|
|
1058
|
-
* @returns Result of a OneAuth token acquisition.
|
|
1059
|
-
*/
|
|
1060
|
-
acquireEntraToken: async (params) => connection.sendRequest("accounts.acquireEntraToken", params)
|
|
1061
1091
|
}
|
|
1062
1092
|
};
|
|
1063
1093
|
}
|
|
1064
1094
|
function createSessionRpc(connection, sessionId) {
|
|
1065
1095
|
return {
|
|
1096
|
+
/** @experimental */
|
|
1097
|
+
providers: {
|
|
1098
|
+
/**
|
|
1099
|
+
* Returns adapter definitions and supported operations in this session's effective provider catalog, without running discovery. Does not list provider instances or select inference models.
|
|
1100
|
+
*
|
|
1101
|
+
* @returns Normalized model-provider adapter definitions available to the session, not discovered instances.
|
|
1102
|
+
*/
|
|
1103
|
+
getCatalog: async () => connection.sendRequest("session.providers.getCatalog", { sessionId }),
|
|
1104
|
+
/**
|
|
1105
|
+
* Discovers reachable instances using an adapter from this session's effective provider catalog and provider-specific discovery input.
|
|
1106
|
+
*
|
|
1107
|
+
* @param params Provider discovery parameters.
|
|
1108
|
+
*
|
|
1109
|
+
* @returns Provider instances found by a discovery operation.
|
|
1110
|
+
*/
|
|
1111
|
+
discover: async (params) => connection.sendRequest("session.providers.discover", { ...params, sessionId }),
|
|
1112
|
+
/**
|
|
1113
|
+
* Gets current health and version information for a discovered model-provider instance.
|
|
1114
|
+
*
|
|
1115
|
+
* @param params Provider status request parameters.
|
|
1116
|
+
*
|
|
1117
|
+
* @returns Current health information for a provider instance.
|
|
1118
|
+
*/
|
|
1119
|
+
getStatus: async (params) => connection.sendRequest("session.providers.getStatus", { ...params, sessionId }),
|
|
1120
|
+
/** @experimental */
|
|
1121
|
+
models: {
|
|
1122
|
+
/**
|
|
1123
|
+
* Lists models installed or otherwise available from a discovered model-provider instance.
|
|
1124
|
+
*
|
|
1125
|
+
* @param params Provider model inventory request parameters.
|
|
1126
|
+
*
|
|
1127
|
+
* @returns Models offered for agent conversations by one provider instance. Adapters exclude known-incompatible models, but retain candidates with unknown capabilities. Listing does not guarantee compatibility.
|
|
1128
|
+
*/
|
|
1129
|
+
list: async (params) => connection.sendRequest("session.providers.models.list", { ...params, sessionId }),
|
|
1130
|
+
/**
|
|
1131
|
+
* Translates a discovered model into the provider and model configuration needed to use it, and reports whether each is already registered in this session. Prepares only: it registers nothing, writes nothing, and performs no provider requests.
|
|
1132
|
+
*
|
|
1133
|
+
* @param params A discovered instance and one of its models to translate into provider configuration. Pass back the instance and model as returned by `session.providers.discover` and `session.providers.models.list`.
|
|
1134
|
+
*
|
|
1135
|
+
* @returns Provider configuration prepared from a discovered model. Preparing a plan changes nothing: it neither registers the model with the session nor writes durable configuration. To apply it, pass `provider` and `model` to `session.provider.add`, omitting whichever the dispositions report as already configured.
|
|
1136
|
+
*/
|
|
1137
|
+
prepareConfiguration: async (params) => connection.sendRequest("session.providers.models.prepareConfiguration", { ...params, sessionId })
|
|
1138
|
+
}
|
|
1139
|
+
},
|
|
1066
1140
|
/**
|
|
1067
1141
|
* Suspends the session while preserving persisted state for later resume.
|
|
1068
1142
|
*
|
|
@@ -1670,16 +1744,18 @@ function createSessionRpc(connection, sessionId) {
|
|
|
1670
1744
|
*/
|
|
1671
1745
|
getSources: async () => connection.sendRequest("session.instructions.getSources", { sessionId }),
|
|
1672
1746
|
/**
|
|
1673
|
-
*
|
|
1747
|
+
* For local sessions, invalidates instruction discovery and the model-facing prompt, then returns freshly discovered sources. The updated prompt takes effect on the next turn. Remote sessions must reload on their agent host instead.
|
|
1748
|
+
*
|
|
1749
|
+
* @returns Instruction sources loaded for the session, in merge order.
|
|
1674
1750
|
*/
|
|
1675
1751
|
reload: async () => connection.sendRequest("session.instructions.reload", { sessionId })
|
|
1676
1752
|
},
|
|
1677
1753
|
/** @experimental */
|
|
1678
1754
|
customizations: {
|
|
1679
1755
|
/**
|
|
1680
|
-
*
|
|
1756
|
+
* For local sessions, reconciles repository context and discovered instructions, plugins, skills, agents, hooks, MCP servers, and extensions after files appear or change under the working directory. Independent component failures are returned in outcomes and errors; a rejected call can have partially applied earlier steps. Remote sessions must reload on their agent host instead. The model-facing context is rebuilt on the next turn.
|
|
1681
1757
|
*
|
|
1682
|
-
* @returns
|
|
1758
|
+
* @returns Results of reloading discovered session customizations. Inspect outcomes for reloaded, skipped, or failed subsystems; a rejection may follow partial mutation. Changes to the model-facing prompt and tools apply on the next turn.
|
|
1683
1759
|
*/
|
|
1684
1760
|
reload: async () => connection.sendRequest("session.customizations.reload", { sessionId })
|
|
1685
1761
|
},
|
|
@@ -3383,6 +3459,33 @@ function createInternalSessionRpc(connection, sessionId) {
|
|
|
3383
3459
|
finalizeInvocationEffect: async (params) => connection.sendRequest("session.commands.finalizeInvocationEffect", { ...params, sessionId })
|
|
3384
3460
|
},
|
|
3385
3461
|
/** @experimental */
|
|
3462
|
+
ui: {
|
|
3463
|
+
/**
|
|
3464
|
+
* Resolves a pending elicitation request after direct interaction in the trusted in-process client. Only an accepted response to the built-in ask_user tool can become trusted human evidence.
|
|
3465
|
+
*
|
|
3466
|
+
* @param params Pending elicitation request ID and the user's response (accept/decline/cancel + form values).
|
|
3467
|
+
*
|
|
3468
|
+
* @returns Indicates whether the elicitation response was accepted; false if it was already resolved by another client.
|
|
3469
|
+
*/
|
|
3470
|
+
handleHumanAskUser: async (params) => connection.sendRequest("session.ui.handleHumanAskUser", { ...params, sessionId }),
|
|
3471
|
+
/**
|
|
3472
|
+
* Resolves a pending `user_input.requested` event after direct interaction in the trusted in-process client.
|
|
3473
|
+
*
|
|
3474
|
+
* @param params Request ID of a pending `user_input.requested` event and the user's response.
|
|
3475
|
+
*
|
|
3476
|
+
* @returns Indicates whether the pending UI request was resolved by this call.
|
|
3477
|
+
*/
|
|
3478
|
+
handleHumanUserInput: async (params) => connection.sendRequest("session.ui.handleHumanUserInput", { ...params, sessionId }),
|
|
3479
|
+
/**
|
|
3480
|
+
* Resolves a pending `exit_plan_mode.requested` event after direct interaction in the trusted in-process client.
|
|
3481
|
+
*
|
|
3482
|
+
* @param params Request ID of a pending `exit_plan_mode.requested` event and the user's response.
|
|
3483
|
+
*
|
|
3484
|
+
* @returns Indicates whether the pending UI request was resolved by this call.
|
|
3485
|
+
*/
|
|
3486
|
+
handleHumanExitPlanMode: async (params) => connection.sendRequest("session.ui.handleHumanExitPlanMode", { ...params, sessionId })
|
|
3487
|
+
},
|
|
3488
|
+
/** @experimental */
|
|
3386
3489
|
settings: {
|
|
3387
3490
|
/**
|
|
3388
3491
|
* Returns a redacted snapshot of session runtime settings, with secrets and raw feature flags excluded. Internal: the runtime settings shape is a runtime-internal surface and is deliberately kept out of the public SDK, because consumers should not depend on the runtime's internal settings layout. It remains callable in-process and is expected to be reworked as the runtime internals are consolidated.
|
|
@@ -3535,11 +3638,21 @@ function registerClientSessionApiHandlers(connection, getHandlers) {
|
|
|
3535
3638
|
if (!handler) throw new Error(`No sessionFs handler registered for session: ${params.sessionId}`);
|
|
3536
3639
|
return handler.readFile(params);
|
|
3537
3640
|
});
|
|
3641
|
+
connection.onRequest("sessionFs.readFileBytes", async (params) => {
|
|
3642
|
+
const handler = getHandlers(params.sessionId).sessionFs;
|
|
3643
|
+
if (!handler) throw new Error(`No sessionFs handler registered for session: ${params.sessionId}`);
|
|
3644
|
+
return handler.readFileBytes(params);
|
|
3645
|
+
});
|
|
3538
3646
|
connection.onRequest("sessionFs.writeFile", async (params) => {
|
|
3539
3647
|
const handler = getHandlers(params.sessionId).sessionFs;
|
|
3540
3648
|
if (!handler) throw new Error(`No sessionFs handler registered for session: ${params.sessionId}`);
|
|
3541
3649
|
return handler.writeFile(params);
|
|
3542
3650
|
});
|
|
3651
|
+
connection.onRequest("sessionFs.writeFileBytes", async (params) => {
|
|
3652
|
+
const handler = getHandlers(params.sessionId).sessionFs;
|
|
3653
|
+
if (!handler) throw new Error(`No sessionFs handler registered for session: ${params.sessionId}`);
|
|
3654
|
+
return handler.writeFileBytes(params);
|
|
3655
|
+
});
|
|
3543
3656
|
connection.onRequest("sessionFs.appendFile", async (params) => {
|
|
3544
3657
|
const handler = getHandlers(params.sessionId).sessionFs;
|
|
3545
3658
|
if (!handler) throw new Error(`No sessionFs handler registered for session: ${params.sessionId}`);
|
package/dist/cjs/index.js
CHANGED
|
@@ -32,6 +32,7 @@ __export(index_exports, {
|
|
|
32
32
|
RuntimeConnection: () => import_types.RuntimeConnection,
|
|
33
33
|
SYSTEM_MESSAGE_SECTIONS: () => import_types2.SYSTEM_MESSAGE_SECTIONS,
|
|
34
34
|
SessionFsSqliteTransactionFailure: () => import_types2.SessionFsSqliteTransactionFailure,
|
|
35
|
+
SessionFsWriteFailure: () => import_types2.SessionFsWriteFailure,
|
|
35
36
|
ToolSet: () => import_toolSet.ToolSet,
|
|
36
37
|
WorkflowResumeError: () => import_workflow.WorkflowResumeError,
|
|
37
38
|
approveAll: () => import_types2.approveAll,
|
|
@@ -68,6 +69,7 @@ var import_types2 = require("./types.js");
|
|
|
68
69
|
RuntimeConnection,
|
|
69
70
|
SYSTEM_MESSAGE_SECTIONS,
|
|
70
71
|
SessionFsSqliteTransactionFailure,
|
|
72
|
+
SessionFsWriteFailure,
|
|
71
73
|
ToolSet,
|
|
72
74
|
WorkflowResumeError,
|
|
73
75
|
approveAll,
|
package/dist/cjs/session.js
CHANGED
|
@@ -38,6 +38,18 @@ function copyDefinedWorkflowAgentOption(source, target, key) {
|
|
|
38
38
|
target[key] = value;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
+
function toToolDefinition(tool) {
|
|
42
|
+
return {
|
|
43
|
+
name: tool.name,
|
|
44
|
+
description: tool.description ?? "",
|
|
45
|
+
parameters: (0, import_schema.toJsonSchema)(tool.parameters),
|
|
46
|
+
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
47
|
+
skipPermission: tool.skipPermission,
|
|
48
|
+
defer: tool.defer,
|
|
49
|
+
metadata: tool.metadata,
|
|
50
|
+
isTerminal: tool.isTerminal
|
|
51
|
+
};
|
|
52
|
+
}
|
|
41
53
|
const workflowExecutionStore = new import_node_async_hooks.AsyncLocalStorage();
|
|
42
54
|
function throwIfWorkflowExecutionIsActive() {
|
|
43
55
|
if (workflowExecutionStore.getStore()?.active) {
|
|
@@ -258,6 +270,8 @@ class CopilotSession {
|
|
|
258
270
|
eventHandlers = /* @__PURE__ */ new Set();
|
|
259
271
|
typedEventHandlers = /* @__PURE__ */ new Map();
|
|
260
272
|
toolHandlers = /* @__PURE__ */ new Map();
|
|
273
|
+
/** Settles once every earlier `setTools` call has finished. */
|
|
274
|
+
setToolsQueue = Promise.resolve();
|
|
261
275
|
pendingExternalTools = /* @__PURE__ */ new Map();
|
|
262
276
|
canvases = /* @__PURE__ */ new Map();
|
|
263
277
|
bearerTokenProviders = /* @__PURE__ */ new Map();
|
|
@@ -1069,7 +1083,20 @@ class CopilotSession {
|
|
|
1069
1083
|
}
|
|
1070
1084
|
for (const tool of tools) {
|
|
1071
1085
|
if (tool.handler) {
|
|
1072
|
-
|
|
1086
|
+
const handler = tool.handler;
|
|
1087
|
+
if (tool.name === "apply_patch" && tool.overridesBuiltInTool && (0, import_schema.toJsonSchema)(tool.parameters)?.type === "string") {
|
|
1088
|
+
this.toolHandlers.set(tool.name, (args, invocation) => {
|
|
1089
|
+
if (typeof args === "string") {
|
|
1090
|
+
return handler(args, invocation);
|
|
1091
|
+
}
|
|
1092
|
+
if (typeof args === "object" && args !== null && "input" in args && typeof args.input === "string") {
|
|
1093
|
+
return handler(args.input, invocation);
|
|
1094
|
+
}
|
|
1095
|
+
throw new TypeError("apply_patch string override requires a string input");
|
|
1096
|
+
});
|
|
1097
|
+
} else {
|
|
1098
|
+
this.toolHandlers.set(tool.name, handler);
|
|
1099
|
+
}
|
|
1073
1100
|
}
|
|
1074
1101
|
}
|
|
1075
1102
|
}
|
|
@@ -1664,7 +1691,9 @@ class CopilotSession {
|
|
|
1664
1691
|
sessionStart: this.hooks.onSessionStart,
|
|
1665
1692
|
sessionEnd: this.hooks.onSessionEnd,
|
|
1666
1693
|
errorOccurred: this.hooks.onErrorOccurred,
|
|
1667
|
-
agentStop: this.hooks.onAgentStop
|
|
1694
|
+
agentStop: this.hooks.onAgentStop,
|
|
1695
|
+
subagentStart: this.hooks.onSubagentStart,
|
|
1696
|
+
subagentStop: this.hooks.onSubagentStop
|
|
1668
1697
|
};
|
|
1669
1698
|
const handler = handlerMap[hookType];
|
|
1670
1699
|
if (!handler) {
|
|
@@ -1828,6 +1857,59 @@ class CopilotSession {
|
|
|
1828
1857
|
async setAutoTier(autoTier) {
|
|
1829
1858
|
return await this.rpc.model.switchAutoTier({ autoTier });
|
|
1830
1859
|
}
|
|
1860
|
+
/**
|
|
1861
|
+
* Replace the tools this client supplies to the session.
|
|
1862
|
+
*
|
|
1863
|
+
* `tools` becomes the complete set of tools this client implements,
|
|
1864
|
+
* replacing the ones it supplied when the session was created or resumed,
|
|
1865
|
+
* or in an earlier call. Built-in, MCP, and plugin tools, and tools other
|
|
1866
|
+
* connected clients supply, are unaffected. Pass an empty array to remove
|
|
1867
|
+
* all of this client's tools.
|
|
1868
|
+
*
|
|
1869
|
+
* Tools are defined the same way as for `createSession`: calls to tools
|
|
1870
|
+
* with a `handler` are dispatched to it, and tools without one are
|
|
1871
|
+
* declaration-only. Once the runtime accepts the replacement, every tool
|
|
1872
|
+
* call this session dispatches uses the new handlers; calls already
|
|
1873
|
+
* running finish on their original handlers. If the runtime rejects the
|
|
1874
|
+
* replacement, this rejects and the previous tools and handlers stay in
|
|
1875
|
+
* place. Concurrent calls on the same session are applied one at a time,
|
|
1876
|
+
* in the order they are made.
|
|
1877
|
+
*
|
|
1878
|
+
* The agent sees the new tools from its next model request, which can fall
|
|
1879
|
+
* within a turn in progress. A model request already in flight was made
|
|
1880
|
+
* with the previous tools, so the agent can still call a tool you removed.
|
|
1881
|
+
* This session doesn't answer that call, and it can stay pending until the
|
|
1882
|
+
* turn is aborted. If a running turn might still call a tool you remove,
|
|
1883
|
+
* replace tools while the session is idle.
|
|
1884
|
+
*
|
|
1885
|
+
* @param tools - The complete set of tools this client supplies
|
|
1886
|
+
*
|
|
1887
|
+
* @experimental Wraps the experimental `session.tools.set` RPC and may change
|
|
1888
|
+
* or be removed in a future release.
|
|
1889
|
+
*
|
|
1890
|
+
* @example
|
|
1891
|
+
* ```typescript
|
|
1892
|
+
* await session.setTools([
|
|
1893
|
+
* defineTool("search_issues", {
|
|
1894
|
+
* description: "Search the issues shown on the current page",
|
|
1895
|
+
* parameters: z.object({ query: z.string() }),
|
|
1896
|
+
* handler: async ({ query }) => searchIssues(query),
|
|
1897
|
+
* }),
|
|
1898
|
+
* ]);
|
|
1899
|
+
* ```
|
|
1900
|
+
*/
|
|
1901
|
+
async setTools(tools) {
|
|
1902
|
+
const definitions = tools.map(toToolDefinition);
|
|
1903
|
+
const replacement = this.setToolsQueue.then(async () => {
|
|
1904
|
+
await this.rpc.tools.set({ tools: definitions });
|
|
1905
|
+
this.registerTools(tools);
|
|
1906
|
+
});
|
|
1907
|
+
this.setToolsQueue = replacement.then(
|
|
1908
|
+
() => void 0,
|
|
1909
|
+
() => void 0
|
|
1910
|
+
);
|
|
1911
|
+
await replacement;
|
|
1912
|
+
}
|
|
1831
1913
|
/**
|
|
1832
1914
|
* Log a message to the session timeline.
|
|
1833
1915
|
* The message appears in the session event stream and is visible to SDK consumers
|
|
@@ -19,9 +19,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var sessionFsProvider_exports = {};
|
|
20
20
|
__export(sessionFsProvider_exports, {
|
|
21
21
|
SessionFsSqliteTransactionFailure: () => SessionFsSqliteTransactionFailure,
|
|
22
|
+
SessionFsWriteFailure: () => SessionFsWriteFailure,
|
|
22
23
|
createSessionFsAdapter: () => createSessionFsAdapter
|
|
23
24
|
});
|
|
24
25
|
module.exports = __toCommonJS(sessionFsProvider_exports);
|
|
26
|
+
const MAX_BINARY_BYTES = (64 * 1024 * 1024 - 1024) / 4 * 3;
|
|
27
|
+
const MAX_BINARY_CONTENT_LENGTH = Math.ceil(MAX_BINARY_BYTES / 3) * 4;
|
|
25
28
|
class SessionFsSqliteTransactionFailure extends Error {
|
|
26
29
|
/** Failure classification reported to the runtime. */
|
|
27
30
|
errorClass;
|
|
@@ -31,6 +34,9 @@ class SessionFsSqliteTransactionFailure extends Error {
|
|
|
31
34
|
this.errorClass = errorClass;
|
|
32
35
|
}
|
|
33
36
|
}
|
|
37
|
+
class SessionFsWriteFailure extends Error {
|
|
38
|
+
writeChanged = true;
|
|
39
|
+
}
|
|
34
40
|
function normalizeSqliteParams(params) {
|
|
35
41
|
if (!params) {
|
|
36
42
|
return void 0;
|
|
@@ -53,10 +59,60 @@ function createSessionFsAdapter(provider) {
|
|
|
53
59
|
return { content: "", error: toSessionFsError(err) };
|
|
54
60
|
}
|
|
55
61
|
},
|
|
62
|
+
readFileBytes: async ({ path }) => {
|
|
63
|
+
if (!provider.readFileBytes) {
|
|
64
|
+
return {
|
|
65
|
+
content: "",
|
|
66
|
+
error: { code: "UNKNOWN", message: "Binary reads are not supported" }
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const bytes = await provider.readFileBytes(path);
|
|
71
|
+
if (bytes.length > MAX_BINARY_BYTES) {
|
|
72
|
+
return {
|
|
73
|
+
content: "",
|
|
74
|
+
error: {
|
|
75
|
+
code: "UNKNOWN",
|
|
76
|
+
message: "sessionFs.readFileBytes content exceeds the binary read limit"
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
content: Buffer.from(bytes).toString("base64")
|
|
82
|
+
};
|
|
83
|
+
} catch (err) {
|
|
84
|
+
return { content: "", error: toSessionFsError(err) };
|
|
85
|
+
}
|
|
86
|
+
},
|
|
56
87
|
writeFile: async ({ path, content, mode }) => {
|
|
57
88
|
try {
|
|
58
89
|
await provider.writeFile(path, content, mode);
|
|
59
90
|
return void 0;
|
|
91
|
+
} catch (err) {
|
|
92
|
+
const error = toSessionFsError(err);
|
|
93
|
+
return err instanceof SessionFsWriteFailure ? { ...error, writeChanged: true } : error;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
writeFileBytes: async ({ path, content, mode }) => {
|
|
97
|
+
if (!provider.writeFileBytes) {
|
|
98
|
+
return { code: "UNKNOWN", message: "Binary writes are not supported" };
|
|
99
|
+
}
|
|
100
|
+
if (content.length > MAX_BINARY_CONTENT_LENGTH) {
|
|
101
|
+
return {
|
|
102
|
+
code: "UNKNOWN",
|
|
103
|
+
message: "sessionFs.writeFileBytes content exceeds the binary write limit"
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const bytes = Buffer.from(content, "base64");
|
|
107
|
+
if (bytes.toString("base64") !== content || bytes.length > MAX_BINARY_BYTES) {
|
|
108
|
+
return {
|
|
109
|
+
code: "UNKNOWN",
|
|
110
|
+
message: "invalid sessionFs.writeFileBytes base64 content"
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
await provider.writeFileBytes(path, bytes, mode);
|
|
115
|
+
return void 0;
|
|
60
116
|
} catch (err) {
|
|
61
117
|
return toSessionFsError(err);
|
|
62
118
|
}
|
|
@@ -194,5 +250,6 @@ function toSqliteTransactionError(err) {
|
|
|
194
250
|
// Annotate the CommonJS export names for ESM import in node:
|
|
195
251
|
0 && (module.exports = {
|
|
196
252
|
SessionFsSqliteTransactionFailure,
|
|
253
|
+
SessionFsWriteFailure,
|
|
197
254
|
createSessionFsAdapter
|
|
198
255
|
});
|