@cat-factory/orchestration 0.70.1 → 0.71.0
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/container.d.ts +23 -2
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +43 -10
- package/dist/container.js.map +1 -1
- package/dist/modules/clarity/ClarityReviewService.d.ts +21 -1
- package/dist/modules/clarity/ClarityReviewService.d.ts.map +1 -1
- package/dist/modules/clarity/ClarityReviewService.js +27 -1
- package/dist/modules/clarity/ClarityReviewService.js.map +1 -1
- package/dist/modules/clarity/clarity.logic.d.ts +8 -0
- package/dist/modules/clarity/clarity.logic.d.ts.map +1 -1
- package/dist/modules/clarity/clarity.logic.js +23 -0
- package/dist/modules/clarity/clarity.logic.js.map +1 -1
- package/dist/modules/execution/AgentContextBuilder.d.ts +3 -0
- package/dist/modules/execution/AgentContextBuilder.d.ts.map +1 -1
- package/dist/modules/execution/AgentContextBuilder.js +2 -1
- package/dist/modules/execution/AgentContextBuilder.js.map +1 -1
- package/dist/modules/execution/ExecutionService.d.ts +60 -10
- package/dist/modules/execution/ExecutionService.d.ts.map +1 -1
- package/dist/modules/execution/ExecutionService.js +192 -27
- package/dist/modules/execution/ExecutionService.js.map +1 -1
- package/dist/modules/execution/MergeResolver.d.ts +21 -2
- package/dist/modules/execution/MergeResolver.d.ts.map +1 -1
- package/dist/modules/execution/MergeResolver.js +9 -3
- package/dist/modules/execution/MergeResolver.js.map +1 -1
- package/dist/modules/execution/RunDispatcher.d.ts +33 -1
- package/dist/modules/execution/RunDispatcher.d.ts.map +1 -1
- package/dist/modules/execution/RunDispatcher.js +144 -14
- package/dist/modules/execution/RunDispatcher.js.map +1 -1
- package/dist/modules/execution/RunStateMachine.d.ts +5 -2
- package/dist/modules/execution/RunStateMachine.d.ts.map +1 -1
- package/dist/modules/execution/RunStateMachine.js +4 -1
- package/dist/modules/execution/RunStateMachine.js.map +1 -1
- package/dist/modules/execution/bugInvestigation.logic.d.ts +3 -0
- package/dist/modules/execution/bugInvestigation.logic.d.ts.map +1 -0
- package/dist/modules/execution/bugInvestigation.logic.js +44 -0
- package/dist/modules/execution/bugInvestigation.logic.js.map +1 -0
- package/dist/modules/execution/mergeOrder.logic.d.ts +23 -0
- package/dist/modules/execution/mergeOrder.logic.d.ts.map +1 -0
- package/dist/modules/execution/mergeOrder.logic.js +30 -0
- package/dist/modules/execution/mergeOrder.logic.js.map +1 -0
- package/dist/modules/initiative/InitiativeLoopService.d.ts +7 -1
- package/dist/modules/initiative/InitiativeLoopService.d.ts.map +1 -1
- package/dist/modules/initiative/InitiativeLoopService.js +16 -3
- package/dist/modules/initiative/InitiativeLoopService.js.map +1 -1
- package/dist/modules/initiative/InitiativeService.d.ts +15 -1
- package/dist/modules/initiative/InitiativeService.d.ts.map +1 -1
- package/dist/modules/initiative/InitiativeService.js +46 -1
- package/dist/modules/initiative/InitiativeService.js.map +1 -1
- package/dist/modules/initiative/initiative.logic.d.ts +59 -1
- package/dist/modules/initiative/initiative.logic.d.ts.map +1 -1
- package/dist/modules/initiative/initiative.logic.js +241 -19
- package/dist/modules/initiative/initiative.logic.js.map +1 -1
- package/dist/modules/pipelines/PipelineService.d.ts.map +1 -1
- package/dist/modules/pipelines/PipelineService.js +15 -1
- package/dist/modules/pipelines/PipelineService.js.map +1 -1
- package/dist/modules/pipelines/pipelineShape.d.ts +15 -0
- package/dist/modules/pipelines/pipelineShape.d.ts.map +1 -1
- package/dist/modules/pipelines/pipelineShape.js +14 -4
- package/dist/modules/pipelines/pipelineShape.js.map +1 -1
- package/dist/modules/recurring/RecurringPipelineService.d.ts +18 -0
- package/dist/modules/recurring/RecurringPipelineService.d.ts.map +1 -1
- package/dist/modules/recurring/RecurringPipelineService.js +50 -4
- package/dist/modules/recurring/RecurringPipelineService.js.map +1 -1
- package/dist/modules/review/IterativeReviewService.d.ts +12 -0
- package/dist/modules/review/IterativeReviewService.d.ts.map +1 -1
- package/dist/modules/review/IterativeReviewService.js +23 -5
- package/dist/modules/review/IterativeReviewService.js.map +1 -1
- package/dist/modules/sandbox/SandboxRunService.d.ts +3 -0
- package/dist/modules/sandbox/SandboxRunService.d.ts.map +1 -1
- package/dist/modules/sandbox/SandboxRunService.js +1 -1
- package/dist/modules/sandbox/SandboxRunService.js.map +1 -1
- package/dist/modules/sandbox/SandboxService.d.ts +3 -0
- package/dist/modules/sandbox/SandboxService.d.ts.map +1 -1
- package/dist/modules/sandbox/SandboxService.js +3 -3
- package/dist/modules/sandbox/SandboxService.js.map +1 -1
- package/dist/validation/validateRegistrations.d.ts +9 -3
- package/dist/validation/validateRegistrations.d.ts.map +1 -1
- package/dist/validation/validateRegistrations.js +7 -7
- package/dist/validation/validateRegistrations.js.map +1 -1
- package/package.json +11 -11
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { ConflictError, DEFAULT_MERGE_PRESET, getErrorMessage, getProvider, INITIATIVE_ANALYST_AGENT_KIND, INITIATIVE_COMMITTER_AGENT_KIND, INITIATIVE_INTERVIEWER_AGENT_KIND, INITIATIVE_PLANNER_AGENT_KIND, isAsyncAgentExecutor, NotFoundError, parseLocalModelId, recordGateAttempt, registeredGateFactories, registeredStepResolverFactories, requireProvider, sameSubtasks, } from '@cat-factory/kernel';
|
|
2
2
|
import { frontendOriginsForService, parseBlueprintService, parseSpecDoc, } from '@cat-factory/contracts';
|
|
3
|
-
import { blueprintPostOp, commitInitiativeTracker, isCompanionKind, isContainerBackedCompanion, moduleSlug,
|
|
3
|
+
import { blueprintPostOp, commitInitiativeTracker, isCompanionKind, isContainerBackedCompanion, moduleSlug, runRepoOps, specPostOp, TASK_ESTIMATOR_AGENT_KIND, } from '@cat-factory/agents';
|
|
4
4
|
import { DEPLOYER_AGENT_KIND, isDeployStep } from '@cat-factory/integrations';
|
|
5
|
+
import { BUG_INTAKE_AGENT_KIND } from '../pipelines/pipelineShape.js';
|
|
5
6
|
import { coerceTaskEstimate, summarizeEstimate } from '../estimation/estimate.logic.js';
|
|
6
7
|
import { reviewableArtifactOutput } from './artifact-review.logic.js';
|
|
7
8
|
import { deployEvictionEpoch, deployJobId, orderProvisionTargets } from './deployer.logic.js';
|
|
9
|
+
import { renderInvestigationDigest } from './bugInvestigation.logic.js';
|
|
8
10
|
import { frameOf, validInvolvedServiceFrames } from './frame.logic.js';
|
|
9
|
-
import { ANALYSIS_AGENT_KIND, ARCHITECTURE_BRAINSTORM_AGENT_KIND, BLUEPRINTS_AGENT_KIND, CLARITY_REVIEW_AGENT_KIND, CONFLICTS_AGENT_KIND, HUMAN_TEST_AGENT_KIND, isTesterKind, MERGER_AGENT_KIND, REQUIREMENTS_BRAINSTORM_AGENT_KIND, REQUIREMENTS_REVIEW_AGENT_KIND, SPEC_WRITER_AGENT_KIND, TESTER_AGENT_KIND, TRACKER_AGENT_KIND, UI_TESTER_AGENT_KIND, VISUAL_CONFIRM_AGENT_KIND, } from './ci.logic.js';
|
|
11
|
+
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, REQUIREMENTS_BRAINSTORM_AGENT_KIND, REQUIREMENTS_REVIEW_AGENT_KIND, SPEC_WRITER_AGENT_KIND, TESTER_AGENT_KIND, TRACKER_AGENT_KIND, UI_TESTER_AGENT_KIND, VISUAL_CONFIRM_AGENT_KIND, } from './ci.logic.js';
|
|
10
12
|
import { followUpsToSendBack, hasPendingFollowUps, renderFollowUpRework, shouldLoopCoder, } from './followUp.logic.js';
|
|
11
13
|
import { agentFailureKindFromCause, classifyAgentFailure, isContainerEvictionError, isTransientEviction, MAX_EVICTION_RECOVERIES, MAX_TRANSIENT_EVICTION_RECOVERIES, } from './job.logic.js';
|
|
12
14
|
import { AgentContextBuilder } from './AgentContextBuilder.js';
|
|
@@ -97,6 +99,7 @@ export class RunDispatcher {
|
|
|
97
99
|
blockRepository;
|
|
98
100
|
executionRepository;
|
|
99
101
|
agentExecutor;
|
|
102
|
+
agentKindRegistry;
|
|
100
103
|
workRunner;
|
|
101
104
|
events;
|
|
102
105
|
idGenerator;
|
|
@@ -120,6 +123,7 @@ export class RunDispatcher {
|
|
|
120
123
|
environmentProvisioning;
|
|
121
124
|
ticketTrackerProvider;
|
|
122
125
|
issueWriteback;
|
|
126
|
+
bugIntakeService;
|
|
123
127
|
notificationService;
|
|
124
128
|
blueprintReconciler;
|
|
125
129
|
initiativeService;
|
|
@@ -139,6 +143,7 @@ export class RunDispatcher {
|
|
|
139
143
|
this.blockRepository = deps.blockRepository;
|
|
140
144
|
this.executionRepository = deps.executionRepository;
|
|
141
145
|
this.agentExecutor = deps.agentExecutor;
|
|
146
|
+
this.agentKindRegistry = deps.agentKindRegistry;
|
|
142
147
|
this.workRunner = deps.workRunner;
|
|
143
148
|
this.events = deps.events;
|
|
144
149
|
this.idGenerator = deps.idGenerator;
|
|
@@ -162,6 +167,7 @@ export class RunDispatcher {
|
|
|
162
167
|
this.environmentProvisioning = deps.environmentProvisioning;
|
|
163
168
|
this.ticketTrackerProvider = deps.ticketTrackerProvider;
|
|
164
169
|
this.issueWriteback = deps.issueWriteback;
|
|
170
|
+
this.bugIntakeService = deps.bugIntakeService;
|
|
165
171
|
this.notificationService = deps.notificationService;
|
|
166
172
|
this.blueprintReconciler = deps.blueprintReconciler;
|
|
167
173
|
this.initiativeService = deps.initiativeService;
|
|
@@ -902,23 +908,28 @@ export class RunDispatcher {
|
|
|
902
908
|
step.rework = undefined;
|
|
903
909
|
// A repo-operating step (the container "implementer" agent) opened a PR for
|
|
904
910
|
// its work. Record it on the block so the board can surface and link to it,
|
|
905
|
-
// regardless of whether this is the final step.
|
|
906
|
-
|
|
911
|
+
// regardless of whether this is the final step. A multi-repo run
|
|
912
|
+
// (service-connections phase 3) additionally reports the PRs it opened in the
|
|
913
|
+
// connected involved-service repos; record them beside the own-service PR (they may
|
|
914
|
+
// even arrive when the own service was a no-op and only a peer changed).
|
|
915
|
+
if (result.pullRequest || result.peerPullRequests?.length) {
|
|
907
916
|
// Read the block before the update so we can tell whether this PR is newly
|
|
908
917
|
// opened (vs. the same PR re-reported by a re-run/retry of the coder step).
|
|
909
918
|
const priorBlock = this.issueWriteback
|
|
910
919
|
? await this.blockRepository.get(workspaceId, instance.blockId)
|
|
911
920
|
: null;
|
|
912
921
|
await this.blockRepository.update(workspaceId, instance.blockId, {
|
|
913
|
-
pullRequest: result.pullRequest,
|
|
922
|
+
...(result.pullRequest ? { pullRequest: result.pullRequest } : {}),
|
|
923
|
+
...(result.peerPullRequests?.length ? { peerPullRequests: result.peerPullRequests } : {}),
|
|
914
924
|
});
|
|
915
925
|
// Best-effort writeback: comment on the task's linked tracker issue(s) that a
|
|
916
|
-
// PR opened. Only
|
|
917
|
-
// same PR must not re-comment (the tracker comment is not
|
|
918
|
-
// inside the provider by the workspace setting + per-task
|
|
919
|
-
// fire-and-forget so a tracker outage never fails the run.
|
|
926
|
+
// PR opened. Only for the OWN-service PR, and only when it is newly recorded — a
|
|
927
|
+
// retry that re-reports the same PR must not re-comment (the tracker comment is not
|
|
928
|
+
// idempotent). Gated inside the provider by the workspace setting + per-task
|
|
929
|
+
// override; fire-and-forget so a tracker outage never fails the run.
|
|
920
930
|
if (this.issueWriteback &&
|
|
921
931
|
priorBlock &&
|
|
932
|
+
result.pullRequest &&
|
|
922
933
|
priorBlock.pullRequest?.url !== result.pullRequest.url) {
|
|
923
934
|
await this.issueWriteback
|
|
924
935
|
.onPullRequestOpened(workspaceId, priorBlock, result.pullRequest)
|
|
@@ -1548,6 +1559,89 @@ export class RunDispatcher {
|
|
|
1548
1559
|
return { output: `Could not file a tracking ticket: ${getErrorMessage(error)}` };
|
|
1549
1560
|
}
|
|
1550
1561
|
}
|
|
1562
|
+
/**
|
|
1563
|
+
* Run a `bug-intake` step — the recurring bug-triage pipeline's inbound dual of `tracker`
|
|
1564
|
+
* (design §3). Pull ONE matching open issue from the schedule's configured tracker board,
|
|
1565
|
+
* claim it (import + replace-link onto the reused block, mark it in-progress + comment), and
|
|
1566
|
+
* seed the block's title/description from it so every downstream step works THAT bug. When
|
|
1567
|
+
* nothing matches — or no task source is wired — the run completes SUCCESSFULLY with every
|
|
1568
|
+
* remaining step skipped (there is nothing to investigate / reproduce / fix), no notification.
|
|
1569
|
+
* Best-effort throughout: the intake helper never throws (a tracker outage resolves to a
|
|
1570
|
+
* no-op), and the pickup writeback is fire-and-forget.
|
|
1571
|
+
*/
|
|
1572
|
+
async runBugIntake(workspaceId, instance, step, block, isFinalStep) {
|
|
1573
|
+
const outcome = this.bugIntakeService
|
|
1574
|
+
? await this.bugIntakeService.pickForBlock(workspaceId, block.id)
|
|
1575
|
+
: { picked: null, summary: 'Issue intake is not configured on this deployment.' };
|
|
1576
|
+
if (!outcome.picked) {
|
|
1577
|
+
return this.completeRunSkippingRemaining(workspaceId, instance, step, outcome.summary);
|
|
1578
|
+
}
|
|
1579
|
+
const pickup = outcome.picked;
|
|
1580
|
+
// Seed the reused recurring block from the picked issue so each fire works a different bug
|
|
1581
|
+
// through the same block (the same block-seeding `createTaskFromIssue` does, applied in place).
|
|
1582
|
+
// Clear the previous fire's peer PRs too — this fire works a DIFFERENT bug, so a prior bug's
|
|
1583
|
+
// connected-repo PRs must not linger on the block. (The own-service `pullRequest` is overwritten
|
|
1584
|
+
// by this run's coder step before any step reads it; it is a non-nullable `BlockPatch` field, so
|
|
1585
|
+
// it cannot be cleared here anyway.)
|
|
1586
|
+
await this.blockRepository.update(workspaceId, block.id, {
|
|
1587
|
+
title: pickup.seedTitle,
|
|
1588
|
+
description: pickup.seedDescription,
|
|
1589
|
+
peerPullRequests: [],
|
|
1590
|
+
});
|
|
1591
|
+
// Best-effort: claim the issue where it was filed (in-progress mark + "taken by cat-factory"
|
|
1592
|
+
// comment). Fire-and-forget — a tracker hiccup must never fail the run, mirroring the PR
|
|
1593
|
+
// open/merge writeback hooks; and unlike them this is NOT gated on the writeback settings.
|
|
1594
|
+
if (this.issueWriteback) {
|
|
1595
|
+
await this.issueWriteback
|
|
1596
|
+
.onIssuePickedUp(workspaceId, block.id, pickup.inProgressLabel ? { inProgressLabel: pickup.inProgressLabel } : {})
|
|
1597
|
+
.catch(() => { });
|
|
1598
|
+
}
|
|
1599
|
+
return this.recordStepResult(workspaceId, instance, step, isFinalStep, {
|
|
1600
|
+
output: pickup.summary,
|
|
1601
|
+
});
|
|
1602
|
+
}
|
|
1603
|
+
/**
|
|
1604
|
+
* Complete the run successfully after a `bug-intake` step found no issue to work: record the
|
|
1605
|
+
* intake step's own no-match output (it SUCCEEDED — it made the decision), then mark every
|
|
1606
|
+
* REMAINING step `skipped` and finalize the reused block `done`, with NO notification (the
|
|
1607
|
+
* outcome is visible in the schedule's run history).
|
|
1608
|
+
*
|
|
1609
|
+
* The block is finalized `done` DIRECTLY here rather than through `RunStateMachine.finalizeBlock`:
|
|
1610
|
+
* for a mergerless task block (every bug-triage pipeline) finalizeBlock's terminal branch treats
|
|
1611
|
+
* the run as "work complete but unmerged" — it flips the block `pr_ready` and raises a
|
|
1612
|
+
* `pipeline_complete` "confirm + merge the PR" notification. This fire did NO work and opened NO
|
|
1613
|
+
* PR, so that card would be spurious (and its payload would reference a STALE PR carried over from
|
|
1614
|
+
* a prior fire). Setting the terminal status inline keeps the no-op silent, as documented.
|
|
1615
|
+
*/
|
|
1616
|
+
async completeRunSkippingRemaining(workspaceId, instance, step, summary) {
|
|
1617
|
+
step.output = summary;
|
|
1618
|
+
step.progress = 1;
|
|
1619
|
+
step.subtasks = undefined;
|
|
1620
|
+
this.stepGraph.finishStep(step);
|
|
1621
|
+
for (let i = instance.currentStep + 1; i < instance.steps.length; i++) {
|
|
1622
|
+
const remaining = instance.steps[i];
|
|
1623
|
+
if (!remaining)
|
|
1624
|
+
continue;
|
|
1625
|
+
remaining.skipped = true;
|
|
1626
|
+
remaining.output = '';
|
|
1627
|
+
remaining.progress = 1;
|
|
1628
|
+
remaining.subtasks = undefined;
|
|
1629
|
+
this.stepGraph.finishStep(remaining);
|
|
1630
|
+
}
|
|
1631
|
+
instance.currentStep = instance.steps.length - 1;
|
|
1632
|
+
instance.status = 'done';
|
|
1633
|
+
const block = await this.blockRepository.get(workspaceId, instance.blockId);
|
|
1634
|
+
if (block && block.status !== 'done') {
|
|
1635
|
+
await this.blockRepository.update(workspaceId, instance.blockId, {
|
|
1636
|
+
status: 'done',
|
|
1637
|
+
progress: 1,
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
await this.executionRepository.upsert(workspaceId, instance);
|
|
1641
|
+
await this.runStateMachine.emitInstance(workspaceId, instance);
|
|
1642
|
+
await this.runStateMachine.stopRunContainer(workspaceId, instance);
|
|
1643
|
+
return { kind: 'done' };
|
|
1644
|
+
}
|
|
1551
1645
|
/**
|
|
1552
1646
|
* Persist an APPROVED initiative plan for an `initiative-committer` step: flip the
|
|
1553
1647
|
* entity to `executing` and mirror the tracker into the repo's default branch
|
|
@@ -1686,13 +1780,13 @@ export class RunDispatcher {
|
|
|
1686
1780
|
* unchanged without the feature. A throwing op propagates to fail the step.
|
|
1687
1781
|
*/
|
|
1688
1782
|
async runRegisteredPreOps(workspaceId, block, step, context) {
|
|
1689
|
-
const ops =
|
|
1783
|
+
const ops = this.agentKindRegistry.preOps(step.agentKind);
|
|
1690
1784
|
if (ops.length === 0)
|
|
1691
1785
|
return;
|
|
1692
1786
|
const runRepo = await this.resolveRunRepo(workspaceId, block.id);
|
|
1693
1787
|
if (!runRepo)
|
|
1694
1788
|
return;
|
|
1695
|
-
const branch = await this.resolveRepoOpBranch(
|
|
1789
|
+
const branch = await this.resolveRepoOpBranch(this.agentKindRegistry.agentStep(step.agentKind), block, runRepo);
|
|
1696
1790
|
await runRepoOps(ops, { repo: runRepo.repo, context, branch });
|
|
1697
1791
|
}
|
|
1698
1792
|
/**
|
|
@@ -1717,7 +1811,7 @@ export class RunDispatcher {
|
|
|
1717
1811
|
* {@link runRegisteredPreOps}; the agent's {@link AgentRunResult} is threaded through.
|
|
1718
1812
|
*/
|
|
1719
1813
|
async runRegisteredPostOps(workspaceId, instance, step, isFinalStep, result) {
|
|
1720
|
-
const registered =
|
|
1814
|
+
const registered = this.agentKindRegistry.postOps(step.agentKind);
|
|
1721
1815
|
const builtIn = this.builtInPostOps(step.agentKind);
|
|
1722
1816
|
if (registered.length === 0 && builtIn.length === 0)
|
|
1723
1817
|
return;
|
|
@@ -1730,7 +1824,7 @@ export class RunDispatcher {
|
|
|
1730
1824
|
const context = await this.contextBuilder.buildContext(workspaceId, instance, step, isFinalStep, block);
|
|
1731
1825
|
// Registered (custom) kinds resolve their branch from their declared clone target.
|
|
1732
1826
|
if (registered.length > 0) {
|
|
1733
|
-
const branch = await this.resolveRepoOpBranch(
|
|
1827
|
+
const branch = await this.resolveRepoOpBranch(this.agentKindRegistry.agentStep(step.agentKind), block, runRepo);
|
|
1734
1828
|
await runRepoOps(registered, { repo: runRepo.repo, context, branch, result });
|
|
1735
1829
|
}
|
|
1736
1830
|
// Built-in (migrated) kinds resolve their branch to MATCH their container dispatch
|
|
@@ -1837,6 +1931,17 @@ export class RunDispatcher {
|
|
|
1837
1931
|
return this.recordStepResult(workspaceId, instance, step, isFinalStep, result);
|
|
1838
1932
|
},
|
|
1839
1933
|
},
|
|
1934
|
+
// A `bug-intake` step (the recurring bug-triage pipeline) pulls ONE matching open issue from
|
|
1935
|
+
// the schedule's tracker board, claims it, and seeds the reused block from it — no LLM of its
|
|
1936
|
+
// own, the inbound dual of `tracker`. On no match (or no task source wired) it completes the
|
|
1937
|
+
// run successfully, skipping every remaining step. Handled entirely inside
|
|
1938
|
+
// {@link runBugIntake}, so it always claims the step.
|
|
1939
|
+
{
|
|
1940
|
+
kind: BUG_INTAKE_AGENT_KIND,
|
|
1941
|
+
order: 111,
|
|
1942
|
+
canHandle: ({ step }) => step.agentKind === BUG_INTAKE_AGENT_KIND,
|
|
1943
|
+
handle: ({ workspaceId, instance, step, block, isFinalStep }) => this.runBugIntake(workspaceId, instance, step, block, isFinalStep),
|
|
1944
|
+
},
|
|
1840
1945
|
// The `initiative-interviewer` step interviews the human on goals/constraints — an
|
|
1841
1946
|
// inline LLM gate that PARKS the planning run on a decision-wait while they answer
|
|
1842
1947
|
// through the planning window, then synthesizes the brief onto the entity and advances
|
|
@@ -2113,6 +2218,22 @@ export class RunDispatcher {
|
|
|
2113
2218
|
// whether the single-actor estimator or the consensus ranked-scoring variant produced
|
|
2114
2219
|
// the JSON. Running at the post-completion slot keeps the summary in `step.output`
|
|
2115
2220
|
// before the approval gate reads it as the proposal.
|
|
2221
|
+
// A `bug-investigator` step returns its STRUCTURED triage as `result.custom` (kept on
|
|
2222
|
+
// `step.custom` for the generic-structured view + the clarity gate's structured read).
|
|
2223
|
+
// Render a prose digest into `step.output` at the post-completion slot so downstream
|
|
2224
|
+
// steps (estimator / repro-test / coder) read the investigation via `priorOutputs`
|
|
2225
|
+
// (which carries only `step.output`), and the clarity gate's investigation-prose context
|
|
2226
|
+
// sees it too. An unparseable result leaves the agent's raw reply on `step.output`.
|
|
2227
|
+
{
|
|
2228
|
+
kind: BUG_INVESTIGATOR_AGENT_KIND,
|
|
2229
|
+
phase: 'post-completion',
|
|
2230
|
+
applies: (result) => result.custom !== undefined,
|
|
2231
|
+
resolve: async ({ result }) => {
|
|
2232
|
+
const digest = renderInvestigationDigest(result.custom);
|
|
2233
|
+
if (digest)
|
|
2234
|
+
return { output: digest };
|
|
2235
|
+
},
|
|
2236
|
+
},
|
|
2116
2237
|
{
|
|
2117
2238
|
kind: TASK_ESTIMATOR_AGENT_KIND,
|
|
2118
2239
|
phase: 'post-completion',
|
|
@@ -2224,6 +2345,12 @@ export class RunDispatcher {
|
|
|
2224
2345
|
const gateState = step.gate;
|
|
2225
2346
|
const probe = await this.runInitiatorScope(instance.initiatedBy, () => gate.probe(workspaceId, block.id, gateState));
|
|
2226
2347
|
step.gate.headSha = probe.headSha;
|
|
2348
|
+
// Multi-repo (service-connections phase 4): the CI / conflicts gates aggregate across every
|
|
2349
|
+
// PR the task opened; persist the per-repo head shas (and, for the conflicts gate, which repo
|
|
2350
|
+
// conflicted) so the run-detail UI can group checks by service and the conflict-resolver can
|
|
2351
|
+
// target the conflicted repo.
|
|
2352
|
+
step.gate.headShas = probe.headShas ?? null;
|
|
2353
|
+
step.gate.conflictTarget = probe.conflictTarget ?? null;
|
|
2227
2354
|
// Persist the precheck outcome so the run-detail UI can surface why the gate is
|
|
2228
2355
|
// looping (the failing checks / conflict reason) — detail that was previously fed
|
|
2229
2356
|
// only to the helper agent and then discarded.
|
|
@@ -2244,7 +2371,10 @@ export class RunDispatcher {
|
|
|
2244
2371
|
return { kind: 'awaiting_gate', stepIndex: instance.currentStep };
|
|
2245
2372
|
}
|
|
2246
2373
|
// probe.status === 'fail'.
|
|
2247
|
-
|
|
2374
|
+
// A gate can decline escalation for a failure its helper can't fix (e.g. the conflicts
|
|
2375
|
+
// gate on a PEER-repo conflict it has no resolver for) — go straight to give-up instead
|
|
2376
|
+
// of burning the attempt budget on a helper that can't touch the problem.
|
|
2377
|
+
const canEscalate = isAsyncAgentExecutor(this.agentExecutor) && probe.escalatable !== false;
|
|
2248
2378
|
if (canEscalate && step.gate.attempts < step.gate.maxAttempts) {
|
|
2249
2379
|
return this.dispatchGateHelper(workspaceId, instance, step, block, isFinalStep, gate, probe.failureSummary);
|
|
2250
2380
|
}
|