@github/copilot-sdk 1.0.14 → 1.0.15-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/README.md +116 -11
- package/dist/cjs/cliVersion.js +1 -1
- package/dist/cjs/client.js +24 -17
- package/dist/cjs/copilotRequestHandler.js +156 -20
- package/dist/cjs/extension.js +12 -1
- package/dist/cjs/generated/rpc.js +349 -8
- package/dist/cjs/index.js +9 -2
- package/dist/cjs/schema.js +40 -0
- package/dist/cjs/session.js +625 -3
- package/dist/cjs/workflow.js +134 -0
- package/dist/cliVersion.d.ts +1 -1
- package/dist/cliVersion.js +1 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.js +22 -15
- package/dist/copilotRequestHandler.js +156 -20
- package/dist/extension.d.ts +22 -8
- package/dist/extension.js +13 -1
- package/dist/generated/rpc.d.ts +2824 -315
- package/dist/generated/rpc.js +349 -8
- package/dist/generated/session-events.d.ts +565 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.js +5 -1
- package/dist/schema.d.ts +4 -0
- package/dist/schema.js +14 -0
- package/dist/session.d.ts +26 -3
- package/dist/session.js +630 -3
- package/dist/types.d.ts +37 -5
- package/dist/workflow.d.ts +364 -0
- package/dist/workflow.js +106 -0
- package/docs/extensions.md +1 -0
- package/docs/workflows.md +257 -0
- package/package.json +17 -14
package/README.md
CHANGED
|
@@ -14,10 +14,14 @@ verified `github/copilot-cli` release assets when the SDK is published, so
|
|
|
14
14
|
starting the SDK performs no runtime download. Set `COPILOT_CLI_PATH` to use an
|
|
15
15
|
existing installation instead.
|
|
16
16
|
|
|
17
|
-
The checked-in
|
|
18
|
-
`
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
The checked-in `copilotCliVersion` in `package.json` and compiled metadata in
|
|
18
|
+
`src/cliVersion.ts` use a development placeholder. The public SDK snapshot
|
|
19
|
+
replaces both with the CLI version published for that snapshot.
|
|
20
|
+
|
|
21
|
+
Do not change these pins for runtime-repository development. If they contain
|
|
22
|
+
`0.0.0-dev`, use the same-checkout runtime; release snapshot export owns replacing
|
|
23
|
+
development placeholders with a published CLI version. See
|
|
24
|
+
[checkout preparation](../CONTRIBUTING.md#testing-an-unreleased-runtime-api).
|
|
21
25
|
|
|
22
26
|
`npm run pack:release` builds the main package and all platform packages. Set
|
|
23
27
|
`COPILOT_CLI_DOWNLOAD_BASE_URL` to use a release mirror while packaging.
|
|
@@ -26,6 +30,12 @@ containing validated runtime npm package roots named for all eight platforms.
|
|
|
26
30
|
This keeps `COPILOT_CLI_USE_NPM_PACKAGE` false and embeds those runtime files in
|
|
27
31
|
the self-contained SDK platform packages.
|
|
28
32
|
|
|
33
|
+
In the runtime repository, packaging uses the prepared same-checkout runtime.
|
|
34
|
+
Set `COPILOT_SDK_RUNTIME_PLATFORMS` to the available target (for example,
|
|
35
|
+
`linux-x64`) for both `pack:release` and `verify:release-packages`. SDK CI checks
|
|
36
|
+
that target only; public release workflows leave this unset to package and
|
|
37
|
+
verify all eight platforms.
|
|
38
|
+
|
|
29
39
|
## Installation
|
|
30
40
|
|
|
31
41
|
```bash
|
|
@@ -34,7 +44,11 @@ npm install @github/copilot-sdk
|
|
|
34
44
|
|
|
35
45
|
## Run the Sample
|
|
36
46
|
|
|
37
|
-
Try the interactive chat sample
|
|
47
|
+
Try the interactive chat sample from the SDK root (`src/sdk` when nested).
|
|
48
|
+
In the runtime repository, first run `pnpm run build:cli` from the runtime root
|
|
49
|
+
to prepare the same-checkout executable, then return to `src/sdk`.
|
|
50
|
+
Building the Node SDK alone does not build the runtime. For dependency
|
|
51
|
+
prerequisites, see [development setup](#development).
|
|
38
52
|
|
|
39
53
|
```bash
|
|
40
54
|
cd nodejs
|
|
@@ -118,6 +132,7 @@ new CopilotClient(options?: CopilotClientOptions)
|
|
|
118
132
|
- `mode?: "empty" | "copilot-cli"` - Defaulting strategy. Use `"empty"` for multi-user server mode; defaults to `"copilot-cli"`.
|
|
119
133
|
- `workingDirectory?: string` - Working directory for the runtime process (default: current process cwd).
|
|
120
134
|
- `baseDirectory?: string` - Base directory for Copilot data (session state, config, etc.). Sets `COPILOT_HOME` on the spawned runtime. When not set, the runtime defaults to `~/.copilot`. Ignored when connecting via `RuntimeConnection.forUri`.
|
|
135
|
+
- `extensionLaunchProvider?: ExtensionLaunchProvider` - Experimental connection-level resolver for extension launch profiles. The client installs the reverse-RPC handler and registers the provider during startup before sessions can be created.
|
|
121
136
|
- `logLevel?: "none" | "error" | "warning" | "info" | "debug" | "all"` - Log level. When omitted, the runtime uses its own default (currently `"info"`).
|
|
122
137
|
- `env?: Record<string, string | undefined>` - Environment variables for the runtime process. When omitted, inherits `process.env`.
|
|
123
138
|
- `gitHubToken?: string` - GitHub token for authentication. When provided, takes priority over other auth methods.
|
|
@@ -305,6 +320,87 @@ Send a message and wait until the session becomes idle.
|
|
|
305
320
|
|
|
306
321
|
Returns the final assistant message event, or undefined if none was received.
|
|
307
322
|
|
|
323
|
+
##### Structured output (preview)
|
|
324
|
+
|
|
325
|
+
Requires a runtime build with `responseFormat` and `originatingMessageId` support.
|
|
326
|
+
Pass a raw JSON Schema or a Zod schema as `responseSchema` to `send` or
|
|
327
|
+
`sendAndWait`. As with custom tool parameters, the SDK converts Zod schemas to
|
|
328
|
+
JSON Schema before sending them:
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
import { z } from "zod";
|
|
332
|
+
|
|
333
|
+
const answerSchema = z.object({ answer: z.number().int() });
|
|
334
|
+
const message = await session.sendAndWait({
|
|
335
|
+
prompt: "What is 19 + 23?",
|
|
336
|
+
responseSchema: answerSchema,
|
|
337
|
+
});
|
|
338
|
+
console.log(message?.data.content); // JSON text
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
For a typed result, pass the Zod schema as the **second argument** instead:
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
const answer = await session.sendAndWait("What is 19 + 23?", answerSchema);
|
|
345
|
+
console.log(answer.answer); // number; TResult is inferred from answerSchema
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
`sendAndWait<TResult>(options, schema, timeout?)` generates the JSON Schema from
|
|
349
|
+
the schema value, parses the final JSON, and validates it with the schema's
|
|
350
|
+
`parse` method. TypeScript cannot derive a runtime schema from an erased type
|
|
351
|
+
parameter alone. Invalid JSON, a schema mismatch, or a completed run without a
|
|
352
|
+
matching assistant message throws. Do not also set `options.responseSchema` when
|
|
353
|
+
using the typed overload.
|
|
354
|
+
|
|
355
|
+
The schema belongs to the submitted run, including its tool-call iterations.
|
|
356
|
+
Internally generated stop-hook corrections retain the schema and originating
|
|
357
|
+
message ID, so the wait returns the corrected answer. Independent subsequent
|
|
358
|
+
sends do not inherit it. Ordinary immediate steering inherits the active schema
|
|
359
|
+
and originating message ID, even when it arrives too late for the current model
|
|
360
|
+
request and is promoted into a follow-up run. Specifying a schema with
|
|
361
|
+
`mode: "immediate"` is rejected, even while idle.
|
|
362
|
+
The generated `session.rpc.send` and `session.rpc.sendMessages` wrappers expose
|
|
363
|
+
the full `responseFormat` contract when you need to set its name, description,
|
|
364
|
+
or strict option rather than using the convenience defaults (`name: "response"`,
|
|
365
|
+
`strict: true`).
|
|
366
|
+
Each batch starts one run: the final returned message ID is its origin, preceding
|
|
367
|
+
messages are context, and an empty batch has no origin. An immediate batch
|
|
368
|
+
steers the active run instead and retains its origin.
|
|
369
|
+
The schema is not a persisted session default: autonomous resume-pending work
|
|
370
|
+
after a restart does not restore it. A terminal tool that clears context ends
|
|
371
|
+
the old run; its fresh seed does not inherit the schema or origin. Such a run
|
|
372
|
+
can finish without a structured result, in which case the typed wait throws.
|
|
373
|
+
After a successful terminal tool, the runtime disables tools while the model
|
|
374
|
+
produces the structured result. Stop-hook corrections remain supported.
|
|
375
|
+
Remote sessions and known HydraFusion routes reject response formats before
|
|
376
|
+
admission. Schemas larger than 32 MiB when JSON-encoded are also rejected before
|
|
377
|
+
admission, using the runtime's existing request-size ceiling. This does not
|
|
378
|
+
guarantee the schema plus conversation and tools fits the provider's budget.
|
|
379
|
+
|
|
380
|
+
Structured waits select the last root-agent message whose `originatingMessageId`
|
|
381
|
+
matches the ID returned by their send, then return at a non-autopilot
|
|
382
|
+
`session.idle`. Other queued work can delay that idle, but cannot replace the
|
|
383
|
+
selected result. The existing unformatted overload retains its session-wide
|
|
384
|
+
behavior. `turnId` identifies an individual model/tool iteration, not the whole
|
|
385
|
+
run; telemetry interaction IDs are not unique run identifiers.
|
|
386
|
+
|
|
387
|
+
For event-driven consumption with `send`, subscribe before sending and collect
|
|
388
|
+
root `assistant.message` events whose `data.originatingMessageId` matches the ID
|
|
389
|
+
returned by `send`; events may arrive before that acknowledgement. Wait for
|
|
390
|
+
`session.idle`, then parse the last matching message without tool requests.
|
|
391
|
+
An earlier response may be superseded by a stop-hook correction. Handle
|
|
392
|
+
`session.error` and aborted idle events rather than returning a partial result.
|
|
393
|
+
|
|
394
|
+
Streaming still delivers ordinary text events, including intermediate messages
|
|
395
|
+
and tool calls. Only the final selected message is parsed by the typed overload;
|
|
396
|
+
not every event is necessarily a complete schema-conforming JSON document.
|
|
397
|
+
Provider errors, refusals, cancellation, truncation, session errors, and timeouts
|
|
398
|
+
can prevent a typed result. A timeout stops waiting, not the runtime's work.
|
|
399
|
+
Use a model and endpoint that support native structured output. An API-compatible
|
|
400
|
+
gateway may ignore format fields even when it accepts the request; for example,
|
|
401
|
+
the Claude Chat-completions compatibility route is not equivalent to Anthropic's
|
|
402
|
+
native `output_config.format` endpoint.
|
|
403
|
+
|
|
308
404
|
##### `on(eventType: string, handler: TypedSessionEventHandler): () => void`
|
|
309
405
|
|
|
310
406
|
Subscribe to a specific event type. The handler receives properly typed events.
|
|
@@ -1192,19 +1288,28 @@ try {
|
|
|
1192
1288
|
|
|
1193
1289
|
## Development
|
|
1194
1290
|
|
|
1195
|
-
|
|
1291
|
+
Follow [SDK development setup](../CONTRIBUTING.md#developing-an-sdk) first,
|
|
1292
|
+
including the harness and corrections-script dependencies. From the SDK root
|
|
1293
|
+
(`src/sdk` in the runtime repository, or the standalone repository root):
|
|
1196
1294
|
|
|
1197
1295
|
```bash
|
|
1198
|
-
|
|
1199
|
-
npm
|
|
1296
|
+
npm run build:nodejs
|
|
1297
|
+
npm run test:nodejs
|
|
1298
|
+
npm run check:nodejs
|
|
1200
1299
|
```
|
|
1201
1300
|
|
|
1301
|
+
In the runtime layout, these build/test commands refresh the projection and
|
|
1302
|
+
prepare the checked-out runtime for tests. For focused unit tests after
|
|
1303
|
+
installing Node dependencies:
|
|
1304
|
+
|
|
1202
1305
|
```bash
|
|
1203
|
-
|
|
1204
|
-
npm ci
|
|
1205
|
-
npm test
|
|
1306
|
+
npm --prefix nodejs run test:unit
|
|
1206
1307
|
```
|
|
1207
1308
|
|
|
1309
|
+
For native Vitest selectors on E2Es, use the
|
|
1310
|
+
[prepared-runtime instructions](../CONTRIBUTING.md#testing-an-unreleased-runtime-api);
|
|
1311
|
+
the SDK facade does not forward selectors.
|
|
1312
|
+
|
|
1208
1313
|
## License
|
|
1209
1314
|
|
|
1210
1315
|
MIT
|
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.
|
|
25
|
+
const COPILOT_CLI_VERSION = "1.0.89-0";
|
|
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
|
@@ -45,13 +45,11 @@ var import_cliVersion = require("./cliVersion.js");
|
|
|
45
45
|
var import_sessionFsProvider = require("./sessionFsProvider.js");
|
|
46
46
|
var import_copilotRequestHandler = require("./copilotRequestHandler.js");
|
|
47
47
|
var import_telemetry = require("./telemetry.js");
|
|
48
|
+
var import_schema = require("./schema.js");
|
|
48
49
|
var import_toolSet = require("./toolSet.js");
|
|
49
50
|
var import_types = require("./types.js");
|
|
50
51
|
const MIN_PROTOCOL_VERSION = 3;
|
|
51
52
|
const RUNTIME_SHUTDOWN_TIMEOUT_MS = 1e4;
|
|
52
|
-
function isZodSchema(value) {
|
|
53
|
-
return value != null && typeof value === "object" && "toJSONSchema" in value && typeof value.toJSONSchema === "function";
|
|
54
|
-
}
|
|
55
53
|
async function withTimeout(promise, timeoutMs, message) {
|
|
56
54
|
let timeout;
|
|
57
55
|
try {
|
|
@@ -96,13 +94,6 @@ async function waitForChildExit(child, timeoutMs) {
|
|
|
96
94
|
}
|
|
97
95
|
});
|
|
98
96
|
}
|
|
99
|
-
function toJsonSchema(parameters) {
|
|
100
|
-
if (!parameters) return void 0;
|
|
101
|
-
if (isZodSchema(parameters)) {
|
|
102
|
-
return parameters.toJSONSchema();
|
|
103
|
-
}
|
|
104
|
-
return parameters;
|
|
105
|
-
}
|
|
106
97
|
const DEFAULT_PROVIDER_NAME = "default";
|
|
107
98
|
function extractBearerTokenProviders(provider, providers) {
|
|
108
99
|
const callbacks = /* @__PURE__ */ new Map();
|
|
@@ -235,6 +226,7 @@ class CopilotClient {
|
|
|
235
226
|
cliProcess = null;
|
|
236
227
|
ffiHost = null;
|
|
237
228
|
connection = null;
|
|
229
|
+
requestAdapter = null;
|
|
238
230
|
messageWriter = null;
|
|
239
231
|
connectionClosed = false;
|
|
240
232
|
socket = null;
|
|
@@ -272,6 +264,7 @@ class CopilotClient {
|
|
|
272
264
|
/** Connection-level session filesystem config, set via constructor option. */
|
|
273
265
|
sessionFsConfig = null;
|
|
274
266
|
requestHandler = null;
|
|
267
|
+
extensionLaunchProvider;
|
|
275
268
|
builtinPluginDirectories = [];
|
|
276
269
|
onGitHubTelemetry;
|
|
277
270
|
clientGlobalHandlers = {};
|
|
@@ -429,6 +422,7 @@ class CopilotClient {
|
|
|
429
422
|
this.onGetTraceContext = options.onGetTraceContext;
|
|
430
423
|
this.sessionFsConfig = options.sessionFs ?? null;
|
|
431
424
|
this.requestHandler = options.requestHandler ?? null;
|
|
425
|
+
this.extensionLaunchProvider = options.extensionLaunchProvider;
|
|
432
426
|
this.onGitHubTelemetry = options.onGitHubTelemetry;
|
|
433
427
|
this.setupClientGlobalHandlers();
|
|
434
428
|
const connEnv = conn.kind === "stdio" || conn.kind === "tcp" ? conn.env : void 0;
|
|
@@ -531,14 +525,16 @@ class CopilotClient {
|
|
|
531
525
|
}
|
|
532
526
|
setupClientGlobalHandlers() {
|
|
533
527
|
const handlers = {};
|
|
528
|
+
handlers.extensionLaunchProvider = this.extensionLaunchProvider;
|
|
534
529
|
if (this.requestHandler) {
|
|
535
|
-
|
|
530
|
+
this.requestAdapter = (0, import_copilotRequestHandler.createCopilotRequestAdapter)(this.requestHandler, () => {
|
|
536
531
|
if (!this.connection) {
|
|
537
532
|
return void 0;
|
|
538
533
|
}
|
|
539
534
|
this._rpc ??= (0, import_rpc.createServerRpc)(this.connection);
|
|
540
535
|
return this._rpc;
|
|
541
536
|
});
|
|
537
|
+
handlers.llmInference = this.requestAdapter;
|
|
542
538
|
}
|
|
543
539
|
if (this.onGitHubTelemetry) {
|
|
544
540
|
const onGitHubTelemetry = this.onGitHubTelemetry;
|
|
@@ -643,6 +639,9 @@ class CopilotClient {
|
|
|
643
639
|
}
|
|
644
640
|
await this.connectToServer();
|
|
645
641
|
await this.verifyProtocolVersion();
|
|
642
|
+
if (this.extensionLaunchProvider) {
|
|
643
|
+
await this.rpc.registerExtensionLaunchProvider();
|
|
644
|
+
}
|
|
646
645
|
if (this.builtinPluginDirectories.length > 0) {
|
|
647
646
|
try {
|
|
648
647
|
await this.connection.sendRequest("plugins.builtin.set", {
|
|
@@ -731,6 +730,7 @@ class CopilotClient {
|
|
|
731
730
|
}
|
|
732
731
|
this.sessions.clear();
|
|
733
732
|
this.githubTokenProviders.clear();
|
|
733
|
+
this.requestAdapter?.cancelPending();
|
|
734
734
|
if (this.connection && !this.connectionClosed && (this.cliProcess || this.ffiHost) && !this.isExternalServer) {
|
|
735
735
|
const runtimeShutdownStart = Date.now();
|
|
736
736
|
const shutdownPromise = this.rpc.runtime.shutdown();
|
|
@@ -886,6 +886,7 @@ class CopilotClient {
|
|
|
886
886
|
}
|
|
887
887
|
this.sessions.clear();
|
|
888
888
|
this.githubTokenProviders.clear();
|
|
889
|
+
this.requestAdapter?.cancelPending();
|
|
889
890
|
if (this.messageWriter) {
|
|
890
891
|
this.messageWriter.suppressWriteErrors = true;
|
|
891
892
|
}
|
|
@@ -1188,7 +1189,7 @@ class CopilotClient {
|
|
|
1188
1189
|
tools: config.tools?.map((tool) => ({
|
|
1189
1190
|
name: tool.name,
|
|
1190
1191
|
description: tool.description,
|
|
1191
|
-
parameters: toJsonSchema(tool.parameters),
|
|
1192
|
+
parameters: (0, import_schema.toJsonSchema)(tool.parameters),
|
|
1192
1193
|
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
1193
1194
|
skipPermission: tool.skipPermission,
|
|
1194
1195
|
defer: tool.defer,
|
|
@@ -1336,11 +1337,14 @@ class CopilotClient {
|
|
|
1336
1337
|
async resumeSession(sessionId, config) {
|
|
1337
1338
|
return this.resumeSessionInternal(sessionId, config);
|
|
1338
1339
|
}
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
return this.resumeSessionInternal(sessionId, config, factories, extensionOptions);
|
|
1340
|
+
async resumeSessionForExtension(sessionId, config, contributions = {}, extensionOptions) {
|
|
1341
|
+
return this.resumeSessionInternal(sessionId, config, contributions, extensionOptions);
|
|
1342
1342
|
}
|
|
1343
|
-
async resumeSessionInternal(sessionId, config,
|
|
1343
|
+
async resumeSessionInternal(sessionId, config, contributions = {}, extensionOptions) {
|
|
1344
|
+
const { factories, workflows } = Array.isArray(contributions) ? { factories: contributions, workflows: void 0 } : contributions;
|
|
1345
|
+
if (factories !== void 0 && workflows !== void 0) {
|
|
1346
|
+
throw new Error("Session configuration cannot include both factories and workflows");
|
|
1347
|
+
}
|
|
1344
1348
|
if (config.gitHubToken !== void 0 && config.gitHubTokenProvider !== void 0) {
|
|
1345
1349
|
throw new Error("gitHubToken and gitHubTokenProvider are mutually exclusive");
|
|
1346
1350
|
}
|
|
@@ -1361,6 +1365,7 @@ class CopilotClient {
|
|
|
1361
1365
|
session.registerCanvases(config.canvases);
|
|
1362
1366
|
session.registerCommands(config.commands);
|
|
1363
1367
|
session.registerFactories(factories);
|
|
1368
|
+
session.registerWorkflows(workflows);
|
|
1364
1369
|
const {
|
|
1365
1370
|
wireProvider: bearerWireProvider,
|
|
1366
1371
|
wireProviders: bearerWireProviders,
|
|
@@ -1432,7 +1437,7 @@ class CopilotClient {
|
|
|
1432
1437
|
tools: config.tools?.map((tool) => ({
|
|
1433
1438
|
name: tool.name,
|
|
1434
1439
|
description: tool.description,
|
|
1435
|
-
parameters: toJsonSchema(tool.parameters),
|
|
1440
|
+
parameters: (0, import_schema.toJsonSchema)(tool.parameters),
|
|
1436
1441
|
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
1437
1442
|
skipPermission: tool.skipPermission,
|
|
1438
1443
|
defer: tool.defer,
|
|
@@ -1442,6 +1447,7 @@ class CopilotClient {
|
|
|
1442
1447
|
toolSearch: config.toolSearch,
|
|
1443
1448
|
canvases: config.canvases?.map((canvas) => canvas.declaration),
|
|
1444
1449
|
factories: factories?.map((factory) => factory.meta),
|
|
1450
|
+
workflows: workflows?.map((workflow) => workflow.meta),
|
|
1445
1451
|
requestCanvasRenderer: config.requestCanvasRenderer,
|
|
1446
1452
|
requestExtensions: config.requestExtensions,
|
|
1447
1453
|
extensionSdkPath: config.extensionSdkPath,
|
|
@@ -2294,6 +2300,7 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
2294
2300
|
}
|
|
2295
2301
|
this.sessions.clear();
|
|
2296
2302
|
this.githubTokenProviders.clear();
|
|
2303
|
+
this.requestAdapter?.cancelPending();
|
|
2297
2304
|
};
|
|
2298
2305
|
this.connection.onClose(markDisconnected);
|
|
2299
2306
|
this.connection.onError(() => {
|
|
@@ -27,6 +27,7 @@ __export(copilotRequestHandler_exports, {
|
|
|
27
27
|
module.exports = __toCommonJS(copilotRequestHandler_exports);
|
|
28
28
|
const sharedTextDecoder = new TextDecoder("utf-8", { fatal: false });
|
|
29
29
|
const sharedTextEncoder = new TextEncoder();
|
|
30
|
+
const HTTP_RESPONSE_READ_AHEAD_BYTES = 32 * 1024;
|
|
30
31
|
const kBridge = /* @__PURE__ */ Symbol("copilotWebSocketResponseBridge");
|
|
31
32
|
const kCompletion = /* @__PURE__ */ Symbol("copilotWebSocketCompletion");
|
|
32
33
|
const kOpen = /* @__PURE__ */ Symbol("copilotWebSocketOpen");
|
|
@@ -265,7 +266,9 @@ function createCopilotRequestAdapter(handler, getServerRpc) {
|
|
|
265
266
|
const message = err instanceof Error ? err.message : String(err);
|
|
266
267
|
await finalize(exchange, 502, message);
|
|
267
268
|
} finally {
|
|
268
|
-
pending.
|
|
269
|
+
if (pending.get(exchange.requestId) === exchange) {
|
|
270
|
+
pending.delete(exchange.requestId);
|
|
271
|
+
}
|
|
269
272
|
}
|
|
270
273
|
}
|
|
271
274
|
return {
|
|
@@ -278,6 +281,13 @@ function createCopilotRequestAdapter(handler, getServerRpc) {
|
|
|
278
281
|
async httpRequestChunk(params) {
|
|
279
282
|
routeChunk(getOrCreate(params.requestId), params);
|
|
280
283
|
return {};
|
|
284
|
+
},
|
|
285
|
+
cancelPending() {
|
|
286
|
+
const exchanges = [...pending.values()];
|
|
287
|
+
pending.clear();
|
|
288
|
+
for (const exchange of exchanges) {
|
|
289
|
+
exchange.pushCancel("RPC connection closed");
|
|
290
|
+
}
|
|
281
291
|
}
|
|
282
292
|
};
|
|
283
293
|
}
|
|
@@ -526,30 +536,156 @@ async function drainAsync(stream) {
|
|
|
526
536
|
return out;
|
|
527
537
|
}
|
|
528
538
|
async function streamResponse(response, exchange) {
|
|
529
|
-
|
|
530
|
-
status: response.status,
|
|
531
|
-
statusText: response.statusText || void 0,
|
|
532
|
-
headers: headersToMultiMap(response.headers)
|
|
533
|
-
});
|
|
534
|
-
const body = response.body;
|
|
535
|
-
if (!body) {
|
|
536
|
-
await exchange.endResponse();
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
const reader = body.getReader();
|
|
539
|
+
const reader = response.body ? new HttpResponseReader(response.body, exchange.signal) : void 0;
|
|
540
540
|
try {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
541
|
+
await exchange.startResponse({
|
|
542
|
+
status: response.status,
|
|
543
|
+
statusText: response.statusText || void 0,
|
|
544
|
+
headers: headersToMultiMap(response.headers)
|
|
545
|
+
});
|
|
546
|
+
if (reader) {
|
|
547
|
+
for (; ; ) {
|
|
548
|
+
const chunk = await reader.nextChunk();
|
|
549
|
+
if (!chunk) {
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
await exchange.writeResponse(chunk);
|
|
548
553
|
}
|
|
549
554
|
}
|
|
550
555
|
await exchange.endResponse();
|
|
551
556
|
} finally {
|
|
552
|
-
reader
|
|
557
|
+
await reader?.dispose();
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
class HttpResponseReader {
|
|
561
|
+
#reader;
|
|
562
|
+
#signal;
|
|
563
|
+
#frames = [];
|
|
564
|
+
#pump;
|
|
565
|
+
#onAbort;
|
|
566
|
+
#queued = 0;
|
|
567
|
+
#done = false;
|
|
568
|
+
#cancelled = false;
|
|
569
|
+
#hasError = false;
|
|
570
|
+
#error;
|
|
571
|
+
#dataWaker;
|
|
572
|
+
#spaceWaker;
|
|
573
|
+
#cancelPromise;
|
|
574
|
+
constructor(body, signal) {
|
|
575
|
+
this.#reader = body.getReader();
|
|
576
|
+
this.#signal = signal;
|
|
577
|
+
this.#onAbort = () => {
|
|
578
|
+
void this.cancel(signal.reason);
|
|
579
|
+
};
|
|
580
|
+
signal.addEventListener("abort", this.#onAbort, { once: true });
|
|
581
|
+
this.#pump = this.#pumpSource();
|
|
582
|
+
if (signal.aborted) {
|
|
583
|
+
this.#onAbort();
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
async nextChunk() {
|
|
587
|
+
while (this.#frames.length === 0 && !this.#done && !this.#hasError) {
|
|
588
|
+
await new Promise((resolve) => {
|
|
589
|
+
this.#dataWaker = resolve;
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
if (this.#frames.length > 0) {
|
|
593
|
+
const chunk = this.#takeQueued();
|
|
594
|
+
this.#wakeSpace();
|
|
595
|
+
return chunk;
|
|
596
|
+
}
|
|
597
|
+
if (this.#hasError) {
|
|
598
|
+
this.#hasError = false;
|
|
599
|
+
throw this.#error;
|
|
600
|
+
}
|
|
601
|
+
return void 0;
|
|
602
|
+
}
|
|
603
|
+
#takeQueued() {
|
|
604
|
+
const frames = this.#frames;
|
|
605
|
+
const total = this.#queued;
|
|
606
|
+
this.#queued = 0;
|
|
607
|
+
if (frames.length === 1) {
|
|
608
|
+
return frames.pop();
|
|
609
|
+
}
|
|
610
|
+
const chunk = new Uint8Array(total);
|
|
611
|
+
let offset = 0;
|
|
612
|
+
for (const frame of frames) {
|
|
613
|
+
chunk.set(frame, offset);
|
|
614
|
+
offset += frame.byteLength;
|
|
615
|
+
}
|
|
616
|
+
frames.length = 0;
|
|
617
|
+
return chunk;
|
|
618
|
+
}
|
|
619
|
+
async dispose() {
|
|
620
|
+
this.#signal.removeEventListener("abort", this.#onAbort);
|
|
621
|
+
if (!this.#done) {
|
|
622
|
+
await this.cancel();
|
|
623
|
+
} else if (this.#cancelPromise) {
|
|
624
|
+
await this.#cancelPromise;
|
|
625
|
+
}
|
|
626
|
+
await this.#pump;
|
|
627
|
+
}
|
|
628
|
+
cancel(reason) {
|
|
629
|
+
if (this.#done) {
|
|
630
|
+
return Promise.resolve();
|
|
631
|
+
}
|
|
632
|
+
if (!this.#cancelPromise) {
|
|
633
|
+
this.#cancelled = true;
|
|
634
|
+
this.#done = true;
|
|
635
|
+
this.#hasError = true;
|
|
636
|
+
this.#error = reason instanceof Error ? reason : new Error("HTTP response body cancelled.");
|
|
637
|
+
this.#frames.length = 0;
|
|
638
|
+
this.#queued = 0;
|
|
639
|
+
this.#wakeData();
|
|
640
|
+
this.#wakeSpace();
|
|
641
|
+
this.#cancelPromise = this.#reader.cancel(reason).catch(() => void 0);
|
|
642
|
+
}
|
|
643
|
+
return this.#cancelPromise;
|
|
644
|
+
}
|
|
645
|
+
async #pumpSource() {
|
|
646
|
+
try {
|
|
647
|
+
while (!this.#cancelled) {
|
|
648
|
+
while (this.#queued >= HTTP_RESPONSE_READ_AHEAD_BYTES && !this.#cancelled) {
|
|
649
|
+
await new Promise((resolve) => {
|
|
650
|
+
this.#spaceWaker = resolve;
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
if (this.#cancelled) {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
const { value, done } = await this.#reader.read();
|
|
657
|
+
if (done) {
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
if (value.byteLength > 0) {
|
|
661
|
+
this.#frames.push(value);
|
|
662
|
+
this.#queued += value.byteLength;
|
|
663
|
+
this.#wakeData();
|
|
664
|
+
continue;
|
|
665
|
+
}
|
|
666
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
667
|
+
}
|
|
668
|
+
} catch (error) {
|
|
669
|
+
if (!this.#cancelled) {
|
|
670
|
+
this.#hasError = true;
|
|
671
|
+
this.#error = error;
|
|
672
|
+
}
|
|
673
|
+
} finally {
|
|
674
|
+
this.#done = true;
|
|
675
|
+
this.#wakeData();
|
|
676
|
+
this.#wakeSpace();
|
|
677
|
+
this.#reader.releaseLock();
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
#wakeData() {
|
|
681
|
+
const waker = this.#dataWaker;
|
|
682
|
+
this.#dataWaker = void 0;
|
|
683
|
+
waker?.();
|
|
684
|
+
}
|
|
685
|
+
#wakeSpace() {
|
|
686
|
+
const waker = this.#spaceWaker;
|
|
687
|
+
this.#spaceWaker = void 0;
|
|
688
|
+
waker?.();
|
|
553
689
|
}
|
|
554
690
|
}
|
|
555
691
|
function headersToMultiMap(headers) {
|
package/dist/cjs/extension.js
CHANGED
|
@@ -21,9 +21,12 @@ __export(extension_exports, {
|
|
|
21
21
|
Canvas: () => import_canvas.Canvas,
|
|
22
22
|
CanvasError: () => import_canvas.CanvasError,
|
|
23
23
|
FactoryResumeError: () => import_factory.FactoryResumeError,
|
|
24
|
+
WorkflowResumeError: () => import_workflow.WorkflowResumeError,
|
|
24
25
|
createCanvas: () => import_canvas.createCanvas,
|
|
25
26
|
defineFactory: () => import_factory.defineFactory,
|
|
27
|
+
defineWorkflow: () => import_workflow.defineWorkflow,
|
|
26
28
|
isFactoryRunTerminal: () => import_factory.isFactoryRunTerminal,
|
|
29
|
+
isWorkflowRunTerminal: () => import_workflow.isWorkflowRunTerminal,
|
|
27
30
|
joinSession: () => joinSession
|
|
28
31
|
});
|
|
29
32
|
module.exports = __toCommonJS(extension_exports);
|
|
@@ -31,6 +34,7 @@ var import_client = require("./client.js");
|
|
|
31
34
|
var import_types = require("./types.js");
|
|
32
35
|
var import_canvas = require("./canvas.js");
|
|
33
36
|
var import_factory = require("./factory.js");
|
|
37
|
+
var import_workflow = require("./workflow.js");
|
|
34
38
|
async function joinSession(config = {}) {
|
|
35
39
|
const sessionId = process.env.SESSION_ID;
|
|
36
40
|
if (!sessionId) {
|
|
@@ -42,10 +46,14 @@ async function joinSession(config = {}) {
|
|
|
42
46
|
const {
|
|
43
47
|
extensionSdkPath: _stripped,
|
|
44
48
|
factories,
|
|
49
|
+
workflows,
|
|
45
50
|
requestedEnvironmentVariables,
|
|
46
51
|
...rest
|
|
47
52
|
} = config;
|
|
48
53
|
void _stripped;
|
|
54
|
+
if (factories !== void 0 && workflows !== void 0) {
|
|
55
|
+
throw new Error("joinSession cannot register both factories and workflows");
|
|
56
|
+
}
|
|
49
57
|
return client.resumeSessionForExtension(
|
|
50
58
|
sessionId,
|
|
51
59
|
{
|
|
@@ -53,7 +61,7 @@ async function joinSession(config = {}) {
|
|
|
53
61
|
onPermissionRequest: config.onPermissionRequest ?? import_types.defaultJoinSessionPermissionHandler,
|
|
54
62
|
suppressResumeEvent: config.suppressResumeEvent ?? true
|
|
55
63
|
},
|
|
56
|
-
factories,
|
|
64
|
+
{ factories, workflows },
|
|
57
65
|
requestedEnvironmentVariables?.length ? { requestedEnvironmentVariables } : void 0
|
|
58
66
|
);
|
|
59
67
|
}
|
|
@@ -62,8 +70,11 @@ async function joinSession(config = {}) {
|
|
|
62
70
|
Canvas,
|
|
63
71
|
CanvasError,
|
|
64
72
|
FactoryResumeError,
|
|
73
|
+
WorkflowResumeError,
|
|
65
74
|
createCanvas,
|
|
66
75
|
defineFactory,
|
|
76
|
+
defineWorkflow,
|
|
67
77
|
isFactoryRunTerminal,
|
|
78
|
+
isWorkflowRunTerminal,
|
|
68
79
|
joinSession
|
|
69
80
|
});
|