@agwab/pi-workflow 0.3.0 → 0.4.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/README.md +3 -1
- package/dist/artifact-graph-runtime.d.ts +1 -1
- package/dist/artifact-graph-runtime.js +10 -5
- package/dist/artifact-graph-schema.js +127 -5
- package/dist/compiler.js +46 -11
- package/dist/dynamic-decision.d.ts +1 -0
- package/dist/dynamic-decision.js +7 -0
- package/dist/dynamic-generated-task-runtime.js +3 -1
- package/dist/dynamic-profiles.d.ts +1 -0
- package/dist/dynamic-profiles.js +3 -0
- package/dist/engine-run-graph.d.ts +2 -0
- package/dist/engine-run-graph.js +55 -5
- package/dist/engine.js +278 -15
- package/dist/extension.js +3 -2
- package/dist/index.d.ts +8 -0
- package/dist/index.js +4 -0
- package/dist/prompt-json.d.ts +7 -0
- package/dist/prompt-json.js +13 -0
- package/dist/roles.d.ts +1 -1
- package/dist/roles.js +5 -8
- package/dist/store.d.ts +20 -1
- package/dist/store.js +89 -29
- package/dist/strings.d.ts +11 -0
- package/dist/strings.js +24 -0
- package/dist/subagent-backend.js +557 -13
- package/dist/types.d.ts +101 -1
- package/dist/verification-ontology.d.ts +31 -0
- package/dist/verification-ontology.js +66 -0
- package/dist/workflow-artifact-tool.js +5 -6
- package/dist/workflow-artifacts.d.ts +7 -0
- package/dist/workflow-artifacts.js +55 -4
- package/dist/workflow-fetch-cache-extension.d.ts +1 -0
- package/dist/workflow-fetch-cache-extension.js +57 -9
- package/dist/workflow-metrics.d.ts +113 -0
- package/dist/workflow-metrics.js +272 -0
- package/dist/workflow-output-artifacts.js +5 -3
- package/dist/workflow-partial-output.d.ts +45 -0
- package/dist/workflow-partial-output.js +205 -0
- package/dist/workflow-progress-health.js +42 -10
- package/dist/workflow-web-source-extension.js +27 -4
- package/dist/workflow-web-source.js +26 -12
- package/docs/usage.md +76 -29
- package/node_modules/@agwab/pi-subagent/package.json +1 -1
- package/node_modules/@agwab/pi-subagent/src/index.ts +53 -5
- package/node_modules/@agwab/pi-subagent/src/panel.ts +7 -3
- package/package.json +2 -2
- package/skills/workflow-guide/SKILL.md +1 -0
- package/src/artifact-graph-runtime.ts +19 -13
- package/src/artifact-graph-schema.ts +143 -3
- package/src/cli.mjs +52 -0
- package/src/compiler.ts +49 -9
- package/src/dynamic-decision.ts +11 -0
- package/src/dynamic-generated-task-runtime.ts +3 -1
- package/src/dynamic-profiles.ts +4 -0
- package/src/engine-run-graph.ts +63 -4
- package/src/engine.ts +400 -14
- package/src/extension.ts +3 -2
- package/src/index.ts +49 -0
- package/src/prompt-json.ts +13 -0
- package/src/roles.ts +6 -9
- package/src/store.ts +123 -34
- package/src/strings.ts +38 -0
- package/src/subagent-backend.ts +727 -41
- package/src/types.ts +110 -2
- package/src/verification-ontology.ts +88 -0
- package/src/workflow-artifact-tool.ts +5 -7
- package/src/workflow-artifacts.ts +83 -3
- package/src/workflow-fetch-cache-extension.ts +78 -13
- package/src/workflow-metrics.ts +478 -0
- package/src/workflow-output-artifacts.ts +5 -3
- package/src/workflow-partial-output.ts +299 -0
- package/src/workflow-progress-health.ts +47 -15
- package/src/workflow-web-source-extension.ts +33 -4
- package/src/workflow-web-source.ts +36 -12
- package/workflows/README.md +7 -25
- package/workflows/deep-research/batched-verification.spec.json +253 -0
- package/workflows/deep-research/helpers/batch-verification-candidates.mjs +136 -0
- package/workflows/deep-research/helpers/claim-evidence-gate.mjs +173 -20
- package/workflows/deep-research/helpers/normalize-input-packet.mjs +80 -1
- package/workflows/deep-research/helpers/render-executive.mjs +32 -5
- package/workflows/deep-research/helpers/shadow-select-verification.mjs +229 -0
- package/workflows/deep-research/helpers/verification-ontology.mjs +77 -0
- package/workflows/deep-research/schemas/deep-research-executive-render-control.schema.json +3 -2
- package/workflows/deep-research/schemas/deep-research-research-questions-control.schema.json +38 -0
- package/workflows/deep-research/schemas/deep-research-sanitize-claims-control.schema.json +63 -0
- package/workflows/deep-research/schemas/deep-research-verify-claims-batch-control.schema.json +47 -0
- package/workflows/deep-research/schemas/deep-research-verify-claims-control.schema.json +10 -3
- package/workflows/deep-research/spec.json +32 -12
- package/skills/workflow-guide/scaffolds/dag-required-reads/spec.json.validate.stderr +0 -0
- package/skills/workflow-guide/scaffolds/dag-required-reads/spec.json.validate.stdout +0 -13
package/dist/engine.js
CHANGED
|
@@ -4,11 +4,12 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
4
4
|
import { Worker } from "node:worker_threads";
|
|
5
5
|
import { compileWorkflow } from "./compiler.js";
|
|
6
6
|
import { loadWorkflowSpec } from "./schema.js";
|
|
7
|
-
import { createRunRecord, createTaskRunRecord, compiledWorkflowPath, fromProjectPath, indexSupervisorErrorPath, isTerminalWorkflowStatus, isTerminalTaskStatus, listRunRecords, readIndex, readJson, readRunRecord, resetTaskForResume, setTaskTerminal, supervisorPath, toProjectPath, updateIndex, withRunLease, workflowRunPath, writeJsonAtomic, writeRunRecord, writeCompiledRunArtifact, writeStaticRunArtifacts, } from "./store.js";
|
|
7
|
+
import { createRunRecord, createTaskRunRecord, compiledWorkflowPath, fromProjectPath, indexSupervisorErrorPath, isBlockedTaskResumableForResume, isTerminalWorkflowStatus, isTerminalTaskStatus, listRunRecords, readIndex, readJson, readRunRecord, resetTaskForResume, setTaskTerminal, supervisorPath, toProjectPath, updateIndex, withRunLease, workflowRunPath, writeJsonAtomic, writeRunRecord, writeCompiledRunArtifact, writeStaticRunArtifacts, } from "./store.js";
|
|
8
8
|
import { resolveWorkflowBackend } from "./backend.js";
|
|
9
9
|
import { ensureManagedWorktree } from "./worktree.js";
|
|
10
10
|
import { resolveWorkflowHelperRef } from "./workflow-helpers.js";
|
|
11
11
|
import { buildAvailableToolView } from "./tool-metadata.js";
|
|
12
|
+
import { summarizeWorkflowTelemetry } from "./workflow-artifacts.js";
|
|
12
13
|
import { workflowBundleFingerprint, workflowBundleSpecPath, } from "./workflow-source-context-runtime.js";
|
|
13
14
|
import { readSimpleJsonPath, } from "./workflow-runtime.js";
|
|
14
15
|
import { dynamicRunDir, hashDynamicRequest, readDynamicEvents, } from "./dynamic-events.js";
|
|
@@ -18,10 +19,11 @@ import { assertDynamicRuntimeBudgetAvailable, dynamicRuntimeBudgetExceededMessag
|
|
|
18
19
|
import { assertDynamicGeneratedMetadataMatches, assertDynamicGenerationBudgetAvailable, buildDynamicGeneratedCompiledTask, dynamicGeneratedInsertIndex, isDynamicCompiledTaskPayload, normalizeDynamicAgentRequest, readDynamicGeneratedTaskResult, } from "./dynamic-generated-task-runtime.js";
|
|
19
20
|
import { optionalEventString, runDynamicHelperCall, runDynamicNestedWorkflowCall, } from "./dynamic-controller-calls.js";
|
|
20
21
|
import { normalizeDynamicFanoutPlanRequest, runDynamicDecisionLoopStatusPersistCall, runDynamicDecisionPersistCall, runDynamicFanoutPlanPersistCall, runDynamicResultReadCall, runDynamicStateIndexPersistCall, } from "./dynamic-control-ops.js";
|
|
21
|
-
import { assertRunTaskPositionalAlignment, buildForeachGeneratedTasks, dependenciesReady, markDagDependentsSkipped, nextTaskRecordIndex, reconcileDynamicGeneratedRunRecords, reconcileForeachGeneratedRunRecords, recoverStaleRunningDynamicControllers, replaceDependencyList, sourceStageIdsForFrom, stageSourcePolicy, updateDownstreamDependencies, } from "./engine-run-graph.js";
|
|
22
|
+
import { assertRunTaskPositionalAlignment, buildForeachGeneratedTasks, dependenciesReady, foreachStreamingEnabled, foreachStreamingMinChunk, markDagDependentsSkipped, nextTaskRecordIndex, reconcileDynamicGeneratedRunRecords, reconcileForeachGeneratedRunRecords, recoverStaleRunningDynamicControllers, replaceDependencyList, sourceStageIdsForFrom, stageSourcePolicy, updateDownstreamDependencies, } from "./engine-run-graph.js";
|
|
22
23
|
import { reconcileLoopTaskMaterialization, scheduleLoop, } from "./loop-runtime.js";
|
|
23
24
|
import { executeSupportTask, normalizeDynamicControllerOutput, prepareArtifactGraphRetryTask, prepareDagTask, readArtifactGraphControl, readArtifactGraphSupportSources, readSupportSources, writeArtifactGraphDynamicResult, } from "./artifact-graph-runtime.js";
|
|
24
25
|
import { DIRECT_DYNAMIC_RUNTIME_VERSION, ensureDirectDynamicRuntimeBundle, } from "./dynamic-runtime-bundle.js";
|
|
26
|
+
import { hasFatalPartialOutputIssue, readWorkflowPartialOutputLedger, writeWorkflowPartialOutputLedgerFromFile, } from "./workflow-partial-output.js";
|
|
25
27
|
import { WORKFLOW_RUN_TYPE, } from "./types.js";
|
|
26
28
|
export { buildRunSourceContext } from "./workflow-source-context-runtime.js";
|
|
27
29
|
export { evaluateLoopUntilCondition } from "./loop-runtime.js";
|
|
@@ -126,6 +128,18 @@ export async function waitForRun(cwd, runIdOrPrefix, timeoutMs, options = {}) {
|
|
|
126
128
|
}
|
|
127
129
|
return run;
|
|
128
130
|
}
|
|
131
|
+
function assertBlockedRunResumable(run) {
|
|
132
|
+
if (run.status !== "blocked")
|
|
133
|
+
return;
|
|
134
|
+
const blockers = run.tasks.filter((task) => task.status === "blocked" && !isBlockedTaskResumableForResume(task));
|
|
135
|
+
if (blockers.length === 0)
|
|
136
|
+
return;
|
|
137
|
+
const details = blockers
|
|
138
|
+
.slice(0, 3)
|
|
139
|
+
.map((task) => `${task.specId} statusDetail=${task.statusDetail}`)
|
|
140
|
+
.join(", ");
|
|
141
|
+
throw new Error(`Cannot resume blocked run ${run.runId}: non-resumable blocked task(s): ${details}. Resolve the attention/approval blocker before resuming.`);
|
|
142
|
+
}
|
|
129
143
|
export async function stopRun(cwd, runIdOrPrefix) {
|
|
130
144
|
const current = await readRunRecord(cwd, runIdOrPrefix);
|
|
131
145
|
const stopped = await withRunLease(cwd, current.runId, async () => {
|
|
@@ -160,6 +174,7 @@ export async function resumeRun(cwd, runIdOrPrefix, options = {}) {
|
|
|
160
174
|
current.status !== "blocked") {
|
|
161
175
|
throw new Error(`resume requires a failed, interrupted, or resumable blocked run; ${current.runId} is ${current.status}`);
|
|
162
176
|
}
|
|
177
|
+
assertBlockedRunResumable(current);
|
|
163
178
|
const compiledFlow = await readCompiledWorkflow(cwd, current.runId);
|
|
164
179
|
const hasLoopTasks = compiledFlow?.tasks.some((task) => task.kind === "loop" ||
|
|
165
180
|
task.loopPlaceholder !== undefined ||
|
|
@@ -170,6 +185,7 @@ export async function resumeRun(cwd, runIdOrPrefix, options = {}) {
|
|
|
170
185
|
const resetTaskIds = [];
|
|
171
186
|
const updated = await withRunLease(cwd, current.runId, async () => {
|
|
172
187
|
const run = await readRunRecord(cwd, current.runId);
|
|
188
|
+
assertBlockedRunResumable(run);
|
|
173
189
|
await resolveWorkflowBackend(run)
|
|
174
190
|
.cleanupRun(cwd, run)
|
|
175
191
|
.catch(() => undefined);
|
|
@@ -271,8 +287,19 @@ function isMissingRunError(error) {
|
|
|
271
287
|
return (isEnoentError(error) ||
|
|
272
288
|
(error instanceof Error && /^Flow run not found: /.test(error.message)));
|
|
273
289
|
}
|
|
290
|
+
function assertScheduleLeaseActive(signal) {
|
|
291
|
+
if (!signal?.aborted)
|
|
292
|
+
return;
|
|
293
|
+
const reason = signal.reason;
|
|
294
|
+
if (reason instanceof Error)
|
|
295
|
+
throw reason;
|
|
296
|
+
throw new Error(reason === undefined
|
|
297
|
+
? "Lost supervisor lease"
|
|
298
|
+
: `Lost supervisor lease: ${String(reason)}`);
|
|
299
|
+
}
|
|
274
300
|
export async function scheduleRun(cwd, runId, compiled, options = {}) {
|
|
275
|
-
return withRunLease(cwd, runId, async () => {
|
|
301
|
+
return withRunLease(cwd, runId, async (leaseSignal) => {
|
|
302
|
+
assertScheduleLeaseActive(leaseSignal);
|
|
276
303
|
let run = await readRunRecord(cwd, runId);
|
|
277
304
|
run = await resolveWorkflowBackend(run).refreshRun(cwd, run);
|
|
278
305
|
if (isTerminalWorkflowStatus(run.status))
|
|
@@ -287,7 +314,8 @@ export async function scheduleRun(cwd, runId, compiled, options = {}) {
|
|
|
287
314
|
if (compiledFlow.type !== WORKFLOW_RUN_TYPE) {
|
|
288
315
|
throw new Error(`unsupported compiled workflow type: ${compiledFlow.type}`);
|
|
289
316
|
}
|
|
290
|
-
await scheduleDag(cwd, run, compiledFlow, options);
|
|
317
|
+
await scheduleDag(cwd, run, compiledFlow, options, leaseSignal);
|
|
318
|
+
assertScheduleLeaseActive(leaseSignal);
|
|
291
319
|
run = await readRunRecord(cwd, run.runId);
|
|
292
320
|
return run;
|
|
293
321
|
});
|
|
@@ -299,13 +327,13 @@ export async function formatStatus(cwd) {
|
|
|
299
327
|
const refreshed = (await readIndex(cwd).catch(() => cached)) ?? cached;
|
|
300
328
|
if (refreshed.runs.length === 0)
|
|
301
329
|
return "No workflow runs found.";
|
|
302
|
-
return formatIndex(refreshed);
|
|
330
|
+
return formatIndex(cwd, refreshed);
|
|
303
331
|
}
|
|
304
332
|
await reconcileActiveRuns(cwd);
|
|
305
333
|
const rebuilt = await updateIndex(cwd).catch(() => readIndex(cwd));
|
|
306
334
|
if (!rebuilt || rebuilt.runs.length === 0)
|
|
307
335
|
return "No workflow runs found.";
|
|
308
|
-
return formatIndex(rebuilt);
|
|
336
|
+
return formatIndex(cwd, rebuilt);
|
|
309
337
|
}
|
|
310
338
|
export async function formatRunDetails(cwd, runIdOrPrefix) {
|
|
311
339
|
const run = await refreshRun(cwd, runIdOrPrefix);
|
|
@@ -336,10 +364,12 @@ export async function formatLogs(cwd, runIdOrPrefix, taskId = "task-1", lineCoun
|
|
|
336
364
|
return `${run.runId}/${task.taskId} output=${task.files.output}\n${tail || "(empty log)"}`;
|
|
337
365
|
}
|
|
338
366
|
export function formatRun(run, detail = "summary") {
|
|
367
|
+
const telemetry = summarizeWorkflowTelemetry(run);
|
|
339
368
|
const lines = [
|
|
340
369
|
`${run.runId} [${run.status}] type=${run.type} backend=${run.backend.type}/${run.backend.mode}`,
|
|
341
370
|
`created=${run.createdAt} updated=${run.updatedAt}`,
|
|
342
371
|
`tasks=${run.taskSummary.completed}/${run.taskSummary.total} completed, running=${run.taskSummary.running}, pending=${run.taskSummary.pending}, blocked=${run.taskSummary.blocked}, failed=${run.taskSummary.failed}, interrupted=${run.taskSummary.interrupted}`,
|
|
372
|
+
`completion=${telemetry.completion.health}, outputRetries=${telemetry.retryCounts.output}, launchRetries=${telemetry.retryCounts.launch}, resumeEvents=${telemetry.resumeCounts.events}, contextLimitFailures=${telemetry.completion.contextLimitFailures}`,
|
|
343
373
|
];
|
|
344
374
|
for (const task of run.tasks) {
|
|
345
375
|
lines.push(formatTask(task, detail));
|
|
@@ -372,7 +402,8 @@ async function recordSupervisorError(cwd, runId, error) {
|
|
|
372
402
|
error: error instanceof Error ? error.message : String(error),
|
|
373
403
|
}).catch(() => undefined);
|
|
374
404
|
}
|
|
375
|
-
async function scheduleDag(cwd, run, compiledFlow, options = {}) {
|
|
405
|
+
async function scheduleDag(cwd, run, compiledFlow, options = {}, leaseSignal) {
|
|
406
|
+
assertScheduleLeaseActive(leaseSignal);
|
|
376
407
|
if (compiledFlow.type === WORKFLOW_RUN_TYPE) {
|
|
377
408
|
const loopReconciled = await reconcileLoopTaskMaterialization(cwd, run, compiledFlow);
|
|
378
409
|
if (loopReconciled)
|
|
@@ -398,6 +429,7 @@ async function scheduleDag(cwd, run, compiledFlow, options = {}) {
|
|
|
398
429
|
let running = run.tasks.filter((task) => task.status === "running").length;
|
|
399
430
|
const bySpecId = new Map(run.tasks.map((task) => [task.specId, task]));
|
|
400
431
|
for (let index = 0; index < run.tasks.length && running < maxConcurrency; index += 1) {
|
|
432
|
+
assertScheduleLeaseActive(leaseSignal);
|
|
401
433
|
const task = run.tasks[index];
|
|
402
434
|
const compiledTask = compiledFlow.tasks[index];
|
|
403
435
|
if (!task || !compiledTask || task.status !== "pending")
|
|
@@ -417,6 +449,8 @@ async function scheduleDag(cwd, run, compiledFlow, options = {}) {
|
|
|
417
449
|
const changed = await materializeForeachTask(cwd, run, compiledFlow, index, compiledTask);
|
|
418
450
|
if (changed)
|
|
419
451
|
return;
|
|
452
|
+
if (foreachStreamingEnabled(compiledTask))
|
|
453
|
+
continue;
|
|
420
454
|
}
|
|
421
455
|
if (compiledTask.stageMaxConcurrency !== undefined) {
|
|
422
456
|
const runningInStage = run.tasks.filter((candidate) => candidate.stageId === compiledTask.stageId &&
|
|
@@ -425,7 +459,9 @@ async function scheduleDag(cwd, run, compiledFlow, options = {}) {
|
|
|
425
459
|
Math.max(1, Math.min(MAX_CONCURRENCY, compiledTask.stageMaxConcurrency)))
|
|
426
460
|
continue;
|
|
427
461
|
}
|
|
462
|
+
assertScheduleLeaseActive(leaseSignal);
|
|
428
463
|
const launched = await launchPendingTaskAt(cwd, run, compiledFlow, index, options);
|
|
464
|
+
assertScheduleLeaseActive(leaseSignal);
|
|
429
465
|
if (launched && run.tasks[index]?.status === "running")
|
|
430
466
|
running += 1;
|
|
431
467
|
}
|
|
@@ -505,10 +541,12 @@ async function materializeForeachTask(cwd, run, compiledFlow, index, template) {
|
|
|
505
541
|
return false;
|
|
506
542
|
const sourceStageIds = sourceStageIdsForFrom(template.foreach.from);
|
|
507
543
|
const sourceTasks = run.tasks.filter((task) => sourceStageIds.includes(task.stageId ?? ""));
|
|
544
|
+
const streaming = foreachStreamingEnabled(template);
|
|
508
545
|
const extracted = await extractArtifactGraphForeachItems(cwd, {
|
|
509
546
|
from: template.foreach.from,
|
|
510
547
|
sourcePolicy: stageSourcePolicy(compiledFlow, template.stageId),
|
|
511
548
|
maxItems: template.foreach.maxItems,
|
|
549
|
+
streaming,
|
|
512
550
|
}, sourceTasks);
|
|
513
551
|
if (extracted.error) {
|
|
514
552
|
setTaskTerminal(templateRunTask, "blocked", "foreach_expansion_blocked", {
|
|
@@ -527,6 +565,21 @@ async function materializeForeachTask(cwd, run, compiledFlow, index, template) {
|
|
|
527
565
|
return true;
|
|
528
566
|
}
|
|
529
567
|
const placeholderSpecId = template.id;
|
|
568
|
+
if (streaming) {
|
|
569
|
+
return await materializeStreamingForeachTask({
|
|
570
|
+
cwd,
|
|
571
|
+
run,
|
|
572
|
+
compiledFlow,
|
|
573
|
+
index,
|
|
574
|
+
templateRunTask,
|
|
575
|
+
placeholderSpecId,
|
|
576
|
+
sourceTaskSpecIds: sourceTasks.map((task) => task.specId),
|
|
577
|
+
itemMetas: extracted.itemMetas ?? [],
|
|
578
|
+
generatedTasks: generated.tasks,
|
|
579
|
+
waitingForSources: extracted.waitingForSources ?? false,
|
|
580
|
+
minChunk: foreachStreamingMinChunk(template),
|
|
581
|
+
});
|
|
582
|
+
}
|
|
530
583
|
const generatedSpecIds = generated.tasks.map((task) => task.id);
|
|
531
584
|
const hasDownstreamDependents = compiledFlow.tasks.some((task, taskIndex) => taskIndex !== index && (task.dependsOn ?? []).includes(placeholderSpecId));
|
|
532
585
|
if (generatedSpecIds.length === 0 && !hasDownstreamDependents) {
|
|
@@ -550,16 +603,183 @@ async function materializeForeachTask(cwd, run, compiledFlow, index, template) {
|
|
|
550
603
|
await writeRunRecord(cwd, run);
|
|
551
604
|
return true;
|
|
552
605
|
}
|
|
606
|
+
async function materializeStreamingForeachTask(input) {
|
|
607
|
+
const sourceTaskSpecIdSet = new Set(input.sourceTaskSpecIds);
|
|
608
|
+
const generatedTasksWithItemDeps = input.generatedTasks.map((task, index) => {
|
|
609
|
+
const itemMeta = input.itemMetas[index];
|
|
610
|
+
if (!itemMeta)
|
|
611
|
+
return task;
|
|
612
|
+
return {
|
|
613
|
+
...task,
|
|
614
|
+
dependsOn: replaceSourceDependenciesWithItemSource(task.dependsOn ?? [], sourceTaskSpecIdSet, itemMeta, {
|
|
615
|
+
keepPartialSourceDependency: partialGeneratedTaskNeedsCompletedSourceContext(task),
|
|
616
|
+
}),
|
|
617
|
+
foreachGenerated: {
|
|
618
|
+
...(task.foreachGenerated ?? {
|
|
619
|
+
placeholderSpecId: input.placeholderSpecId,
|
|
620
|
+
}),
|
|
621
|
+
itemHash: itemMeta.itemHash,
|
|
622
|
+
itemSourceSpecId: itemMeta.sourceSpecId,
|
|
623
|
+
itemSourceKind: itemMeta.sourceKind,
|
|
624
|
+
itemRef: itemMeta.itemRef,
|
|
625
|
+
},
|
|
626
|
+
};
|
|
627
|
+
});
|
|
628
|
+
const existingGeneratedTasks = input.compiledFlow.tasks.filter((task) => task.foreachGenerated?.placeholderSpecId === input.placeholderSpecId);
|
|
629
|
+
const existingGeneratedSpecIds = existingGeneratedTasks.map((task) => task.id);
|
|
630
|
+
const existingGeneratedTaskBySpecId = new Map(existingGeneratedTasks.map((task) => [task.id, task]));
|
|
631
|
+
for (const task of generatedTasksWithItemDeps) {
|
|
632
|
+
const existing = existingGeneratedTaskBySpecId.get(task.id);
|
|
633
|
+
const existingHash = existing?.foreachGenerated?.itemHash;
|
|
634
|
+
const nextHash = task.foreachGenerated?.itemHash;
|
|
635
|
+
if (existing && existingHash && nextHash && existingHash !== nextHash) {
|
|
636
|
+
setTaskTerminal(input.templateRunTask, "blocked", "foreach_expansion_blocked", {
|
|
637
|
+
lastMessage: `foreach streaming item ${task.id} changed after materialization`,
|
|
638
|
+
});
|
|
639
|
+
await writeRunRecord(input.cwd, input.run);
|
|
640
|
+
return true;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
const existingGeneratedSpecIdSet = new Set(existingGeneratedSpecIds);
|
|
644
|
+
const finalGeneratedSpecIdSet = new Set(generatedTasksWithItemDeps.map((task) => task.id));
|
|
645
|
+
if (!input.waitingForSources) {
|
|
646
|
+
const withdrawn = existingGeneratedTasks.find((task) => task.foreachGenerated?.itemSourceKind === "partial" &&
|
|
647
|
+
!finalGeneratedSpecIdSet.has(task.id));
|
|
648
|
+
if (withdrawn) {
|
|
649
|
+
setTaskTerminal(input.templateRunTask, "blocked", "foreach_expansion_blocked", {
|
|
650
|
+
lastMessage: `foreach streaming item ${withdrawn.id} was published as partial output but is missing from final control`,
|
|
651
|
+
});
|
|
652
|
+
await writeRunRecord(input.cwd, input.run);
|
|
653
|
+
return true;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
const newGeneratedTasks = generatedTasksWithItemDeps.filter((task) => !existingGeneratedSpecIdSet.has(task.id));
|
|
657
|
+
const allGeneratedSpecIds = [
|
|
658
|
+
...existingGeneratedSpecIds,
|
|
659
|
+
...newGeneratedTasks.map((task) => task.id),
|
|
660
|
+
];
|
|
661
|
+
const shouldHoldForMinChunk = input.waitingForSources &&
|
|
662
|
+
newGeneratedTasks.length > 0 &&
|
|
663
|
+
newGeneratedTasks.length < input.minChunk;
|
|
664
|
+
if (shouldHoldForMinChunk)
|
|
665
|
+
return false;
|
|
666
|
+
let changed = false;
|
|
667
|
+
if (newGeneratedTasks.length > 0) {
|
|
668
|
+
let compiledInsertIndex = input.index + 1;
|
|
669
|
+
while (input.compiledFlow.tasks[compiledInsertIndex]?.foreachGenerated
|
|
670
|
+
?.placeholderSpecId === input.placeholderSpecId) {
|
|
671
|
+
compiledInsertIndex += 1;
|
|
672
|
+
}
|
|
673
|
+
input.compiledFlow.tasks.splice(compiledInsertIndex, 0, ...newGeneratedTasks);
|
|
674
|
+
let runInsertIndex = input.index + 1;
|
|
675
|
+
while (input.run.tasks[runInsertIndex]?.foreachGenerated?.placeholderSpecId ===
|
|
676
|
+
input.placeholderSpecId) {
|
|
677
|
+
runInsertIndex += 1;
|
|
678
|
+
}
|
|
679
|
+
const nextIndex = nextTaskRecordIndex(input.run);
|
|
680
|
+
const generatedRunTasks = newGeneratedTasks.map((task, offset) => createTaskRunRecord(input.cwd, input.run.runId, task, nextIndex + offset));
|
|
681
|
+
input.run.tasks.splice(runInsertIndex, 0, ...generatedRunTasks);
|
|
682
|
+
changed = true;
|
|
683
|
+
}
|
|
684
|
+
const dependencyTargets = [input.placeholderSpecId, ...allGeneratedSpecIds];
|
|
685
|
+
for (const task of input.compiledFlow.tasks) {
|
|
686
|
+
if (!task.dependsOn)
|
|
687
|
+
continue;
|
|
688
|
+
const replaced = replaceDependencyList(task.dependsOn, input.placeholderSpecId, dependencyTargets);
|
|
689
|
+
if (JSON.stringify(task.dependsOn) !== JSON.stringify(replaced)) {
|
|
690
|
+
task.dependsOn = replaced;
|
|
691
|
+
changed = true;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
for (const task of input.run.tasks) {
|
|
695
|
+
if (!task.dependsOn)
|
|
696
|
+
continue;
|
|
697
|
+
const replaced = replaceDependencyList(task.dependsOn, input.placeholderSpecId, dependencyTargets);
|
|
698
|
+
if (JSON.stringify(task.dependsOn) !== JSON.stringify(replaced)) {
|
|
699
|
+
task.dependsOn = replaced;
|
|
700
|
+
changed = true;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (!input.waitingForSources) {
|
|
704
|
+
const statusDetail = allGeneratedSpecIds.length === 0
|
|
705
|
+
? "foreach_empty"
|
|
706
|
+
: "foreach_streaming_complete";
|
|
707
|
+
const lastMessage = allGeneratedSpecIds.length === 0
|
|
708
|
+
? "foreach produced 0 item(s)"
|
|
709
|
+
: `foreach streaming materialized ${allGeneratedSpecIds.length} item(s)`;
|
|
710
|
+
setTaskTerminal(input.templateRunTask, "completed", statusDetail, {
|
|
711
|
+
lastMessage,
|
|
712
|
+
});
|
|
713
|
+
changed = true;
|
|
714
|
+
}
|
|
715
|
+
else if (newGeneratedTasks.length > 0) {
|
|
716
|
+
input.templateRunTask.statusDetail = "foreach_streaming_waiting";
|
|
717
|
+
input.templateRunTask.lastMessage = `foreach streaming materialized ${allGeneratedSpecIds.length} item(s); waiting for more source tasks`;
|
|
718
|
+
changed = true;
|
|
719
|
+
}
|
|
720
|
+
if (!changed)
|
|
721
|
+
return false;
|
|
722
|
+
await writeJsonAtomic(compiledWorkflowPath(input.cwd, input.run.runId), input.compiledFlow);
|
|
723
|
+
await writeRunRecord(input.cwd, input.run);
|
|
724
|
+
return true;
|
|
725
|
+
}
|
|
726
|
+
function replaceSourceDependenciesWithItemSource(dependsOn, sourceTaskSpecIds, itemMeta, options = {}) {
|
|
727
|
+
const replaced = [];
|
|
728
|
+
let inserted = false;
|
|
729
|
+
const shouldReplaceWithSource = itemMeta.sourceKind !== "partial" ||
|
|
730
|
+
options.keepPartialSourceDependency === true;
|
|
731
|
+
for (const dep of dependsOn) {
|
|
732
|
+
if (!sourceTaskSpecIds.has(dep)) {
|
|
733
|
+
replaced.push(dep);
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
if (!shouldReplaceWithSource)
|
|
737
|
+
continue;
|
|
738
|
+
if (!inserted) {
|
|
739
|
+
replaced.push(itemMeta.sourceSpecId);
|
|
740
|
+
inserted = true;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
if (!inserted && shouldReplaceWithSource) {
|
|
744
|
+
replaced.push(itemMeta.sourceSpecId);
|
|
745
|
+
}
|
|
746
|
+
return [...new Set(replaced)];
|
|
747
|
+
}
|
|
748
|
+
function partialGeneratedTaskNeedsCompletedSourceContext(task) {
|
|
749
|
+
const artifactGraph = task.artifactGraph;
|
|
750
|
+
if (artifactGraph?.artifactAccess === "none")
|
|
751
|
+
return false;
|
|
752
|
+
return Boolean(artifactGraph?.sourceProjection !== undefined ||
|
|
753
|
+
(artifactGraph?.requiredReads?.length ?? 0) > 0);
|
|
754
|
+
}
|
|
553
755
|
async function extractArtifactGraphForeachItems(cwd, stage, sourceTasks) {
|
|
554
756
|
const items = [];
|
|
757
|
+
const itemMetas = [];
|
|
555
758
|
const path = stage.from?.path;
|
|
556
759
|
if (typeof path !== "string" || !path.startsWith("$.")) {
|
|
557
760
|
return {
|
|
558
761
|
error: "foreach.from.path must be a control JSONPath like $.items",
|
|
559
762
|
};
|
|
560
763
|
}
|
|
764
|
+
let waitingForSources = false;
|
|
561
765
|
for (const task of sourceTasks) {
|
|
562
766
|
if (task.status !== "completed") {
|
|
767
|
+
if (stage.streaming && !isTerminalTaskStatus(task.status)) {
|
|
768
|
+
const partial = await extractPartialForeachItems(cwd, task, path);
|
|
769
|
+
if (partial.error)
|
|
770
|
+
return { error: partial.error };
|
|
771
|
+
for (const item of partial.items) {
|
|
772
|
+
items.push(item.item);
|
|
773
|
+
itemMetas.push({
|
|
774
|
+
sourceSpecId: task.specId,
|
|
775
|
+
sourceKind: "partial",
|
|
776
|
+
itemHash: item.itemHash,
|
|
777
|
+
itemRef: `${task.specId}:${item.itemRef}`,
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
waitingForSources = true;
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
563
783
|
if (stage.sourcePolicy !== "partial")
|
|
564
784
|
return { error: `${task.taskId} did not complete` };
|
|
565
785
|
continue;
|
|
@@ -575,7 +795,15 @@ async function extractArtifactGraphForeachItems(cwd, stage, sourceTasks) {
|
|
|
575
795
|
}
|
|
576
796
|
continue;
|
|
577
797
|
}
|
|
578
|
-
|
|
798
|
+
for (const [index, item] of value.entries()) {
|
|
799
|
+
items.push(item);
|
|
800
|
+
itemMetas.push({
|
|
801
|
+
sourceSpecId: task.specId,
|
|
802
|
+
sourceKind: "control",
|
|
803
|
+
itemHash: hashDynamicRequest(item),
|
|
804
|
+
itemRef: `${task.specId}:control:${path}[${index}]`,
|
|
805
|
+
});
|
|
806
|
+
}
|
|
579
807
|
}
|
|
580
808
|
catch (error) {
|
|
581
809
|
if (stage.sourcePolicy !== "partial") {
|
|
@@ -590,7 +818,27 @@ async function extractArtifactGraphForeachItems(cwd, stage, sourceTasks) {
|
|
|
590
818
|
error: `foreach extracted ${items.length} items, exceeding maxItems=${stage.maxItems}`,
|
|
591
819
|
};
|
|
592
820
|
}
|
|
593
|
-
return { items };
|
|
821
|
+
return { items, itemMetas, waitingForSources };
|
|
822
|
+
}
|
|
823
|
+
async function extractPartialForeachItems(cwd, task, path) {
|
|
824
|
+
const partialPaths = task.artifactGraph?.output.partial?.paths ?? [];
|
|
825
|
+
if (!partialPaths.includes(path))
|
|
826
|
+
return { items: [] };
|
|
827
|
+
const taskDir = dirname(fromProjectPath(cwd, task.files.result));
|
|
828
|
+
let ledger = await readWorkflowPartialOutputLedger(taskDir).catch(() => undefined);
|
|
829
|
+
if (!ledger) {
|
|
830
|
+
ledger = await writeWorkflowPartialOutputLedgerFromFile({
|
|
831
|
+
taskDir,
|
|
832
|
+
outputFile: fromProjectPath(cwd, task.files.output),
|
|
833
|
+
allowedPaths: partialPaths,
|
|
834
|
+
}).catch(() => undefined);
|
|
835
|
+
}
|
|
836
|
+
if (!ledger)
|
|
837
|
+
return { items: [] };
|
|
838
|
+
const fatal = hasFatalPartialOutputIssue(ledger);
|
|
839
|
+
if (fatal)
|
|
840
|
+
return { items: [], error: fatal.message };
|
|
841
|
+
return { items: ledger.items.filter((item) => item.path === path) };
|
|
594
842
|
}
|
|
595
843
|
async function launchPendingTaskAt(cwd, run, compiledFlow, index, options = {}) {
|
|
596
844
|
const task = run.tasks[index];
|
|
@@ -1900,21 +2148,36 @@ function uniqueStrings(values) {
|
|
|
1900
2148
|
async function readCompiledWorkflow(cwd, runId) {
|
|
1901
2149
|
return readJson(compiledWorkflowPath(cwd, runId));
|
|
1902
2150
|
}
|
|
1903
|
-
function formatIndex(index) {
|
|
1904
|
-
|
|
1905
|
-
.map((run) => {
|
|
2151
|
+
async function formatIndex(cwd, index) {
|
|
2152
|
+
const blocks = await Promise.all(index.runs.map(async (run) => {
|
|
1906
2153
|
const lines = [
|
|
1907
2154
|
`${run.runId} [${run.status}] type=${run.type} updated=${run.updatedAt}`,
|
|
1908
2155
|
`tasks=${run.taskSummary.completed}/${run.taskSummary.total} completed, running=${run.taskSummary.running}, pending=${run.taskSummary.pending}, blocked=${run.taskSummary.blocked}, failed=${run.taskSummary.failed}, skipped=${run.taskSummary.skipped}, interrupted=${run.taskSummary.interrupted}`,
|
|
1909
2156
|
];
|
|
1910
|
-
for (const task of run
|
|
2157
|
+
for (const task of await indexTasksForStatus(cwd, run)) {
|
|
1911
2158
|
const message = task.lastMessage ? ` — ${task.lastMessage}` : "";
|
|
1912
2159
|
const kind = task.kind && task.kind !== "main" ? ` ${task.kind}` : "";
|
|
1913
2160
|
lines.push(`- ${task.taskId}${kind} ${task.agent} [${task.status}/${task.statusDetail}]${message}`);
|
|
1914
2161
|
}
|
|
1915
2162
|
return lines.join("\n");
|
|
1916
|
-
})
|
|
1917
|
-
|
|
2163
|
+
}));
|
|
2164
|
+
return blocks.join("\n\n");
|
|
2165
|
+
}
|
|
2166
|
+
async function indexTasksForStatus(cwd, run) {
|
|
2167
|
+
if (Array.isArray(run.tasks))
|
|
2168
|
+
return run.tasks;
|
|
2169
|
+
const fullRun = await readRunRecord(cwd, run.runId).catch(() => undefined);
|
|
2170
|
+
return (fullRun?.tasks.map((task) => ({
|
|
2171
|
+
taskId: task.taskId,
|
|
2172
|
+
displayName: task.displayName,
|
|
2173
|
+
agent: task.agent,
|
|
2174
|
+
kind: task.kind,
|
|
2175
|
+
stageId: task.stageId,
|
|
2176
|
+
backendHandle: task.backendHandle,
|
|
2177
|
+
status: task.status,
|
|
2178
|
+
statusDetail: task.statusDetail,
|
|
2179
|
+
lastMessage: task.lastMessage,
|
|
2180
|
+
})) ?? []);
|
|
1918
2181
|
}
|
|
1919
2182
|
function formatTask(task, detail) {
|
|
1920
2183
|
const elapsed = task.elapsedMs !== undefined
|
package/dist/extension.js
CHANGED
|
@@ -73,7 +73,7 @@ const WORKFLOW_DYNAMIC_TOOL_PARAMETERS = {
|
|
|
73
73
|
};
|
|
74
74
|
export default function workflowExtension(pi) {
|
|
75
75
|
let workflowCompletionCache = [];
|
|
76
|
-
pi.on("session_start", async (
|
|
76
|
+
pi.on("session_start", async (event, ctx) => {
|
|
77
77
|
if (!isWorkflowSupervisorEnabled())
|
|
78
78
|
return;
|
|
79
79
|
workflowCompletionCache = await listWorkflows(ctx.cwd).catch(() => workflowCompletionCache);
|
|
@@ -81,7 +81,8 @@ export default function workflowExtension(pi) {
|
|
|
81
81
|
dynamicUi: dynamicUiFromContext(ctx),
|
|
82
82
|
}).catch(() => undefined);
|
|
83
83
|
await notifyUnfinishedRuns(ctx.cwd, (message, type) => ctx.ui.notify(message, type)).catch(() => undefined);
|
|
84
|
-
|
|
84
|
+
if (event.reason !== "reload")
|
|
85
|
+
await deliverMissedWorkflowFeedback(ctx, pi).catch(() => undefined);
|
|
85
86
|
});
|
|
86
87
|
registerWorkflowNaturalLanguageTools(pi);
|
|
87
88
|
pi.registerCommand(WORKFLOW_COMMAND, {
|
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,13 @@ export type { AgentDefinition, ApprovalMode, BackendOptions, CompiledWorkflow, C
|
|
|
10
10
|
export { WorkflowValidationError } from "./types.js";
|
|
11
11
|
export { runDynamicDecisionLoop } from "./dynamic-decision-loop.js";
|
|
12
12
|
export type { DynamicDecisionLoopControllerContext, DynamicDecisionLoopResult, DynamicDecisionLoopRunResult, RunDynamicDecisionLoopOptions, } from "./dynamic-decision-loop.js";
|
|
13
|
+
export { assertValidDynamicDecision, validateDynamicDecision, } from "./dynamic-decision.js";
|
|
14
|
+
export type { DynamicDecisionAction, DynamicDecisionPhase, DynamicDecisionStatus, DynamicDecisionValidationContext, DynamicDecisionValidationResult, NormalizedDynamicDecision, } from "./dynamic-decision.js";
|
|
15
|
+
export { dynamicOutputProfileValues } from "./dynamic-profiles.js";
|
|
16
|
+
export type { DynamicOutputProfile } from "./dynamic-profiles.js";
|
|
17
|
+
export { buildWorkflowRunMetrics, WORKFLOW_METRICS_PRICING_MODEL_VERSION, WORKFLOW_METRICS_SCHEMA_VERSION, } from "./workflow-metrics.js";
|
|
18
|
+
export { VERIFICATION_STATUS, VERIFICATION_STATUS_BUCKETS, VERIFICATION_STATUS_LABELS, VERIFICATION_STATUS_VALUES, canonicalVerificationStatus, isNonVerifiedTerminalStatus, isVerificationBlockedStatus, isVerifiedStatus, verificationStatusBucket, } from "./verification-ontology.js";
|
|
19
|
+
export type { TerminalVerificationStatus, VerificationStatus, } from "./verification-ontology.js";
|
|
20
|
+
export type { WorkflowLaunchTimingMetrics, WorkflowMetricValue, WorkflowMetricsPricingModelVersion, WorkflowMetricsPricingSource, WorkflowMetricsSchemaVersion, WorkflowRetryMetrics, WorkflowRunMetrics, WorkflowRunMetricsMetadata, WorkflowRunMetricsRollup, WorkflowStageMetrics, WorkflowTaskMetrics, WorkflowTaskStatusCounts, WorkflowUsageMetrics, } from "./workflow-metrics.js";
|
|
13
21
|
export declare const WORKFLOW_COMMAND = "workflow";
|
|
14
22
|
export declare const WORKFLOW_HELP = "pi-workflow\n\nUsage:\n /workflow [run-id]\n /workflow help\n /workflow validate <workflow-name-or-path>\n /workflow roles <workflow-name-or-path>\n /workflow agents\n /workflow list\n /workflow run [--model MODEL] [--thinking LEVEL] <workflow-name-or-path> \"<task>\" [--detach]\n /workflow dynamic [--model MODEL] [--thinking LEVEL] \"<task>\" [--detach]\n /workflow status [run-id]\n /workflow show <run-id-or-workflow-name>\n /workflow logs <run-id> [task-id] [lines]\n /workflow wait <run-id> [timeout-ms]\n /workflow resume <run-id>\n /workflow stop <run-id>\n\n/workflow opens the read-only workflow board TUI.\n/workflow <run-id> opens the board focused on that run.\n/workflow dynamic starts a spec-less direct dynamic run: no workflow name,\nuser-selected spec, or generated workflow spec is required.\n\nWith --detach, a standalone supervisor process (pi-workflow supervise) keeps\nthe run progressing after this session exits.\n";
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,10 @@ export { loadWorkflow, loadWorkflowSpec, parseWorkflow } from "./schema.js";
|
|
|
6
6
|
export { parseArtifactGraphWorkflowSpec } from "./artifact-graph-schema.js";
|
|
7
7
|
export { WorkflowValidationError } from "./types.js";
|
|
8
8
|
export { runDynamicDecisionLoop } from "./dynamic-decision-loop.js";
|
|
9
|
+
export { assertValidDynamicDecision, validateDynamicDecision, } from "./dynamic-decision.js";
|
|
10
|
+
export { dynamicOutputProfileValues } from "./dynamic-profiles.js";
|
|
11
|
+
export { buildWorkflowRunMetrics, WORKFLOW_METRICS_PRICING_MODEL_VERSION, WORKFLOW_METRICS_SCHEMA_VERSION, } from "./workflow-metrics.js";
|
|
12
|
+
export { VERIFICATION_STATUS, VERIFICATION_STATUS_BUCKETS, VERIFICATION_STATUS_LABELS, VERIFICATION_STATUS_VALUES, canonicalVerificationStatus, isNonVerifiedTerminalStatus, isVerificationBlockedStatus, isVerifiedStatus, verificationStatusBucket, } from "./verification-ontology.js";
|
|
9
13
|
export const WORKFLOW_COMMAND = "workflow";
|
|
10
14
|
export const WORKFLOW_HELP = `pi-workflow
|
|
11
15
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialize JSON embedded directly in prompts/model context.
|
|
3
|
+
*
|
|
4
|
+
* Persisted artifacts can stay pretty-printed for humans, but prompt context
|
|
5
|
+
* should avoid indentation bytes when the JSON data is otherwise identical.
|
|
6
|
+
*/
|
|
7
|
+
export declare function stringifyPromptJson(value: unknown): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialize JSON embedded directly in prompts/model context.
|
|
3
|
+
*
|
|
4
|
+
* Persisted artifacts can stay pretty-printed for humans, but prompt context
|
|
5
|
+
* should avoid indentation bytes when the JSON data is otherwise identical.
|
|
6
|
+
*/
|
|
7
|
+
export function stringifyPromptJson(value) {
|
|
8
|
+
const serialized = JSON.stringify(value);
|
|
9
|
+
if (serialized === undefined) {
|
|
10
|
+
throw new TypeError("prompt JSON value must be JSON-serializable");
|
|
11
|
+
}
|
|
12
|
+
return serialized;
|
|
13
|
+
}
|
package/dist/roles.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AgentDefinition, CompiledRole, RoleSpec } from "./types.js";
|
|
1
|
+
import type { AgentDefinition, CompiledRole, RoleSpec } from "./types.js";
|
|
2
2
|
export declare const DEFAULT_SAFE_SECTIONS: readonly ["Core Principles", "Domain Expertise", "Safety Review", "Rules", "Research Manifest"];
|
|
3
3
|
export declare function compileRole(name: string, spec: RoleSpec, sourceAgent?: AgentDefinition): CompiledRole;
|
|
4
4
|
export declare function extractMarkdownSections(markdown: string, includeSections: readonly string[], excludeSections: readonly string[]): string;
|
package/dist/roles.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { compactStrings } from "./strings.js";
|
|
1
2
|
export const DEFAULT_SAFE_SECTIONS = [
|
|
2
3
|
"Core Principles",
|
|
3
4
|
"Domain Expertise",
|
|
@@ -19,14 +20,10 @@ export function compileRole(name, spec, sourceAgent) {
|
|
|
19
20
|
const maxChars = spec.maxChars ?? DEFAULT_MAX_ROLE_CHARS;
|
|
20
21
|
const includeSections = spec.includeSections ?? [...DEFAULT_SAFE_SECTIONS];
|
|
21
22
|
const excludedSections = [...ALWAYS_EXCLUDED_SECTIONS, ...(spec.excludeSections ?? [])];
|
|
22
|
-
const parts = [
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
parts.push(extracted.trim());
|
|
27
|
-
}
|
|
28
|
-
if (spec.prompt?.trim())
|
|
29
|
-
parts.push(spec.prompt.trim());
|
|
23
|
+
const parts = compactStrings([
|
|
24
|
+
sourceAgent ? extractMarkdownSections(sourceAgent.body, includeSections, excludedSections) : undefined,
|
|
25
|
+
spec.prompt,
|
|
26
|
+
], { unique: false });
|
|
30
27
|
const fullContent = parts.join("\n\n");
|
|
31
28
|
const truncated = fullContent.length > maxChars;
|
|
32
29
|
return {
|
package/dist/store.d.ts
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
import { type CompiledWorkflow, type CompiledTask, type WorkflowIndexRecord, type WorkflowRunRecord, type WorkflowRunStatus, type WorkflowTaskRunRecord, type TaskRunStatus, type TaskSummary } from "./types.js";
|
|
2
|
+
type RunLeaseTestHooks = {
|
|
3
|
+
heartbeatIntervalMs?: number;
|
|
4
|
+
onAfterReclaimRename?: (context: {
|
|
5
|
+
lockFile: string;
|
|
6
|
+
reclaimFile: string;
|
|
7
|
+
}) => void | Promise<void>;
|
|
8
|
+
onBeforeRestoreReclaimFile?: (context: {
|
|
9
|
+
lockFile: string;
|
|
10
|
+
reclaimFile: string;
|
|
11
|
+
}) => void | Promise<void>;
|
|
12
|
+
onBeforeReleaseLockRename?: (context: {
|
|
13
|
+
lockFile: string;
|
|
14
|
+
releaseFile: string;
|
|
15
|
+
ownerId: string;
|
|
16
|
+
}) => void | Promise<void>;
|
|
17
|
+
};
|
|
2
18
|
export declare function nowIso(): string;
|
|
3
19
|
export declare function makeRunId(): string;
|
|
4
20
|
export declare function workflowsRoot(cwd: string): string;
|
|
@@ -15,7 +31,8 @@ export declare function fromProjectPath(cwd: string, filePath: string): string;
|
|
|
15
31
|
export declare function ensureDir(dir: string): Promise<void>;
|
|
16
32
|
export declare function readJson<T>(file: string): Promise<T | undefined>;
|
|
17
33
|
export declare function writeJsonAtomic(file: string, value: unknown): Promise<void>;
|
|
18
|
-
export declare function
|
|
34
|
+
export declare function setRunLeaseTestHooksForTests(hooks?: RunLeaseTestHooks): void;
|
|
35
|
+
export declare function withRunLease<T>(cwd: string, runId: string, action: (abortSignal: AbortSignal) => Promise<T>): Promise<T | undefined>;
|
|
19
36
|
export declare function createRunRecord(cwd: string, compiled: CompiledWorkflow, specPath: string, options?: {
|
|
20
37
|
runId?: string;
|
|
21
38
|
parentRunId?: string;
|
|
@@ -44,6 +61,7 @@ export declare function setTaskTerminal(task: WorkflowTaskRunRecord, status: Tas
|
|
|
44
61
|
exitCode?: number;
|
|
45
62
|
lastMessage?: string;
|
|
46
63
|
}): boolean;
|
|
64
|
+
export declare function isBlockedTaskResumableForResume(task: Pick<WorkflowTaskRunRecord, "status" | "statusDetail">): boolean;
|
|
47
65
|
export declare function resetTaskForResume(task: WorkflowTaskRunRecord): boolean;
|
|
48
66
|
export declare function createTaskRunRecord(cwd: string, runId: string, task: CompiledTask, index: number): WorkflowTaskRunRecord;
|
|
49
67
|
export declare function resolveFlowsCwd(cwd: string): Promise<string>;
|
|
@@ -56,3 +74,4 @@ export declare function workflowSupervisorOwnerIdForTests(): string;
|
|
|
56
74
|
export declare function workflowProcessRoleForTests(): string;
|
|
57
75
|
export declare function acquireSupervisorLease(cwd: string, runId: string): Promise<boolean>;
|
|
58
76
|
export declare function heartbeatSupervisorLease(cwd: string, runId: string): Promise<boolean>;
|
|
77
|
+
export {};
|