@github/copilot-sdk 1.0.15-unstable.35395657398.gad69ee1 → 1.0.15
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 +56 -4
- package/dist/cjs/cliVersion.js +1 -1
- package/dist/cjs/client.js +37 -6
- package/dist/cjs/copilotRequestHandler.js +156 -20
- package/dist/cjs/extension.js +9 -9
- package/dist/cjs/generated/rpc.js +582 -111
- package/dist/cjs/index.js +7 -7
- package/dist/cjs/installationConfirmation.js +98 -0
- package/dist/cjs/session.js +122 -135
- package/dist/cjs/{factory.js → workflow.js} +33 -33
- package/dist/cliVersion.d.ts +1 -1
- package/dist/cliVersion.js +1 -1
- package/dist/client.d.ts +3 -0
- package/dist/client.js +39 -6
- package/dist/copilotRequestHandler.js +156 -20
- package/dist/extension.d.ts +6 -6
- package/dist/extension.js +9 -9
- package/dist/generated/rpc.d.ts +16537 -12361
- package/dist/generated/rpc.js +582 -111
- package/dist/generated/session-events.d.ts +780 -120
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/installationConfirmation.d.ts +19 -0
- package/dist/installationConfirmation.js +77 -0
- package/dist/session.d.ts +10 -16
- package/dist/session.js +126 -139
- package/dist/types.d.ts +46 -69
- package/dist/workflow.d.ts +367 -0
- package/dist/{factory.js → workflow.js} +25 -25
- package/docs/extensions.md +1 -1
- package/docs/workflows.md +255 -0
- package/package.json +11 -10
- package/dist/factory.d.ts +0 -327
- package/docs/factories.md +0 -296
- package/docs/factory-patterns.md +0 -194
package/dist/cjs/session.js
CHANGED
|
@@ -28,27 +28,27 @@ var import_canvas = require("./canvas.js");
|
|
|
28
28
|
var import_telemetry = require("./telemetry.js");
|
|
29
29
|
var import_schema = require("./schema.js");
|
|
30
30
|
var import_types = require("./types.js");
|
|
31
|
-
var
|
|
32
|
-
function
|
|
33
|
-
return value === "not_found" || value === "non_resumable" || value === "already_active" || value === "
|
|
31
|
+
var import_workflow = require("./workflow.js");
|
|
32
|
+
function isWorkflowResumeErrorCode(value) {
|
|
33
|
+
return value === "not_found" || value === "non_resumable" || value === "workflow_run_not_resumable" || value === "already_active" || value === "workflow_already_running" || value === "workflow_limits_invalid" || value === "workflow_session_disposed" || value === "workflow_storage_unavailable" || value === "workflow_storage_corrupt";
|
|
34
34
|
}
|
|
35
|
-
function
|
|
35
|
+
function copyDefinedWorkflowAgentOption(source, target, key) {
|
|
36
36
|
const value = source[key];
|
|
37
37
|
if (value !== void 0) {
|
|
38
38
|
target[key] = value;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
const
|
|
42
|
-
function
|
|
43
|
-
if (
|
|
41
|
+
const workflowExecutionStore = new import_node_async_hooks.AsyncLocalStorage();
|
|
42
|
+
function throwIfWorkflowExecutionIsActive() {
|
|
43
|
+
if (workflowExecutionStore.getStore()?.active) {
|
|
44
44
|
throw new Error(
|
|
45
|
-
"
|
|
45
|
+
"workflow.run, workflow.resume, and workflow.pause are not allowed while a workflow body is running on this call path."
|
|
46
46
|
);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
function
|
|
50
|
-
const current =
|
|
51
|
-
return
|
|
49
|
+
function runInWorkflowHelperScope(helperScope, callback) {
|
|
50
|
+
const current = workflowExecutionStore.getStore();
|
|
51
|
+
return workflowExecutionStore.run({ active: current?.active ?? false, helperScope }, callback);
|
|
52
52
|
}
|
|
53
53
|
function deserializeHookInput(raw) {
|
|
54
54
|
if (!raw || typeof raw !== "object" || typeof raw.timestamp !== "number") {
|
|
@@ -72,20 +72,20 @@ function isOpenCanvasInstance(value) {
|
|
|
72
72
|
}
|
|
73
73
|
const FACTORY_LOG_FLUSH_DELAY_MS = 10;
|
|
74
74
|
const MAX_FACTORY_FANOUT_ITEMS = 4096;
|
|
75
|
-
function
|
|
75
|
+
function assertWorkflowFanoutSize(kind, size) {
|
|
76
76
|
if (size > MAX_FACTORY_FANOUT_ITEMS) {
|
|
77
77
|
throw new Error(
|
|
78
78
|
`${kind}() accepts at most ${MAX_FACTORY_FANOUT_ITEMS} items; got ${size}.`
|
|
79
79
|
);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
-
async function
|
|
82
|
+
async function runWorkflowParallel(thunks) {
|
|
83
83
|
if (!Array.isArray(thunks)) {
|
|
84
84
|
throw new Error(
|
|
85
85
|
"parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)"
|
|
86
86
|
);
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
assertWorkflowFanoutSize("parallel", thunks.length);
|
|
89
89
|
if (thunks.some((thunk) => typeof thunk !== "function")) {
|
|
90
90
|
throw new Error(
|
|
91
91
|
"parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)"
|
|
@@ -93,8 +93,8 @@ async function runFactoryParallel(thunks) {
|
|
|
93
93
|
}
|
|
94
94
|
return Promise.all(
|
|
95
95
|
thunks.map(
|
|
96
|
-
(thunk) => Promise.resolve().then(() =>
|
|
97
|
-
if (
|
|
96
|
+
(thunk) => Promise.resolve().then(() => runInWorkflowHelperScope("parallel", thunk)).catch((error) => {
|
|
97
|
+
if (isWorkflowFatalError(error)) {
|
|
98
98
|
throw error;
|
|
99
99
|
}
|
|
100
100
|
return null;
|
|
@@ -102,22 +102,22 @@ async function runFactoryParallel(thunks) {
|
|
|
102
102
|
)
|
|
103
103
|
);
|
|
104
104
|
}
|
|
105
|
-
async function
|
|
105
|
+
async function runWorkflowPipeline(items, ...stages) {
|
|
106
106
|
if (!Array.isArray(items)) {
|
|
107
107
|
throw new Error("pipeline(items, ...stages): items must be an array");
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
assertWorkflowFanoutSize("pipeline", items.length);
|
|
110
110
|
return Promise.all(
|
|
111
111
|
items.map(async (item, index) => {
|
|
112
112
|
let previous = item;
|
|
113
113
|
for (const stage of stages) {
|
|
114
114
|
try {
|
|
115
|
-
previous = await
|
|
115
|
+
previous = await runInWorkflowHelperScope(
|
|
116
116
|
"pipeline",
|
|
117
117
|
() => stage(previous, item, index)
|
|
118
118
|
);
|
|
119
119
|
} catch (error) {
|
|
120
|
-
if (
|
|
120
|
+
if (isWorkflowFatalError(error)) {
|
|
121
121
|
throw error;
|
|
122
122
|
}
|
|
123
123
|
return null;
|
|
@@ -127,7 +127,7 @@ async function runFactoryPipeline(items, ...stages) {
|
|
|
127
127
|
})
|
|
128
128
|
);
|
|
129
129
|
}
|
|
130
|
-
class
|
|
130
|
+
class WorkflowProgressBuffer {
|
|
131
131
|
constructor(send) {
|
|
132
132
|
this.send = send;
|
|
133
133
|
}
|
|
@@ -141,7 +141,7 @@ class FactoryProgressBuffer {
|
|
|
141
141
|
closed = false;
|
|
142
142
|
enqueue(kind, text) {
|
|
143
143
|
if (this.closed) {
|
|
144
|
-
throw new Error("Cannot log after the
|
|
144
|
+
throw new Error("Cannot log after the workflow run has settled");
|
|
145
145
|
}
|
|
146
146
|
this.pending.push({ seq: this.nextSeq++, kind, text });
|
|
147
147
|
this.scheduleFlush();
|
|
@@ -173,7 +173,7 @@ class FactoryProgressBuffer {
|
|
|
173
173
|
await this.flushTail;
|
|
174
174
|
if (this.flushFailed) {
|
|
175
175
|
console.warn(
|
|
176
|
-
"Ignoring a background
|
|
176
|
+
"Ignoring a background workflow progress flush failure after the workflow body settled",
|
|
177
177
|
this.flushError
|
|
178
178
|
);
|
|
179
179
|
}
|
|
@@ -182,7 +182,7 @@ class FactoryProgressBuffer {
|
|
|
182
182
|
await this.send(lines);
|
|
183
183
|
} catch (error) {
|
|
184
184
|
console.warn(
|
|
185
|
-
"Failed to flush final
|
|
185
|
+
"Failed to flush final workflow progress after the workflow body settled",
|
|
186
186
|
error
|
|
187
187
|
);
|
|
188
188
|
}
|
|
@@ -206,30 +206,30 @@ class FactoryProgressBuffer {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
|
-
async function
|
|
209
|
+
async function awaitWorkflowOperation(operation, signal) {
|
|
210
210
|
let rejectAbort;
|
|
211
211
|
const abortPromise = new Promise((_resolve, reject) => {
|
|
212
212
|
rejectAbort = reject;
|
|
213
213
|
});
|
|
214
|
-
const onAbort = () => rejectAbort?.(signal.reason ?? new DOMException("
|
|
214
|
+
const onAbort = () => rejectAbort?.(signal.reason ?? new DOMException("Workflow run was aborted", "AbortError"));
|
|
215
215
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
216
216
|
try {
|
|
217
|
-
|
|
217
|
+
throwIfWorkflowAborted(signal);
|
|
218
218
|
return await Promise.race([operation(), abortPromise]);
|
|
219
219
|
} finally {
|
|
220
220
|
signal.removeEventListener("abort", onAbort);
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
|
-
function
|
|
223
|
+
function throwIfWorkflowAborted(signal) {
|
|
224
224
|
if (signal.aborted) {
|
|
225
|
-
throw signal.reason ?? new DOMException("
|
|
225
|
+
throw signal.reason ?? new DOMException("Workflow run was aborted", "AbortError");
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
|
-
function
|
|
228
|
+
function isWorkflowAbortError(error) {
|
|
229
229
|
return typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
|
|
230
230
|
}
|
|
231
|
-
function
|
|
232
|
-
return
|
|
231
|
+
function isWorkflowFatalError(error) {
|
|
232
|
+
return isWorkflowAbortError(error) || error instanceof import_node.ResponseError || error instanceof import_node.ConnectionError;
|
|
233
233
|
}
|
|
234
234
|
const TOOL_SEARCH_TOOL_NAME = "tool_search_tool";
|
|
235
235
|
class CopilotSession {
|
|
@@ -261,8 +261,8 @@ class CopilotSession {
|
|
|
261
261
|
canvases = /* @__PURE__ */ new Map();
|
|
262
262
|
bearerTokenProviders = /* @__PURE__ */ new Map();
|
|
263
263
|
commandHandlers = /* @__PURE__ */ new Map();
|
|
264
|
-
|
|
265
|
-
|
|
264
|
+
workflows = /* @__PURE__ */ new Map();
|
|
265
|
+
workflowAbortControllers = /* @__PURE__ */ new Map();
|
|
266
266
|
permissionHandler;
|
|
267
267
|
mcpAuthHandler;
|
|
268
268
|
userInputHandler;
|
|
@@ -284,23 +284,16 @@ class CopilotSession {
|
|
|
284
284
|
/** @internal Client session API handlers, populated by CopilotClient during create/resume. */
|
|
285
285
|
clientSessionApis = {};
|
|
286
286
|
/**
|
|
287
|
-
* Friendly
|
|
287
|
+
* Friendly workflow API for running registered workflows by name or handle.
|
|
288
288
|
*
|
|
289
|
-
* @experimental Part of the experimental
|
|
289
|
+
* @experimental Part of the experimental Dynamic Workflows surface and may
|
|
290
290
|
* change or be removed in future SDK or CLI releases.
|
|
291
291
|
*/
|
|
292
|
-
|
|
292
|
+
workflow = {
|
|
293
293
|
run: (async (nameOrHandle, options) => {
|
|
294
|
-
|
|
295
|
-
const name = typeof nameOrHandle === "string" ? nameOrHandle : (0,
|
|
296
|
-
|
|
297
|
-
return this.factory.resume(options.resumeFromRunId, {
|
|
298
|
-
limits: options.limits,
|
|
299
|
-
notifyOnComplete: options.notifyOnComplete,
|
|
300
|
-
logPhaseNames: options.logPhaseNames
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
const envelope = await this.rpc.factory.run({
|
|
294
|
+
throwIfWorkflowExecutionIsActive();
|
|
295
|
+
const name = typeof nameOrHandle === "string" ? nameOrHandle : (0, import_workflow.getWorkflowDefinition)(nameOrHandle).meta.name;
|
|
296
|
+
const envelope = await this.rpc.workflow.run({
|
|
304
297
|
name,
|
|
305
298
|
args: options?.args === void 0 ? {} : options.args,
|
|
306
299
|
options: {
|
|
@@ -309,13 +302,13 @@ class CopilotSession {
|
|
|
309
302
|
logPhaseNames: options?.logPhaseNames
|
|
310
303
|
}
|
|
311
304
|
});
|
|
312
|
-
return this.
|
|
305
|
+
return this.settleWorkflowRun(envelope);
|
|
313
306
|
}),
|
|
314
307
|
resume: (async (runId, options) => {
|
|
315
|
-
|
|
308
|
+
throwIfWorkflowExecutionIsActive();
|
|
316
309
|
let response;
|
|
317
310
|
try {
|
|
318
|
-
response = await this.rpc.
|
|
311
|
+
response = await this.rpc.workflow.resume({
|
|
319
312
|
runId,
|
|
320
313
|
limits: options?.limits,
|
|
321
314
|
notifyOnComplete: options?.notifyOnComplete,
|
|
@@ -324,43 +317,36 @@ class CopilotSession {
|
|
|
324
317
|
} catch (error) {
|
|
325
318
|
if (error instanceof import_node.ResponseError && typeof error.data === "object" && error.data !== null) {
|
|
326
319
|
const code = error.data.code;
|
|
327
|
-
if (
|
|
328
|
-
throw new
|
|
320
|
+
if (isWorkflowResumeErrorCode(code)) {
|
|
321
|
+
throw new import_workflow.WorkflowResumeError(code, error.message);
|
|
329
322
|
}
|
|
330
323
|
}
|
|
331
324
|
throw error;
|
|
332
325
|
}
|
|
333
|
-
return this.
|
|
326
|
+
return this.settleWorkflowRun(response.run);
|
|
334
327
|
}),
|
|
335
|
-
getRun: async (runId) => this.rpc.
|
|
336
|
-
waitForRun: (runId, options) => this.
|
|
328
|
+
getRun: async (runId) => this.rpc.workflow.getRun({ runId }),
|
|
329
|
+
waitForRun: (runId, options) => this.waitForWorkflowRun(runId, options?.signal),
|
|
337
330
|
listRuns: (async (options) => {
|
|
338
|
-
const page = await this.rpc.
|
|
331
|
+
const page = await this.rpc.workflow.listRuns(options ?? {});
|
|
339
332
|
return options === void 0 ? page.runs : page;
|
|
340
333
|
}),
|
|
341
|
-
getRunDetail: (runId) => this.rpc.
|
|
342
|
-
getRunProgress: (runId, options = {}) => this.rpc.
|
|
334
|
+
getRunDetail: (runId) => this.rpc.workflow.getRunDetail({ runId }),
|
|
335
|
+
getRunProgress: (runId, options = {}) => this.rpc.workflow.getRunProgress({ runId, ...options }),
|
|
343
336
|
pause: async (runId) => {
|
|
344
|
-
|
|
345
|
-
return this.rpc.
|
|
337
|
+
throwIfWorkflowExecutionIsActive();
|
|
338
|
+
return this.rpc.workflow.pause({ runId });
|
|
346
339
|
},
|
|
347
|
-
cancel: async (runId) => this.rpc.
|
|
340
|
+
cancel: async (runId) => this.rpc.workflow.cancel({ runId })
|
|
348
341
|
};
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
*
|
|
352
|
-
* The CLI may answer `session.factory.run` and `session.factory.resume`
|
|
353
|
-
* before the run settles, so a non-terminal envelope is followed by a wait
|
|
354
|
-
* on the run's terminal state.
|
|
355
|
-
*/
|
|
356
|
-
settleFactoryRun(envelope) {
|
|
357
|
-
if ((0, import_factory.isFactoryRunTerminal)(envelope.status)) {
|
|
342
|
+
settleWorkflowRun(envelope) {
|
|
343
|
+
if ((0, import_workflow.isWorkflowRunTerminal)(envelope.status)) {
|
|
358
344
|
return Promise.resolve(envelope);
|
|
359
345
|
}
|
|
360
|
-
return this.
|
|
346
|
+
return this.waitForWorkflowRun(envelope.runId);
|
|
361
347
|
}
|
|
362
348
|
/**
|
|
363
|
-
* Resolve when a
|
|
349
|
+
* Resolve when a workflow run reaches a terminal status.
|
|
364
350
|
*
|
|
365
351
|
* The subscription is installed *before* the first read so a transition
|
|
366
352
|
* landing between the two cannot be missed, and re-reads are serialized so
|
|
@@ -369,8 +355,8 @@ class CopilotSession {
|
|
|
369
355
|
* collapse into a single in-flight read. A bounded periodic re-read keeps a
|
|
370
356
|
* dropped invalidation from leaving the wait pending forever.
|
|
371
357
|
*/
|
|
372
|
-
|
|
373
|
-
const abortError = () => signal?.reason ?? new DOMException("
|
|
358
|
+
waitForWorkflowRun(runId, signal) {
|
|
359
|
+
const abortError = () => signal?.reason ?? new DOMException("Workflow run wait was aborted", "AbortError");
|
|
374
360
|
if (signal?.aborted === true) {
|
|
375
361
|
return Promise.reject(abortError());
|
|
376
362
|
}
|
|
@@ -407,8 +393,8 @@ class CopilotSession {
|
|
|
407
393
|
try {
|
|
408
394
|
do {
|
|
409
395
|
rereadRequested = false;
|
|
410
|
-
const envelope = await this.rpc.
|
|
411
|
-
if ((0,
|
|
396
|
+
const envelope = await this.rpc.workflow.getRun({ runId });
|
|
397
|
+
if ((0, import_workflow.isWorkflowRunTerminal)(envelope.status)) {
|
|
412
398
|
finish(() => resolve(envelope));
|
|
413
399
|
return;
|
|
414
400
|
}
|
|
@@ -423,7 +409,7 @@ class CopilotSession {
|
|
|
423
409
|
onAbort = () => finish(() => reject(abortError()));
|
|
424
410
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
425
411
|
}
|
|
426
|
-
unsubscribe = this.on("
|
|
412
|
+
unsubscribe = this.on("workflow.run_updated", (event) => {
|
|
427
413
|
if (event.data.runId === runId) {
|
|
428
414
|
void read();
|
|
429
415
|
}
|
|
@@ -549,6 +535,7 @@ class CopilotSession {
|
|
|
549
535
|
});
|
|
550
536
|
let lastAssistantMessage;
|
|
551
537
|
const unsubscribe = this.on((event) => {
|
|
538
|
+
if (event.agentId) return;
|
|
552
539
|
if (event.type === "assistant.message") {
|
|
553
540
|
lastAssistantMessage = event;
|
|
554
541
|
} else if (event.type === "session.idle" && event.data.mode !== "autopilot") {
|
|
@@ -688,13 +675,13 @@ class CopilotSession {
|
|
|
688
675
|
this.autoModeSwitchHandler = void 0;
|
|
689
676
|
this.commandHandlers.clear();
|
|
690
677
|
this.canvases.clear();
|
|
691
|
-
this.
|
|
692
|
-
for (const controllersForRun of this.
|
|
678
|
+
this.workflows.clear();
|
|
679
|
+
for (const controllersForRun of this.workflowAbortControllers.values()) {
|
|
693
680
|
for (const controller of controllersForRun.values()) {
|
|
694
681
|
controller.abort();
|
|
695
682
|
}
|
|
696
683
|
}
|
|
697
|
-
this.
|
|
684
|
+
this.workflowAbortControllers.clear();
|
|
698
685
|
this.transformCallbacks?.clear();
|
|
699
686
|
}
|
|
700
687
|
/** @internal */
|
|
@@ -1143,46 +1130,46 @@ class CopilotSession {
|
|
|
1143
1130
|
};
|
|
1144
1131
|
}
|
|
1145
1132
|
/**
|
|
1146
|
-
* Registers
|
|
1133
|
+
* Registers workflow closures and reverse-RPC handlers for this session.
|
|
1147
1134
|
*
|
|
1148
|
-
* @param
|
|
1135
|
+
* @param workflows - Workflow handles declared by the joining extension.
|
|
1149
1136
|
* @internal Called by the SDK when an extension joins a session.
|
|
1150
1137
|
*/
|
|
1151
|
-
|
|
1152
|
-
this.
|
|
1153
|
-
if (!
|
|
1154
|
-
delete this.clientSessionApis.
|
|
1138
|
+
registerWorkflows(workflows) {
|
|
1139
|
+
this.workflows.clear();
|
|
1140
|
+
if (!workflows || workflows.length === 0) {
|
|
1141
|
+
delete this.clientSessionApis.workflow;
|
|
1155
1142
|
return;
|
|
1156
1143
|
}
|
|
1157
|
-
for (const handle of
|
|
1158
|
-
const definition = (0,
|
|
1159
|
-
if (this.
|
|
1144
|
+
for (const handle of workflows) {
|
|
1145
|
+
const definition = (0, import_workflow.getWorkflowDefinition)(handle);
|
|
1146
|
+
if (this.workflows.has(definition.meta.name)) {
|
|
1160
1147
|
throw new Error(
|
|
1161
|
-
`Duplicate
|
|
1148
|
+
`Duplicate workflow name "${definition.meta.name}". Workflow names must be unique within a joinSession call.`
|
|
1162
1149
|
);
|
|
1163
1150
|
}
|
|
1164
|
-
this.
|
|
1151
|
+
this.workflows.set(definition.meta.name, definition);
|
|
1165
1152
|
}
|
|
1166
1153
|
const self = this;
|
|
1167
|
-
this.clientSessionApis.
|
|
1154
|
+
this.clientSessionApis.workflow = {
|
|
1168
1155
|
async execute(params) {
|
|
1169
|
-
const definition = self.
|
|
1156
|
+
const definition = self.workflows.get(params.name);
|
|
1170
1157
|
if (!definition) {
|
|
1171
|
-
const message = `No
|
|
1158
|
+
const message = `No workflow registered with name "${params.name}"`;
|
|
1172
1159
|
throw new import_node.ResponseError(import_node.ErrorCodes.InvalidParams, message, {
|
|
1173
|
-
code: "
|
|
1160
|
+
code: "workflow_not_found",
|
|
1174
1161
|
name: params.name
|
|
1175
1162
|
});
|
|
1176
1163
|
}
|
|
1177
1164
|
const controller = new AbortController();
|
|
1178
|
-
let controllersForRun = self.
|
|
1165
|
+
let controllersForRun = self.workflowAbortControllers.get(params.runId);
|
|
1179
1166
|
if (controllersForRun === void 0) {
|
|
1180
1167
|
controllersForRun = /* @__PURE__ */ new Map();
|
|
1181
|
-
self.
|
|
1168
|
+
self.workflowAbortControllers.set(params.runId, controllersForRun);
|
|
1182
1169
|
}
|
|
1183
1170
|
controllersForRun.set(params.executionToken, controller);
|
|
1184
|
-
const progress = new
|
|
1185
|
-
await self.rpc.
|
|
1171
|
+
const progress = new WorkflowProgressBuffer(async (lines) => {
|
|
1172
|
+
await self.rpc.workflow.log({
|
|
1186
1173
|
runId: params.runId,
|
|
1187
1174
|
executionToken: params.executionToken,
|
|
1188
1175
|
lines
|
|
@@ -1195,22 +1182,22 @@ class CopilotSession {
|
|
|
1195
1182
|
session: self,
|
|
1196
1183
|
signal: controller.signal,
|
|
1197
1184
|
phase: (title) => {
|
|
1198
|
-
|
|
1185
|
+
throwIfWorkflowAborted(controller.signal);
|
|
1199
1186
|
progress.enqueue("phase", title);
|
|
1200
1187
|
},
|
|
1201
1188
|
log: (message) => {
|
|
1202
|
-
|
|
1189
|
+
throwIfWorkflowAborted(controller.signal);
|
|
1203
1190
|
progress.enqueue("log", message);
|
|
1204
1191
|
},
|
|
1205
1192
|
agent: async (prompt, options = {}) => {
|
|
1206
1193
|
await progress.flush();
|
|
1207
1194
|
const opts = {};
|
|
1208
|
-
for (const key of
|
|
1209
|
-
|
|
1195
|
+
for (const key of import_workflow.WORKFLOW_AGENT_OPTION_KEYS) {
|
|
1196
|
+
copyDefinedWorkflowAgentOption(options, opts, key);
|
|
1210
1197
|
}
|
|
1211
|
-
const response = await
|
|
1212
|
-
() => self.rpc.
|
|
1213
|
-
|
|
1198
|
+
const response = await awaitWorkflowOperation(
|
|
1199
|
+
() => self.rpc.workflow.agent({
|
|
1200
|
+
workflowRunId: params.runId,
|
|
1214
1201
|
executionToken: params.executionToken,
|
|
1215
1202
|
prompt,
|
|
1216
1203
|
opts
|
|
@@ -1222,11 +1209,11 @@ class CopilotSession {
|
|
|
1222
1209
|
step: async (key, producer, options = {}) => {
|
|
1223
1210
|
await progress.flush();
|
|
1224
1211
|
if (options.volatile) {
|
|
1225
|
-
|
|
1212
|
+
throwIfWorkflowAborted(controller.signal);
|
|
1226
1213
|
return producer();
|
|
1227
1214
|
}
|
|
1228
|
-
const cached = await
|
|
1229
|
-
() => self.rpc.
|
|
1215
|
+
const cached = await awaitWorkflowOperation(
|
|
1216
|
+
() => self.rpc.workflow.journal.get({
|
|
1230
1217
|
runId: params.runId,
|
|
1231
1218
|
executionToken: params.executionToken,
|
|
1232
1219
|
key
|
|
@@ -1239,13 +1226,13 @@ class CopilotSession {
|
|
|
1239
1226
|
`step("${key}") journal returned a hit without a result`
|
|
1240
1227
|
);
|
|
1241
1228
|
}
|
|
1242
|
-
|
|
1229
|
+
assertWorkflowStepResult(cached.resultJson, key);
|
|
1243
1230
|
return cached.resultJson;
|
|
1244
1231
|
}
|
|
1245
1232
|
const result2 = await producer();
|
|
1246
|
-
|
|
1247
|
-
await
|
|
1248
|
-
() => self.rpc.
|
|
1233
|
+
assertWorkflowStepResult(result2, key);
|
|
1234
|
+
await awaitWorkflowOperation(
|
|
1235
|
+
() => self.rpc.workflow.journal.put({
|
|
1249
1236
|
runId: params.runId,
|
|
1250
1237
|
executionToken: params.executionToken,
|
|
1251
1238
|
key,
|
|
@@ -1257,17 +1244,17 @@ class CopilotSession {
|
|
|
1257
1244
|
},
|
|
1258
1245
|
pause: async (key) => {
|
|
1259
1246
|
if (typeof key !== "string" || key.length === 0) {
|
|
1260
|
-
throw new Error("
|
|
1247
|
+
throw new Error("Workflow pause checkpoint key must not be empty");
|
|
1261
1248
|
}
|
|
1262
|
-
const helperScope =
|
|
1249
|
+
const helperScope = workflowExecutionStore.getStore()?.helperScope;
|
|
1263
1250
|
if (helperScope !== void 0) {
|
|
1264
1251
|
throw new Error(
|
|
1265
|
-
`
|
|
1252
|
+
`Workflow pause checkpoints are not allowed inside ${helperScope}() branches`
|
|
1266
1253
|
);
|
|
1267
1254
|
}
|
|
1268
1255
|
await progress.flush();
|
|
1269
|
-
const response = await
|
|
1270
|
-
() => self.internalRpc.
|
|
1256
|
+
const response = await awaitWorkflowOperation(
|
|
1257
|
+
() => self.internalRpc.workflow.pauseAtCheckpoint({
|
|
1271
1258
|
runId: params.runId,
|
|
1272
1259
|
executionToken: params.executionToken,
|
|
1273
1260
|
key
|
|
@@ -1278,21 +1265,21 @@ class CopilotSession {
|
|
|
1278
1265
|
case "continue":
|
|
1279
1266
|
return;
|
|
1280
1267
|
case "pause":
|
|
1281
|
-
await
|
|
1268
|
+
await awaitWorkflowOperation(
|
|
1282
1269
|
() => new Promise(() => {
|
|
1283
1270
|
}),
|
|
1284
1271
|
controller.signal
|
|
1285
1272
|
);
|
|
1286
1273
|
}
|
|
1287
1274
|
},
|
|
1288
|
-
parallel:
|
|
1289
|
-
pipeline:
|
|
1290
|
-
|
|
1291
|
-
throw new Error("nested
|
|
1275
|
+
parallel: runWorkflowParallel,
|
|
1276
|
+
pipeline: runWorkflowPipeline,
|
|
1277
|
+
workflow: async () => {
|
|
1278
|
+
throw new Error("nested workflows are not supported");
|
|
1292
1279
|
}
|
|
1293
1280
|
};
|
|
1294
1281
|
const execution = { active: true };
|
|
1295
|
-
const result = await
|
|
1282
|
+
const result = await workflowExecutionStore.run(execution, async () => {
|
|
1296
1283
|
try {
|
|
1297
1284
|
return await definition.run(context);
|
|
1298
1285
|
} finally {
|
|
@@ -1302,27 +1289,27 @@ class CopilotSession {
|
|
|
1302
1289
|
if (result === void 0) {
|
|
1303
1290
|
return {};
|
|
1304
1291
|
}
|
|
1305
|
-
|
|
1292
|
+
assertWorkflowResult(result);
|
|
1306
1293
|
return { result };
|
|
1307
1294
|
} finally {
|
|
1308
1295
|
try {
|
|
1309
1296
|
await progress.close();
|
|
1310
1297
|
} finally {
|
|
1311
|
-
const controllersForRun2 = self.
|
|
1298
|
+
const controllersForRun2 = self.workflowAbortControllers.get(params.runId);
|
|
1312
1299
|
if (controllersForRun2?.get(params.executionToken) === controller) {
|
|
1313
1300
|
controllersForRun2.delete(params.executionToken);
|
|
1314
1301
|
if (controllersForRun2.size === 0) {
|
|
1315
|
-
self.
|
|
1302
|
+
self.workflowAbortControllers.delete(params.runId);
|
|
1316
1303
|
}
|
|
1317
1304
|
}
|
|
1318
1305
|
}
|
|
1319
1306
|
}
|
|
1320
1307
|
},
|
|
1321
1308
|
async abort(params) {
|
|
1322
|
-
const controllersForRun = self.
|
|
1309
|
+
const controllersForRun = self.workflowAbortControllers.get(params.runId);
|
|
1323
1310
|
const controller = controllersForRun?.get(params.executionToken);
|
|
1324
1311
|
if (controller !== void 0) {
|
|
1325
|
-
controller.abort(new DOMException("
|
|
1312
|
+
controller.abort(new DOMException("Workflow run was aborted", "AbortError"));
|
|
1326
1313
|
}
|
|
1327
1314
|
return {};
|
|
1328
1315
|
}
|
|
@@ -2008,17 +1995,17 @@ function assertStrictJson(value, context) {
|
|
|
2008
1995
|
};
|
|
2009
1996
|
visit(value, "$", context.allowTopLevelUndefined);
|
|
2010
1997
|
}
|
|
2011
|
-
function
|
|
1998
|
+
function assertWorkflowResult(value) {
|
|
2012
1999
|
assertStrictJson(value, {
|
|
2013
|
-
code: "
|
|
2014
|
-
label: "
|
|
2000
|
+
code: "workflow_result_not_json",
|
|
2001
|
+
label: "Workflow result",
|
|
2015
2002
|
allowTopLevelUndefined: true
|
|
2016
2003
|
});
|
|
2017
2004
|
}
|
|
2018
|
-
function
|
|
2005
|
+
function assertWorkflowStepResult(value, key) {
|
|
2019
2006
|
assertStrictJson(value, {
|
|
2020
|
-
code: "
|
|
2021
|
-
label: `
|
|
2007
|
+
code: "workflow_step_not_json",
|
|
2008
|
+
label: `Workflow step "${key}" result`,
|
|
2022
2009
|
allowTopLevelUndefined: false
|
|
2023
2010
|
});
|
|
2024
2011
|
}
|