@abelxiaoxing/cadence 1.2.1 → 1.2.3
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 +7 -1
- package/agents/diagnosis-worker.md +6 -2
- package/agents/implementation-worker.md +9 -2
- package/config/routes.example.json +0 -1
- package/package.json +1 -1
- package/prompts/abel-design.md +15 -4
- package/skills/abel-workflow/SKILL.md +5 -3
- package/src/apply-transaction.ts +1 -5
- package/src/child-session.ts +37 -46
- package/src/contracts.ts +278 -32
- package/src/control-contracts.ts +62 -0
- package/src/delivery-compiler.ts +239 -124
- package/src/design-control.ts +72 -27
- package/src/design-journal.ts +2 -2
- package/src/file-snapshot.ts +1 -1
- package/src/index.ts +295 -58
- package/src/packet-runtime.ts +79 -21
- package/src/parent-provider.ts +63 -30
- package/src/route-policy.ts +58 -14
- package/src/run-store.ts +115 -23
- package/src/subagent-activity.ts +82 -6
- package/src/submit-tool.ts +431 -39
- package/src/task-ledger.ts +1 -2
- package/src/worker-broker.ts +72 -13
- package/src/workflow-engine.ts +782 -54
- package/src/workspace-store.ts +2 -10
package/src/index.ts
CHANGED
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
verificationSteps,
|
|
39
39
|
} from "./contracts.ts";
|
|
40
40
|
import {
|
|
41
|
+
CONTROL_COMMAND_PARAMETERS,
|
|
41
42
|
canonicalizeControlCommandToolInput,
|
|
42
43
|
validateControlCommand,
|
|
43
44
|
} from "./control-contracts.ts";
|
|
@@ -45,14 +46,15 @@ import {
|
|
|
45
46
|
assessDeliveryTraceability,
|
|
46
47
|
compileImplementPlan,
|
|
47
48
|
DeliveryValidationError,
|
|
49
|
+
DesignPlanValidationError,
|
|
48
50
|
type GateApprovalProof,
|
|
49
|
-
IMPLEMENT_PLAN_SCHEMA_VERSION,
|
|
50
51
|
parseGateAReceipt,
|
|
51
52
|
parseImplementPlan,
|
|
52
53
|
parseReadyReceipt,
|
|
53
54
|
} from "./delivery-compiler.ts";
|
|
54
55
|
import {
|
|
55
56
|
DesignController,
|
|
57
|
+
DesignFinalizationError,
|
|
56
58
|
validateDesignControlRequest,
|
|
57
59
|
} from "./design-control.ts";
|
|
58
60
|
import { canonicalJson, hashCanonicalValue } from "./implement-graph.ts";
|
|
@@ -67,6 +69,7 @@ import {
|
|
|
67
69
|
unavailableRoutePolicy,
|
|
68
70
|
type WorkerRoutePolicy,
|
|
69
71
|
} from "./route-policy.ts";
|
|
72
|
+
import { RunStoreFormatError } from "./run-store.ts";
|
|
70
73
|
import { observeSafePath } from "./safe-path.ts";
|
|
71
74
|
import { resolveStateRoot } from "./state-root.ts";
|
|
72
75
|
import {
|
|
@@ -229,15 +232,15 @@ const DESIGN_CONTROL_REQUEST_SCHEMA = {
|
|
|
229
232
|
required: ["operation", "operationId", field],
|
|
230
233
|
additionalProperties: false,
|
|
231
234
|
})),
|
|
232
|
-
{
|
|
233
|
-
type: "object",
|
|
235
|
+
...(["status", "validate-plan-draft"] as const).map((operation) => ({
|
|
236
|
+
type: "object" as const,
|
|
234
237
|
properties: {
|
|
235
|
-
operation: { type: "string", enum: [
|
|
236
|
-
runId: { type: "string" },
|
|
238
|
+
operation: { type: "string" as const, enum: [operation] },
|
|
239
|
+
runId: { type: "string" as const },
|
|
237
240
|
},
|
|
238
241
|
required: ["operation", "runId"],
|
|
239
242
|
additionalProperties: false,
|
|
240
|
-
},
|
|
243
|
+
})),
|
|
241
244
|
{
|
|
242
245
|
type: "object",
|
|
243
246
|
properties: {
|
|
@@ -421,6 +424,89 @@ function splitUsage(result: unknown): { payload: unknown; usage?: unknown } {
|
|
|
421
424
|
return { payload, usage };
|
|
422
425
|
}
|
|
423
426
|
|
|
427
|
+
const SAFE_DESIGN_ERROR_CODE = /^[a-z0-9](?:[a-z0-9._:-]{0,126}[a-z0-9])?$/iu;
|
|
428
|
+
const MAX_DESIGN_ERROR_DIAGNOSTICS = 64;
|
|
429
|
+
|
|
430
|
+
type SafeDesignFailure = {
|
|
431
|
+
kind: "design-control-failure";
|
|
432
|
+
operation: string;
|
|
433
|
+
code: string;
|
|
434
|
+
diagnostics: ReadonlyArray<Record<string, string>>;
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
function safeDesignFailure(
|
|
438
|
+
error: unknown,
|
|
439
|
+
operation: string,
|
|
440
|
+
): SafeDesignFailure {
|
|
441
|
+
const message = error instanceof Error ? error.message : "";
|
|
442
|
+
const code =
|
|
443
|
+
error instanceof DesignPlanValidationError
|
|
444
|
+
? "design-plan-validation-invalid"
|
|
445
|
+
: SAFE_DESIGN_ERROR_CODE.test(message)
|
|
446
|
+
? message
|
|
447
|
+
: "design-control-failed";
|
|
448
|
+
const rawDiagnostics: readonly unknown[] =
|
|
449
|
+
error instanceof DesignFinalizationError ||
|
|
450
|
+
error instanceof DesignPlanValidationError ||
|
|
451
|
+
error instanceof DeliveryValidationError
|
|
452
|
+
? error.diagnostics
|
|
453
|
+
: [];
|
|
454
|
+
const diagnostics = rawDiagnostics
|
|
455
|
+
.flatMap((candidate) => {
|
|
456
|
+
if (typeof candidate === "string") {
|
|
457
|
+
const diagnosticCode = candidate.split(":", 1)[0] ?? "";
|
|
458
|
+
return SAFE_DESIGN_ERROR_CODE.test(diagnosticCode)
|
|
459
|
+
? [{ code: diagnosticCode }]
|
|
460
|
+
: [];
|
|
461
|
+
}
|
|
462
|
+
if (
|
|
463
|
+
candidate === null ||
|
|
464
|
+
typeof candidate !== "object" ||
|
|
465
|
+
Array.isArray(candidate)
|
|
466
|
+
) {
|
|
467
|
+
return [];
|
|
468
|
+
}
|
|
469
|
+
const admitted = Object.fromEntries(
|
|
470
|
+
Object.entries(candidate as Record<string, unknown>)
|
|
471
|
+
.filter(
|
|
472
|
+
(entry): entry is [string, string] =>
|
|
473
|
+
[
|
|
474
|
+
"code",
|
|
475
|
+
"taskId",
|
|
476
|
+
"phase",
|
|
477
|
+
"field",
|
|
478
|
+
"category",
|
|
479
|
+
"owner",
|
|
480
|
+
"verificationId",
|
|
481
|
+
"outputId",
|
|
482
|
+
"dependencyTaskId",
|
|
483
|
+
"producerTaskId",
|
|
484
|
+
"producerPhase",
|
|
485
|
+
].includes(entry[0]) &&
|
|
486
|
+
typeof entry[1] === "string" &&
|
|
487
|
+
SAFE_DESIGN_ERROR_CODE.test(entry[1]),
|
|
488
|
+
)
|
|
489
|
+
.sort(([left], [right]) => left.localeCompare(right)),
|
|
490
|
+
);
|
|
491
|
+
return typeof admitted.code === "string" ? [admitted] : [];
|
|
492
|
+
})
|
|
493
|
+
.sort((left, right) =>
|
|
494
|
+
canonicalJson(left).localeCompare(canonicalJson(right)),
|
|
495
|
+
)
|
|
496
|
+
.filter(
|
|
497
|
+
(candidate, index, values) =>
|
|
498
|
+
index === 0 ||
|
|
499
|
+
canonicalJson(candidate) !== canonicalJson(values[index - 1]),
|
|
500
|
+
)
|
|
501
|
+
.slice(0, MAX_DESIGN_ERROR_DIAGNOSTICS);
|
|
502
|
+
return {
|
|
503
|
+
kind: "design-control-failure",
|
|
504
|
+
operation: SAFE_DESIGN_ERROR_CODE.test(operation) ? operation : "unknown",
|
|
505
|
+
code,
|
|
506
|
+
diagnostics,
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
|
|
424
510
|
export interface WorkflowControlEngine {
|
|
425
511
|
execute(
|
|
426
512
|
command: unknown,
|
|
@@ -733,7 +819,10 @@ export function packageDeliverySource(
|
|
|
733
819
|
try {
|
|
734
820
|
receipt = parseReadyReceipt(receiptBytes);
|
|
735
821
|
} catch {
|
|
736
|
-
throw new DeliveryValidationError([
|
|
822
|
+
throw new DeliveryValidationError([
|
|
823
|
+
"delivery-receipt-invalid",
|
|
824
|
+
"delivery-recompile-required",
|
|
825
|
+
]);
|
|
737
826
|
}
|
|
738
827
|
const diagnostics = new Set<string>();
|
|
739
828
|
if (receipt.change !== input.change) {
|
|
@@ -899,7 +988,6 @@ export function packageDeliverySource(
|
|
|
899
988
|
}
|
|
900
989
|
if (
|
|
901
990
|
receipt.plan.path !== "implement-plan.json" ||
|
|
902
|
-
receipt.plan.schemaVersion !== IMPLEMENT_PLAN_SCHEMA_VERSION ||
|
|
903
991
|
receipt.plan.rawSha256 !== sha256(planBytes) ||
|
|
904
992
|
receipt.plan.canonicalHash !== hashCanonicalValue(plan)
|
|
905
993
|
) {
|
|
@@ -982,7 +1070,6 @@ export function packageDeliverySource(
|
|
|
982
1070
|
throw new DeliveryValidationError([...diagnostics]);
|
|
983
1071
|
}
|
|
984
1072
|
return {
|
|
985
|
-
version: 2,
|
|
986
1073
|
gate: "gate-b",
|
|
987
1074
|
revision: receipt.deliveryRevision,
|
|
988
1075
|
receiptHash,
|
|
@@ -1251,7 +1338,7 @@ function normalizedFailureIdentities(input: {
|
|
|
1251
1338
|
if (vitestFailures.length > 0) {
|
|
1252
1339
|
return [...new Set(vitestFailures)]
|
|
1253
1340
|
.sort()
|
|
1254
|
-
.map((failure) => sha256(`vitest-failure
|
|
1341
|
+
.map((failure) => sha256(`vitest-failure\0${failure}`));
|
|
1255
1342
|
}
|
|
1256
1343
|
const normalizedOutput = input.output
|
|
1257
1344
|
.replace(new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "gu"), "")
|
|
@@ -1261,7 +1348,6 @@ function normalizedFailureIdentities(input: {
|
|
|
1261
1348
|
return [
|
|
1262
1349
|
sha256(
|
|
1263
1350
|
canonicalJson({
|
|
1264
|
-
version: 1,
|
|
1265
1351
|
verificationId: input.step.id,
|
|
1266
1352
|
exitCode: input.exitCode,
|
|
1267
1353
|
output: normalizedOutput,
|
|
@@ -1514,6 +1600,8 @@ export function openPackageWorkflowControlEngine(
|
|
|
1514
1600
|
context,
|
|
1515
1601
|
parentPayloadBridge,
|
|
1516
1602
|
input.signal,
|
|
1603
|
+
process.env,
|
|
1604
|
+
{ onResponse: input.onHeaders },
|
|
1517
1605
|
);
|
|
1518
1606
|
if (!phaseRuntime.ok) {
|
|
1519
1607
|
if (phaseRuntime.failure.kind === "cancelled") {
|
|
@@ -1525,19 +1613,49 @@ export function openPackageWorkflowControlEngine(
|
|
|
1525
1613
|
if (!phase) {
|
|
1526
1614
|
return { kind: "paused", code: "task-phase-unavailable" };
|
|
1527
1615
|
}
|
|
1616
|
+
const taskPhases = Object.values(input.task.phases);
|
|
1617
|
+
const executionBoundary = input.artifactCorrection
|
|
1618
|
+
? {
|
|
1619
|
+
read: [
|
|
1620
|
+
...new Set(
|
|
1621
|
+
taskPhases.flatMap((boundary) => [
|
|
1622
|
+
...boundary.read,
|
|
1623
|
+
...boundary.write,
|
|
1624
|
+
...boundary.delete,
|
|
1625
|
+
]),
|
|
1626
|
+
),
|
|
1627
|
+
].sort(),
|
|
1628
|
+
write: [
|
|
1629
|
+
...new Set(taskPhases.flatMap((boundary) => boundary.write)),
|
|
1630
|
+
].sort(),
|
|
1631
|
+
delete: [
|
|
1632
|
+
...new Set(taskPhases.flatMap((boundary) => boundary.delete)),
|
|
1633
|
+
].sort(),
|
|
1634
|
+
}
|
|
1635
|
+
: {
|
|
1636
|
+
read: [...phase.read],
|
|
1637
|
+
write: [...phase.write],
|
|
1638
|
+
delete: [...phase.delete],
|
|
1639
|
+
};
|
|
1528
1640
|
const phaseContract = {
|
|
1529
1641
|
candidateId: input.candidateArtifact.identity.candidateId,
|
|
1530
1642
|
taskId: input.taskId,
|
|
1531
1643
|
phase: input.phase,
|
|
1532
|
-
readSet:
|
|
1533
|
-
writeSet:
|
|
1534
|
-
deleteSet:
|
|
1644
|
+
readSet: executionBoundary.read,
|
|
1645
|
+
writeSet: executionBoundary.write,
|
|
1646
|
+
deleteSet: executionBoundary.delete,
|
|
1535
1647
|
verification: structuredClone(phase.verification),
|
|
1536
1648
|
agentsImpact: input.task.agents.impact,
|
|
1537
1649
|
agentsTarget: input.task.agents.target ?? null,
|
|
1538
1650
|
agentsManagedOnly: true,
|
|
1539
1651
|
agentsWriteAllowed: false,
|
|
1540
1652
|
impactClosure: structuredClone(input.task.impactClosure),
|
|
1653
|
+
...(input.artifactCorrection
|
|
1654
|
+
? { artifactCorrection: structuredClone(input.artifactCorrection) }
|
|
1655
|
+
: {}),
|
|
1656
|
+
...(input.contextRequest
|
|
1657
|
+
? { requestedContext: structuredClone(input.contextRequest) }
|
|
1658
|
+
: {}),
|
|
1541
1659
|
...(input.repair
|
|
1542
1660
|
? {
|
|
1543
1661
|
repair: {
|
|
@@ -1570,14 +1688,17 @@ export function openPackageWorkflowControlEngine(
|
|
|
1570
1688
|
path.resolve(input.workspaceRoot, root),
|
|
1571
1689
|
),
|
|
1572
1690
|
allowedPaths: [
|
|
1573
|
-
...new Set([
|
|
1691
|
+
...new Set([
|
|
1692
|
+
...executionBoundary.read,
|
|
1693
|
+
...executionBoundary.write,
|
|
1694
|
+
...executionBoundary.delete,
|
|
1695
|
+
]),
|
|
1574
1696
|
],
|
|
1575
1697
|
timeoutMs: LIMITS.phaseTimeoutMs,
|
|
1576
1698
|
signal: input.signal,
|
|
1577
1699
|
failureOverride: phaseRuntime.failureOverride,
|
|
1578
1700
|
ledgerProjection: input.ledgerProjection,
|
|
1579
1701
|
candidateArtifact: input.candidateArtifact,
|
|
1580
|
-
onStreamStart: input.onHeaders,
|
|
1581
1702
|
onStreamProgress: input.onProgress,
|
|
1582
1703
|
});
|
|
1583
1704
|
if (!child.ok) {
|
|
@@ -1593,18 +1714,43 @@ export function openPackageWorkflowControlEngine(
|
|
|
1593
1714
|
if (child.failure.kind === "result-limit") {
|
|
1594
1715
|
return { kind: "paused", code: "needs-task-split" };
|
|
1595
1716
|
}
|
|
1717
|
+
const attemptDiagnostic = {
|
|
1718
|
+
finalCategory: child.classification.finalCategory,
|
|
1719
|
+
submitAttempts: child.classification.attempts,
|
|
1720
|
+
schema: child.classification.schema,
|
|
1721
|
+
identityMismatch: Object.entries(child.classification.identity)
|
|
1722
|
+
.filter(([, matches]) => !matches)
|
|
1723
|
+
.map(([dimension]) => dimension),
|
|
1724
|
+
};
|
|
1596
1725
|
return child.failure.kind === "environment" ||
|
|
1597
1726
|
child.failure.kind === "verification-adapter"
|
|
1598
|
-
? { kind: "paused", code: child.failure.code }
|
|
1599
|
-
: { kind: "retryable", code: child.failure.code };
|
|
1727
|
+
? { kind: "paused", code: child.failure.code, attemptDiagnostic }
|
|
1728
|
+
: { kind: "retryable", code: child.failure.code, attemptDiagnostic };
|
|
1600
1729
|
}
|
|
1601
1730
|
const result = child.result;
|
|
1602
1731
|
if (result.kind === "context-request") {
|
|
1603
|
-
return classifyCandidateContextRequest(result,
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1732
|
+
return classifyCandidateContextRequest(result, {
|
|
1733
|
+
phase: input.phase,
|
|
1734
|
+
readPaths: phase.read,
|
|
1735
|
+
writePaths: phase.write,
|
|
1736
|
+
deletePaths: phase.delete,
|
|
1737
|
+
taskPaths: [
|
|
1738
|
+
...new Set(
|
|
1739
|
+
Object.values(input.task.phases).flatMap((boundary) => [
|
|
1740
|
+
...boundary.read,
|
|
1741
|
+
...boundary.write,
|
|
1742
|
+
...boundary.delete,
|
|
1743
|
+
]),
|
|
1744
|
+
),
|
|
1745
|
+
],
|
|
1746
|
+
redWritePaths: input.task.phases.red.write,
|
|
1747
|
+
agents: {
|
|
1748
|
+
impact: input.task.agents.impact,
|
|
1749
|
+
...(input.task.agents.target
|
|
1750
|
+
? { target: input.task.agents.target }
|
|
1751
|
+
: {}),
|
|
1752
|
+
},
|
|
1753
|
+
});
|
|
1608
1754
|
}
|
|
1609
1755
|
if (result.kind !== "sealed-candidate") {
|
|
1610
1756
|
return { kind: "retryable", code: "candidate-diff-invalid" };
|
|
@@ -1716,6 +1862,39 @@ export function openPackageWorkflowControlEngine(
|
|
|
1716
1862
|
};
|
|
1717
1863
|
}
|
|
1718
1864
|
|
|
1865
|
+
function runStoreUnavailableStatus(
|
|
1866
|
+
error: RunStoreFormatError,
|
|
1867
|
+
command: {
|
|
1868
|
+
stage: "abel-implement";
|
|
1869
|
+
change: string;
|
|
1870
|
+
},
|
|
1871
|
+
): Record<string, unknown> {
|
|
1872
|
+
return {
|
|
1873
|
+
stage: command.stage,
|
|
1874
|
+
change: command.change,
|
|
1875
|
+
state: "paused",
|
|
1876
|
+
durable: false,
|
|
1877
|
+
completed: false,
|
|
1878
|
+
pause: { code: error.code },
|
|
1879
|
+
legalCommands: ["status", "start"],
|
|
1880
|
+
tasks: [],
|
|
1881
|
+
queue: [],
|
|
1882
|
+
controlStore: {
|
|
1883
|
+
code: error.code,
|
|
1884
|
+
databasePath: error.databasePath,
|
|
1885
|
+
recovery: structuredClone(error.recovery),
|
|
1886
|
+
},
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
function runStoreResetError(error: RunStoreFormatError): Error {
|
|
1891
|
+
const reset = new Error(
|
|
1892
|
+
`${error.code}: back up and remove the private run store at ${error.databasePath}, then retry the operation`,
|
|
1893
|
+
);
|
|
1894
|
+
reset.name = "RunStoreResetError";
|
|
1895
|
+
return reset;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1719
1898
|
function visibleRoutePolicyStatus(
|
|
1720
1899
|
resolution: RoutePolicyResolution,
|
|
1721
1900
|
brokerStatus: Record<string, unknown> | undefined,
|
|
@@ -1735,6 +1914,7 @@ export function registerWorkflowControl(
|
|
|
1735
1914
|
const parentPayloadBridge = new ParentPayloadBridge();
|
|
1736
1915
|
const activity = new ActivityController();
|
|
1737
1916
|
const engines = new Map<string, Promise<WorkflowControlEngine>>();
|
|
1917
|
+
const designFailures = new Map<string, SafeDesignFailure>();
|
|
1738
1918
|
let pendingPrompt: EligiblePrompt | undefined;
|
|
1739
1919
|
let activePrompt: EligiblePrompt | undefined;
|
|
1740
1920
|
let designToolSnapshot: string[] | undefined;
|
|
@@ -1827,30 +2007,15 @@ export function registerWorkflowControl(
|
|
|
1827
2007
|
|
|
1828
2008
|
// Pi validates tool arguments before execute(), so expose only the schema
|
|
1829
2009
|
// legal for the active stage instead of one ambiguous command/packet union.
|
|
1830
|
-
const
|
|
2010
|
+
const PACKET_PARAMETERS = {
|
|
1831
2011
|
type: "object",
|
|
1832
2012
|
properties: {
|
|
1833
|
-
|
|
1834
|
-
type: "string",
|
|
1835
|
-
enum: ["start", "status", "resume", "rebind", "cancel", "discard"],
|
|
1836
|
-
},
|
|
1837
|
-
stage: {
|
|
2013
|
+
action: {
|
|
1838
2014
|
type: "string",
|
|
1839
|
-
enum: ["
|
|
2015
|
+
enum: [...PACKET_ACTIONS, "design"],
|
|
2016
|
+
description:
|
|
2017
|
+
"Top-level dispatch action. design and run require request; finish is explicit stage exit and MUST omit request.",
|
|
1840
2018
|
},
|
|
1841
|
-
change: { type: "string" },
|
|
1842
|
-
operationId: { type: "string" },
|
|
1843
|
-
deliveryRevision: { type: "integer", minimum: 1 },
|
|
1844
|
-
receiptHash: { type: "string" },
|
|
1845
|
-
routeId: { type: "string" },
|
|
1846
|
-
},
|
|
1847
|
-
required: ["command", "stage", "change"],
|
|
1848
|
-
additionalProperties: false,
|
|
1849
|
-
} as const;
|
|
1850
|
-
const PACKET_PARAMETERS = {
|
|
1851
|
-
type: "object",
|
|
1852
|
-
properties: {
|
|
1853
|
-
action: { type: "string", enum: [...PACKET_ACTIONS, "design"] },
|
|
1854
2019
|
request: {
|
|
1855
2020
|
anyOf: [
|
|
1856
2021
|
DESIGN_REQUEST_SCHEMA,
|
|
@@ -1902,6 +2067,9 @@ export function registerWorkflowControl(
|
|
|
1902
2067
|
) {
|
|
1903
2068
|
throw new Error("control-envelope-ambiguous");
|
|
1904
2069
|
}
|
|
2070
|
+
if (record.action === "finish" && Object.hasOwn(record, "request")) {
|
|
2071
|
+
throw new Error("control-envelope-ambiguous");
|
|
2072
|
+
}
|
|
1905
2073
|
if (
|
|
1906
2074
|
activePrompt !== "abel-design" &&
|
|
1907
2075
|
activePrompt !== "abel-diagnose"
|
|
@@ -1914,22 +2082,40 @@ export function registerWorkflowControl(
|
|
|
1914
2082
|
}
|
|
1915
2083
|
const designRequest = validateDesignControlRequest(record.request);
|
|
1916
2084
|
if (!designRequest.ok) throw new Error(designRequest.code);
|
|
1917
|
-
|
|
2085
|
+
let engine: WorkflowControlEngine;
|
|
2086
|
+
try {
|
|
2087
|
+
engine = await engineFor(ctx);
|
|
2088
|
+
} catch (error) {
|
|
2089
|
+
if (error instanceof RunStoreFormatError)
|
|
2090
|
+
throw runStoreResetError(error);
|
|
2091
|
+
throw error;
|
|
2092
|
+
}
|
|
1918
2093
|
if (!engine.executeDesign)
|
|
1919
2094
|
throw new Error("design-control-unavailable");
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
2095
|
+
try {
|
|
2096
|
+
const payload = await engine.executeDesign(designRequest.value);
|
|
2097
|
+
if (
|
|
2098
|
+
designRequest.value.operation === "finalize-delivery" &&
|
|
2099
|
+
payload.state === "completed"
|
|
2100
|
+
) {
|
|
2101
|
+
await deactivateStage();
|
|
2102
|
+
}
|
|
2103
|
+
return {
|
|
2104
|
+
content: [
|
|
2105
|
+
{ type: "text" as const, text: JSON.stringify(payload) },
|
|
2106
|
+
],
|
|
2107
|
+
details: payload,
|
|
2108
|
+
};
|
|
2109
|
+
} catch (error) {
|
|
2110
|
+
const failure = safeDesignFailure(
|
|
2111
|
+
error,
|
|
2112
|
+
designRequest.value.operation,
|
|
2113
|
+
);
|
|
2114
|
+
designFailures.set(toolCallId, failure);
|
|
2115
|
+
const sanitized = new Error(failure.code);
|
|
2116
|
+
sanitized.name = "DesignControlError";
|
|
2117
|
+
throw sanitized;
|
|
1926
2118
|
}
|
|
1927
|
-
return {
|
|
1928
|
-
content: [
|
|
1929
|
-
{ type: "text" as const, text: JSON.stringify(payload) },
|
|
1930
|
-
],
|
|
1931
|
-
details: payload,
|
|
1932
|
-
};
|
|
1933
2119
|
}
|
|
1934
2120
|
let designEngine: WorkflowControlEngine | undefined;
|
|
1935
2121
|
if (record.action === "run") {
|
|
@@ -1940,7 +2126,13 @@ export function registerWorkflowControl(
|
|
|
1940
2126
|
);
|
|
1941
2127
|
}
|
|
1942
2128
|
if (packet.value.stage === "abel-design") {
|
|
1943
|
-
|
|
2129
|
+
try {
|
|
2130
|
+
designEngine = await engineFor(ctx);
|
|
2131
|
+
} catch (error) {
|
|
2132
|
+
if (error instanceof RunStoreFormatError)
|
|
2133
|
+
throw runStoreResetError(error);
|
|
2134
|
+
throw error;
|
|
2135
|
+
}
|
|
1944
2136
|
if (!designEngine.assertDesignRun || !packet.value.runId) {
|
|
1945
2137
|
throw new Error("design-control-unavailable");
|
|
1946
2138
|
}
|
|
@@ -2028,7 +2220,17 @@ export function registerWorkflowControl(
|
|
|
2028
2220
|
) {
|
|
2029
2221
|
throw new Error("stage-control-mismatch");
|
|
2030
2222
|
}
|
|
2031
|
-
|
|
2223
|
+
let engine: WorkflowControlEngine;
|
|
2224
|
+
try {
|
|
2225
|
+
engine = await engineFor(ctx);
|
|
2226
|
+
} catch (error) {
|
|
2227
|
+
if (!(error instanceof RunStoreFormatError)) throw error;
|
|
2228
|
+
const payload = runStoreUnavailableStatus(error, validation.value);
|
|
2229
|
+
return {
|
|
2230
|
+
content: [{ type: "text" as const, text: JSON.stringify(payload) }],
|
|
2231
|
+
details: payload,
|
|
2232
|
+
};
|
|
2233
|
+
}
|
|
2032
2234
|
const tuiControl = ctx.mode === "tui";
|
|
2033
2235
|
if (tuiControl) {
|
|
2034
2236
|
try {
|
|
@@ -2113,6 +2315,39 @@ export function registerWorkflowControl(
|
|
|
2113
2315
|
};
|
|
2114
2316
|
registerDispatchTool("packet");
|
|
2115
2317
|
|
|
2318
|
+
pi.on("tool_result", (event) => {
|
|
2319
|
+
if (
|
|
2320
|
+
event.toolName !== DISPATCH_TOOL ||
|
|
2321
|
+
!event.isError ||
|
|
2322
|
+
event.input.action !== "design"
|
|
2323
|
+
) {
|
|
2324
|
+
return;
|
|
2325
|
+
}
|
|
2326
|
+
const errorText = event.content
|
|
2327
|
+
.flatMap((item) =>
|
|
2328
|
+
item.type === "text" && typeof item.text === "string"
|
|
2329
|
+
? [item.text]
|
|
2330
|
+
: [],
|
|
2331
|
+
)
|
|
2332
|
+
.join("\n");
|
|
2333
|
+
const failure = safeDesignFailure(
|
|
2334
|
+
new Error(errorText.trim()),
|
|
2335
|
+
typeof (event.input.request as Record<string, unknown> | undefined)
|
|
2336
|
+
?.operation === "string"
|
|
2337
|
+
? String((event.input.request as Record<string, unknown>).operation)
|
|
2338
|
+
: "unknown",
|
|
2339
|
+
);
|
|
2340
|
+
const details =
|
|
2341
|
+
event.details && typeof event.details === "object"
|
|
2342
|
+
? (event.details as Record<string, unknown>)
|
|
2343
|
+
: {};
|
|
2344
|
+
const visible = designFailures.get(event.toolCallId) ?? failure;
|
|
2345
|
+
designFailures.delete(event.toolCallId);
|
|
2346
|
+
return {
|
|
2347
|
+
content: [{ type: "text" as const, text: JSON.stringify(visible) }],
|
|
2348
|
+
details: { ...details, designFailure: visible },
|
|
2349
|
+
};
|
|
2350
|
+
});
|
|
2116
2351
|
pi.on("input", (event) => {
|
|
2117
2352
|
pendingPrompt = invokedPrompt(event.text);
|
|
2118
2353
|
return { action: "continue" };
|
|
@@ -2166,6 +2401,7 @@ export function registerWorkflowControl(
|
|
|
2166
2401
|
pi.on("session_start", async (_event, ctx) => {
|
|
2167
2402
|
pendingPrompt = undefined;
|
|
2168
2403
|
activePrompt = undefined;
|
|
2404
|
+
designFailures.clear();
|
|
2169
2405
|
activity.detach();
|
|
2170
2406
|
await packetRuntime.drain();
|
|
2171
2407
|
await closeEngines();
|
|
@@ -2181,6 +2417,7 @@ export function registerWorkflowControl(
|
|
|
2181
2417
|
});
|
|
2182
2418
|
pi.on("session_shutdown", async () => {
|
|
2183
2419
|
activePrompt = undefined;
|
|
2420
|
+
designFailures.clear();
|
|
2184
2421
|
activity.detach();
|
|
2185
2422
|
await packetRuntime.drain();
|
|
2186
2423
|
await closeEngines();
|