@cat-factory/orchestration 0.129.2 → 0.129.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/dist/modules/execution/RunDispatcher.d.ts +7 -2
- package/dist/modules/execution/RunDispatcher.d.ts.map +1 -1
- package/dist/modules/execution/RunDispatcher.js +56 -432
- package/dist/modules/execution/RunDispatcher.js.map +1 -1
- package/dist/modules/execution/dispatcher-registries.d.ts +85 -0
- package/dist/modules/execution/dispatcher-registries.d.ts.map +1 -0
- package/dist/modules/execution/dispatcher-registries.js +451 -0
- package/dist/modules/execution/dispatcher-registries.js.map +1 -0
- package/dist/modules/requirements/RequirementReviewService.d.ts +7 -0
- package/dist/modules/requirements/RequirementReviewService.d.ts.map +1 -1
- package/dist/modules/requirements/RequirementReviewService.js +48 -39
- package/dist/modules/requirements/RequirementReviewService.js.map +1 -1
- package/package.json +3 -3
|
@@ -177,6 +177,13 @@ export declare class RunDispatcher {
|
|
|
177
177
|
private stepHandlerCache?;
|
|
178
178
|
/** Lazily-built, order-sorted completion-path interceptor list. */
|
|
179
179
|
private stepCompletionInterceptorCache?;
|
|
180
|
+
/**
|
|
181
|
+
* The seam the built-in dispatch-registry builders ({@link buildStepHandlerRegistryImpl} et al.)
|
|
182
|
+
* close over — this dispatcher's collaborators plus bound call-backs to its own completion /
|
|
183
|
+
* gate / phase methods. Assembled once at the end of the constructor; the builders live in
|
|
184
|
+
* `dispatcher-registries.ts` so the large declarative registration stays out of this class.
|
|
185
|
+
*/
|
|
186
|
+
private readonly registryDeps;
|
|
180
187
|
constructor(deps: RunDispatcherDeps);
|
|
181
188
|
/**
|
|
182
189
|
* Run a durable-driver entry point, turning a lost optimistic-concurrency race into a
|
|
@@ -424,8 +431,6 @@ export declare class RunDispatcher {
|
|
|
424
431
|
private buildStepCompletionInterceptors;
|
|
425
432
|
private stepResolverFor;
|
|
426
433
|
private buildStepResolverRegistry;
|
|
427
|
-
/** The shared engine seams handed to a deployment-registered step resolver's factory. */
|
|
428
|
-
private makeResolverContext;
|
|
429
434
|
private buildGateRegistry;
|
|
430
435
|
/** The shared engine seams handed to a deployment-registered gate's factory. */
|
|
431
436
|
private makeGateContext;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RunDispatcher.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/RunDispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EAEb,eAAe,EACf,cAAc,EACd,KAAK,EACL,eAAe,EAEf,iBAAiB,EACjB,aAAa,EACb,KAAK,EAEL,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"RunDispatcher.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/RunDispatcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import { ConflictError, DEFAULT_RISK_POLICY, failureKindFromHarnessCause, FIXER_AGENT_KIND, getErrorMessage,
|
|
1
|
+
import { ConflictError, DEFAULT_RISK_POLICY, failureKindFromHarnessCause, FIXER_AGENT_KIND, getErrorMessage, isAsyncAgentExecutor, NotFoundError, parseLocalModelId, recordGateAttempt, RunContendedError, sameSubtasks, } from '@cat-factory/kernel';
|
|
2
2
|
import { parseBlueprintService, parseSpecDoc } from '@cat-factory/contracts';
|
|
3
|
-
import { commitInitiativeTracker, FORK_PROPOSER_KIND, PR_REVIEWER_KIND
|
|
4
|
-
import {
|
|
5
|
-
import { BUG_INTAKE_AGENT_KIND } from '../pipelines/pipelineShape.js';
|
|
6
|
-
import { coerceTaskEstimate, summarizeEstimate } from '../estimation/estimate.logic.js';
|
|
3
|
+
import { commitInitiativeTracker, FORK_PROPOSER_KIND, PR_REVIEWER_KIND } from '@cat-factory/agents';
|
|
4
|
+
import { isDeployStep } from '@cat-factory/integrations';
|
|
7
5
|
import { reviewableArtifactOutput } from './artifact-review.logic.js';
|
|
8
|
-
import {
|
|
9
|
-
import { renderReproDigest } from './reproTest.logic.js';
|
|
10
|
-
import { ANALYSIS_AGENT_KIND, ARCHITECTURE_BRAINSTORM_AGENT_KIND, BLUEPRINTS_AGENT_KIND, BUG_INVESTIGATOR_AGENT_KIND, CLARITY_REVIEW_AGENT_KIND, CONFLICTS_AGENT_KIND, HUMAN_TEST_AGENT_KIND, isTesterKind, MERGER_AGENT_KIND, REPRO_TEST_AGENT_KIND, REQUIREMENTS_BRAINSTORM_AGENT_KIND, REQUIREMENTS_REVIEW_AGENT_KIND, SPEC_WRITER_AGENT_KIND, TRACKER_AGENT_KIND, VISUAL_CONFIRM_AGENT_KIND, } from './ci.logic.js';
|
|
6
|
+
import { ANALYSIS_AGENT_KIND, CONFLICTS_AGENT_KIND, HUMAN_TEST_AGENT_KIND, isTesterKind, VISUAL_CONFIRM_AGENT_KIND, } from './ci.logic.js';
|
|
11
7
|
import { classifyDispatchFailure, MAX_EVICTION_RECOVERIES, MAX_TRANSIENT_EVICTION_RECOVERIES, } from './job.logic.js';
|
|
12
8
|
import { AgentContextBuilder } from './AgentContextBuilder.js';
|
|
13
9
|
import { DeployerStepController } from './DeployerStepController.js';
|
|
@@ -18,26 +14,16 @@ import { HumanTestController } from './HumanTestController.js';
|
|
|
18
14
|
import { MergeResolver } from './MergeResolver.js';
|
|
19
15
|
import { ReviewGateController } from './ReviewGateController.js';
|
|
20
16
|
import { ForkDecisionController } from './ForkDecisionController.js';
|
|
21
|
-
import { PrReviewController
|
|
17
|
+
import { PrReviewController } from './PrReviewController.js';
|
|
22
18
|
import { buildPrReviewPost, initialPrReviewState, renderPrReviewFixerFeedback, } from './prReview.logic.js';
|
|
23
|
-
import { DEFAULT_FORK_MAX_CHAT_TURNS,
|
|
19
|
+
import { DEFAULT_FORK_MAX_CHAT_TURNS, resolveForkTriState, shouldProposeForkAuto, } from './forkDecision.logic.js';
|
|
24
20
|
import { RunStateMachine } from './RunStateMachine.js';
|
|
25
21
|
import { StepGraph } from './StepGraph.js';
|
|
26
22
|
import { TesterController } from './TesterController.js';
|
|
27
23
|
import { RalphController } from './RalphController.js';
|
|
28
|
-
import { isRalphKind } from './ralph.logic.js';
|
|
29
24
|
import { VisualConfirmationController } from './VisualConfirmationController.js';
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
* The inline review/brainstorm gate kinds, all driven through the {@link ReviewGateController}
|
|
33
|
-
* by the dispatcher's `review-gate` StepHandler. Kept in sync with the handler's `switch`.
|
|
34
|
-
*/
|
|
35
|
-
const REVIEW_GATE_AGENT_KINDS = new Set([
|
|
36
|
-
REQUIREMENTS_REVIEW_AGENT_KIND,
|
|
37
|
-
CLARITY_REVIEW_AGENT_KIND,
|
|
38
|
-
REQUIREMENTS_BRAINSTORM_AGENT_KIND,
|
|
39
|
-
ARCHITECTURE_BRAINSTORM_AGENT_KIND,
|
|
40
|
-
]);
|
|
25
|
+
import {} from './step-handler-registry.js';
|
|
26
|
+
import { buildStepCompletionInterceptors as buildStepCompletionInterceptorsImpl, buildStepHandlerRegistry as buildStepHandlerRegistryImpl, buildStepResolverRegistry as buildStepResolverRegistryImpl, } from './dispatcher-registries.js';
|
|
41
27
|
/**
|
|
42
28
|
* The PR number a `review` task targets: the explicit `prNumber` field wins, else parse it from
|
|
43
29
|
* the `prUrl` (`…/pull/42` on GitHub, `…/merge_requests/42` on GitLab). Undefined when neither
|
|
@@ -134,6 +120,13 @@ export class RunDispatcher {
|
|
|
134
120
|
stepHandlerCache;
|
|
135
121
|
/** Lazily-built, order-sorted completion-path interceptor list. */
|
|
136
122
|
stepCompletionInterceptorCache;
|
|
123
|
+
/**
|
|
124
|
+
* The seam the built-in dispatch-registry builders ({@link buildStepHandlerRegistryImpl} et al.)
|
|
125
|
+
* close over — this dispatcher's collaborators plus bound call-backs to its own completion /
|
|
126
|
+
* gate / phase methods. Assembled once at the end of the constructor; the builders live in
|
|
127
|
+
* `dispatcher-registries.ts` so the large declarative registration stays out of this class.
|
|
128
|
+
*/
|
|
129
|
+
registryDeps;
|
|
137
130
|
constructor(deps) {
|
|
138
131
|
this.blockRepository = deps.blockRepository;
|
|
139
132
|
this.executionRepository = deps.executionRepository;
|
|
@@ -205,6 +198,44 @@ export class RunDispatcher {
|
|
|
205
198
|
resolveRunRepoContext: deps.resolveRunRepoContext,
|
|
206
199
|
issueWriteback: deps.issueWriteback,
|
|
207
200
|
});
|
|
201
|
+
// Assemble the seam the extracted dispatch-registry builders close over: the collaborators
|
|
202
|
+
// above + bound call-backs into this dispatcher's completion / gate / phase methods, so the
|
|
203
|
+
// built-ins resolve everything at call time exactly as the former inline closures did.
|
|
204
|
+
this.registryDeps = {
|
|
205
|
+
blockRepository: this.blockRepository,
|
|
206
|
+
clock: this.clock,
|
|
207
|
+
agentKindRegistry: this.agentKindRegistry,
|
|
208
|
+
stepResolverRegistry: this.stepResolverRegistry,
|
|
209
|
+
runInitiatorScope: this.runInitiatorScope,
|
|
210
|
+
environmentProvisioning: this.environmentProvisioning,
|
|
211
|
+
initiativeService: this.initiativeService,
|
|
212
|
+
deployer: this.deployer,
|
|
213
|
+
companionController: this.companionController,
|
|
214
|
+
testerController: this.testerController,
|
|
215
|
+
ralphController: this.ralphController,
|
|
216
|
+
humanTestController: this.humanTestController,
|
|
217
|
+
visualConfirmationController: this.visualConfirmationController,
|
|
218
|
+
reviewGate: this.reviewGate,
|
|
219
|
+
forkDecisionController: this.forkDecisionController,
|
|
220
|
+
prReviewController: this.prReviewController,
|
|
221
|
+
mergeResolver: this.mergeResolver,
|
|
222
|
+
requirementsKind: this.requirementsKind,
|
|
223
|
+
clarityKind: this.clarityKind,
|
|
224
|
+
requirementsBrainstormKind: this.requirementsBrainstormKind,
|
|
225
|
+
architectureBrainstormKind: this.architectureBrainstormKind,
|
|
226
|
+
interviewControllers: this.interviewControllers,
|
|
227
|
+
recordStepResult: (ws, instance, step, isFinalStep, result) => this.recordStepResult(ws, instance, step, isFinalStep, result),
|
|
228
|
+
runTracker: (ws, instance, block) => this.runTracker(ws, instance, block),
|
|
229
|
+
runBugIntake: (ws, instance, step, block, isFinalStep) => this.runBugIntake(ws, instance, step, block, isFinalStep),
|
|
230
|
+
runInitiativeCommitter: (ws, block) => this.runInitiativeCommitter(ws, block),
|
|
231
|
+
evaluateGate: (ws, instance, step, block, isFinalStep, gate) => this.evaluateGate(ws, instance, step, block, isFinalStep, gate),
|
|
232
|
+
gateFor: (kind) => this.gateFor(kind),
|
|
233
|
+
handleForkDecisionPhase: (ctx) => this.handleForkDecisionPhase(ctx),
|
|
234
|
+
handlePrReviewResolution: (ctx) => this.handlePrReviewResolution(ctx),
|
|
235
|
+
handleAgentStep: (ctx) => this.handleAgentStep(ctx),
|
|
236
|
+
ingestBlueprint: (ws, blockId, raw) => this.ingestBlueprint(ws, blockId, raw),
|
|
237
|
+
ingestSpec: (ws, raw) => this.ingestSpec(ws, raw),
|
|
238
|
+
};
|
|
208
239
|
}
|
|
209
240
|
/**
|
|
210
241
|
* Run a durable-driver entry point, turning a lost optimistic-concurrency race into a
|
|
@@ -1425,183 +1456,7 @@ export class RunDispatcher {
|
|
|
1425
1456
|
* the generic fallthrough; later phases prepend more-specific handlers with lower `order`.
|
|
1426
1457
|
*/
|
|
1427
1458
|
buildStepHandlerRegistry() {
|
|
1428
|
-
|
|
1429
|
-
// A `deployer` step provisions an ephemeral environment deterministically via the
|
|
1430
|
-
// provider — no LLM, no token usage — when the integration is wired. Unwired, its
|
|
1431
|
-
// `canHandle` is false so the step falls through to the generic agent path.
|
|
1432
|
-
{
|
|
1433
|
-
kind: DEPLOYER_AGENT_KIND,
|
|
1434
|
-
order: 100,
|
|
1435
|
-
canHandle: ({ step }) => !!this.environmentProvisioning && isDeployStep(step.agentKind),
|
|
1436
|
-
handle: ({ workspaceId, instance, step, block, isFinalStep }) => this.deployer.runDeployerStep(workspaceId, instance, step, block, isFinalStep),
|
|
1437
|
-
},
|
|
1438
|
-
// A `tracker` step files a GitHub issue / Jira ticket from the preceding `analysis`
|
|
1439
|
-
// output (the tech-debt pipeline) — no LLM of its own. It is a pass-through when no
|
|
1440
|
-
// tracker provider is wired or none is configured for the workspace (handled inside
|
|
1441
|
-
// {@link runTracker}, which still records a result), so it always claims the step.
|
|
1442
|
-
{
|
|
1443
|
-
kind: TRACKER_AGENT_KIND,
|
|
1444
|
-
order: 110,
|
|
1445
|
-
canHandle: ({ step }) => step.agentKind === TRACKER_AGENT_KIND,
|
|
1446
|
-
handle: async ({ workspaceId, instance, step, block, isFinalStep }) => {
|
|
1447
|
-
const result = await this.runTracker(workspaceId, instance, block);
|
|
1448
|
-
return this.recordStepResult(workspaceId, instance, step, isFinalStep, result);
|
|
1449
|
-
},
|
|
1450
|
-
},
|
|
1451
|
-
// A `bug-intake` step (the recurring bug-triage pipeline) pulls ONE matching open issue from
|
|
1452
|
-
// the schedule's tracker board, claims it, and seeds the reused block from it — no LLM of its
|
|
1453
|
-
// own, the inbound dual of `tracker`. On no match (or no task source wired) it completes the
|
|
1454
|
-
// run successfully, skipping every remaining step. Handled entirely inside
|
|
1455
|
-
// {@link runBugIntake}, so it always claims the step.
|
|
1456
|
-
{
|
|
1457
|
-
kind: BUG_INTAKE_AGENT_KIND,
|
|
1458
|
-
order: 111,
|
|
1459
|
-
canHandle: ({ step }) => step.agentKind === BUG_INTAKE_AGENT_KIND,
|
|
1460
|
-
handle: ({ workspaceId, instance, step, block, isFinalStep }) => this.runBugIntake(workspaceId, instance, step, block, isFinalStep),
|
|
1461
|
-
},
|
|
1462
|
-
// The interactive-INTERVIEWER gates (`initiative-interviewer`, `doc-interviewer`, …): an
|
|
1463
|
-
// inline LLM gate that PARKS the run on a decision-wait while the human answers the
|
|
1464
|
-
// interviewer's questions through a dedicated window, then synthesizes a brief and advances
|
|
1465
|
-
// (see {@link InterviewGateController}). Routed by the `interview-gate` TRAIT — the same
|
|
1466
|
-
// marker the re-park + approval guards key off — and dispatched to the controller registered
|
|
1467
|
-
// for the step's `agentKind`, so a new interviewer just carries the trait + wires its
|
|
1468
|
-
// controller (no new branch here). Pass-through when the interviewer isn't wired (no model /
|
|
1469
|
-
// no store) so pipelines + conformance run unchanged; a wired-but-unmatched trait kind is a
|
|
1470
|
-
// pipeline authoring error, but we still advance rather than wedge the run.
|
|
1471
|
-
{
|
|
1472
|
-
kind: 'interview-gate',
|
|
1473
|
-
order: 113,
|
|
1474
|
-
canHandle: ({ step }) => hasTrait(step.agentKind, INTERVIEW_GATE_TRAIT, this.agentKindRegistry),
|
|
1475
|
-
handle: ({ workspaceId, instance, step, block, isFinalStep }) => {
|
|
1476
|
-
const controller = this.interviewControllers.get(step.agentKind);
|
|
1477
|
-
return controller
|
|
1478
|
-
? controller.evaluate(workspaceId, instance, step, block, isFinalStep)
|
|
1479
|
-
: this.recordStepResult(workspaceId, instance, step, isFinalStep, { output: '' });
|
|
1480
|
-
},
|
|
1481
|
-
},
|
|
1482
|
-
// The `initiative-committer` step persists an APPROVED initiative plan: it runs
|
|
1483
|
-
// strictly after the planner's human gate, flips the entity to `executing`, and
|
|
1484
|
-
// mirrors the tracker into the repo (`docs/initiatives/<slug>/`) when GitHub is
|
|
1485
|
-
// wired — no LLM of its own (the `tracker`-style deterministic one-shot).
|
|
1486
|
-
{
|
|
1487
|
-
kind: INITIATIVE_COMMITTER_AGENT_KIND,
|
|
1488
|
-
order: 115,
|
|
1489
|
-
canHandle: ({ step }) => step.agentKind === INITIATIVE_COMMITTER_AGENT_KIND,
|
|
1490
|
-
handle: async ({ workspaceId, instance, step, block, isFinalStep }) => {
|
|
1491
|
-
const outcome = await this.runInitiativeCommitter(workspaceId, block);
|
|
1492
|
-
if (outcome.kind === 'failed') {
|
|
1493
|
-
return { kind: 'job_failed', error: outcome.error, failureKind: 'agent' };
|
|
1494
|
-
}
|
|
1495
|
-
return this.recordStepResult(workspaceId, instance, step, isFinalStep, outcome.result);
|
|
1496
|
-
},
|
|
1497
|
-
},
|
|
1498
|
-
// The `requirements-review` / `clarity-review` / `requirements-brainstorm` /
|
|
1499
|
-
// `architecture-brainstorm` steps are inline reviewers that park for their dedicated
|
|
1500
|
-
// window and drive the iterative answer → incorporate → re-review loop — NOT
|
|
1501
|
-
// container/prose agents. All four run through the {@link ReviewGateController},
|
|
1502
|
-
// parameterised by their {@link ReviewKind} (the per-case `switch` binds each kind's
|
|
1503
|
-
// review type so `evaluate`'s generic infers). Pass-through when the service isn't wired.
|
|
1504
|
-
{
|
|
1505
|
-
kind: 'review-gate',
|
|
1506
|
-
order: 120,
|
|
1507
|
-
canHandle: ({ step }) => REVIEW_GATE_AGENT_KINDS.has(step.agentKind),
|
|
1508
|
-
handle: ({ workspaceId, instance, step, block, isFinalStep }) => {
|
|
1509
|
-
switch (step.agentKind) {
|
|
1510
|
-
case REQUIREMENTS_REVIEW_AGENT_KIND:
|
|
1511
|
-
return this.reviewGate.evaluate(this.requirementsKind, workspaceId, instance, step, block, isFinalStep);
|
|
1512
|
-
case CLARITY_REVIEW_AGENT_KIND:
|
|
1513
|
-
return this.reviewGate.evaluate(this.clarityKind, workspaceId, instance, step, block, isFinalStep);
|
|
1514
|
-
case REQUIREMENTS_BRAINSTORM_AGENT_KIND:
|
|
1515
|
-
return this.reviewGate.evaluate(this.requirementsBrainstormKind, workspaceId, instance, step, block, isFinalStep);
|
|
1516
|
-
case ARCHITECTURE_BRAINSTORM_AGENT_KIND:
|
|
1517
|
-
return this.reviewGate.evaluate(this.architectureBrainstormKind, workspaceId, instance, step, block, isFinalStep);
|
|
1518
|
-
// `canHandle` admits only the kinds in REVIEW_GATE_AGENT_KINDS, so every member
|
|
1519
|
-
// must have an explicit case above. Throw loudly if the two ever drift (a new
|
|
1520
|
-
// review kind added to the Set without a case here) rather than silently routing
|
|
1521
|
-
// it to the wrong reviewer.
|
|
1522
|
-
default:
|
|
1523
|
-
throw new Error(`Unhandled review-gate agentKind "${step.agentKind}"`);
|
|
1524
|
-
}
|
|
1525
|
-
},
|
|
1526
|
-
},
|
|
1527
|
-
// A `human-test` gate spins up an ephemeral environment and PARKS for a human to
|
|
1528
|
-
// validate the change in a live URL — NOT a container/prose agent and NOT a
|
|
1529
|
-
// programmatic polling gate (the human is the verdict). Degrades to a manual (no-env)
|
|
1530
|
-
// mode when no ephemeral-environment provider is wired. See {@link HumanTestController}.
|
|
1531
|
-
{
|
|
1532
|
-
kind: HUMAN_TEST_AGENT_KIND,
|
|
1533
|
-
order: 130,
|
|
1534
|
-
canHandle: ({ step }) => step.agentKind === HUMAN_TEST_AGENT_KIND,
|
|
1535
|
-
handle: ({ workspaceId, instance, step, block, isFinalStep }) => this.humanTestController.evaluate(workspaceId, instance, step, block, isFinalStep),
|
|
1536
|
-
},
|
|
1537
|
-
// A `visual-confirmation` gate gathers the UI tester's screenshots + uploaded reference
|
|
1538
|
-
// designs and PARKS for a human to review actual-vs-reference, then on demand dispatches
|
|
1539
|
-
// the Tester's `fixer`. Passes through when no binary-artifact store is wired.
|
|
1540
|
-
// See {@link VisualConfirmationController}.
|
|
1541
|
-
{
|
|
1542
|
-
kind: VISUAL_CONFIRM_AGENT_KIND,
|
|
1543
|
-
order: 140,
|
|
1544
|
-
canHandle: ({ step }) => step.agentKind === VISUAL_CONFIRM_AGENT_KIND,
|
|
1545
|
-
handle: ({ workspaceId, instance, step, block, isFinalStep }) => this.visualConfirmationController.evaluate(workspaceId, instance, step, block, isFinalStep),
|
|
1546
|
-
},
|
|
1547
|
-
// A polling gate step (`ci` / `conflicts` / `post-release-health` / `human-review`) runs
|
|
1548
|
-
// a programmatic precheck and only escalates to a helper container agent on a negative
|
|
1549
|
-
// verdict — no LLM of its own. Pass-through when the gate's provider is not wired. One
|
|
1550
|
-
// generic machine drives every gate; see {@link evaluateGate}. `canHandle` is the gate
|
|
1551
|
-
// registry lookup, so this claims exactly the registered gate kinds.
|
|
1552
|
-
{
|
|
1553
|
-
kind: 'polling-gate',
|
|
1554
|
-
order: 150,
|
|
1555
|
-
canHandle: ({ step }) => this.gateFor(step.agentKind) !== undefined,
|
|
1556
|
-
handle: ({ workspaceId, instance, step, block, isFinalStep }) => this.evaluateGate(workspaceId, instance, step, block, isFinalStep, this.gateFor(step.agentKind)),
|
|
1557
|
-
},
|
|
1558
|
-
// An INLINE companion (architect-companion / spec-companion) grades the nearest
|
|
1559
|
-
// preceding producer right here and loops it back for automatic rework below the
|
|
1560
|
-
// threshold before any human gate. CONTAINER-backed companions (reviewer / doc-reviewer)
|
|
1561
|
-
// do NOT match — they fall through to the generic async container dispatch and have their
|
|
1562
|
-
// verdict resolved by the completion interceptor instead. See {@link CompanionController}.
|
|
1563
|
-
{
|
|
1564
|
-
kind: 'inline-companion',
|
|
1565
|
-
order: 160,
|
|
1566
|
-
canHandle: ({ step }) => isCompanionKind(step.agentKind) && !isContainerBackedCompanion(step.agentKind),
|
|
1567
|
-
handle: ({ workspaceId, instance, step, block, isFinalStep, options }) => this.companionController.evaluate(workspaceId, instance, step, block, isFinalStep, options),
|
|
1568
|
-
},
|
|
1569
|
-
// The optional implementation-fork decision phase on a Coder step (Phase A): when the
|
|
1570
|
-
// per-task tri-state + the risk-policy gate call for it, dispatch the read-only
|
|
1571
|
-
// `fork-proposer` explore job as a helper off THIS coder step. Claims the step only
|
|
1572
|
-
// while the phase is pending (tri-state not `off`, not yet resolved); once resolved
|
|
1573
|
-
// (`chosen` / `single_path` / `skipped`) it falls through so the Coder dispatches
|
|
1574
|
-
// normally (Phase B). A parked `awaiting_choice` step is short-circuited by the
|
|
1575
|
-
// run-lifecycle re-entry guard before this handler runs. See {@link handleForkDecisionPhase}.
|
|
1576
|
-
{
|
|
1577
|
-
kind: 'fork-decision',
|
|
1578
|
-
order: 170,
|
|
1579
|
-
canHandle: ({ step, block }) => forkPhasePending(step, resolveForkTriState(block.agentConfig)),
|
|
1580
|
-
handle: (ctx) => this.handleForkDecisionPhase(ctx),
|
|
1581
|
-
},
|
|
1582
|
-
// The PR deep-review RESOLUTION phase (PR 3): after the human resolved a parked review with
|
|
1583
|
-
// `fix` / `post`, `PrReviewController.resolve` re-armed this `pr-reviewer` step and woke the
|
|
1584
|
-
// driver. Claim it by the re-armed status so it re-dispatches as the Fixer (`fixing`) or
|
|
1585
|
-
// posts the selected findings as inline PR comments (`posting`) — never the generic
|
|
1586
|
-
// pr-reviewer clone the fallthrough would run. A `reviewing`/`awaiting_selection`/resolved
|
|
1587
|
-
// step falls through (this handler doesn't claim it). See {@link handlePrReviewResolution}.
|
|
1588
|
-
{
|
|
1589
|
-
kind: 'pr-review-resolution',
|
|
1590
|
-
order: 175,
|
|
1591
|
-
canHandle: ({ step }) => step.agentKind === PR_REVIEW_STEP_KIND &&
|
|
1592
|
-
(step.prReview?.status === 'fixing' || step.prReview?.status === 'posting'),
|
|
1593
|
-
handle: (ctx) => this.handlePrReviewResolution(ctx),
|
|
1594
|
-
},
|
|
1595
|
-
// The generic container/inline-agent step — claims every step no more-specific handler
|
|
1596
|
-
// did. Highest order so it always runs last. See {@link handleAgentStep}.
|
|
1597
|
-
{
|
|
1598
|
-
kind: 'agent',
|
|
1599
|
-
order: FALLTHROUGH_STEP_HANDLER_ORDER,
|
|
1600
|
-
canHandle: () => true,
|
|
1601
|
-
handle: (ctx) => this.handleAgentStep(ctx),
|
|
1602
|
-
},
|
|
1603
|
-
];
|
|
1604
|
-
return handlers.sort((a, b) => a.order - b.order);
|
|
1459
|
+
return buildStepHandlerRegistryImpl(this.registryDeps);
|
|
1605
1460
|
}
|
|
1606
1461
|
/**
|
|
1607
1462
|
* Run the first completion-path interceptor that claims this finished step, returning its
|
|
@@ -1628,81 +1483,7 @@ export class RunDispatcher {
|
|
|
1628
1483
|
* inline closing over `this`, no public registration seam.
|
|
1629
1484
|
*/
|
|
1630
1485
|
buildStepCompletionInterceptors() {
|
|
1631
|
-
|
|
1632
|
-
// A container-backed companion (reviewer / doc-reviewer) just finished reviewing the
|
|
1633
|
-
// real repository on the producer's PR branch and returned its verdict as
|
|
1634
|
-
// `result.custom`. Hand it to the companion loop, which parses the verdict and applies
|
|
1635
|
-
// the SAME threshold / rework / human-gate handling an inline companion gets. Routed
|
|
1636
|
-
// here (not the normal step completion) so the verdict drives the loop instead of being
|
|
1637
|
-
// recorded as plain output. Falls through (returns null) when the block can't be loaded.
|
|
1638
|
-
{
|
|
1639
|
-
kind: 'companion-verdict',
|
|
1640
|
-
order: 100,
|
|
1641
|
-
canIntercept: ({ step }) => isCompanionKind(step.agentKind) && isContainerBackedCompanion(step.agentKind),
|
|
1642
|
-
intercept: async ({ workspaceId, instance, step, isFinalStep, result }) => {
|
|
1643
|
-
const companionBlock = await this.blockRepository.get(workspaceId, instance.blockId);
|
|
1644
|
-
if (!companionBlock)
|
|
1645
|
-
return null;
|
|
1646
|
-
return this.companionController.resolveContainerVerdict(workspaceId, instance, step, companionBlock, isFinalStep, result);
|
|
1647
|
-
},
|
|
1648
|
-
},
|
|
1649
|
-
// The `fork-proposer` explore job (Phase A of the fork decision) just finished on a
|
|
1650
|
-
// coder step. Its structured `result.custom` is the proposal; record it onto the step's
|
|
1651
|
-
// `forkDecision` and either park for the human to choose (≥2 usable forks) or auto-advance
|
|
1652
|
-
// a single path — never the normal output/PR/follow-up/approval completion (none applies
|
|
1653
|
-
// to the proposer). Keyed on the coder step carrying `forkDecision.status === 'proposing'`.
|
|
1654
|
-
{
|
|
1655
|
-
kind: 'fork-proposal',
|
|
1656
|
-
order: 105,
|
|
1657
|
-
canIntercept: ({ step }) => step.agentKind === 'coder' && step.forkDecision?.status === 'proposing',
|
|
1658
|
-
intercept: ({ workspaceId, instance, step, result }) => {
|
|
1659
|
-
const proposal = this.agentKindRegistry
|
|
1660
|
-
.structuredOutput(FORK_PROPOSER_KIND)
|
|
1661
|
-
?.safeParse(result.custom);
|
|
1662
|
-
return this.forkDecisionController.recordProposal(workspaceId, instance, step, proposal, step.model);
|
|
1663
|
-
},
|
|
1664
|
-
},
|
|
1665
|
-
// The read-only `pr-reviewer` deep-review job just finished on a review task's step. Its
|
|
1666
|
-
// structured `result.custom` is the sliced, prioritized findings; record them onto the
|
|
1667
|
-
// step's `prReview` and PARK for the human to select which findings matter (≥1 finding),
|
|
1668
|
-
// rather than the normal completion. A clean PR (no findings) returns null and falls
|
|
1669
|
-
// through to the normal finish. Keyed on the `pr-reviewer` step kind.
|
|
1670
|
-
{
|
|
1671
|
-
kind: 'pr-review',
|
|
1672
|
-
order: 106,
|
|
1673
|
-
canIntercept: ({ step }) => step.agentKind === PR_REVIEW_STEP_KIND,
|
|
1674
|
-
intercept: async ({ workspaceId, instance, step, result }) => {
|
|
1675
|
-
const output = this.agentKindRegistry
|
|
1676
|
-
.structuredOutput(PR_REVIEWER_KIND)
|
|
1677
|
-
?.safeParse(result.custom);
|
|
1678
|
-
const block = await this.blockRepository.get(workspaceId, instance.blockId);
|
|
1679
|
-
return this.prReviewController.recordFindings(workspaceId, instance, step, output, result.model ?? step.model, block);
|
|
1680
|
-
},
|
|
1681
|
-
},
|
|
1682
|
-
// A `tester` step returned a structured report. On a withheld greenlight we do NOT
|
|
1683
|
-
// finish the step: loop the `fixer` (within the attempt budget) and re-test, mirroring
|
|
1684
|
-
// the CI gate. A greenlight (or no provider) returns null and falls through to the
|
|
1685
|
-
// normal finish/advance below. Records the report on the step either way.
|
|
1686
|
-
{
|
|
1687
|
-
kind: 'tester-verdict',
|
|
1688
|
-
order: 110,
|
|
1689
|
-
canIntercept: ({ step, result }) => isTesterKind(step.agentKind) && result.testReport !== undefined,
|
|
1690
|
-
intercept: ({ workspaceId, instance, step, result }) => this.testerController.resolveTesterResult(workspaceId, instance, step, result),
|
|
1691
|
-
},
|
|
1692
|
-
// A `ralph` iteration finished and the harness attached its programmatic validation
|
|
1693
|
-
// verdict. Hand it to the ralph loop: a passing command finishes + advances (returns
|
|
1694
|
-
// null → normal completion), a failing one re-dispatches a fresh iteration within the
|
|
1695
|
-
// budget or gives up for a human — never the normal single-shot completion. Keyed on the
|
|
1696
|
-
// `ralph` kind carrying a `ralphVerdict`; a ralph run that errored before validation (no
|
|
1697
|
-
// verdict) falls through to the normal failure path.
|
|
1698
|
-
{
|
|
1699
|
-
kind: 'ralph-verdict',
|
|
1700
|
-
order: 115,
|
|
1701
|
-
canIntercept: ({ step, result }) => isRalphKind(step.agentKind) && result.ralphVerdict !== undefined,
|
|
1702
|
-
intercept: ({ workspaceId, instance, step, result }) => this.ralphController.resolveRalphResult(workspaceId, instance, step, result),
|
|
1703
|
-
},
|
|
1704
|
-
];
|
|
1705
|
-
return interceptors.sort((a, b) => a.order - b.order);
|
|
1486
|
+
return buildStepCompletionInterceptorsImpl(this.registryDeps);
|
|
1706
1487
|
}
|
|
1707
1488
|
stepResolverFor(agentKind) {
|
|
1708
1489
|
if (!this.stepResolverCache)
|
|
@@ -1710,164 +1491,7 @@ export class RunDispatcher {
|
|
|
1710
1491
|
return this.stepResolverCache.get(agentKind);
|
|
1711
1492
|
}
|
|
1712
1493
|
buildStepResolverRegistry() {
|
|
1713
|
-
|
|
1714
|
-
// The `merger` agent OWNS the merge decision, but the merge itself is mechanical
|
|
1715
|
-
// and uses backend-held GitHub credentials the sandboxed agent never sees — so the
|
|
1716
|
-
// engine performs it deterministically from the agent's assessment here, the moment
|
|
1717
|
-
// the merger step finishes (NOT only when it is the pipeline's last step, which is
|
|
1718
|
-
// why a trailing `post-release-health` step no longer disables auto-merge).
|
|
1719
|
-
{
|
|
1720
|
-
kind: MERGER_AGENT_KIND,
|
|
1721
|
-
applies: (result) => result.mergeAssessment !== undefined,
|
|
1722
|
-
resolve: async ({ workspaceId, instance, step, result }) => {
|
|
1723
|
-
// The real merge runs the engine GitHub client under the run initiator's
|
|
1724
|
-
// ambient context, so a per-user PAT (when set) authors the merge.
|
|
1725
|
-
const decision = await this.runInitiatorScope(instance.initiatedBy, () => this.mergeResolver.resolveMergerStep(workspaceId, instance, result.mergeAssessment));
|
|
1726
|
-
// Record the structured verdict on the step so the SPA's dedicated merger result
|
|
1727
|
-
// view renders the assessment + explains the auto-merge / awaiting-review decision,
|
|
1728
|
-
// instead of showing the agent's raw JSON.
|
|
1729
|
-
if (decision) {
|
|
1730
|
-
step.custom = decision;
|
|
1731
|
-
// Drop the raw JSON only when we captured a structured assessment (the view
|
|
1732
|
-
// renders it from `step.custom`). When the merger produced NO parseable
|
|
1733
|
-
// assessment, keep the raw reply so an operator can still diagnose what it sent.
|
|
1734
|
-
if (decision.assessment)
|
|
1735
|
-
step.output = '';
|
|
1736
|
-
}
|
|
1737
|
-
return { ownsTerminalStatus: true };
|
|
1738
|
-
},
|
|
1739
|
-
},
|
|
1740
|
-
// POST-COMPLETION resolvers — run at the early slot (after output is recorded, before
|
|
1741
|
-
// the follow-up/approval gates), reshaping the agent's structured result into domain
|
|
1742
|
-
// state. Lifted verbatim from the old inline `recordStepResult` branches.
|
|
1743
|
-
//
|
|
1744
|
-
// A Blueprinter step produced a fresh service decomposition. Validate it with the
|
|
1745
|
-
// authoritative schema (a bad payload must never touch the board), then reconcile it
|
|
1746
|
-
// in place onto the run's service frame.
|
|
1747
|
-
{
|
|
1748
|
-
kind: BLUEPRINTS_AGENT_KIND,
|
|
1749
|
-
phase: 'post-completion',
|
|
1750
|
-
resolve: async ({ workspaceId, instance, result }) => {
|
|
1751
|
-
if (result.blueprintService !== undefined) {
|
|
1752
|
-
await this.ingestBlueprint(workspaceId, instance.blockId, result.blueprintService);
|
|
1753
|
-
}
|
|
1754
|
-
},
|
|
1755
|
-
},
|
|
1756
|
-
// An initiative-analyst step produced a prose codebase analysis. Fold it onto the
|
|
1757
|
-
// block's `initiatives` entity (`analysisSummary`) so the planner's prompt is grounded
|
|
1758
|
-
// in it. Best-effort: an empty analysis or an unwired store simply leaves the summary
|
|
1759
|
-
// unchanged (the planner still runs); never fail the run on a missing analysis.
|
|
1760
|
-
{
|
|
1761
|
-
kind: INITIATIVE_ANALYST_AGENT_KIND,
|
|
1762
|
-
phase: 'post-completion',
|
|
1763
|
-
resolve: async ({ workspaceId, instance, result }) => {
|
|
1764
|
-
const summary = result.output?.trim();
|
|
1765
|
-
if (!this.initiativeService || !summary)
|
|
1766
|
-
return;
|
|
1767
|
-
await this.initiativeService.recordAnalysis(workspaceId, instance.blockId, summary);
|
|
1768
|
-
},
|
|
1769
|
-
},
|
|
1770
|
-
// An initiative-planner step produced a plan draft. Ingest it into the block's
|
|
1771
|
-
// `initiatives` entity (strict-parse at the trust boundary; replay-idempotent —
|
|
1772
|
-
// the same draft re-applies to identical content). The run then parks at the
|
|
1773
|
-
// planner's human gate; the committer step later mirrors the APPROVED plan into
|
|
1774
|
-
// the repo. A malformed draft fails the step loudly — completing the run without
|
|
1775
|
-
// an ingested plan would strand the initiative in `planning` with a green run.
|
|
1776
|
-
{
|
|
1777
|
-
kind: INITIATIVE_PLANNER_AGENT_KIND,
|
|
1778
|
-
phase: 'post-completion',
|
|
1779
|
-
resolve: async ({ workspaceId, instance, result }) => {
|
|
1780
|
-
if (!this.initiativeService)
|
|
1781
|
-
return;
|
|
1782
|
-
if (result.initiativePlan === undefined) {
|
|
1783
|
-
throw new Error('The initiative planner returned no usable plan (malformed or empty JSON)');
|
|
1784
|
-
}
|
|
1785
|
-
const ingested = await this.initiativeService.ingestPlan(workspaceId, instance.blockId, result.initiativePlan);
|
|
1786
|
-
if (!ingested) {
|
|
1787
|
-
throw new Error('No initiative entity found for this block — cannot ingest the plan');
|
|
1788
|
-
}
|
|
1789
|
-
},
|
|
1790
|
-
},
|
|
1791
|
-
// A spec-writer step produced the service's unified specification (`spec.json`) and
|
|
1792
|
-
// committed it to the implementation branch — strict-validate it then nudge clients —
|
|
1793
|
-
// and reports its BUSINESS-vs-TECHNICAL determination. "No business specs" (a purely
|
|
1794
|
-
// technical task) is a valid outcome the spec-companion's convergence later combines
|
|
1795
|
-
// with its `technicalCorroborated` verdict; recorded even when false so a re-run
|
|
1796
|
-
// reflects the latest.
|
|
1797
|
-
{
|
|
1798
|
-
kind: SPEC_WRITER_AGENT_KIND,
|
|
1799
|
-
phase: 'post-completion',
|
|
1800
|
-
resolve: async ({ workspaceId, step, result }) => {
|
|
1801
|
-
if (result.spec !== undefined)
|
|
1802
|
-
await this.ingestSpec(workspaceId, result.spec);
|
|
1803
|
-
step.noBusinessSpecs = result.noBusinessSpecs === true;
|
|
1804
|
-
},
|
|
1805
|
-
},
|
|
1806
|
-
// A `task-estimator` step emits a JSON triage (complexity/risk/impact). Parse it
|
|
1807
|
-
// tolerantly, persist it on the block (used to gate consensus steps + surfaced in the
|
|
1808
|
-
// UI), and replace the raw JSON output with a readable summary. An unparseable estimate
|
|
1809
|
-
// leaves the block untouched and keeps the raw output (no run failure). Works the same
|
|
1810
|
-
// whether the single-actor estimator or the consensus ranked-scoring variant produced
|
|
1811
|
-
// the JSON. Running at the post-completion slot keeps the summary in `step.output`
|
|
1812
|
-
// before the approval gate reads it as the proposal.
|
|
1813
|
-
// A `bug-investigator` step returns its STRUCTURED triage as `result.custom` (kept on
|
|
1814
|
-
// `step.custom` for the generic-structured view + the clarity gate's structured read).
|
|
1815
|
-
// Render a prose digest into `step.output` at the post-completion slot so downstream
|
|
1816
|
-
// steps (estimator / repro-test / coder) read the investigation via `priorOutputs`
|
|
1817
|
-
// (which carries only `step.output`), and the clarity gate's investigation-prose context
|
|
1818
|
-
// sees it too. An unparseable result leaves the agent's raw reply on `step.output`.
|
|
1819
|
-
{
|
|
1820
|
-
kind: BUG_INVESTIGATOR_AGENT_KIND,
|
|
1821
|
-
phase: 'post-completion',
|
|
1822
|
-
applies: (result) => result.custom !== undefined,
|
|
1823
|
-
resolve: async ({ result }) => {
|
|
1824
|
-
const digest = renderInvestigationDigest(result.custom);
|
|
1825
|
-
if (digest)
|
|
1826
|
-
return { output: digest };
|
|
1827
|
-
},
|
|
1828
|
-
},
|
|
1829
|
-
// A `repro-test` step returns its STRUCTURED outcome as `result.custom` (kept on
|
|
1830
|
-
// `step.custom` for the generic-structured view). Render a short prose digest into
|
|
1831
|
-
// `step.output` at the post-completion slot so the coder reads the reproduction result
|
|
1832
|
-
// (reproduced / conceded + why) via `priorOutputs` (which carries only `step.output`).
|
|
1833
|
-
// Conceding never fails the run — the container tolerates a no-op (`noChangesTolerated`),
|
|
1834
|
-
// so this only reshapes the output. An unparseable result leaves the raw reply on
|
|
1835
|
-
// `step.output`.
|
|
1836
|
-
{
|
|
1837
|
-
kind: REPRO_TEST_AGENT_KIND,
|
|
1838
|
-
phase: 'post-completion',
|
|
1839
|
-
applies: (result) => result.custom !== undefined,
|
|
1840
|
-
resolve: async ({ result }) => {
|
|
1841
|
-
const digest = renderReproDigest(result.custom);
|
|
1842
|
-
if (digest)
|
|
1843
|
-
return { output: digest };
|
|
1844
|
-
},
|
|
1845
|
-
},
|
|
1846
|
-
{
|
|
1847
|
-
kind: TASK_ESTIMATOR_AGENT_KIND,
|
|
1848
|
-
phase: 'post-completion',
|
|
1849
|
-
resolve: async ({ workspaceId, instance, step, result }) => {
|
|
1850
|
-
const estimate = coerceTaskEstimate(step.output ?? '', result.model ?? step.model ?? null, this.clock.now());
|
|
1851
|
-
if (estimate) {
|
|
1852
|
-
await this.blockRepository.update(workspaceId, instance.blockId, { estimate });
|
|
1853
|
-
return { output: summarizeEstimate(estimate) };
|
|
1854
|
-
}
|
|
1855
|
-
},
|
|
1856
|
-
},
|
|
1857
|
-
];
|
|
1858
|
-
const map = new Map(resolvers.map((r) => [r.kind, r]));
|
|
1859
|
-
// Merge deployment-registered resolvers, mirroring the gate registry below. A
|
|
1860
|
-
// registered resolver of the same kind replaces the built-in (last registration wins).
|
|
1861
|
-
// The registry is the app-owned instance injected through `CoreDependencies`, not a
|
|
1862
|
-
// module global.
|
|
1863
|
-
const ctx = this.makeResolverContext();
|
|
1864
|
-
for (const { kind, factory } of this.stepResolverRegistry.factories())
|
|
1865
|
-
map.set(kind, factory(ctx));
|
|
1866
|
-
return map;
|
|
1867
|
-
}
|
|
1868
|
-
/** The shared engine seams handed to a deployment-registered step resolver's factory. */
|
|
1869
|
-
makeResolverContext() {
|
|
1870
|
-
return { runInitiatorScope: this.runInitiatorScope };
|
|
1494
|
+
return buildStepResolverRegistryImpl(this.registryDeps);
|
|
1871
1495
|
}
|
|
1872
1496
|
buildGateRegistry() {
|
|
1873
1497
|
// The built-in gate suite (ci / conflicts / post-release-health) is no longer inline:
|