@github/copilot-sdk 1.0.9 → 1.0.11-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/cjs/client.js +12 -6
- package/dist/cjs/factory.js +10 -0
- package/dist/cjs/generated/rpc.js +24 -2
- package/dist/cjs/session.js +40 -16
- package/dist/client.js +12 -6
- package/dist/factory.d.ts +24 -34
- package/dist/factory.js +9 -0
- package/dist/generated/rpc.d.ts +404 -130
- package/dist/generated/rpc.js +24 -2
- package/dist/generated/session-events.d.ts +73 -109
- package/dist/index.d.ts +1 -1
- package/dist/session.js +41 -16
- package/dist/types.d.ts +82 -1
- package/docs/factories.md +4 -4
- package/package.json +2 -2
package/dist/session.js
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
1
2
|
import { ConnectionError, ErrorCodes, ResponseError } from "vscode-jsonrpc/node.js";
|
|
2
3
|
import { createSessionRpc } from "./generated/rpc.js";
|
|
3
4
|
import { CanvasError } from "./canvas.js";
|
|
4
5
|
import { getTraceContext } from "./telemetry.js";
|
|
5
6
|
import {
|
|
7
|
+
FACTORY_AGENT_OPTION_KEYS,
|
|
6
8
|
getFactoryDefinition,
|
|
7
9
|
FactoryResumeError,
|
|
8
10
|
isFactoryRunTerminal
|
|
9
11
|
} from "./factory.js";
|
|
10
12
|
function isFactoryResumeErrorCode(value) {
|
|
11
|
-
return value === "not_found" || value === "non_resumable" || value === "already_active" || value === "
|
|
13
|
+
return value === "not_found" || value === "non_resumable" || value === "already_active" || value === "factory_already_running" || value === "factory_limits_invalid" || value === "factory_session_disposed" || value === "factory_storage_unavailable" || value === "factory_storage_corrupt";
|
|
14
|
+
}
|
|
15
|
+
function copyDefinedFactoryAgentOption(source, target, key) {
|
|
16
|
+
const value = source[key];
|
|
17
|
+
if (value !== void 0) {
|
|
18
|
+
target[key] = value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const factoryExecutionStore = new AsyncLocalStorage();
|
|
22
|
+
function throwIfFactoryExecutionIsActive() {
|
|
23
|
+
if (factoryExecutionStore.getStore()?.active) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
"factory.run and factory.resume are not allowed while a factory body is running on this call path."
|
|
26
|
+
);
|
|
27
|
+
}
|
|
12
28
|
}
|
|
13
29
|
function deserializeHookInput(raw) {
|
|
14
30
|
if (!raw || typeof raw !== "object" || typeof raw.timestamp !== "number") {
|
|
@@ -129,7 +145,10 @@ class FactoryProgressBuffer {
|
|
|
129
145
|
const lines = this.pending.splice(0);
|
|
130
146
|
await this.flushTail;
|
|
131
147
|
if (this.flushFailed) {
|
|
132
|
-
|
|
148
|
+
console.warn(
|
|
149
|
+
"Ignoring a background factory progress flush failure after the factory body settled",
|
|
150
|
+
this.flushError
|
|
151
|
+
);
|
|
133
152
|
}
|
|
134
153
|
if (lines.length > 0) {
|
|
135
154
|
try {
|
|
@@ -160,9 +179,6 @@ class FactoryProgressBuffer {
|
|
|
160
179
|
}
|
|
161
180
|
}
|
|
162
181
|
}
|
|
163
|
-
function toPublicFactoryRunResult(envelope) {
|
|
164
|
-
return envelope;
|
|
165
|
-
}
|
|
166
182
|
async function awaitFactoryOperation(operation, signal) {
|
|
167
183
|
let rejectAbort;
|
|
168
184
|
const abortPromise = new Promise((_resolve, reject) => {
|
|
@@ -242,6 +258,7 @@ class CopilotSession {
|
|
|
242
258
|
*/
|
|
243
259
|
factory = {
|
|
244
260
|
run: (async (nameOrHandle, options) => {
|
|
261
|
+
throwIfFactoryExecutionIsActive();
|
|
245
262
|
const name = typeof nameOrHandle === "string" ? nameOrHandle : getFactoryDefinition(nameOrHandle).meta.name;
|
|
246
263
|
if (options?.resumeFromRunId !== void 0) {
|
|
247
264
|
return this.factory.resume(options.resumeFromRunId, {
|
|
@@ -258,6 +275,7 @@ class CopilotSession {
|
|
|
258
275
|
return this.settleFactoryRun(envelope);
|
|
259
276
|
}),
|
|
260
277
|
resume: (async (runId, options) => {
|
|
278
|
+
throwIfFactoryExecutionIsActive();
|
|
261
279
|
let response;
|
|
262
280
|
try {
|
|
263
281
|
response = await this.rpc.factory.resume({
|
|
@@ -275,12 +293,12 @@ class CopilotSession {
|
|
|
275
293
|
}
|
|
276
294
|
return this.settleFactoryRun(response.run);
|
|
277
295
|
}),
|
|
278
|
-
getRun: async (runId) =>
|
|
296
|
+
getRun: async (runId) => this.rpc.factory.getRun({ runId }),
|
|
279
297
|
waitForRun: (runId, options) => this.waitForFactoryRun(runId, options?.signal),
|
|
280
|
-
listRuns: async () => (await this.rpc.factory.listRuns()).runs,
|
|
298
|
+
listRuns: async () => (await this.rpc.factory.listRuns({})).runs,
|
|
281
299
|
getRunDetail: (runId) => this.rpc.factory.getRunDetail({ runId }),
|
|
282
300
|
getRunProgress: (runId, options = {}) => this.rpc.factory.getRunProgress({ runId, ...options }),
|
|
283
|
-
cancel: async (runId) =>
|
|
301
|
+
cancel: async (runId) => this.rpc.factory.cancel({ runId })
|
|
284
302
|
};
|
|
285
303
|
/**
|
|
286
304
|
* Resolve a start/resume envelope into the terminal envelope callers expect.
|
|
@@ -291,7 +309,7 @@ class CopilotSession {
|
|
|
291
309
|
*/
|
|
292
310
|
settleFactoryRun(envelope) {
|
|
293
311
|
if (isFactoryRunTerminal(envelope.status)) {
|
|
294
|
-
return Promise.resolve(
|
|
312
|
+
return Promise.resolve(envelope);
|
|
295
313
|
}
|
|
296
314
|
return this.waitForFactoryRun(envelope.runId);
|
|
297
315
|
}
|
|
@@ -345,7 +363,7 @@ class CopilotSession {
|
|
|
345
363
|
rereadRequested = false;
|
|
346
364
|
const envelope = await this.rpc.factory.getRun({ runId });
|
|
347
365
|
if (isFactoryRunTerminal(envelope.status)) {
|
|
348
|
-
finish(() => resolve(
|
|
366
|
+
finish(() => resolve(envelope));
|
|
349
367
|
return;
|
|
350
368
|
}
|
|
351
369
|
} while (rereadRequested && !settled);
|
|
@@ -945,16 +963,16 @@ class CopilotSession {
|
|
|
945
963
|
},
|
|
946
964
|
agent: async (prompt, options = {}) => {
|
|
947
965
|
await progress.flush();
|
|
966
|
+
const opts = {};
|
|
967
|
+
for (const key of FACTORY_AGENT_OPTION_KEYS) {
|
|
968
|
+
copyDefinedFactoryAgentOption(options, opts, key);
|
|
969
|
+
}
|
|
948
970
|
const response = await awaitFactoryOperation(
|
|
949
971
|
() => self.rpc.factory.agent({
|
|
950
972
|
factoryRunId: params.runId,
|
|
951
973
|
executionToken: params.executionToken,
|
|
952
974
|
prompt,
|
|
953
|
-
opts
|
|
954
|
-
label: options.label,
|
|
955
|
-
schema: options.schema,
|
|
956
|
-
model: options.model
|
|
957
|
-
}
|
|
975
|
+
opts
|
|
958
976
|
}),
|
|
959
977
|
controller.signal
|
|
960
978
|
);
|
|
@@ -1002,7 +1020,14 @@ class CopilotSession {
|
|
|
1002
1020
|
throw new Error("nested factories are not supported");
|
|
1003
1021
|
}
|
|
1004
1022
|
};
|
|
1005
|
-
const
|
|
1023
|
+
const execution = { active: true };
|
|
1024
|
+
const result = await factoryExecutionStore.run(execution, async () => {
|
|
1025
|
+
try {
|
|
1026
|
+
return await definition.run(context);
|
|
1027
|
+
} finally {
|
|
1028
|
+
execution.active = false;
|
|
1029
|
+
}
|
|
1030
|
+
});
|
|
1006
1031
|
if (result === void 0) {
|
|
1007
1032
|
return {};
|
|
1008
1033
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { SessionFsProvider } from "./sessionFsProvider.js";
|
|
|
6
6
|
import type { CopilotRequestHandler } from "./copilotRequestHandler.js";
|
|
7
7
|
import type { PermissionRequest as GeneratedPermissionRequest, PermissionRequestedData as GeneratedPermissionRequestedData, PermissionRequestedEvent as GeneratedPermissionRequestedEvent, ReasoningSummary, SessionLimitsConfig, SessionEvent as GeneratedSessionEvent } from "./generated/session-events.js";
|
|
8
8
|
import type { CopilotSession } from "./session.js";
|
|
9
|
+
import type { JsonValue } from "./factory.js";
|
|
9
10
|
import type { GitHubTelemetryNotification, ModelBillingTokenPrices, OpenCanvasInstance, RemoteSessionMode, CurrentToolMetadata } from "./generated/rpc.js";
|
|
10
11
|
import type { ToolSet } from "./toolSet.js";
|
|
11
12
|
export type { RemoteSessionMode } from "./generated/rpc.js";
|
|
@@ -355,7 +356,7 @@ export type ToolBinaryResult = {
|
|
|
355
356
|
type: "image" | "resource";
|
|
356
357
|
description?: string;
|
|
357
358
|
};
|
|
358
|
-
export type ToolTelemetry = Record<string, Record<string,
|
|
359
|
+
export type ToolTelemetry = Record<string, Record<string, JsonValue> | undefined>;
|
|
359
360
|
export type ToolResultObject = {
|
|
360
361
|
textResultForLlm: string;
|
|
361
362
|
binaryResultsForLlm?: ToolBinaryResult[];
|
|
@@ -484,6 +485,17 @@ export interface Tool<TArgs = unknown> {
|
|
|
484
485
|
* Unknown keys are preserved and round-tripped untouched.
|
|
485
486
|
*/
|
|
486
487
|
metadata?: Record<string, unknown>;
|
|
488
|
+
/**
|
|
489
|
+
* When true, a successful call to this tool ends the agent turn: the runtime's
|
|
490
|
+
* tool phase halts instead of feeding the tool result back to the model for
|
|
491
|
+
* another round. A failed call (for example input validation) leaves the loop
|
|
492
|
+
* running so the model can read the error and retry.
|
|
493
|
+
*
|
|
494
|
+
* Use this for tools whose whole purpose is to terminate the turn, such as a
|
|
495
|
+
* context clear that replaces the conversation the model would otherwise
|
|
496
|
+
* continue from.
|
|
497
|
+
*/
|
|
498
|
+
isTerminal?: boolean;
|
|
487
499
|
}
|
|
488
500
|
/**
|
|
489
501
|
* Helper to define a tool with Zod schema and get type inference for the handler.
|
|
@@ -497,6 +509,7 @@ export declare function defineTool<T = unknown>(name: string, config: {
|
|
|
497
509
|
skipPermission?: boolean;
|
|
498
510
|
defer?: "auto" | "never";
|
|
499
511
|
metadata?: Record<string, unknown>;
|
|
512
|
+
isTerminal?: boolean;
|
|
500
513
|
}): Tool<T>;
|
|
501
514
|
/**
|
|
502
515
|
* SDK-supplied override for the runtime's built-in tool-search behavior.
|
|
@@ -1682,6 +1695,43 @@ export interface GitHubMcpToolConfig {
|
|
|
1682
1695
|
enableInsidersMode?: boolean;
|
|
1683
1696
|
disableFormDeferral?: boolean;
|
|
1684
1697
|
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Permissions-only managed policy injected by the host via
|
|
1700
|
+
* {@link SessionConfigBase.managedSettings}.
|
|
1701
|
+
*
|
|
1702
|
+
* Rule strings use the same vocabulary the runtime accepts for fetched managed
|
|
1703
|
+
* policy (e.g. `"Read(**)"`, `"Shell(git push *)"`); malformed rules are
|
|
1704
|
+
* rejected at session creation.
|
|
1705
|
+
*/
|
|
1706
|
+
export interface ManagedSettingsPermissions {
|
|
1707
|
+
/**
|
|
1708
|
+
* When set to `"disable"`, bypass-permissions ("yolo") mode is turned off
|
|
1709
|
+
* for the session. This is deny-wins: it cannot be re-enabled by any other
|
|
1710
|
+
* layer.
|
|
1711
|
+
*/
|
|
1712
|
+
disableBypassPermissionsMode?: "disable";
|
|
1713
|
+
/** Operations that must always be denied. Unioned across managed layers. */
|
|
1714
|
+
deny?: string[];
|
|
1715
|
+
/**
|
|
1716
|
+
* Operations that must prompt for approval. Unioned across managed layers.
|
|
1717
|
+
*/
|
|
1718
|
+
ask?: string[];
|
|
1719
|
+
/**
|
|
1720
|
+
* Operations permitted without prompting. Every declared `allow` list
|
|
1721
|
+
* (across managed layers) must admit an operation for it to be allowed.
|
|
1722
|
+
*/
|
|
1723
|
+
allow?: string[];
|
|
1724
|
+
}
|
|
1725
|
+
/**
|
|
1726
|
+
* Host-injected enterprise managed settings. The first supported contract is
|
|
1727
|
+
* permissions-only; unknown sibling keys are rejected by the runtime.
|
|
1728
|
+
*
|
|
1729
|
+
* @see {@link SessionConfigBase.managedSettings}
|
|
1730
|
+
*/
|
|
1731
|
+
export interface ManagedSettings {
|
|
1732
|
+
/** Managed permission policy for the session. */
|
|
1733
|
+
permissions?: ManagedSettingsPermissions;
|
|
1734
|
+
}
|
|
1685
1735
|
/**
|
|
1686
1736
|
* Shared configuration fields used by both {@link SessionConfig} (for
|
|
1687
1737
|
* creating a new session) and {@link ResumeSessionConfig} (for resuming
|
|
@@ -1888,6 +1938,13 @@ export interface SessionConfigBase {
|
|
|
1888
1938
|
* @experimental
|
|
1889
1939
|
*/
|
|
1890
1940
|
enableCitations?: boolean;
|
|
1941
|
+
/**
|
|
1942
|
+
* Opt in to capturing file changes for session rewind and cumulative session
|
|
1943
|
+
* diff. On create, capture starts with the first turn. On resume, this can
|
|
1944
|
+
* enable tracking only when the session still has a valid baseline; it cannot
|
|
1945
|
+
* reconstruct changes from earlier untracked turns.
|
|
1946
|
+
*/
|
|
1947
|
+
enableFileChangeTracking?: boolean;
|
|
1891
1948
|
/**
|
|
1892
1949
|
* Limits applied to this session's current accounting window.
|
|
1893
1950
|
*
|
|
@@ -2118,6 +2175,30 @@ export interface SessionConfigBase {
|
|
|
2118
2175
|
* if omitted, the runtime is expected to reject session creation (fail-closed).
|
|
2119
2176
|
*/
|
|
2120
2177
|
enableManagedSettings?: boolean;
|
|
2178
|
+
/**
|
|
2179
|
+
* Host-injected enterprise managed settings for this session.
|
|
2180
|
+
*
|
|
2181
|
+
* Unlike {@link SessionConfigBase.enableManagedSettings} — which asks the
|
|
2182
|
+
* runtime to *self-fetch* account/org and device policy — this field lets
|
|
2183
|
+
* the host supply the managed policy directly. The runtime validates it
|
|
2184
|
+
* with the same managed-permission parser it uses for fetched policy and
|
|
2185
|
+
* composes it restrictively with any self-fetched (server) and
|
|
2186
|
+
* device-managed (MDM) layers: `deny`/`ask` rules are unioned, every
|
|
2187
|
+
* declared `allow` list must admit an operation, and
|
|
2188
|
+
* `disableBypassPermissionsMode: "disable"` is deny-wins.
|
|
2189
|
+
*
|
|
2190
|
+
* This is startup-only. It is **not** persisted: it must be re-supplied on
|
|
2191
|
+
* {@link CopilotClient.resumeSession | resume}, where it replaces the prior
|
|
2192
|
+
* injected layer (omitting it clears the layer, so warm and cold resume
|
|
2193
|
+
* behave identically). It may be combined with `enableManagedSettings`;
|
|
2194
|
+
* when both are supplied the injected, server, and device restrictions all
|
|
2195
|
+
* apply.
|
|
2196
|
+
*
|
|
2197
|
+
* Requires a Copilot runtime whose RPC schema includes `managedSettings`.
|
|
2198
|
+
* Older runtimes may ignore this additive field, so hosts must not rely on
|
|
2199
|
+
* injected policy until they ship a compatible runtime.
|
|
2200
|
+
*/
|
|
2201
|
+
managedSettings?: ManagedSettings;
|
|
2121
2202
|
/**
|
|
2122
2203
|
* When true, skips embedding-based retrieval for this session.
|
|
2123
2204
|
* Use in multitenant deployments to prevent cross-session information leakage
|
package/docs/factories.md
CHANGED
|
@@ -53,7 +53,7 @@ The `run()` context provides:
|
|
|
53
53
|
|
|
54
54
|
- `ctx.runId`: Stable ID reused across resumed attempts.
|
|
55
55
|
- `ctx.args`: Invocation arguments, forwarded verbatim. When the caller omits `args`, this is `{}` rather than `undefined`.
|
|
56
|
-
- `ctx.agent(prompt, options?)`: Runs one factory-owned subagent. Options are exactly `label`, `schema`, and `
|
|
56
|
+
- `ctx.agent(prompt, options?)`: Runs one factory-owned subagent. Options are exactly `label`, `schema`, `model`, `agent`, `reasoningEffort`, and `contextTier`. See [Subagent calls](#subagent-calls).
|
|
57
57
|
- `ctx.parallel(thunks)`: Runs thunks concurrently and awaits all of them (a barrier). A thunk that throws becomes `null` in the result array, so one failed item does not lose the rest. Cancellation and hard runtime failures (`ResponseError`, `ConnectionError`) are the exception — those propagate and reject the whole call, because they mean the run itself is in trouble rather than one item having failed. Handle them at run level; do not assume every failure arrives as a `null`. Rejects above 4096 items.
|
|
58
58
|
- `ctx.pipeline(items, ...stages)`: Flows each item through every stage without a barrier between stages, so one item can be in a later stage while another is still in an earlier one. Each stage is called as `(previous, item, index)`, where `previous` is the prior stage's result and `item` is the original input. A stage that throws drops that item to `null` and skips its remaining stages, with the same exception for cancellation and hard runtime failures. Rejects above 4096 items.
|
|
59
59
|
- `ctx.phase(title)`: Starts a named progress phase. This sets a single run-global value, so calling it from inside concurrent `parallel`/`pipeline` stages races. Call it at run-level transitions and distinguish concurrent work by `label` instead.
|
|
@@ -61,7 +61,7 @@ The `run()` context provides:
|
|
|
61
61
|
- `ctx.step(key, producer, options?)`: Journals the producer's JSON result under a stable key so a resume replays it without re-running the producer. A journaled (default) producer must return a JSON-serializable value; `undefined` or a non-JSON value is rejected. Pass `{ volatile: true }` to bypass the journal and run the producer every time.
|
|
62
62
|
|
|
63
63
|
The key is the *sole* identity: neither the producer body nor its inputs contribute to it. A resume replays the cached value for a matching key even if the producer has since changed, so version the key (`"scan-v2"`) whenever its inputs or meaning change. Journaled producers are best-effort at-least-once and may run again across crashes or concurrent same-key callers, so keep side effects idempotent.
|
|
64
|
-
- `ctx.session`: The
|
|
64
|
+
- `ctx.session`: The session returned by `joinSession`. It refuses calls that start or resume a factory run. Call `extensions_manage` with `operation: "guide"` to read more about the session APIs.
|
|
65
65
|
- `ctx.signal`: Cooperative cancellation signal for extension work and subprocesses.
|
|
66
66
|
- `ctx.factory(...)`: Always rejects because nested factories are not supported.
|
|
67
67
|
|
|
@@ -156,7 +156,7 @@ session.factory.resume(
|
|
|
156
156
|
): Promise<FactoryRunResult>;
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
-
Both resolve with the run envelope (`FactoryRunResult`) for **every** outcome — `completed`, `error`, `halted`, and `cancelled` alike. Inspect `status` and read `result` only when the run completed; a limit breach carries a typed `failure`.
|
|
159
|
+
Both resolve with the run envelope (`FactoryRunResult`) for **every** outcome — `completed`, `error`, `halted`, and `cancelled` alike. Inspect `status` and read `result` only when the run completed; a limit breach carries a typed `failure`. SDK-initiated `run` and `resume` do not request permission, so they have no declined outcome. The model's `run_factory` tool requests permission before the durable row exists; declining it creates no run row. An SDK-initiated run is refused only when the session already has its maximum number of active top-level runs. Pre-execution resume failures throw `FactoryResumeError`, whose `code` is one of `not_found`, `non_resumable`, `already_active`, `factory_already_running`, `factory_limits_invalid`, `factory_session_disposed`, `factory_storage_unavailable`, or `factory_storage_corrupt`.
|
|
160
160
|
|
|
161
161
|
An agent that no longer has a prior run's ID in context can recover it with `factories_manage` and `operation: "runs"`, which lists the session's factory runs with their IDs and statuses. This matters for resume: a run that reached a limit keeps its journal, so resuming it replays completed work for free, while restarting it from scratch pays for that work twice.
|
|
162
162
|
|
|
@@ -210,7 +210,7 @@ const page = await session.factory.getRunProgress(runId, {
|
|
|
210
210
|
});
|
|
211
211
|
```
|
|
212
212
|
|
|
213
|
-
- `listRuns()` returns
|
|
213
|
+
- `listRuns()` returns the newest default page of this session's durable factory runs.
|
|
214
214
|
- `getRunDetail(runId)` returns phases, prompt-safe agent summaries, and the latest progress page.
|
|
215
215
|
- `getRunProgress(runId, options?)` pages progress forward, backward, by phase, or from the latest tail.
|
|
216
216
|
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"type": "git",
|
|
5
5
|
"url": "https://github.com/github/copilot-sdk.git"
|
|
6
6
|
},
|
|
7
|
-
"version": "1.0.
|
|
7
|
+
"version": "1.0.11-preview.1",
|
|
8
8
|
"description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC",
|
|
9
9
|
"main": "./dist/cjs/index.js",
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"author": "GitHub",
|
|
57
57
|
"license": "MIT",
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@github/copilot": "^1.0.
|
|
59
|
+
"@github/copilot": "^1.0.79",
|
|
60
60
|
"koffi": "^3.1.0",
|
|
61
61
|
"vscode-jsonrpc": "^8.2.1",
|
|
62
62
|
"zod": "^4.3.6"
|