@abelxiaoxing/cadence 1.0.2 → 1.0.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/src/worker.ts CHANGED
@@ -1,163 +1,92 @@
1
- // Process-local logical Worker registry for private orchestration. A Worker
2
- // is keyed by stable task identity. Its immutable task contract is separate
3
- // from the current phase request, snapshot, verification, and launch budget.
4
- // No credential, transcript, provider diagnostic, or unbounded retry ledger
5
- // is retained.
6
-
7
- import type { RequestEnvelope, VerificationContract } from "./contracts.ts";
8
-
9
- export interface WorkerContract {
10
- stage: string;
11
- role: string;
12
- taskId: string;
13
- objective: string;
14
- roots: string[];
15
- agents: string;
16
- contractText: string;
17
- read: string[];
18
- conflicts: string[];
19
- resources: string[];
20
- output: string;
21
- currentPhase: WorkerPhaseContract;
22
- }
23
-
24
- export interface WorkerTaskContract {
25
- stage: string;
26
- role: string;
27
- taskId: string;
28
- objective: string;
29
- roots: string[];
30
- agents: string;
31
- contractText: string;
32
- read: string[];
33
- conflicts: string[];
34
- resources: string[];
35
- output: string;
36
- }
37
-
38
- export interface WorkerPhaseContract {
39
- requestId: string;
40
- phase: string;
41
- readSet: string[];
42
- writeSet: string[];
43
- conflicts: string[];
44
- resources: string[];
45
- verificationLock?: string;
46
- snapshot?: unknown;
47
- verification?: VerificationContract;
48
- correctionIndex: 0 | 1;
49
- }
50
-
51
- export interface LogicalWorker {
52
- identity: string;
53
- taskContract: WorkerTaskContract;
54
- currentPhase: WorkerPhaseContract;
55
- state: WorkerState;
1
+ // Process-local task registry for the private Implement runtime.
2
+
3
+ import type {
4
+ CandidateFailure,
5
+ ImplementationPhase,
6
+ PhaseAttempt,
7
+ TaskBoundary,
8
+ TaskFailure,
9
+ } from "./contracts.ts";
10
+ import type { ConflictDeclaration } from "./scheduler.ts";
11
+
12
+ export type TaskState =
13
+ | {
14
+ kind: "ready";
15
+ phase: ImplementationPhase;
16
+ launchIndex: 0 | 1;
17
+ correction?: CandidateFailure;
18
+ }
19
+ | {
20
+ kind: "candidate-pending";
21
+ phase: ImplementationPhase;
22
+ launchIndex: 0 | 1;
23
+ originRequestId: string;
24
+ resultId: string;
25
+ }
26
+ | {
27
+ kind: "agents-checkpoint-pending";
28
+ finalPhase: "green" | "refactor";
29
+ attemptIndex: 0 | 1;
30
+ }
31
+ | { kind: "blocked"; phase: ImplementationPhase; failure: TaskFailure }
32
+ | { kind: "completed"; finalPhase: "green" | "refactor" };
33
+
34
+ export interface TaskRecord {
35
+ key: string;
36
+ workspaceRoot: string;
37
+ workerIdentity: string;
38
+ boundary: TaskBoundary;
39
+ conflict: ConflictDeclaration;
40
+ state: TaskState;
56
41
  }
57
42
 
58
- export type WorkerState =
59
- | { kind: "ready" }
60
- | { kind: "candidate-pending" }
61
- | { kind: "phase-applied" }
62
- | { kind: "artifact-correction-pending"; rejection: string }
63
- | { kind: "stale-redispatch-pending" }
64
- | { kind: "blocked"; reason: "artifact" | "mechanical" };
65
-
66
- export function contractOf(envelope: RequestEnvelope): WorkerContract {
67
- return {
68
- stage: envelope.stage,
69
- role: envelope.role,
70
- taskId: envelope.taskId ?? envelope.id,
71
- objective: envelope.objective,
72
- roots: [...envelope.roots],
73
- agents: envelope.context.agents,
74
- contractText: envelope.context.contract,
75
- read: [...envelope.declared.read],
76
- conflicts: [...envelope.declared.conflicts],
77
- resources: [...envelope.declared.resources],
78
- output: envelope.output,
79
- currentPhase: phaseOf(envelope, 0),
80
- };
43
+ export function taskRecordKey(
44
+ workspaceRoot: string,
45
+ changeId: string,
46
+ taskId: string,
47
+ ): string {
48
+ return `${workspaceRoot}\0${changeId}\0${taskId}`;
81
49
  }
82
50
 
83
- export function sameContract(
84
- a: WorkerTaskContract,
85
- b: WorkerTaskContract,
86
- ): boolean {
87
- if (
88
- a.stage !== b.stage ||
89
- a.role !== b.role ||
90
- a.taskId !== b.taskId ||
91
- a.objective !== b.objective ||
92
- a.agents !== b.agents ||
93
- a.contractText !== b.contractText ||
94
- a.output !== b.output
95
- )
96
- return false;
97
- return (
98
- arrayEqual(a.roots, b.roots) &&
99
- arrayEqual(a.read, b.read) &&
100
- arrayEqual(a.conflicts, b.conflicts) &&
101
- arrayEqual(a.resources, b.resources)
102
- );
103
- }
104
-
105
- export function samePhaseContract(
106
- a: WorkerPhaseContract,
107
- b: WorkerPhaseContract,
108
- ): boolean {
109
- return (
110
- a.phase === b.phase &&
111
- arrayEqual(a.readSet, b.readSet) &&
112
- arrayEqual(a.writeSet, b.writeSet) &&
113
- arrayEqual(a.conflicts, b.conflicts) &&
114
- arrayEqual(a.resources, b.resources) &&
115
- a.verificationLock === b.verificationLock &&
116
- JSON.stringify(a.verification) === JSON.stringify(b.verification)
117
- );
118
- }
119
-
120
- function phaseOf(
121
- envelope: RequestEnvelope,
122
- correctionIndex: 0 | 1,
123
- ): WorkerPhaseContract {
51
+ export function taskConflictOf(boundary: TaskBoundary): ConflictDeclaration {
52
+ const phases = [
53
+ boundary.phases.red,
54
+ boundary.phases.green,
55
+ ...(boundary.phases.refactor ? [boundary.phases.refactor] : []),
56
+ ];
57
+ const write = new Set(phases.flatMap((phase) => phase.write));
58
+ if (boundary.agents.impact !== "none" && boundary.agents.target) {
59
+ write.add(boundary.agents.target);
60
+ }
124
61
  return {
125
- requestId: envelope.id,
126
- phase: envelope.phase,
127
- readSet: [...envelope.declared.read],
128
- writeSet: [...envelope.declared.write],
129
- conflicts: [...envelope.declared.conflicts],
130
- resources: [...envelope.declared.resources],
131
- verificationLock: envelope.declared.verificationLock,
132
- snapshot:
133
- envelope.snapshot === undefined
134
- ? undefined
135
- : structuredClone(envelope.snapshot),
136
- verification:
137
- envelope.verification === undefined
138
- ? undefined
139
- : {
140
- ...envelope.verification,
141
- argv: [...envelope.verification.argv],
142
- },
143
- correctionIndex,
62
+ taskId: boundary.taskId,
63
+ read: [...new Set(phases.flatMap((phase) => phase.read))],
64
+ write: [...write],
65
+ conflicts: [...boundary.scheduling.conflicts],
66
+ resources: [...boundary.scheduling.resources],
67
+ verificationLocks: [
68
+ ...new Set(
69
+ phases.flatMap((phase) =>
70
+ phase.verificationLock ? [phase.verificationLock] : [],
71
+ ),
72
+ ),
73
+ ],
144
74
  };
145
75
  }
146
76
 
147
- function arrayEqual(a: string[], b: string[]): boolean {
148
- return a.length === b.length && a.every((value, index) => value === b[index]);
149
- }
150
-
151
- // Stable provider/model/API/thinking identity fingerprint for a phase. Each
152
- // child attempt re-derives it while the phase-local auth boundary is called
153
- // anew, so the identity stays pinned across fresh phases.
77
+ // Stable provider/model/API identity fingerprint. Fresh auth may be acquired
78
+ // for each phase, while the selected execution identity remains pinned.
154
79
  export function workerIdentity(model: {
155
80
  provider?: unknown;
81
+ api?: unknown;
156
82
  baseUrl?: unknown;
157
83
  id?: unknown;
158
84
  name?: unknown;
159
85
  }): string {
160
- const parts: string[] = [`p:${String(model.provider ?? "")}`];
86
+ const parts: string[] = [
87
+ `p:${String(model.provider ?? "")}`,
88
+ `a:${String(model.api ?? "")}`,
89
+ ];
161
90
  if (model.baseUrl !== undefined) parts.push(`u:${String(model.baseUrl)}`);
162
91
  if (typeof model.id === "string") parts.push(`id:${model.id}`);
163
92
  if (typeof model.name === "string") parts.push(`n:${model.name}`);
@@ -165,65 +94,55 @@ export function workerIdentity(model: {
165
94
  }
166
95
 
167
96
  export class WorkerRegistry {
168
- private readonly workers = new Map<string, LogicalWorker>();
97
+ private readonly tasks = new Map<string, TaskRecord>();
169
98
 
170
- has(id: string): boolean {
171
- return this.workers.has(id);
99
+ has(key: string): boolean {
100
+ return this.tasks.has(key);
172
101
  }
173
102
 
174
- get(id: string): LogicalWorker | undefined {
175
- return this.workers.get(id);
103
+ get(key: string): TaskRecord | undefined {
104
+ return this.tasks.get(key);
176
105
  }
177
106
 
178
- pin(contract: WorkerContract, identity: string): LogicalWorker {
179
- const currentPhase = clonePhase(contract.currentPhase);
180
- const worker: LogicalWorker = {
181
- identity,
182
- taskContract: cloneTask(contract),
183
- currentPhase,
184
- state: { kind: "ready" },
185
- };
186
- this.workers.set(contract.taskId, worker);
187
- return worker;
107
+ find(workspaceRoot: string, taskId: string): TaskRecord | undefined {
108
+ const matches = [...this.tasks.values()].filter(
109
+ (record) =>
110
+ record.workspaceRoot === workspaceRoot &&
111
+ record.boundary.taskId === taskId,
112
+ );
113
+ return matches.length === 1 ? matches[0] : undefined;
188
114
  }
189
115
 
190
- setCurrentPhase(
191
- taskId: string,
192
- contract: WorkerContract,
193
- correctionIndex: 0 | 1,
194
- ): LogicalWorker | undefined {
195
- const worker = this.workers.get(taskId);
196
- if (!worker) return undefined;
197
- const currentPhase = {
198
- ...clonePhase(contract.currentPhase),
199
- correctionIndex,
116
+ open(
117
+ boundary: TaskBoundary,
118
+ identity: string,
119
+ workspaceRoot: string,
120
+ attempt: PhaseAttempt,
121
+ ): TaskRecord {
122
+ const key = taskRecordKey(
123
+ workspaceRoot,
124
+ boundary.changeId,
125
+ boundary.taskId,
126
+ );
127
+ if (this.tasks.has(key)) throw new Error("duplicate task open");
128
+ const storedBoundary = structuredClone(boundary);
129
+ const record: TaskRecord = {
130
+ key,
131
+ workspaceRoot,
132
+ workerIdentity: identity,
133
+ boundary: storedBoundary,
134
+ conflict: taskConflictOf(storedBoundary),
135
+ state: { kind: "ready", phase: attempt.phase, launchIndex: 0 },
200
136
  };
201
- worker.currentPhase = currentPhase;
202
- worker.state = { kind: "ready" };
203
- return worker;
137
+ this.tasks.set(key, record);
138
+ return record;
204
139
  }
205
140
 
206
- clear(): void {
207
- this.workers.clear();
141
+ values(): TaskRecord[] {
142
+ return [...this.tasks.values()];
208
143
  }
209
- }
210
144
 
211
- function cloneTask(contract: WorkerContract): WorkerTaskContract {
212
- return {
213
- stage: contract.stage,
214
- role: contract.role,
215
- taskId: contract.taskId,
216
- objective: contract.objective,
217
- roots: [...contract.roots],
218
- agents: contract.agents,
219
- contractText: contract.contractText,
220
- read: [...contract.read],
221
- conflicts: [...contract.conflicts],
222
- resources: [...contract.resources],
223
- output: contract.output,
224
- };
225
- }
226
-
227
- function clonePhase(phase: WorkerPhaseContract): WorkerPhaseContract {
228
- return structuredClone(phase);
145
+ clear(): void {
146
+ this.tasks.clear();
147
+ }
229
148
  }