@abelxiaoxing/cadence 1.8.2 → 1.8.4
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 +71 -531
- package/agents/design-explorer.md +15 -23
- package/agents/diagnosis-worker.md +12 -23
- package/agents/implementation-worker.md +16 -34
- package/config/.env.example +2 -5
- package/package.json +1 -1
- package/prompts/abel-diagnose.md +5 -5
- package/src/candidate-context.ts +289 -0
- package/src/contracts.ts +12 -22
- package/src/durable-contracts.ts +1 -5
- package/src/durable-workflow.ts +3 -159
- package/src/evidence-draft.ts +1 -1
- package/src/index.ts +12 -16
- package/src/package-candidate-process.ts +206 -0
- package/src/package-candidate.ts +11 -214
- package/src/package-workflow.ts +5 -42
- package/src/packet-runtime.ts +144 -255
- package/src/phase-execution.ts +134 -230
- package/src/startup-card.ts +17 -23
- package/src/subagent-process.ts +476 -0
- package/src/transport-budget.ts +1 -3
- package/src/workflow-policy.ts +9 -18
- package/src/workflow-state-machine.ts +1 -15
- package/config/routes.example.json +0 -39
- package/src/child-budget.ts +0 -58
- package/src/child-model.ts +0 -142
- package/src/child-session.ts +0 -640
- package/src/parent-provider.ts +0 -375
- package/src/route-policy.ts +0 -545
- package/src/submit-tool.ts +0 -950
- package/src/worker-broker.ts +0 -806
package/src/package-candidate.ts
CHANGED
|
@@ -1,227 +1,24 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { runChildSession } from "./child-session.ts";
|
|
4
1
|
import type { VerificationFailureSummary } from "./contracts.ts";
|
|
5
|
-
import { LIMITS } from "./contracts.ts";
|
|
6
2
|
import type { DurableWorkflowEngineOptions } from "./durable-contracts.ts";
|
|
7
3
|
import type { ParentModelSource } from "./model-source.ts";
|
|
8
|
-
import {
|
|
9
|
-
import type { WorkerRoutePolicy } from "./route-policy.ts";
|
|
10
|
-
import { isSafeRegularFile } from "./safe-path.ts";
|
|
11
|
-
import {
|
|
12
|
-
classifyCandidateContextRequest,
|
|
13
|
-
permitsContextRead,
|
|
14
|
-
} from "./submit-tool.ts";
|
|
15
|
-
import { transportFailureError } from "./transport-budget.ts";
|
|
4
|
+
import { proposeProcessPackageCandidate } from "./package-candidate-process.ts";
|
|
16
5
|
import type { DurableCandidateProposal } from "./workflow-policy.ts";
|
|
17
6
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
export async function proposePackageCandidate(
|
|
7
|
+
/**
|
|
8
|
+
* Parent-owned candidate adapter. The child only edits the disposable proposal
|
|
9
|
+
* root; this function returns its bounded diff to the existing sealing and
|
|
10
|
+
* verification pipeline.
|
|
11
|
+
*/
|
|
12
|
+
export function proposePackageCandidate(
|
|
26
13
|
input: Parameters<DurableWorkflowEngineOptions["proposeCandidate"]>[0],
|
|
27
14
|
context: ParentModelSource | undefined,
|
|
28
15
|
implementationAgent: { content: string },
|
|
29
16
|
verificationDiagnostics: VerificationFailureSummary[] = [],
|
|
30
17
|
): Promise<DurableCandidateProposal> {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
const phaseRuntime = await runtimeForWorkerRoute(
|
|
35
|
-
input.route as WorkerRoutePolicy,
|
|
18
|
+
return proposeProcessPackageCandidate(
|
|
19
|
+
input,
|
|
36
20
|
context,
|
|
37
|
-
|
|
38
|
-
process.env,
|
|
39
|
-
);
|
|
40
|
-
if (!phaseRuntime.ok) {
|
|
41
|
-
if (phaseRuntime.failure.kind === "cancelled") {
|
|
42
|
-
return { kind: "operation-cancelled", code: "cancelled" };
|
|
43
|
-
}
|
|
44
|
-
throw new Error(phaseRuntime.failure.code);
|
|
45
|
-
}
|
|
46
|
-
const phase = input.task.phases[input.phase];
|
|
47
|
-
if (!phase) {
|
|
48
|
-
return { kind: "paused", code: "task-phase-unavailable" };
|
|
49
|
-
}
|
|
50
|
-
const taskPhases = Object.values(input.task.phases);
|
|
51
|
-
const executionBoundary = input.artifactCorrection
|
|
52
|
-
? {
|
|
53
|
-
read: [
|
|
54
|
-
...new Set(
|
|
55
|
-
taskPhases.flatMap((boundary) => [
|
|
56
|
-
...boundary.read,
|
|
57
|
-
...boundary.write,
|
|
58
|
-
...boundary.delete,
|
|
59
|
-
]),
|
|
60
|
-
),
|
|
61
|
-
].sort(),
|
|
62
|
-
write: [
|
|
63
|
-
...new Set(taskPhases.flatMap((boundary) => boundary.write)),
|
|
64
|
-
].sort(),
|
|
65
|
-
delete: [
|
|
66
|
-
...new Set(taskPhases.flatMap((boundary) => boundary.delete)),
|
|
67
|
-
].sort(),
|
|
68
|
-
}
|
|
69
|
-
: {
|
|
70
|
-
read: [
|
|
71
|
-
...new Set(
|
|
72
|
-
taskPhases.flatMap((boundary) => [
|
|
73
|
-
...boundary.read,
|
|
74
|
-
...boundary.write,
|
|
75
|
-
...boundary.delete,
|
|
76
|
-
]),
|
|
77
|
-
),
|
|
78
|
-
].sort(),
|
|
79
|
-
write: [...phase.write],
|
|
80
|
-
delete: [...phase.delete],
|
|
81
|
-
};
|
|
82
|
-
executionBoundary.read = [
|
|
83
|
-
...new Set([
|
|
84
|
-
...executionBoundary.read,
|
|
85
|
-
...(input.contextReadPaths ?? []).filter(
|
|
86
|
-
(relative) =>
|
|
87
|
-
permitsContextRead(relative, input.task.roots) &&
|
|
88
|
-
isSafeRegularFile(input.workspaceRoot, relative),
|
|
89
|
-
),
|
|
90
|
-
]),
|
|
91
|
-
].sort();
|
|
92
|
-
const phaseContract = {
|
|
21
|
+
implementationAgent,
|
|
93
22
|
verificationDiagnostics,
|
|
94
|
-
|
|
95
|
-
taskId: input.taskId,
|
|
96
|
-
phase: input.phase,
|
|
97
|
-
readSet: executionBoundary.read,
|
|
98
|
-
writeSet: executionBoundary.write,
|
|
99
|
-
deleteSet: executionBoundary.delete,
|
|
100
|
-
verification: structuredClone(phase.verification),
|
|
101
|
-
agentsImpact: input.task.agents.impact,
|
|
102
|
-
agentsTarget: input.task.agents.target ?? null,
|
|
103
|
-
agentsManagedOnly: true,
|
|
104
|
-
agentsWriteAllowed: false,
|
|
105
|
-
impactClosure: structuredClone(input.task.impactClosure),
|
|
106
|
-
...(input.artifactCorrection
|
|
107
|
-
? { artifactCorrection: structuredClone(input.artifactCorrection) }
|
|
108
|
-
: {}),
|
|
109
|
-
...(input.contextRequest
|
|
110
|
-
? { requestedContext: structuredClone(input.contextRequest) }
|
|
111
|
-
: {}),
|
|
112
|
-
...(input.recoveryFeedback
|
|
113
|
-
? { recoveryFeedback: structuredClone(input.recoveryFeedback) }
|
|
114
|
-
: {}),
|
|
115
|
-
...(input.repair
|
|
116
|
-
? {
|
|
117
|
-
repair: {
|
|
118
|
-
attempt: input.repair.attempt,
|
|
119
|
-
attribution: input.repair.attribution,
|
|
120
|
-
failureIdentities: [...input.repair.failureIdentities],
|
|
121
|
-
verification: structuredClone(input.task.repairVerification),
|
|
122
|
-
inBoundaryOnly: true,
|
|
123
|
-
},
|
|
124
|
-
}
|
|
125
|
-
: {}),
|
|
126
|
-
};
|
|
127
|
-
const child = await runChildSession({
|
|
128
|
-
cwd: input.workspaceRoot,
|
|
129
|
-
modelRuntime: phaseRuntime.modelRuntime,
|
|
130
|
-
model: phaseRuntime.model,
|
|
131
|
-
systemPrompt: [
|
|
132
|
-
implementationAgent.content,
|
|
133
|
-
input.task.objective,
|
|
134
|
-
input.task.context.agents,
|
|
135
|
-
input.task.context.contract,
|
|
136
|
-
"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.",
|
|
137
|
-
`<phase-contract>${JSON.stringify(phaseContract)}</phase-contract>`,
|
|
138
|
-
].join("\n\n"),
|
|
139
|
-
requestId: childRequestId(input.operationId, input.taskId, input.phase),
|
|
140
|
-
taskId: input.taskId,
|
|
141
|
-
role: "implementation-worker",
|
|
142
|
-
phase: input.phase,
|
|
143
|
-
output: "diff",
|
|
144
|
-
roots: input.task.roots.map((root) =>
|
|
145
|
-
path.resolve(input.workspaceRoot, root),
|
|
146
|
-
),
|
|
147
|
-
allowedPaths: [
|
|
148
|
-
...new Set([
|
|
149
|
-
...executionBoundary.read,
|
|
150
|
-
...executionBoundary.write,
|
|
151
|
-
...executionBoundary.delete,
|
|
152
|
-
]),
|
|
153
|
-
],
|
|
154
|
-
timeoutMs: LIMITS.phaseTimeoutMs,
|
|
155
|
-
signal: input.signal,
|
|
156
|
-
ledgerProjection: input.ledgerProjection,
|
|
157
|
-
candidateArtifact: input.candidateArtifact,
|
|
158
|
-
onStreamStart: input.onRequestStart,
|
|
159
|
-
onStreamHeaders: input.onHeaders,
|
|
160
|
-
onStreamProgress: input.onProgress,
|
|
161
|
-
});
|
|
162
|
-
if (!child.ok) {
|
|
163
|
-
if (child.failure.kind === "transport") {
|
|
164
|
-
throw transportFailureError(child.failure.code);
|
|
165
|
-
}
|
|
166
|
-
if (child.failure.kind === "cancelled") {
|
|
167
|
-
return { kind: "operation-cancelled", code: "cancelled" };
|
|
168
|
-
}
|
|
169
|
-
if (child.failure.kind === "approval-boundary") {
|
|
170
|
-
return { kind: "approval-needed", code: child.failure.code };
|
|
171
|
-
}
|
|
172
|
-
if (child.failure.kind === "execution-limit") {
|
|
173
|
-
return { kind: "paused", code: "needs-task-split" };
|
|
174
|
-
}
|
|
175
|
-
if (child.failure.kind === "result-limit") {
|
|
176
|
-
return { kind: "retryable", code: "needs-task-split" };
|
|
177
|
-
}
|
|
178
|
-
const attemptDiagnostic = {
|
|
179
|
-
finalCategory: child.classification.finalCategory,
|
|
180
|
-
submitAttempts: child.classification.attempts,
|
|
181
|
-
schema: child.classification.schema,
|
|
182
|
-
identityMismatch: Object.entries(child.classification.identity)
|
|
183
|
-
.filter(([, matches]) => !matches)
|
|
184
|
-
.map(([dimension]) => dimension),
|
|
185
|
-
};
|
|
186
|
-
return child.failure.kind === "environment" ||
|
|
187
|
-
child.failure.kind === "verification-adapter"
|
|
188
|
-
? { kind: "paused", code: child.failure.code, attemptDiagnostic }
|
|
189
|
-
: { kind: "retryable", code: child.failure.code, attemptDiagnostic };
|
|
190
|
-
}
|
|
191
|
-
const result = child.result;
|
|
192
|
-
if (result.kind === "context-request") {
|
|
193
|
-
return classifyCandidateContextRequest(result, {
|
|
194
|
-
phase: input.phase,
|
|
195
|
-
contextReadRoots: input.task.roots,
|
|
196
|
-
readPaths: phase.read,
|
|
197
|
-
writePaths: phase.write,
|
|
198
|
-
deletePaths: phase.delete,
|
|
199
|
-
taskPaths: [
|
|
200
|
-
...new Set(
|
|
201
|
-
Object.values(input.task.phases).flatMap((boundary) => [
|
|
202
|
-
...boundary.read,
|
|
203
|
-
...boundary.write,
|
|
204
|
-
...boundary.delete,
|
|
205
|
-
]),
|
|
206
|
-
),
|
|
207
|
-
],
|
|
208
|
-
redWritePaths: input.task.phases.red.write,
|
|
209
|
-
agents: {
|
|
210
|
-
impact: input.task.agents.impact,
|
|
211
|
-
...(input.task.agents.target
|
|
212
|
-
? { target: input.task.agents.target }
|
|
213
|
-
: {}),
|
|
214
|
-
},
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
if (result.kind !== "sealed-candidate") {
|
|
218
|
-
return { kind: "retryable", code: "candidate-diff-invalid" };
|
|
219
|
-
}
|
|
220
|
-
return {
|
|
221
|
-
kind: "sealed-candidate",
|
|
222
|
-
candidateId: result.candidateId,
|
|
223
|
-
artifactHash: result.artifactHash,
|
|
224
|
-
bytes: result.bytes,
|
|
225
|
-
paths: [...result.paths],
|
|
226
|
-
};
|
|
23
|
+
);
|
|
227
24
|
}
|
package/src/package-workflow.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import type { WorkflowActivityUpdate } from "./activity-contracts.ts";
|
|
5
4
|
import { loadAgentDefinitions } from "./agent-registry.ts";
|
|
@@ -20,12 +19,6 @@ import {
|
|
|
20
19
|
executePackageVerification,
|
|
21
20
|
phaseVerificationResult,
|
|
22
21
|
} from "./package-verification.ts";
|
|
23
|
-
import {
|
|
24
|
-
inspectRoutePolicy,
|
|
25
|
-
loadRoutePolicy,
|
|
26
|
-
type RoutePolicyResolution,
|
|
27
|
-
unavailableRoutePolicy,
|
|
28
|
-
} from "./route-policy.ts";
|
|
29
22
|
import { resolveStateRoot } from "./state-root.ts";
|
|
30
23
|
import { VerificationFeedback } from "./verification-diagnostics.ts";
|
|
31
24
|
import { captureVerificationEnvironmentIdentity } from "./verification-environment.ts";
|
|
@@ -118,11 +111,6 @@ function openPreparedPackageWorkflowService(
|
|
|
118
111
|
initialContext: PackageContext,
|
|
119
112
|
): PackageWorkflowService {
|
|
120
113
|
const consumerRoot = path.resolve(initialContext.cwd);
|
|
121
|
-
const routeResolution = loadRoutePolicy({
|
|
122
|
-
cwd: consumerRoot,
|
|
123
|
-
home: homedir(),
|
|
124
|
-
...(initialContext.model ? { parentModel: initialContext.model } : {}),
|
|
125
|
-
});
|
|
126
114
|
const stateRoot = resolveStateRoot({
|
|
127
115
|
consumerRoot,
|
|
128
116
|
xdgStateHome: process.env.XDG_STATE_HOME,
|
|
@@ -194,9 +182,6 @@ function openPreparedPackageWorkflowService(
|
|
|
194
182
|
verifyFinalizedDelivery: (input) =>
|
|
195
183
|
design.verifyFinalizedDelivery(input),
|
|
196
184
|
}),
|
|
197
|
-
routePolicy: routeResolution.ok
|
|
198
|
-
? routeResolution.policy
|
|
199
|
-
: unavailableRoutePolicy(),
|
|
200
185
|
proposeCandidate: (input) =>
|
|
201
186
|
proposePackageCandidate(
|
|
202
187
|
input,
|
|
@@ -267,16 +252,6 @@ function openPreparedPackageWorkflowService(
|
|
|
267
252
|
signal,
|
|
268
253
|
onActivity,
|
|
269
254
|
) {
|
|
270
|
-
const operationRouteResolution = loadRoutePolicy({
|
|
271
|
-
cwd: consumerRoot,
|
|
272
|
-
home: homedir(),
|
|
273
|
-
...(context.model ? { parentModel: context.model } : {}),
|
|
274
|
-
});
|
|
275
|
-
engine.updateRoutePolicy(
|
|
276
|
-
operationRouteResolution.ok
|
|
277
|
-
? operationRouteResolution.policy
|
|
278
|
-
: unavailableRoutePolicy(),
|
|
279
|
-
);
|
|
280
255
|
const validation = validateControlCommand(command);
|
|
281
256
|
if (!validation.ok) {
|
|
282
257
|
const error = new Error(validation.code);
|
|
@@ -290,13 +265,13 @@ function openPreparedPackageWorkflowService(
|
|
|
290
265
|
signal,
|
|
291
266
|
onActivity,
|
|
292
267
|
);
|
|
293
|
-
const routePolicy = visibleRoutePolicyStatus(
|
|
294
|
-
operationRouteResolution,
|
|
295
|
-
engine.routePolicyStatus(),
|
|
296
|
-
);
|
|
297
268
|
return {
|
|
298
269
|
...outcome,
|
|
299
|
-
|
|
270
|
+
workerExecution: {
|
|
271
|
+
mode: "inherited-pi-model",
|
|
272
|
+
migration:
|
|
273
|
+
"routes.json and endpoint routing were removed; configure the current model in Pi.",
|
|
274
|
+
},
|
|
300
275
|
verificationDiagnostics: feedback.getStore()?.current() ?? [],
|
|
301
276
|
};
|
|
302
277
|
}),
|
|
@@ -328,15 +303,3 @@ function openPreparedPackageWorkflowService(
|
|
|
328
303
|
throw error;
|
|
329
304
|
}
|
|
330
305
|
}
|
|
331
|
-
|
|
332
|
-
function visibleRoutePolicyStatus(
|
|
333
|
-
resolution: RoutePolicyResolution,
|
|
334
|
-
brokerStatus: Record<string, unknown> | undefined,
|
|
335
|
-
): Record<string, unknown> {
|
|
336
|
-
if (!resolution.ok) return inspectRoutePolicy(resolution);
|
|
337
|
-
const inspected = brokerStatus ?? inspectRoutePolicy(resolution);
|
|
338
|
-
return {
|
|
339
|
-
...inspected,
|
|
340
|
-
source: { kind: resolution.source.kind },
|
|
341
|
-
};
|
|
342
|
-
}
|