@abelxiaoxing/cadence 1.4.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -4
- package/agents/design-explorer.md +17 -11
- package/agents/diagnosis-worker.md +9 -1
- package/agents/implementation-worker.md +3 -1
- package/config/plan-draft.example.json +122 -0
- package/config/plan-draft.multiple-tasks.example.json +345 -0
- package/package.json +5 -3
- package/prompts/abel-design.md +93 -44
- package/src/activity-contracts.ts +82 -0
- package/src/candidate-artifact.ts +143 -0
- package/src/candidate-patch.ts +31 -11
- package/src/candidate-workspace.ts +74 -0
- package/src/change-contract-schema.ts +191 -0
- package/src/change-contract.ts +5 -0
- package/src/change-verification.ts +896 -0
- package/src/child-model.ts +129 -0
- package/src/child-session.ts +293 -326
- package/src/contracts.ts +184 -76
- package/src/delivery-compiler.ts +103 -120
- package/src/delivery-revision.ts +42 -0
- package/src/design-control.ts +113 -4
- package/src/design-diagnostics.ts +150 -0
- package/src/durable-contracts.ts +210 -0
- package/src/durable-workflow.ts +148 -3570
- package/src/evidence-draft.ts +122 -0
- package/src/implement-graph.ts +3 -0
- package/src/implement-plan.ts +70 -0
- package/src/index.ts +59 -522
- package/src/model-source.ts +22 -0
- package/src/package-candidate.ts +224 -0
- package/src/package-workflow.ts +253 -0
- package/src/packet-runtime.ts +27 -48
- package/src/parent-provider.ts +86 -198
- package/src/phase-execution.ts +2248 -0
- package/src/pi-adapter.ts +19 -0
- package/src/plan-draft-summary.ts +146 -0
- package/src/plan-draft.ts +493 -0
- package/src/subagent-activity.ts +32 -66
- package/src/submit-tool.ts +20 -59
- package/src/transport-budget.ts +32 -0
- package/src/worker-broker.ts +37 -57
- package/src/workflow-policy.ts +14 -53
- package/src/workflow-recovery-policy.ts +95 -0
- package/src/workflow-scheduling.ts +105 -0
- package/src/workflow-state-machine.ts +105 -497
- package/src/workflow-status.ts +384 -0
- package/src/workspace-io-worker.mjs +7 -0
- package/src/empty-resource-loader.ts +0 -38
- package/src/parent-payload-bridge.ts +0 -523
package/src/index.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { compareCanonicalStrings } from "./canonical.ts";
|
|
2
|
-
import {
|
|
2
|
+
import { CHANGE_CONTRACT_SCHEMA } from "./change-contract-schema.ts";
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from "./package-
|
|
8
|
-
import {
|
|
4
|
+
projectDesignDiagnostic,
|
|
5
|
+
type SafeDesignDiagnostic,
|
|
6
|
+
} from "./design-diagnostics.ts";
|
|
7
|
+
import { openPackageWorkflowService } from "./package-workflow.ts";
|
|
8
|
+
import { packageContext } from "./pi-adapter.ts";
|
|
9
9
|
|
|
10
10
|
export {
|
|
11
11
|
type PackageDeliverySourceOptions,
|
|
@@ -19,10 +19,8 @@ export { executePackageVerification } from "./package-verification.ts";
|
|
|
19
19
|
// the active set at session start. Eligible-stage activation is wired by the
|
|
20
20
|
// workflow routing (abel-design/implement/diagnose provenance) in the prompts
|
|
21
21
|
// integration; abel-init and ordinary prompts never activate dispatch.
|
|
22
|
-
|
|
23
|
-
import {
|
|
24
|
-
import { homedir } from "node:os";
|
|
25
|
-
import path, { dirname, join } from "node:path";
|
|
22
|
+
|
|
23
|
+
import { dirname, join } from "node:path";
|
|
26
24
|
import { fileURLToPath } from "node:url";
|
|
27
25
|
import type {
|
|
28
26
|
AgentToolResult,
|
|
@@ -33,13 +31,8 @@ import type {
|
|
|
33
31
|
ToolRenderResultOptions,
|
|
34
32
|
} from "@earendil-works/pi-coding-agent";
|
|
35
33
|
import { type Activation, activateTool, deactivateTool } from "./activation.ts";
|
|
36
|
-
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
type DesignEvidenceResult,
|
|
40
|
-
LIMITS,
|
|
41
|
-
type StructuredVerificationContract,
|
|
42
|
-
} from "./contracts.ts";
|
|
34
|
+
|
|
35
|
+
import type { DesignEvidenceResult } from "./contracts.ts";
|
|
43
36
|
import {
|
|
44
37
|
CONTROL_COMMAND_PARAMETERS,
|
|
45
38
|
canonicalizeControlCommandToolInput,
|
|
@@ -50,25 +43,16 @@ import {
|
|
|
50
43
|
DesignPlanValidationError,
|
|
51
44
|
} from "./delivery-compiler.ts";
|
|
52
45
|
import {
|
|
53
|
-
|
|
46
|
+
DesignControlValidationError,
|
|
54
47
|
DesignFinalizationError,
|
|
55
48
|
validateDesignControlRequest,
|
|
56
49
|
} from "./design-control.ts";
|
|
57
50
|
import { canonicalJson } from "./implement-graph.ts";
|
|
58
|
-
import { inspectOpenSpecDelivery } from "./openspec-cli.ts";
|
|
59
51
|
import { PACKET_ACTIONS, PacketRuntime } from "./packet-runtime.ts";
|
|
60
|
-
|
|
61
|
-
import { runtimeForWorkerRoute } from "./parent-provider.ts";
|
|
62
|
-
import {
|
|
63
|
-
inspectRoutePolicy,
|
|
64
|
-
loadRoutePolicy,
|
|
65
|
-
type RoutePolicyResolution,
|
|
66
|
-
unavailableRoutePolicy,
|
|
67
|
-
type WorkerRoutePolicy,
|
|
68
|
-
} from "./route-policy.ts";
|
|
52
|
+
|
|
69
53
|
import { RunStoreFormatError, RunStoreMigrationError } from "./run-store.ts";
|
|
70
|
-
|
|
71
|
-
import {
|
|
54
|
+
|
|
55
|
+
import { StateRootError } from "./state-root.ts";
|
|
72
56
|
import {
|
|
73
57
|
ACTIVITY_DETAILS_KEY,
|
|
74
58
|
ActivityController,
|
|
@@ -76,11 +60,6 @@ import {
|
|
|
76
60
|
renderActivityResult,
|
|
77
61
|
type WorkflowActivityUpdate,
|
|
78
62
|
} from "./subagent-activity.ts";
|
|
79
|
-
import {
|
|
80
|
-
classifyCandidateContextRequest,
|
|
81
|
-
permitsContextRead,
|
|
82
|
-
} from "./submit-tool.ts";
|
|
83
|
-
import { openDurableWorkflowEngine } from "./workflow-engine.ts";
|
|
84
63
|
|
|
85
64
|
export {
|
|
86
65
|
inspectOpenSpecDelivery,
|
|
@@ -282,9 +261,9 @@ const DESIGN_CONTROL_REQUEST_SCHEMA = {
|
|
|
282
261
|
operationId: { type: "string" },
|
|
283
262
|
gate: { type: "string", enum: ["gate-a"] },
|
|
284
263
|
contract: {
|
|
285
|
-
anyOf: [{ type: "string" },
|
|
264
|
+
anyOf: [{ type: "string" }, CHANGE_CONTRACT_SCHEMA],
|
|
286
265
|
description:
|
|
287
|
-
"
|
|
266
|
+
"ChangeContract: {goal, acceptance:[{id,statement,verification}], constraints:[{id,statement}], policy:{writeRoots,dependencies,verificationModes}}. Pass the example's changeContract object, not its whole plan. Legacy prose remains readable; code hashes authority.",
|
|
288
267
|
},
|
|
289
268
|
},
|
|
290
269
|
required: ["operation", "runId", "operationId", "gate", "contract"],
|
|
@@ -314,7 +293,7 @@ const DESIGN_CONTROL_REQUEST_SCHEMA = {
|
|
|
314
293
|
content: {
|
|
315
294
|
type: "string",
|
|
316
295
|
maxLength: 16 * 1024 * 1024,
|
|
317
|
-
description:
|
|
296
|
+
description: `Exact bounded UTF-8 artifact content. For plan-draft.json, omit tracking, phase verificationInputs and relatedTests disposition to derive them. Read the complete example at ${join(PACKAGE_ROOT, "config/plan-draft.example.json")}.`,
|
|
318
297
|
},
|
|
319
298
|
},
|
|
320
299
|
required: ["operation", "runId", "operationId", "path", "content"],
|
|
@@ -429,7 +408,7 @@ type SafeDesignFailure = {
|
|
|
429
408
|
kind: "design-control-failure";
|
|
430
409
|
operation: string;
|
|
431
410
|
code: string;
|
|
432
|
-
diagnostics:
|
|
411
|
+
diagnostics: readonly SafeDesignDiagnostic[];
|
|
433
412
|
};
|
|
434
413
|
|
|
435
414
|
type DesignFailureBoundary =
|
|
@@ -478,6 +457,13 @@ function classifyDesignFailure(
|
|
|
478
457
|
field?: string;
|
|
479
458
|
} {
|
|
480
459
|
const message = error instanceof Error ? error.message : "";
|
|
460
|
+
if (error instanceof DesignControlValidationError) {
|
|
461
|
+
return {
|
|
462
|
+
code: "invalid-design-control-request",
|
|
463
|
+
category: "validation",
|
|
464
|
+
retryable: false,
|
|
465
|
+
};
|
|
466
|
+
}
|
|
481
467
|
if (error instanceof DesignPlanValidationError) {
|
|
482
468
|
return {
|
|
483
469
|
code: "design-plan-validation-invalid",
|
|
@@ -600,50 +586,8 @@ function safeDesignFailure(
|
|
|
600
586
|
: [];
|
|
601
587
|
const diagnostics = rawDiagnostics
|
|
602
588
|
.flatMap((candidate) => {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
return SAFE_DESIGN_ERROR_CODE.test(diagnosticCode)
|
|
606
|
-
? [{ code: diagnosticCode }]
|
|
607
|
-
: [];
|
|
608
|
-
}
|
|
609
|
-
if (
|
|
610
|
-
candidate === null ||
|
|
611
|
-
typeof candidate !== "object" ||
|
|
612
|
-
Array.isArray(candidate)
|
|
613
|
-
) {
|
|
614
|
-
return [];
|
|
615
|
-
}
|
|
616
|
-
const admitted = Object.fromEntries(
|
|
617
|
-
Object.entries(candidate as Record<string, unknown>)
|
|
618
|
-
.filter((entry): entry is [string, string | boolean] => {
|
|
619
|
-
if (entry[0] === "retryable") {
|
|
620
|
-
return typeof entry[1] === "boolean";
|
|
621
|
-
}
|
|
622
|
-
return (
|
|
623
|
-
[
|
|
624
|
-
"code",
|
|
625
|
-
"taskId",
|
|
626
|
-
"phase",
|
|
627
|
-
"field",
|
|
628
|
-
"category",
|
|
629
|
-
"owner",
|
|
630
|
-
"verificationId",
|
|
631
|
-
"outputId",
|
|
632
|
-
"dependencyTaskId",
|
|
633
|
-
"producerTaskId",
|
|
634
|
-
"producerPhase",
|
|
635
|
-
"command",
|
|
636
|
-
"reason",
|
|
637
|
-
"systemCode",
|
|
638
|
-
"exitCode",
|
|
639
|
-
].includes(entry[0]) &&
|
|
640
|
-
typeof entry[1] === "string" &&
|
|
641
|
-
SAFE_DESIGN_ERROR_CODE.test(entry[1])
|
|
642
|
-
);
|
|
643
|
-
})
|
|
644
|
-
.sort(([left], [right]) => compareCanonicalStrings(left, right)),
|
|
645
|
-
);
|
|
646
|
-
return typeof admitted.code === "string" ? [admitted] : [];
|
|
589
|
+
const diagnostic = projectDesignDiagnostic(candidate);
|
|
590
|
+
return diagnostic ? [diagnostic] : [];
|
|
647
591
|
})
|
|
648
592
|
.sort((left, right) =>
|
|
649
593
|
compareCanonicalStrings(canonicalJson(left), canonicalJson(right)),
|
|
@@ -693,405 +637,23 @@ export interface WorkflowControlEngine {
|
|
|
693
637
|
|
|
694
638
|
export type WorkflowControlEngineFactory = (
|
|
695
639
|
ctx: ExtensionContext,
|
|
696
|
-
parentPayloadBridge: ParentPayloadBridge,
|
|
697
640
|
) => WorkflowControlEngine | Promise<WorkflowControlEngine>;
|
|
698
641
|
|
|
699
|
-
|
|
700
|
-
return createHash("sha256").update(value).digest("hex");
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
function affectedVerification(
|
|
704
|
-
task: Parameters<
|
|
705
|
-
Parameters<typeof openDurableWorkflowEngine>[0]["proposeCandidate"]
|
|
706
|
-
>[0]["task"],
|
|
707
|
-
): StructuredVerificationContract {
|
|
708
|
-
if (task.affectedVerification) {
|
|
709
|
-
return structuredClone(task.affectedVerification);
|
|
710
|
-
}
|
|
711
|
-
const finalPhase = task.phases.refactor ?? task.phases.green;
|
|
712
|
-
const verification = structuredClone(finalPhase.verification);
|
|
713
|
-
const affected = [...new Set(task.impactClosure.affectedSuite)].sort();
|
|
714
|
-
if (affected.length === 0) return verification;
|
|
715
|
-
if (verification.kind === "vitest") {
|
|
716
|
-
return { ...verification, testFiles: affected };
|
|
717
|
-
}
|
|
718
|
-
if (verification.kind === "steps") {
|
|
719
|
-
return {
|
|
720
|
-
...verification,
|
|
721
|
-
steps: verification.steps.map((step) =>
|
|
722
|
-
step.kind === "vitest" ? { ...step, testFiles: affected } : step,
|
|
723
|
-
),
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
return verification;
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
function childRequestId(
|
|
730
|
-
operationId: string,
|
|
731
|
-
taskId: string,
|
|
732
|
-
phase: string,
|
|
733
|
-
): string {
|
|
734
|
-
return `child-${sha256(`${operationId}\0${taskId}\0${phase}`).slice(0, 40)}`;
|
|
735
|
-
}
|
|
736
|
-
|
|
642
|
+
/** Pi adapter: project host capabilities before entering the package services. */
|
|
737
643
|
export function openPackageWorkflowControlEngine(
|
|
738
644
|
initialContext: ExtensionContext,
|
|
739
|
-
parentPayloadBridge: ParentPayloadBridge,
|
|
740
645
|
): WorkflowControlEngine {
|
|
741
|
-
const
|
|
742
|
-
const routeResolution = loadRoutePolicy({
|
|
743
|
-
cwd: consumerRoot,
|
|
744
|
-
home: homedir(),
|
|
745
|
-
...(initialContext.model ? { parentModel: initialContext.model } : {}),
|
|
746
|
-
});
|
|
747
|
-
const stateRoot = resolveStateRoot({
|
|
748
|
-
consumerRoot,
|
|
749
|
-
xdgStateHome: process.env.XDG_STATE_HOME,
|
|
750
|
-
});
|
|
751
|
-
const contexts = new AsyncLocalStorage<ExtensionContext>();
|
|
752
|
-
const design = DesignController.open({
|
|
753
|
-
consumerRoot,
|
|
754
|
-
stateRoot,
|
|
755
|
-
inspectOpenSpec: inspectOpenSpecDelivery,
|
|
756
|
-
});
|
|
757
|
-
const implementationAgent = loadAgentDefinitions().find(
|
|
758
|
-
(agent) => agent.role === "implementation-worker",
|
|
759
|
-
);
|
|
760
|
-
if (!implementationAgent) {
|
|
761
|
-
throw new Error("implementation-worker-agent-unavailable");
|
|
762
|
-
}
|
|
763
|
-
const hostLimit = (name: string, fallback: number): number => {
|
|
764
|
-
const value =
|
|
765
|
-
process.env[name] === undefined ? fallback : Number(process.env[name]);
|
|
766
|
-
if (!Number.isSafeInteger(value) || value < 1)
|
|
767
|
-
throw new Error("verification-host-limit-invalid");
|
|
768
|
-
return value;
|
|
769
|
-
};
|
|
770
|
-
const maxReportBytes = hostLimit(
|
|
771
|
-
"ABEL_VERIFICATION_MAX_REPORT_BYTES",
|
|
772
|
-
64 * 1024 * 1024,
|
|
773
|
-
);
|
|
774
|
-
const workHardLimit = hostLimit("ABEL_WORK_MAX_UNITS", 512);
|
|
775
|
-
const engine = openDurableWorkflowEngine({
|
|
776
|
-
workHardLimit,
|
|
777
|
-
verificationPolicy: "report-file-v4",
|
|
778
|
-
verificationEnvironment: (plan, signal) =>
|
|
779
|
-
captureVerificationEnvironmentIdentity(
|
|
780
|
-
consumerRoot,
|
|
781
|
-
[
|
|
782
|
-
...plan.tasks.flatMap((task) => [
|
|
783
|
-
...Object.values(task.phases).map((phase) => phase.verification),
|
|
784
|
-
task.affectedVerification,
|
|
785
|
-
task.repairVerification,
|
|
786
|
-
]),
|
|
787
|
-
plan.verification.baseline.fullSuite,
|
|
788
|
-
plan.verification.change.fullSuite,
|
|
789
|
-
plan.verification.change.postApply,
|
|
790
|
-
...(plan.verification.agentsCheckpoint.verification
|
|
791
|
-
? [plan.verification.agentsCheckpoint.verification]
|
|
792
|
-
: []),
|
|
793
|
-
],
|
|
794
|
-
signal,
|
|
795
|
-
),
|
|
796
|
-
consumerRoot,
|
|
797
|
-
stateRoot,
|
|
798
|
-
deliverySource: packageDeliverySource(consumerRoot, {
|
|
799
|
-
verifyGateProof: (input) => design.verifyGateProof(input),
|
|
800
|
-
verifyFinalizedDelivery: (input) => design.verifyFinalizedDelivery(input),
|
|
801
|
-
}),
|
|
802
|
-
routePolicy: routeResolution.ok
|
|
803
|
-
? routeResolution.policy
|
|
804
|
-
: unavailableRoutePolicy(),
|
|
805
|
-
proposeCandidate: async (input) => {
|
|
806
|
-
const context = contexts.getStore();
|
|
807
|
-
if (!context) {
|
|
808
|
-
return { kind: "paused", code: "parent-context-unavailable" };
|
|
809
|
-
}
|
|
810
|
-
const phaseRuntime = await runtimeForWorkerRoute(
|
|
811
|
-
input.route as WorkerRoutePolicy,
|
|
812
|
-
context,
|
|
813
|
-
parentPayloadBridge,
|
|
814
|
-
input.signal,
|
|
815
|
-
process.env,
|
|
816
|
-
{ onResponse: input.onHeaders },
|
|
817
|
-
);
|
|
818
|
-
if (!phaseRuntime.ok) {
|
|
819
|
-
if (phaseRuntime.failure.kind === "cancelled") {
|
|
820
|
-
return { kind: "operation-cancelled", code: "cancelled" };
|
|
821
|
-
}
|
|
822
|
-
throw new Error(phaseRuntime.failure.code);
|
|
823
|
-
}
|
|
824
|
-
const phase = input.task.phases[input.phase];
|
|
825
|
-
if (!phase) {
|
|
826
|
-
return { kind: "paused", code: "task-phase-unavailable" };
|
|
827
|
-
}
|
|
828
|
-
const taskPhases = Object.values(input.task.phases);
|
|
829
|
-
const executionBoundary = input.artifactCorrection
|
|
830
|
-
? {
|
|
831
|
-
read: [
|
|
832
|
-
...new Set(
|
|
833
|
-
taskPhases.flatMap((boundary) => [
|
|
834
|
-
...boundary.read,
|
|
835
|
-
...boundary.write,
|
|
836
|
-
...boundary.delete,
|
|
837
|
-
]),
|
|
838
|
-
),
|
|
839
|
-
].sort(),
|
|
840
|
-
write: [
|
|
841
|
-
...new Set(taskPhases.flatMap((boundary) => boundary.write)),
|
|
842
|
-
].sort(),
|
|
843
|
-
delete: [
|
|
844
|
-
...new Set(taskPhases.flatMap((boundary) => boundary.delete)),
|
|
845
|
-
].sort(),
|
|
846
|
-
}
|
|
847
|
-
: {
|
|
848
|
-
read: [
|
|
849
|
-
...new Set(
|
|
850
|
-
taskPhases.flatMap((boundary) => [
|
|
851
|
-
...boundary.read,
|
|
852
|
-
...boundary.write,
|
|
853
|
-
...boundary.delete,
|
|
854
|
-
]),
|
|
855
|
-
),
|
|
856
|
-
].sort(),
|
|
857
|
-
write: [...phase.write],
|
|
858
|
-
delete: [...phase.delete],
|
|
859
|
-
};
|
|
860
|
-
executionBoundary.read = [
|
|
861
|
-
...new Set([
|
|
862
|
-
...executionBoundary.read,
|
|
863
|
-
...(input.contextReadPaths ?? []).filter(
|
|
864
|
-
(relative) =>
|
|
865
|
-
permitsContextRead(relative, input.task.roots) &&
|
|
866
|
-
isSafeRegularFile(input.workspaceRoot, relative),
|
|
867
|
-
),
|
|
868
|
-
]),
|
|
869
|
-
].sort();
|
|
870
|
-
const phaseContract = {
|
|
871
|
-
candidateId: input.candidateArtifact.identity.candidateId,
|
|
872
|
-
taskId: input.taskId,
|
|
873
|
-
phase: input.phase,
|
|
874
|
-
readSet: executionBoundary.read,
|
|
875
|
-
writeSet: executionBoundary.write,
|
|
876
|
-
deleteSet: executionBoundary.delete,
|
|
877
|
-
verification: structuredClone(phase.verification),
|
|
878
|
-
agentsImpact: input.task.agents.impact,
|
|
879
|
-
agentsTarget: input.task.agents.target ?? null,
|
|
880
|
-
agentsManagedOnly: true,
|
|
881
|
-
agentsWriteAllowed: false,
|
|
882
|
-
impactClosure: structuredClone(input.task.impactClosure),
|
|
883
|
-
...(input.artifactCorrection
|
|
884
|
-
? { artifactCorrection: structuredClone(input.artifactCorrection) }
|
|
885
|
-
: {}),
|
|
886
|
-
...(input.contextRequest
|
|
887
|
-
? { requestedContext: structuredClone(input.contextRequest) }
|
|
888
|
-
: {}),
|
|
889
|
-
...(input.recoveryFeedback
|
|
890
|
-
? { recoveryFeedback: structuredClone(input.recoveryFeedback) }
|
|
891
|
-
: {}),
|
|
892
|
-
...(input.repair
|
|
893
|
-
? {
|
|
894
|
-
repair: {
|
|
895
|
-
attempt: input.repair.attempt,
|
|
896
|
-
attribution: input.repair.attribution,
|
|
897
|
-
failureIdentities: [...input.repair.failureIdentities],
|
|
898
|
-
verification: structuredClone(input.task.repairVerification),
|
|
899
|
-
inBoundaryOnly: true,
|
|
900
|
-
},
|
|
901
|
-
}
|
|
902
|
-
: {}),
|
|
903
|
-
};
|
|
904
|
-
const child = await runChildSession({
|
|
905
|
-
cwd: input.workspaceRoot,
|
|
906
|
-
modelRuntime: phaseRuntime.modelRuntime,
|
|
907
|
-
model: phaseRuntime.model,
|
|
908
|
-
systemPrompt: [
|
|
909
|
-
implementationAgent.content,
|
|
910
|
-
input.task.objective,
|
|
911
|
-
input.task.context.agents,
|
|
912
|
-
input.task.context.contract,
|
|
913
|
-
"Use recoveryFeedback to change the failing approach. For compact-patch, prefer exact replace operations and omit unchanged bodies; submit one complete atomic patch. Never repeat an unchanged failing submission or weaken verification to obtain a pass.",
|
|
914
|
-
`<phase-contract>${JSON.stringify(phaseContract)}</phase-contract>`,
|
|
915
|
-
].join("\n\n"),
|
|
916
|
-
requestId: childRequestId(input.operationId, input.taskId, input.phase),
|
|
917
|
-
taskId: input.taskId,
|
|
918
|
-
role: "implementation-worker",
|
|
919
|
-
phase: input.phase,
|
|
920
|
-
output: "diff",
|
|
921
|
-
roots: input.task.roots.map((root) =>
|
|
922
|
-
path.resolve(input.workspaceRoot, root),
|
|
923
|
-
),
|
|
924
|
-
allowedPaths: [
|
|
925
|
-
...new Set([
|
|
926
|
-
...executionBoundary.read,
|
|
927
|
-
...executionBoundary.write,
|
|
928
|
-
...executionBoundary.delete,
|
|
929
|
-
]),
|
|
930
|
-
],
|
|
931
|
-
timeoutMs: LIMITS.phaseTimeoutMs,
|
|
932
|
-
signal: input.signal,
|
|
933
|
-
failureOverride: phaseRuntime.failureOverride,
|
|
934
|
-
ledgerProjection: input.ledgerProjection,
|
|
935
|
-
candidateArtifact: input.candidateArtifact,
|
|
936
|
-
onStreamProgress: input.onProgress,
|
|
937
|
-
});
|
|
938
|
-
if (!child.ok) {
|
|
939
|
-
if (child.failure.kind === "transport") {
|
|
940
|
-
throw new Error(child.failure.code);
|
|
941
|
-
}
|
|
942
|
-
if (child.failure.kind === "cancelled") {
|
|
943
|
-
return { kind: "operation-cancelled", code: "cancelled" };
|
|
944
|
-
}
|
|
945
|
-
if (child.failure.kind === "approval-boundary") {
|
|
946
|
-
return { kind: "approval-needed", code: child.failure.code };
|
|
947
|
-
}
|
|
948
|
-
if (child.failure.kind === "result-limit") {
|
|
949
|
-
return { kind: "retryable", code: "needs-task-split" };
|
|
950
|
-
}
|
|
951
|
-
const attemptDiagnostic = {
|
|
952
|
-
finalCategory: child.classification.finalCategory,
|
|
953
|
-
submitAttempts: child.classification.attempts,
|
|
954
|
-
schema: child.classification.schema,
|
|
955
|
-
identityMismatch: Object.entries(child.classification.identity)
|
|
956
|
-
.filter(([, matches]) => !matches)
|
|
957
|
-
.map(([dimension]) => dimension),
|
|
958
|
-
};
|
|
959
|
-
return child.failure.kind === "environment" ||
|
|
960
|
-
child.failure.kind === "verification-adapter"
|
|
961
|
-
? { kind: "paused", code: child.failure.code, attemptDiagnostic }
|
|
962
|
-
: { kind: "retryable", code: child.failure.code, attemptDiagnostic };
|
|
963
|
-
}
|
|
964
|
-
const result = child.result;
|
|
965
|
-
if (result.kind === "context-request") {
|
|
966
|
-
return classifyCandidateContextRequest(result, {
|
|
967
|
-
phase: input.phase,
|
|
968
|
-
contextReadRoots: input.task.roots,
|
|
969
|
-
readPaths: phase.read,
|
|
970
|
-
writePaths: phase.write,
|
|
971
|
-
deletePaths: phase.delete,
|
|
972
|
-
taskPaths: [
|
|
973
|
-
...new Set(
|
|
974
|
-
Object.values(input.task.phases).flatMap((boundary) => [
|
|
975
|
-
...boundary.read,
|
|
976
|
-
...boundary.write,
|
|
977
|
-
...boundary.delete,
|
|
978
|
-
]),
|
|
979
|
-
),
|
|
980
|
-
],
|
|
981
|
-
redWritePaths: input.task.phases.red.write,
|
|
982
|
-
agents: {
|
|
983
|
-
impact: input.task.agents.impact,
|
|
984
|
-
...(input.task.agents.target
|
|
985
|
-
? { target: input.task.agents.target }
|
|
986
|
-
: {}),
|
|
987
|
-
},
|
|
988
|
-
});
|
|
989
|
-
}
|
|
990
|
-
if (result.kind !== "sealed-candidate") {
|
|
991
|
-
return { kind: "retryable", code: "candidate-diff-invalid" };
|
|
992
|
-
}
|
|
993
|
-
return {
|
|
994
|
-
kind: "sealed-candidate",
|
|
995
|
-
candidateId: result.candidateId,
|
|
996
|
-
artifactHash: result.artifactHash,
|
|
997
|
-
bytes: result.bytes,
|
|
998
|
-
paths: [...result.paths],
|
|
999
|
-
};
|
|
1000
|
-
},
|
|
1001
|
-
verifyPhase: async (input) =>
|
|
1002
|
-
phaseVerificationResult(
|
|
1003
|
-
await executePackageVerification({
|
|
1004
|
-
maxReportBytes,
|
|
1005
|
-
executionWritePaths: input.executionWritePaths,
|
|
1006
|
-
root: input.root,
|
|
1007
|
-
dependencyOwner: consumerRoot,
|
|
1008
|
-
verification: input.verification,
|
|
1009
|
-
signal: input.signal,
|
|
1010
|
-
}),
|
|
1011
|
-
),
|
|
1012
|
-
verifyChange: async (input) => {
|
|
1013
|
-
const verifications = input.verification
|
|
1014
|
-
? [input.verification]
|
|
1015
|
-
: input.plan.tasks.map((task) => affectedVerification(task));
|
|
1016
|
-
for (const verification of verifications) {
|
|
1017
|
-
const result = await executePackageVerification({
|
|
1018
|
-
maxReportBytes,
|
|
1019
|
-
executionWritePaths: input.plan.tasks.flatMap((task) =>
|
|
1020
|
-
Object.values(task.phases).flatMap((phase) => [
|
|
1021
|
-
...phase.write,
|
|
1022
|
-
...phase.delete,
|
|
1023
|
-
]),
|
|
1024
|
-
),
|
|
1025
|
-
root: input.root,
|
|
1026
|
-
dependencyOwner: consumerRoot,
|
|
1027
|
-
verification,
|
|
1028
|
-
signal: input.signal,
|
|
1029
|
-
});
|
|
1030
|
-
const observed = changeVerificationResult(result);
|
|
1031
|
-
if (!observed.ok) return observed;
|
|
1032
|
-
}
|
|
1033
|
-
return {
|
|
1034
|
-
ok: true,
|
|
1035
|
-
exitCode: 0,
|
|
1036
|
-
classification: "expected-green",
|
|
1037
|
-
};
|
|
1038
|
-
},
|
|
1039
|
-
});
|
|
646
|
+
const service = openPackageWorkflowService(packageContext(initialContext));
|
|
1040
647
|
return {
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
cwd: consumerRoot,
|
|
1049
|
-
home: homedir(),
|
|
1050
|
-
...(context.model ? { parentModel: context.model } : {}),
|
|
1051
|
-
});
|
|
1052
|
-
engine.updateRoutePolicy(
|
|
1053
|
-
operationRouteResolution.ok
|
|
1054
|
-
? operationRouteResolution.policy
|
|
1055
|
-
: unavailableRoutePolicy(),
|
|
1056
|
-
);
|
|
1057
|
-
const validation = validateControlCommand(command);
|
|
1058
|
-
if (!validation.ok) {
|
|
1059
|
-
const error = new Error(validation.code);
|
|
1060
|
-
error.name = "ControlCommandError";
|
|
1061
|
-
throw error;
|
|
1062
|
-
}
|
|
1063
|
-
return contexts.run(context, async () => {
|
|
1064
|
-
const outcome = await engine.execute(
|
|
1065
|
-
validation.value,
|
|
1066
|
-
signal,
|
|
1067
|
-
onActivity,
|
|
1068
|
-
);
|
|
1069
|
-
const routePolicy = visibleRoutePolicyStatus(
|
|
1070
|
-
operationRouteResolution,
|
|
1071
|
-
engine.routePolicyStatus(),
|
|
1072
|
-
);
|
|
1073
|
-
return { ...outcome, routePolicy };
|
|
1074
|
-
});
|
|
1075
|
-
},
|
|
1076
|
-
executeDesign(request: unknown) {
|
|
1077
|
-
return design.execute(request);
|
|
1078
|
-
},
|
|
1079
|
-
executeAmendment(change: string, batchId: string, request: unknown) {
|
|
1080
|
-
return engine.amend(change, batchId, request, (assertAuthority) =>
|
|
1081
|
-
design.executeWithAuthority(request, assertAuthority),
|
|
648
|
+
...service,
|
|
649
|
+
execute(command, context = initialContext, signal, onActivity) {
|
|
650
|
+
return service.execute(
|
|
651
|
+
command,
|
|
652
|
+
packageContext(context),
|
|
653
|
+
signal,
|
|
654
|
+
onActivity,
|
|
1082
655
|
);
|
|
1083
656
|
},
|
|
1084
|
-
assertDesignRun(runId: string) {
|
|
1085
|
-
design.assertDesignRun(runId);
|
|
1086
|
-
},
|
|
1087
|
-
recordDesignEvidence(input) {
|
|
1088
|
-
return design.recordEvidence(input);
|
|
1089
|
-
},
|
|
1090
|
-
async close() {
|
|
1091
|
-
contexts.disable();
|
|
1092
|
-
await engine.close();
|
|
1093
|
-
design.close();
|
|
1094
|
-
},
|
|
1095
657
|
};
|
|
1096
658
|
}
|
|
1097
659
|
|
|
@@ -1128,23 +690,10 @@ function runStoreResetError(error: RunStoreFormatError): Error {
|
|
|
1128
690
|
return reset;
|
|
1129
691
|
}
|
|
1130
692
|
|
|
1131
|
-
function visibleRoutePolicyStatus(
|
|
1132
|
-
resolution: RoutePolicyResolution,
|
|
1133
|
-
brokerStatus: Record<string, unknown> | undefined,
|
|
1134
|
-
): Record<string, unknown> {
|
|
1135
|
-
if (!resolution.ok) return inspectRoutePolicy(resolution);
|
|
1136
|
-
const inspected = brokerStatus ?? inspectRoutePolicy(resolution);
|
|
1137
|
-
return {
|
|
1138
|
-
...inspected,
|
|
1139
|
-
source: { kind: resolution.source.kind },
|
|
1140
|
-
};
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
693
|
export function registerWorkflowControl(
|
|
1144
694
|
pi: ExtensionAPI,
|
|
1145
695
|
engineFactory: WorkflowControlEngineFactory = openPackageWorkflowControlEngine,
|
|
1146
696
|
): void {
|
|
1147
|
-
const parentPayloadBridge = new ParentPayloadBridge();
|
|
1148
697
|
const activity = new ActivityController();
|
|
1149
698
|
const engines = new Map<string, Promise<WorkflowControlEngine>>();
|
|
1150
699
|
const designOperations = new Set<Promise<void>>();
|
|
@@ -1179,13 +728,13 @@ export function registerWorkflowControl(
|
|
|
1179
728
|
return true;
|
|
1180
729
|
}
|
|
1181
730
|
})();
|
|
1182
|
-
const packetRuntime = new PacketRuntime({ activation
|
|
731
|
+
const packetRuntime = new PacketRuntime({ activation });
|
|
1183
732
|
|
|
1184
733
|
const engineFor = (ctx: ExtensionContext) => {
|
|
1185
734
|
const key = ctx.cwd;
|
|
1186
735
|
const existing = engines.get(key);
|
|
1187
736
|
if (existing) return existing;
|
|
1188
|
-
const opened = Promise.resolve(engineFactory(ctx
|
|
737
|
+
const opened = Promise.resolve(engineFactory(ctx));
|
|
1189
738
|
engines.set(key, opened);
|
|
1190
739
|
void opened.catch(() => {
|
|
1191
740
|
if (engines.get(key) === opened) engines.delete(key);
|
|
@@ -1241,7 +790,6 @@ export function registerWorkflowControl(
|
|
|
1241
790
|
activePrompt = undefined;
|
|
1242
791
|
await packetRuntime.drain();
|
|
1243
792
|
deactivate();
|
|
1244
|
-
parentPayloadBridge.clear();
|
|
1245
793
|
};
|
|
1246
794
|
const exitStage = async () => {
|
|
1247
795
|
if (exitingStage) throw new Error("stage-control-mismatch");
|
|
@@ -1383,7 +931,14 @@ export function registerWorkflowControl(
|
|
|
1383
931
|
throw new Error("stage-control-mismatch");
|
|
1384
932
|
}
|
|
1385
933
|
const parsed = validateDesignControlRequest(record.request);
|
|
1386
|
-
if (!parsed.ok)
|
|
934
|
+
if (!parsed.ok) {
|
|
935
|
+
const error = new DesignControlValidationError(parsed.diagnostics);
|
|
936
|
+
designFailures.set(
|
|
937
|
+
toolCallId,
|
|
938
|
+
safeDesignFailure(error, "validation"),
|
|
939
|
+
);
|
|
940
|
+
throw error;
|
|
941
|
+
}
|
|
1387
942
|
const request = parsed.value;
|
|
1388
943
|
if (
|
|
1389
944
|
request.operation === "bind-change" ||
|
|
@@ -1506,7 +1061,16 @@ export function registerWorkflowControl(
|
|
|
1506
1061
|
throw new Error("stage-control-mismatch");
|
|
1507
1062
|
}
|
|
1508
1063
|
const designRequest = validateDesignControlRequest(record.request);
|
|
1509
|
-
if (!designRequest.ok)
|
|
1064
|
+
if (!designRequest.ok) {
|
|
1065
|
+
const error = new DesignControlValidationError(
|
|
1066
|
+
designRequest.diagnostics,
|
|
1067
|
+
);
|
|
1068
|
+
designFailures.set(
|
|
1069
|
+
toolCallId,
|
|
1070
|
+
safeDesignFailure(error, "validation"),
|
|
1071
|
+
);
|
|
1072
|
+
throw error;
|
|
1073
|
+
}
|
|
1510
1074
|
let settleDesign!: () => void;
|
|
1511
1075
|
const settled = new Promise<void>((resolve) => {
|
|
1512
1076
|
settleDesign = resolve;
|
|
@@ -1588,7 +1152,7 @@ export function registerWorkflowControl(
|
|
|
1588
1152
|
? await packetRuntime.execute(
|
|
1589
1153
|
record.action,
|
|
1590
1154
|
operation,
|
|
1591
|
-
ctx,
|
|
1155
|
+
packageContext(ctx),
|
|
1592
1156
|
signal,
|
|
1593
1157
|
activity.observe(
|
|
1594
1158
|
toolCallId,
|
|
@@ -1598,7 +1162,7 @@ export function registerWorkflowControl(
|
|
|
1598
1162
|
: await packetRuntime.execute(
|
|
1599
1163
|
record.action,
|
|
1600
1164
|
operation,
|
|
1601
|
-
ctx,
|
|
1165
|
+
packageContext(ctx),
|
|
1602
1166
|
signal,
|
|
1603
1167
|
);
|
|
1604
1168
|
let payload:
|
|
@@ -1814,7 +1378,7 @@ export function registerWorkflowControl(
|
|
|
1814
1378
|
}
|
|
1815
1379
|
return { action: "continue" };
|
|
1816
1380
|
});
|
|
1817
|
-
pi.on("before_agent_start", (event
|
|
1381
|
+
pi.on("before_agent_start", (event) => {
|
|
1818
1382
|
const prompt = pendingPrompt;
|
|
1819
1383
|
const init =
|
|
1820
1384
|
pendingInit && hasExpandedPromptMarker(event.prompt, "abel-init");
|
|
@@ -1828,15 +1392,6 @@ export function registerWorkflowControl(
|
|
|
1828
1392
|
}
|
|
1829
1393
|
registerDispatchTool(prompt === "abel-implement" ? "command" : "packet");
|
|
1830
1394
|
activePrompt = prompt;
|
|
1831
|
-
const sessionId = ctx.sessionManager?.getSessionId?.();
|
|
1832
|
-
if (typeof sessionId === "string") {
|
|
1833
|
-
parentPayloadBridge.beginSession(sessionId);
|
|
1834
|
-
} else {
|
|
1835
|
-
parentPayloadBridge.clear();
|
|
1836
|
-
}
|
|
1837
|
-
}
|
|
1838
|
-
if (ctx.model) {
|
|
1839
|
-
parentPayloadBridge.install(ctx.model, ctx.modelRegistry);
|
|
1840
1395
|
}
|
|
1841
1396
|
if (prompt) activateDispatcher(pi, activation, prompt, event.prompt);
|
|
1842
1397
|
if (verified && prompt === "abel-design") enforceDesignTools();
|
|
@@ -1847,16 +1402,6 @@ export function registerWorkflowControl(
|
|
|
1847
1402
|
: "Abel workflow is inactive. Handle ordinary engineering requests directly. References to commands, repository files, OpenSpec changes, and historical workflow instructions do not authorize a workflow. Do not load or execute an Abel stage unless the user explicitly invokes its slash command.";
|
|
1848
1403
|
return { systemPrompt: `${event.systemPrompt ?? ""}\n\n${boundary}` };
|
|
1849
1404
|
});
|
|
1850
|
-
pi.on("model_select", (event, ctx) => {
|
|
1851
|
-
const sessionId = ctx.sessionManager?.getSessionId?.();
|
|
1852
|
-
if (typeof sessionId !== "string") {
|
|
1853
|
-
parentPayloadBridge.clear();
|
|
1854
|
-
return;
|
|
1855
|
-
}
|
|
1856
|
-
parentPayloadBridge.beginSession(sessionId);
|
|
1857
|
-
const model = event.model ?? ctx.model;
|
|
1858
|
-
if (model) parentPayloadBridge.install(model, ctx.modelRegistry);
|
|
1859
|
-
});
|
|
1860
1405
|
pi.on("before_provider_request", (event, ctx) => {
|
|
1861
1406
|
if (
|
|
1862
1407
|
activePrompt !== "abel-design" ||
|
|
@@ -1878,13 +1423,6 @@ export function registerWorkflowControl(
|
|
|
1878
1423
|
await packetRuntime.drain();
|
|
1879
1424
|
await closeEngines();
|
|
1880
1425
|
deactivate();
|
|
1881
|
-
const sessionId = ctx.sessionManager?.getSessionId?.();
|
|
1882
|
-
if (typeof sessionId === "string") {
|
|
1883
|
-
parentPayloadBridge.beginSession(sessionId);
|
|
1884
|
-
if (ctx.model) parentPayloadBridge.install(ctx.model, ctx.modelRegistry);
|
|
1885
|
-
} else {
|
|
1886
|
-
parentPayloadBridge.clear();
|
|
1887
|
-
}
|
|
1888
1426
|
if (ctx.mode === "tui") activity.attach(ctx.ui);
|
|
1889
1427
|
});
|
|
1890
1428
|
pi.on("session_shutdown", async () => {
|
|
@@ -1895,7 +1433,6 @@ export function registerWorkflowControl(
|
|
|
1895
1433
|
await closeEngines();
|
|
1896
1434
|
activity.clear();
|
|
1897
1435
|
deactivate();
|
|
1898
|
-
parentPayloadBridge.clear();
|
|
1899
1436
|
});
|
|
1900
1437
|
}
|
|
1901
1438
|
|