@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/worker-broker.ts
CHANGED
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
} from "./route-policy.ts";
|
|
8
8
|
|
|
9
9
|
export const ROUTE_ATTEMPT_BOUNDS = Object.freeze({
|
|
10
|
-
connectMs:
|
|
11
|
-
firstResponseMs:
|
|
12
|
-
idleMs: 60_000,
|
|
13
|
-
totalMs:
|
|
10
|
+
connectMs: 10_000,
|
|
11
|
+
firstResponseMs: 90_000,
|
|
12
|
+
idleMs: 3 * 60_000,
|
|
13
|
+
totalMs: 20 * 60_000,
|
|
14
14
|
cooldownMs: 30_000,
|
|
15
|
-
attemptsPerRoute:
|
|
15
|
+
attemptsPerRoute: 2,
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
export type RouteHealthState = "healthy" | "open" | "half-open";
|
|
@@ -61,6 +61,7 @@ export interface RunWorkerAttemptInput<T> {
|
|
|
61
61
|
requirements?: RouteRequirements;
|
|
62
62
|
signal?: AbortSignal;
|
|
63
63
|
onActivity?: (event: BrokerActivityUpdate) => void;
|
|
64
|
+
classifyResult?: (value: T) => string | undefined;
|
|
64
65
|
execute(context: RouteAttemptContext): Promise<T>;
|
|
65
66
|
}
|
|
66
67
|
|
|
@@ -218,6 +219,16 @@ export class WorkerBroker {
|
|
|
218
219
|
this.#setRouteHealth(routeId, { state: "healthy" });
|
|
219
220
|
}
|
|
220
221
|
|
|
222
|
+
#releaseHalfOpenProbeForRetry(routeId: string, code: string): void {
|
|
223
|
+
const health = this.#routeHealth(routeId);
|
|
224
|
+
if (health.state !== "half-open" || !health.probeInFlight) return;
|
|
225
|
+
this.#setRouteHealth(routeId, {
|
|
226
|
+
state: "open",
|
|
227
|
+
retryAt: this.#now(),
|
|
228
|
+
lastCode: code,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
221
232
|
select(input: {
|
|
222
233
|
role: WorkerRole;
|
|
223
234
|
dialects?: RouteDialect[];
|
|
@@ -372,6 +383,7 @@ export class WorkerBroker {
|
|
|
372
383
|
requirements?: RouteRequirements;
|
|
373
384
|
signal?: AbortSignal;
|
|
374
385
|
onActivity?: (event: BrokerActivityUpdate) => void;
|
|
386
|
+
classifyResult?: (value: T) => string | undefined;
|
|
375
387
|
execute: (context: RouteAttemptContext) => Promise<T>;
|
|
376
388
|
}): Promise<
|
|
377
389
|
| { ok: true; routeId: string; value: T; attempts: BrokerAttemptEvidence[] }
|
|
@@ -397,12 +409,20 @@ export class WorkerBroker {
|
|
|
397
409
|
}
|
|
398
410
|
const attempted = new Set<string>();
|
|
399
411
|
const evidence: BrokerAttemptEvidence[] = [];
|
|
400
|
-
const
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
412
|
+
const capableRouteCount = this.#policy.roles[input.role].filter(
|
|
413
|
+
(routeId) => {
|
|
414
|
+
const route = this.#policy.routes[routeId];
|
|
415
|
+
return route
|
|
416
|
+
? capable(route, input.role, input.requirements ?? {})
|
|
417
|
+
: false;
|
|
418
|
+
},
|
|
419
|
+
).length;
|
|
420
|
+
const maxAttempts = Math.max(
|
|
421
|
+
1,
|
|
422
|
+
capableRouteCount > 1
|
|
423
|
+
? capableRouteCount
|
|
424
|
+
: ROUTE_ATTEMPT_BOUNDS.attemptsPerRoute,
|
|
425
|
+
);
|
|
406
426
|
for (;;) {
|
|
407
427
|
const selection = this.select({
|
|
408
428
|
role: input.role,
|
|
@@ -427,6 +447,9 @@ export class WorkerBroker {
|
|
|
427
447
|
probeExpiresAt: this.#now() + ROUTE_ATTEMPT_BOUNDS.totalMs,
|
|
428
448
|
});
|
|
429
449
|
}
|
|
450
|
+
const routeAttempt = evidence.filter(
|
|
451
|
+
(item) => item.routeId === routeId,
|
|
452
|
+
).length;
|
|
430
453
|
const attempt = evidence.length + 1;
|
|
431
454
|
emitBrokerActivity(input.onActivity, {
|
|
432
455
|
state: "connecting",
|
|
@@ -450,6 +473,31 @@ export class WorkerBroker {
|
|
|
450
473
|
: "worker-progress",
|
|
451
474
|
}),
|
|
452
475
|
);
|
|
476
|
+
const semanticCode = input.classifyResult?.(value);
|
|
477
|
+
if (semanticCode) {
|
|
478
|
+
evidence.push({ routeId, code: semanticCode });
|
|
479
|
+
const routeHasRetry =
|
|
480
|
+
capableRouteCount === 1 &&
|
|
481
|
+
routeAttempt + 1 < ROUTE_ATTEMPT_BOUNDS.attemptsPerRoute;
|
|
482
|
+
if (routeHasRetry) {
|
|
483
|
+
this.#releaseHalfOpenProbeForRetry(routeId, semanticCode);
|
|
484
|
+
attempted.delete(routeId);
|
|
485
|
+
} else {
|
|
486
|
+
this.markFailure(routeId, semanticCode);
|
|
487
|
+
}
|
|
488
|
+
if (attempt < maxAttempts) {
|
|
489
|
+
emitBrokerActivity(input.onActivity, {
|
|
490
|
+
state: "retrying",
|
|
491
|
+
attempt,
|
|
492
|
+
maxAttempts,
|
|
493
|
+
code: semanticCode,
|
|
494
|
+
wait: "bounded-policy",
|
|
495
|
+
});
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
if (routeHasRetry) this.markFailure(routeId, semanticCode);
|
|
499
|
+
return { ok: true, routeId, value, attempts: evidence };
|
|
500
|
+
}
|
|
453
501
|
this.markSuccess(routeId);
|
|
454
502
|
return { ok: true, routeId, value, attempts: evidence };
|
|
455
503
|
} catch (error) {
|
|
@@ -466,8 +514,16 @@ export class WorkerBroker {
|
|
|
466
514
|
}
|
|
467
515
|
return { ok: false, state: "cancelled", code, attempts: evidence };
|
|
468
516
|
}
|
|
469
|
-
|
|
470
|
-
|
|
517
|
+
const routeHasRetry =
|
|
518
|
+
capableRouteCount === 1 &&
|
|
519
|
+
routeAttempt + 1 < ROUTE_ATTEMPT_BOUNDS.attemptsPerRoute;
|
|
520
|
+
if (routeHasRetry) {
|
|
521
|
+
this.#releaseHalfOpenProbeForRetry(routeId, code);
|
|
522
|
+
attempted.delete(routeId);
|
|
523
|
+
} else {
|
|
524
|
+
this.markFailure(routeId, code);
|
|
525
|
+
}
|
|
526
|
+
if (attempt < maxAttempts) {
|
|
471
527
|
emitBrokerActivity(input.onActivity, {
|
|
472
528
|
state: "retrying",
|
|
473
529
|
attempt,
|
|
@@ -475,6 +531,8 @@ export class WorkerBroker {
|
|
|
475
531
|
code,
|
|
476
532
|
wait: "bounded-policy",
|
|
477
533
|
});
|
|
534
|
+
} else if (routeHasRetry) {
|
|
535
|
+
this.markFailure(routeId, code);
|
|
478
536
|
}
|
|
479
537
|
}
|
|
480
538
|
}
|
|
@@ -615,6 +673,7 @@ export class RunWorkerBroker {
|
|
|
615
673
|
...(input.requirements ? { requirements: input.requirements } : {}),
|
|
616
674
|
...(input.signal ? { signal: input.signal } : {}),
|
|
617
675
|
...(input.onActivity ? { onActivity: input.onActivity } : {}),
|
|
676
|
+
...(input.classifyResult ? { classifyResult: input.classifyResult } : {}),
|
|
618
677
|
execute: input.execute,
|
|
619
678
|
});
|
|
620
679
|
if (result.ok) {
|