pi-subagents 0.45.1 → 0.46.0
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/CHANGELOG.md +33 -0
- package/README.md +2 -0
- package/docs/agents.md +342 -0
- package/docs/configuration.md +320 -0
- package/docs/extension-api.md +308 -0
- package/docs/missions.md +117 -0
- package/docs/models.md +190 -0
- package/docs/observability.md +174 -0
- package/docs/tool-reference.md +343 -0
- package/docs/watchdog.md +176 -0
- package/docs/workflows.md +163 -0
- package/package.json +4 -2
- package/skills/pi-subagents/references/execution-controls.md +2 -2
- package/src/agents/agents.ts +17 -8
- package/src/agents/frontmatter.ts +7 -3
- package/src/agents/skills.ts +2 -9
- package/src/api/project-panes.ts +30 -0
- package/src/extension/config.ts +15 -1
- package/src/extension/index.ts +36 -16
- package/src/extension/schemas.ts +3 -2
- package/src/extension/subagent-guide.ts +39 -0
- package/src/extension/tool-description.ts +4 -4
- package/src/inspectors/herdr/project-panes.ts +457 -62
- package/src/missions/actions.ts +25 -2
- package/src/missions/lifecycle.ts +21 -2
- package/src/missions/store.ts +77 -1
- package/src/missions/types.ts +33 -0
- package/src/runs/background/async-execution.ts +7 -1
- package/src/runs/background/completion-replay.ts +267 -0
- package/src/runs/background/result-watcher.ts +12 -4
- package/src/runs/background/resume-guidance.ts +33 -0
- package/src/runs/background/subagent-wait.ts +5 -2
- package/src/runs/background/wait-completions.ts +39 -5
- package/src/runs/background/wait-subscriptions.ts +21 -5
- package/src/runs/foreground/execution.ts +4 -0
- package/src/runs/foreground/foreground-history.ts +137 -0
- package/src/runs/foreground/subagent-executor.ts +326 -38
- package/src/runs/shared/subagent-prompt-runtime.ts +71 -5
- package/src/shared/fork-context.ts +13 -0
- package/src/shared/prompt-resources.ts +51 -0
- package/src/shared/types.ts +30 -1
- package/src/shared/utf8.ts +11 -0
- package/src/slash/prompt-workflows.ts +2 -15
- package/src/slash/slash-commands.ts +19 -1
- package/src/tui/fleet-status.ts +8 -2
- package/src/tui/fleet.ts +135 -25
- package/src/tui/render.ts +120 -7
- package/src/workflows/scripted-workflow.ts +187 -11
|
@@ -10,6 +10,9 @@ const { inspect } = require("node:util");
|
|
|
10
10
|
let nextCallId = 0;
|
|
11
11
|
const pending = new Map();
|
|
12
12
|
const runKeyPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
13
|
+
const trackedPromisePatch = Symbol("trackedPromisePatch");
|
|
14
|
+
const trackedPromiseObservations = new WeakMap();
|
|
15
|
+
let suppressRunObservation = 0;
|
|
13
16
|
|
|
14
17
|
function stableRunJson(value) {
|
|
15
18
|
if (Array.isArray(value)) return "[" + value.map(stableRunJson).join(",") + "]";
|
|
@@ -17,12 +20,124 @@ function stableRunJson(value) {
|
|
|
17
20
|
return JSON.stringify(value) ?? "undefined";
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
function isDirectWorkflowScriptPromiseHandlerCall() {
|
|
24
|
+
const stack = new Error().stack;
|
|
25
|
+
if (typeof stack !== "string") return false;
|
|
26
|
+
const frame = stack.split("\n").slice(1).map((line) => line.trim()).find((line) =>
|
|
27
|
+
line &&
|
|
28
|
+
!line.includes("isDirectWorkflowScriptPromiseHandlerCall") &&
|
|
29
|
+
!line.includes("markObserved") &&
|
|
30
|
+
!line.includes("promise.then") &&
|
|
31
|
+
!line.includes("promise.catch") &&
|
|
32
|
+
!line.includes("promise.finally")
|
|
33
|
+
);
|
|
34
|
+
return frame ? frame.includes("workflow-script.js") && !frame.includes("at async ") : false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function mergeObservations(...groups) {
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
const merged = [];
|
|
40
|
+
for (const group of groups) {
|
|
41
|
+
for (const observation of group) {
|
|
42
|
+
if (!observation || typeof observation.callId !== "number" || typeof observation.key !== "string" || seen.has(observation.callId)) continue;
|
|
43
|
+
seen.add(observation.callId);
|
|
44
|
+
merged.push(observation);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return merged;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function trackedObservations(value) {
|
|
51
|
+
return value && (typeof value === "object" || typeof value === "function") ? trackedPromiseObservations.get(value) ?? [] : [];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function withSuppressedRunObservation(callback) {
|
|
55
|
+
suppressRunObservation += 1;
|
|
56
|
+
try {
|
|
57
|
+
return callback();
|
|
58
|
+
} finally {
|
|
59
|
+
suppressRunObservation -= 1;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function trackRunObservation(observations, promise) {
|
|
64
|
+
const merged = mergeObservations(trackedObservations(promise), observations);
|
|
65
|
+
if (merged.length === 0 || !promise || typeof promise.then !== "function") return promise;
|
|
66
|
+
trackedPromiseObservations.set(promise, merged);
|
|
67
|
+
if (promise[trackedPromisePatch]) return promise;
|
|
68
|
+
|
|
69
|
+
const observedCallIds = new Set();
|
|
70
|
+
const markObserved = () => {
|
|
71
|
+
if (suppressRunObservation > 0 || isDirectWorkflowScriptPromiseHandlerCall()) return;
|
|
72
|
+
for (const observation of trackedObservations(promise)) {
|
|
73
|
+
if (observedCallIds.has(observation.callId)) continue;
|
|
74
|
+
observedCallIds.add(observation.callId);
|
|
75
|
+
parentPort.postMessage({ type: "runObserved", callId: observation.callId, key: observation.key });
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const originalThen = promise.then.bind(promise);
|
|
79
|
+
const originalCatch = promise.catch.bind(promise);
|
|
80
|
+
const originalFinally = promise.finally.bind(promise);
|
|
81
|
+
Object.defineProperty(promise, trackedPromisePatch, { value: true });
|
|
82
|
+
promise.then = (onFulfilled, onRejected) => {
|
|
83
|
+
markObserved();
|
|
84
|
+
return trackRunObservation(trackedObservations(promise), originalThen(onFulfilled, onRejected));
|
|
85
|
+
};
|
|
86
|
+
promise.catch = (onRejected) => {
|
|
87
|
+
markObserved();
|
|
88
|
+
return trackRunObservation(trackedObservations(promise), originalCatch(onRejected));
|
|
89
|
+
};
|
|
90
|
+
promise.finally = (onFinally) => {
|
|
91
|
+
markObserved();
|
|
92
|
+
return trackRunObservation(trackedObservations(promise), originalFinally(onFinally));
|
|
93
|
+
};
|
|
94
|
+
return promise;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function trackPromiseCombinator(items, createPromise) {
|
|
98
|
+
const values = Array.from(items);
|
|
99
|
+
const observations = mergeObservations(...values.map(trackedObservations));
|
|
100
|
+
const promise = withSuppressedRunObservation(() => createPromise(values));
|
|
101
|
+
return observations.length > 0 ? trackRunObservation(observations, promise) : promise;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const workflowPromise = new Proxy(Promise, {
|
|
105
|
+
construct(target, args) {
|
|
106
|
+
return new target(...args);
|
|
107
|
+
},
|
|
108
|
+
get(target, prop) {
|
|
109
|
+
if (prop === "all") return (items) => trackPromiseCombinator(items, (values) => target.all(values));
|
|
110
|
+
if (prop === "allSettled") return (items) => trackPromiseCombinator(items, (values) => target.allSettled(values));
|
|
111
|
+
if (prop === "race") return (items) => trackPromiseCombinator(items, (values) => target.race(values));
|
|
112
|
+
if (prop === "any") return (items) => trackPromiseCombinator(items, (values) => target.any(values));
|
|
113
|
+
if (prop === "resolve") return (value) => {
|
|
114
|
+
const observations = trackedObservations(value);
|
|
115
|
+
const promise = withSuppressedRunObservation(() => target.resolve(value));
|
|
116
|
+
return observations.length > 0 ? trackRunObservation(observations, promise) : promise;
|
|
117
|
+
};
|
|
118
|
+
const value = target[prop];
|
|
119
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
function hostCall(method, args, observation) {
|
|
124
|
+
const callId = ++nextCallId;
|
|
125
|
+
const promise = new Promise((resolve, reject) => {
|
|
23
126
|
pending.set(callId, { resolve, reject });
|
|
24
127
|
parentPort.postMessage({ type: "call", callId, method, args });
|
|
25
128
|
});
|
|
129
|
+
return observation && typeof observation.key === "string"
|
|
130
|
+
? trackRunObservation([{ key: observation.key, callId }], promise)
|
|
131
|
+
: promise;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function runHostCall(key, params, collectFailure) {
|
|
135
|
+
const callId = ++nextCallId;
|
|
136
|
+
const promise = new Promise((resolve, reject) => {
|
|
137
|
+
pending.set(callId, { resolve, reject });
|
|
138
|
+
parentPort.postMessage({ type: "call", callId, method: "run", args: { key, params, ...(collectFailure ? { collectFailure: true } : {}) } });
|
|
139
|
+
});
|
|
140
|
+
return { key, callId, promise };
|
|
26
141
|
}
|
|
27
142
|
|
|
28
143
|
function formatRef(result) {
|
|
@@ -58,7 +173,7 @@ function validateRunCall(key, params, label, fingerprints) {
|
|
|
58
173
|
const runs = Object.freeze({
|
|
59
174
|
run(key, params) {
|
|
60
175
|
validateRunCall(key, params, "runs.run", runFingerprints);
|
|
61
|
-
return hostCall("run", { key, params });
|
|
176
|
+
return hostCall("run", { key, params }, { key });
|
|
62
177
|
},
|
|
63
178
|
all(items) {
|
|
64
179
|
if (!Array.isArray(items)) throw new Error("runs.all(items) requires an array.");
|
|
@@ -73,7 +188,8 @@ const runs = Object.freeze({
|
|
|
73
188
|
calls.push({ key, params });
|
|
74
189
|
}
|
|
75
190
|
for (const { key, params } of calls) runFingerprints.set(key, stableRunJson(params));
|
|
76
|
-
|
|
191
|
+
const launched = calls.map(({ key, params }) => runHostCall(key, params, true));
|
|
192
|
+
return trackRunObservation(launched.map(({ key, callId }) => ({ key, callId })), Promise.all(launched.map(({ promise }) => promise)));
|
|
77
193
|
},
|
|
78
194
|
status(keyOrRunId) { return hostCall("status", { keyOrRunId }); },
|
|
79
195
|
ref: formatRef,
|
|
@@ -97,6 +213,14 @@ const state = Object.freeze({
|
|
|
97
213
|
},
|
|
98
214
|
});
|
|
99
215
|
|
|
216
|
+
const prompts = Object.freeze({
|
|
217
|
+
render(ref, vars) {
|
|
218
|
+
if (typeof ref !== "string" || !ref.trim()) throw new Error("prompts.render(ref, vars) requires a non-empty ref string.");
|
|
219
|
+
if (vars !== undefined) assertJsonValue(vars, "prompts.render vars");
|
|
220
|
+
return hostCall("prompts.render", { ref, vars });
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
|
|
100
224
|
let contextObjectPrototype;
|
|
101
225
|
|
|
102
226
|
const capturedConsole = Object.freeze(Object.fromEntries(
|
|
@@ -139,6 +263,25 @@ function assertJsonValue(value, path = "emit", seen = new Set()) {
|
|
|
139
263
|
seen.delete(value);
|
|
140
264
|
}
|
|
141
265
|
|
|
266
|
+
function isPlainWorkflowObject(value) {
|
|
267
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
268
|
+
const prototype = Object.getPrototypeOf(value);
|
|
269
|
+
return prototype === null || prototype === Object.prototype || prototype === contextObjectPrototype;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function omitUndefinedWorkflowValues(value, seen = new Set()) {
|
|
273
|
+
if (value === null || typeof value !== "object") return value;
|
|
274
|
+
if (seen.has(value)) return value;
|
|
275
|
+
seen.add(value);
|
|
276
|
+
const normalized = Array.isArray(value)
|
|
277
|
+
? value.map((entry) => entry === undefined ? null : omitUndefinedWorkflowValues(entry, seen))
|
|
278
|
+
: isPlainWorkflowObject(value) && Object.getOwnPropertySymbols(value).length === 0
|
|
279
|
+
? Object.fromEntries(Object.entries(value).flatMap(([key, entry]) => entry === undefined ? [] : [[key, omitUndefinedWorkflowValues(entry, seen)]]))
|
|
280
|
+
: value;
|
|
281
|
+
seen.delete(value);
|
|
282
|
+
return normalized;
|
|
283
|
+
}
|
|
284
|
+
|
|
142
285
|
parentPort.on("message", async (message) => {
|
|
143
286
|
if (message.type === "response") {
|
|
144
287
|
const entry = pending.get(message.callId);
|
|
@@ -150,7 +293,7 @@ parentPort.on("message", async (message) => {
|
|
|
150
293
|
}
|
|
151
294
|
if (message.type !== "start") return;
|
|
152
295
|
try {
|
|
153
|
-
const sandbox = { runs, emit(value) { assertJsonValue(value); parentPort.postMessage({ type: "emit", value }); }, console: capturedConsole };
|
|
296
|
+
const sandbox = { runs, prompts, Promise: workflowPromise, emit(value) { assertJsonValue(value); parentPort.postMessage({ type: "emit", value }); }, console: capturedConsole };
|
|
154
297
|
if (message.stateEnabled) sandbox.state = state;
|
|
155
298
|
const context = vm.createContext(sandbox, { codeGeneration: { strings: false, wasm: false } });
|
|
156
299
|
contextObjectPrototype = vm.runInContext("Object.prototype", context);
|
|
@@ -163,7 +306,7 @@ parentPort.on("message", async (message) => {
|
|
|
163
306
|
return;
|
|
164
307
|
}
|
|
165
308
|
const value = await compiled.runInContext(context);
|
|
166
|
-
const persistedValue = value === undefined ? null : value;
|
|
309
|
+
const persistedValue = value === undefined ? null : omitUndefinedWorkflowValues(value);
|
|
167
310
|
assertJsonValue(persistedValue, "return");
|
|
168
311
|
parentPort.postMessage({ type: "complete", value: persistedValue });
|
|
169
312
|
} catch (error) {
|
|
@@ -175,6 +318,8 @@ parentPort.on("message", async (message) => {
|
|
|
175
318
|
export interface WorkflowScriptChildResult {
|
|
176
319
|
key: string;
|
|
177
320
|
ok: boolean;
|
|
321
|
+
/** Canonical child agent name when launch resolution produced one. */
|
|
322
|
+
agent?: string;
|
|
178
323
|
runId?: string;
|
|
179
324
|
output: string;
|
|
180
325
|
error?: string;
|
|
@@ -187,6 +332,8 @@ export interface WorkflowScriptTraceEntry {
|
|
|
187
332
|
operation: "run" | "status";
|
|
188
333
|
key: string;
|
|
189
334
|
state: "started" | "completed" | "failed" | "reused";
|
|
335
|
+
/** Canonical child agent name when resolved launch or result data is available. */
|
|
336
|
+
agent?: string;
|
|
190
337
|
runId?: string;
|
|
191
338
|
durationMs?: number;
|
|
192
339
|
phase?: string;
|
|
@@ -222,6 +369,9 @@ export interface RunWorkflowScriptOptions {
|
|
|
222
369
|
get: (key: string) => unknown | Promise<unknown>;
|
|
223
370
|
set: (key: string, value: unknown) => void | Promise<void>;
|
|
224
371
|
};
|
|
372
|
+
prompts?: {
|
|
373
|
+
render: (ref: string, vars?: unknown) => string | Promise<string>;
|
|
374
|
+
};
|
|
225
375
|
onTrace?: (trace: WorkflowScriptTraceEntry[]) => void;
|
|
226
376
|
onEmit?: (emits: unknown[]) => void;
|
|
227
377
|
}
|
|
@@ -336,7 +486,8 @@ export async function runWorkflowScript(options: RunWorkflowScriptOptions): Prom
|
|
|
336
486
|
const trace: WorkflowScriptTraceEntry[] = [];
|
|
337
487
|
const children = new Map<string, WorkflowScriptChildResult>();
|
|
338
488
|
const childOrder: string[] = [];
|
|
339
|
-
const launches = new Map<string, { fingerprint: string; promise: Promise<WorkflowScriptChildResult
|
|
489
|
+
const launches = new Map<string, { fingerprint: string; promise: Promise<WorkflowScriptChildResult>; observed: boolean }>();
|
|
490
|
+
const observedRunCalls = new Set<number>();
|
|
340
491
|
const childController = new AbortController();
|
|
341
492
|
let settled = false;
|
|
342
493
|
|
|
@@ -353,8 +504,13 @@ export async function runWorkflowScript(options: RunWorkflowScriptOptions): Prom
|
|
|
353
504
|
if (timer) clearTimeout(timer);
|
|
354
505
|
options.signal?.removeEventListener("abort", onAbort);
|
|
355
506
|
void worker.terminate();
|
|
356
|
-
|
|
507
|
+
const unobservedKeys = "value" in outcome ? [...launches].filter(([, launch]) => !launch.observed).map(([key]) => key) : [];
|
|
508
|
+
const completionError = unobservedKeys.length > 0
|
|
509
|
+
? new Error(`workflowScript completed with unawaited runs.run launch(es): ${unobservedKeys.map((key) => `'${key}'`).join(", ")}. Await or return each launch.`)
|
|
510
|
+
: undefined;
|
|
511
|
+
childController.abort("error" in outcome ? outcome.error : completionError ?? new Error("Workflow script completed."));
|
|
357
512
|
if ("error" in outcome) reject(new WorkflowScriptError(outcome.error.message, partial()));
|
|
513
|
+
else if (completionError) reject(new WorkflowScriptError(completionError.message, partial()));
|
|
358
514
|
else resolve({ value: outcome.value, ...partial() });
|
|
359
515
|
};
|
|
360
516
|
const onAbort = () => finish({ error: new Error("Workflow script aborted.") });
|
|
@@ -399,6 +555,13 @@ export async function runWorkflowScript(options: RunWorkflowScriptOptions): Prom
|
|
|
399
555
|
return finish({ value: message.value });
|
|
400
556
|
}
|
|
401
557
|
if (message.type === "error") return finish({ error: new Error(typeof message.error === "string" ? message.error : "Workflow script failed.") });
|
|
558
|
+
if (message.type === "runObserved" && typeof message.callId === "number") {
|
|
559
|
+
const key = typeof message.key === "string" ? message.key : undefined;
|
|
560
|
+
const launch = key ? launches.get(key) : undefined;
|
|
561
|
+
if (launch) launch.observed = true;
|
|
562
|
+
else observedRunCalls.add(message.callId);
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
402
565
|
if (message.type !== "call" || typeof message.callId !== "number" || typeof message.method !== "string" || !isRecord(message.args)) return;
|
|
403
566
|
|
|
404
567
|
const respond = (promise: Promise<unknown>) => {
|
|
@@ -412,6 +575,17 @@ export async function runWorkflowScript(options: RunWorkflowScriptOptions): Prom
|
|
|
412
575
|
);
|
|
413
576
|
};
|
|
414
577
|
|
|
578
|
+
if (message.method === "prompts.render") {
|
|
579
|
+
if (!options.prompts) return respond(Promise.reject(new Error("Workflow prompt rendering is unavailable.")));
|
|
580
|
+
const ref = message.args.ref;
|
|
581
|
+
const vars = message.args.vars;
|
|
582
|
+
if (typeof ref !== "string" || !ref.trim()) return respond(Promise.reject(new Error("prompts.render(ref, vars) requires a non-empty ref string.")));
|
|
583
|
+
return respond(Promise.resolve().then(() => options.prompts!.render(ref, vars)).then((rendered) => {
|
|
584
|
+
if (typeof rendered !== "string") throw new Error("prompts.render must return task text.");
|
|
585
|
+
return rendered;
|
|
586
|
+
}));
|
|
587
|
+
}
|
|
588
|
+
|
|
415
589
|
if (message.method === "state.get" || message.method === "state.set") {
|
|
416
590
|
if (!options.state) return respond(Promise.reject(new Error("Workflow state is unavailable without a mission.")));
|
|
417
591
|
let key: string;
|
|
@@ -482,6 +656,7 @@ export async function runWorkflowScript(options: RunWorkflowScriptOptions): Prom
|
|
|
482
656
|
return respond(Promise.reject(new Error(`runs.run('${key}') resume requires a non-empty task follow-up.`)));
|
|
483
657
|
}
|
|
484
658
|
const collectFailure = message.args.collectFailure === true;
|
|
659
|
+
const callObserved = observedRunCalls.delete(message.callId);
|
|
485
660
|
const deliver = (promise: Promise<WorkflowScriptChildResult>) => collectFailure
|
|
486
661
|
? promise
|
|
487
662
|
: promise.then((result) => {
|
|
@@ -492,6 +667,7 @@ export async function runWorkflowScript(options: RunWorkflowScriptOptions): Prom
|
|
|
492
667
|
const existing = launches.get(key);
|
|
493
668
|
if (existing) {
|
|
494
669
|
if (existing.fingerprint !== fingerprint) return respond(Promise.reject(new Error(`Duplicate workflow key '${key}' used with incompatible launch params.`)));
|
|
670
|
+
if (callObserved) existing.observed = true;
|
|
495
671
|
trace.push({ operation: "run", key, state: "reused", ...workflowStringMetadata(params) });
|
|
496
672
|
traceChanged();
|
|
497
673
|
return respond(deliver(existing.promise));
|
|
@@ -504,7 +680,7 @@ export async function runWorkflowScript(options: RunWorkflowScriptOptions): Prom
|
|
|
504
680
|
const promise = Promise.resolve().then(() => options.launch(key, { ...params, async: params.async ?? false }, childController.signal)).then((result) => {
|
|
505
681
|
const normalized = !result.ok && !result.error ? { ...result, error: result.output } : result;
|
|
506
682
|
children.set(key, normalized);
|
|
507
|
-
trace.push({ operation: "run", key, state: normalized.ok ? "completed" : "failed", durationMs: Date.now() - startedAt, ...workflowStringMetadata(params), ...(normalized.runId ? { runId: normalized.runId } : {}), ...(!normalized.ok ? { error: normalized.error ?? normalized.output } : {}) });
|
|
683
|
+
trace.push({ operation: "run", key, state: normalized.ok ? "completed" : "failed", durationMs: Date.now() - startedAt, ...workflowStringMetadata(params), ...(normalized.agent ? { agent: normalized.agent } : {}), ...(normalized.runId ? { runId: normalized.runId } : {}), ...(!normalized.ok ? { error: normalized.error ?? normalized.output } : {}) });
|
|
508
684
|
traceChanged();
|
|
509
685
|
return normalized;
|
|
510
686
|
}, (error: unknown) => {
|
|
@@ -515,7 +691,7 @@ export async function runWorkflowScript(options: RunWorkflowScriptOptions): Prom
|
|
|
515
691
|
traceChanged();
|
|
516
692
|
return failure;
|
|
517
693
|
});
|
|
518
|
-
launches.set(key, { fingerprint, promise });
|
|
694
|
+
launches.set(key, { fingerprint, promise, observed: callObserved });
|
|
519
695
|
respond(deliver(promise));
|
|
520
696
|
});
|
|
521
697
|
|