@intrect/openswarm 0.17.2 → 0.17.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 +21 -5
- package/config.example.yaml +18 -0
- package/dist/adapters/agenticLoop.d.ts +2 -0
- package/dist/adapters/agenticLoop.d.ts.map +1 -1
- package/dist/adapters/agenticLoop.js +6 -3
- package/dist/adapters/agenticLoop.js.map +1 -1
- package/dist/adapters/base.d.ts.map +1 -1
- package/dist/adapters/base.js +9 -0
- package/dist/adapters/base.js.map +1 -1
- package/dist/adapters/claude.d.ts.map +1 -1
- package/dist/adapters/claude.js +6 -3
- package/dist/adapters/claude.js.map +1 -1
- package/dist/adapters/codex.d.ts.map +1 -1
- package/dist/adapters/codex.js +3 -2
- package/dist/adapters/codex.js.map +1 -1
- package/dist/adapters/codexResponses.d.ts +2 -1
- package/dist/adapters/codexResponses.d.ts.map +1 -1
- package/dist/adapters/codexResponses.js +34 -30
- package/dist/adapters/codexResponses.js.map +1 -1
- package/dist/adapters/errorClassification.d.ts +11 -0
- package/dist/adapters/errorClassification.d.ts.map +1 -1
- package/dist/adapters/errorClassification.js +21 -0
- package/dist/adapters/errorClassification.js.map +1 -1
- package/dist/adapters/gpt.d.ts.map +1 -1
- package/dist/adapters/gpt.js +1 -0
- package/dist/adapters/gpt.js.map +1 -1
- package/dist/adapters/local.d.ts.map +1 -1
- package/dist/adapters/local.js +1 -0
- package/dist/adapters/local.js.map +1 -1
- package/dist/adapters/openrouter.d.ts.map +1 -1
- package/dist/adapters/openrouter.js +1 -0
- package/dist/adapters/openrouter.js.map +1 -1
- package/dist/adapters/processRegistry.d.ts.map +1 -1
- package/dist/adapters/processRegistry.js +8 -0
- package/dist/adapters/processRegistry.js.map +1 -1
- package/dist/adapters/types.d.ts +2 -0
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/agents/pairPipeline.d.ts +10 -139
- package/dist/agents/pairPipeline.d.ts.map +1 -1
- package/dist/agents/pairPipeline.js +161 -37
- package/dist/agents/pairPipeline.js.map +1 -1
- package/dist/agents/pairPipelineTypes.d.ts +111 -0
- package/dist/agents/pairPipelineTypes.d.ts.map +1 -0
- package/dist/agents/pairPipelineTypes.js +2 -0
- package/dist/agents/pairPipelineTypes.js.map +1 -0
- package/dist/agents/pipelineGuards.d.ts.map +1 -1
- package/dist/agents/pipelineGuards.js +346 -0
- package/dist/agents/pipelineGuards.js.map +1 -1
- package/dist/agents/pipelineTaskPrefix.d.ts +3 -0
- package/dist/agents/pipelineTaskPrefix.d.ts.map +1 -0
- package/dist/agents/pipelineTaskPrefix.js +16 -0
- package/dist/agents/pipelineTaskPrefix.js.map +1 -0
- package/dist/agents/reflection.d.ts +9 -1
- package/dist/agents/reflection.d.ts.map +1 -1
- package/dist/agents/reflection.js +27 -1
- package/dist/agents/reflection.js.map +1 -1
- package/dist/agents/reviewer.d.ts +6 -0
- package/dist/agents/reviewer.d.ts.map +1 -1
- package/dist/agents/reviewer.js +4 -1
- package/dist/agents/reviewer.js.map +1 -1
- package/dist/agents/stageErrorClassification.d.ts +16 -0
- package/dist/agents/stageErrorClassification.d.ts.map +1 -0
- package/dist/agents/stageErrorClassification.js +38 -0
- package/dist/agents/stageErrorClassification.js.map +1 -0
- package/dist/agents/stageModelResolver.d.ts +8 -0
- package/dist/agents/stageModelResolver.d.ts.map +1 -0
- package/dist/agents/stageModelResolver.js +22 -0
- package/dist/agents/stageModelResolver.js.map +1 -0
- package/dist/agents/worker.d.ts +33 -0
- package/dist/agents/worker.d.ts.map +1 -1
- package/dist/agents/worker.js +59 -4
- package/dist/agents/worker.js.map +1 -1
- package/dist/agents/workerFanout.d.ts +38 -0
- package/dist/agents/workerFanout.d.ts.map +1 -0
- package/dist/agents/workerFanout.js +292 -0
- package/dist/agents/workerFanout.js.map +1 -0
- package/dist/agents/workerFanoutGate.d.ts +48 -0
- package/dist/agents/workerFanoutGate.d.ts.map +1 -0
- package/dist/agents/workerFanoutGate.js +146 -0
- package/dist/agents/workerFanoutGate.js.map +1 -0
- package/dist/agents/workerValidationEvidence.d.ts +5 -0
- package/dist/agents/workerValidationEvidence.d.ts.map +1 -0
- package/dist/agents/workerValidationEvidence.js +75 -0
- package/dist/agents/workerValidationEvidence.js.map +1 -0
- package/dist/automation/autonomousRunner.d.ts +26 -6
- package/dist/automation/autonomousRunner.d.ts.map +1 -1
- package/dist/automation/autonomousRunner.js +243 -45
- package/dist/automation/autonomousRunner.js.map +1 -1
- package/dist/automation/backlogGrooming.d.ts +52 -0
- package/dist/automation/backlogGrooming.d.ts.map +1 -0
- package/dist/automation/backlogGrooming.js +231 -0
- package/dist/automation/backlogGrooming.js.map +1 -0
- package/dist/automation/runnerExecution.d.ts +1 -1
- package/dist/automation/runnerExecution.d.ts.map +1 -1
- package/dist/automation/runnerExecution.js +31 -9
- package/dist/automation/runnerExecution.js.map +1 -1
- package/dist/automation/runnerState.d.ts +9 -0
- package/dist/automation/runnerState.d.ts.map +1 -1
- package/dist/automation/runnerState.js +17 -0
- package/dist/automation/runnerState.js.map +1 -1
- package/dist/automation/runnerTypes.d.ts +3 -1
- package/dist/automation/runnerTypes.d.ts.map +1 -1
- package/dist/automation/taskSource.d.ts +6 -3
- package/dist/automation/taskSource.d.ts.map +1 -1
- package/dist/automation/taskSource.js +5 -0
- package/dist/automation/taskSource.js.map +1 -1
- package/dist/cli/daemon.d.ts +20 -3
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/daemon.js +42 -2
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/fixBoard.d.ts +14 -0
- package/dist/cli/fixBoard.d.ts.map +1 -0
- package/dist/cli/fixBoard.js +32 -0
- package/dist/cli/fixBoard.js.map +1 -0
- package/dist/cli/fixCommand.d.ts +8 -0
- package/dist/cli/fixCommand.d.ts.map +1 -1
- package/dist/cli/fixCommand.js +47 -8
- package/dist/cli/fixCommand.js.map +1 -1
- package/dist/cli/memoryCommand.d.ts +37 -0
- package/dist/cli/memoryCommand.d.ts.map +1 -0
- package/dist/cli/memoryCommand.js +156 -0
- package/dist/cli/memoryCommand.js.map +1 -0
- package/dist/cli/reviewAudit.d.ts +68 -0
- package/dist/cli/reviewAudit.d.ts.map +1 -1
- package/dist/cli/reviewAudit.js +147 -4
- package/dist/cli/reviewAudit.js.map +1 -1
- package/dist/cli/reviewMaxCommand.d.ts +2 -0
- package/dist/cli/reviewMaxCommand.d.ts.map +1 -1
- package/dist/cli/reviewMaxCommand.js +61 -36
- package/dist/cli/reviewMaxCommand.js.map +1 -1
- package/dist/cli.js +68 -13
- package/dist/cli.js.map +1 -1
- package/dist/core/config.d.ts +413 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +51 -5
- package/dist/core/config.js.map +1 -1
- package/dist/core/eventHub.d.ts +22 -0
- package/dist/core/eventHub.d.ts.map +1 -1
- package/dist/core/eventHub.js +1 -0
- package/dist/core/eventHub.js.map +1 -1
- package/dist/core/providerOverride.d.ts +9 -0
- package/dist/core/providerOverride.d.ts.map +1 -1
- package/dist/core/providerOverride.js +12 -0
- package/dist/core/providerOverride.js.map +1 -1
- package/dist/core/service.d.ts.map +1 -1
- package/dist/core/service.js +8 -2
- package/dist/core/service.js.map +1 -1
- package/dist/core/types.d.ts +61 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/linear/linear.d.ts +2 -1
- package/dist/linear/linear.d.ts.map +1 -1
- package/dist/linear/linear.js +16 -6
- package/dist/linear/linear.js.map +1 -1
- package/dist/locale/prompts/en.d.ts.map +1 -1
- package/dist/locale/prompts/en.js +11 -1
- package/dist/locale/prompts/en.js.map +1 -1
- package/dist/locale/prompts/ko.d.ts.map +1 -1
- package/dist/locale/prompts/ko.js +11 -1
- package/dist/locale/prompts/ko.js.map +1 -1
- package/dist/memory/compaction.d.ts +2 -2
- package/dist/memory/compaction.d.ts.map +1 -1
- package/dist/memory/compaction.js +22 -17
- package/dist/memory/compaction.js.map +1 -1
- package/dist/memory/index.d.ts +3 -3
- package/dist/memory/index.js +3 -3
- package/dist/memory/memoryCore.d.ts +15 -27
- package/dist/memory/memoryCore.d.ts.map +1 -1
- package/dist/memory/memoryCore.js +112 -97
- package/dist/memory/memoryCore.js.map +1 -1
- package/dist/memory/memoryFilters.d.ts +8 -0
- package/dist/memory/memoryFilters.d.ts.map +1 -0
- package/dist/memory/memoryFilters.js +26 -0
- package/dist/memory/memoryFilters.js.map +1 -0
- package/dist/memory/memoryOps.d.ts +7 -23
- package/dist/memory/memoryOps.d.ts.map +1 -1
- package/dist/memory/memoryOps.js +49 -109
- package/dist/memory/memoryOps.js.map +1 -1
- package/dist/memory/repoKnowledge.d.ts.map +1 -1
- package/dist/memory/repoKnowledge.js +48 -3
- package/dist/memory/repoKnowledge.js.map +1 -1
- package/dist/orchestration/conflictDetector.d.ts.map +1 -1
- package/dist/orchestration/conflictDetector.js +26 -7
- package/dist/orchestration/conflictDetector.js.map +1 -1
- package/dist/orchestration/decisionEngine.d.ts +1 -0
- package/dist/orchestration/decisionEngine.d.ts.map +1 -1
- package/dist/orchestration/decisionEngine.js.map +1 -1
- package/dist/orchestration/taskScheduler.d.ts +5 -0
- package/dist/orchestration/taskScheduler.d.ts.map +1 -1
- package/dist/orchestration/taskScheduler.js +36 -12
- package/dist/orchestration/taskScheduler.js.map +1 -1
- package/dist/registry/memoryBridge.js +4 -4
- package/dist/registry/memoryBridge.js.map +1 -1
- package/dist/support/chatMemory.js +1 -1
- package/dist/support/chatMemory.js.map +1 -1
- package/dist/support/dashboardHtml.d.ts +1 -1
- package/dist/support/dashboardHtml.d.ts.map +1 -1
- package/dist/support/dashboardHtml.js +12 -0
- package/dist/support/dashboardHtml.js.map +1 -1
- package/dist/support/gitTracker.d.ts +30 -3
- package/dist/support/gitTracker.d.ts.map +1 -1
- package/dist/support/gitTracker.js +108 -29
- package/dist/support/gitTracker.js.map +1 -1
- package/dist/support/repoMetadata.d.ts +10 -0
- package/dist/support/repoMetadata.d.ts.map +1 -1
- package/dist/support/repoMetadata.js +31 -0
- package/dist/support/repoMetadata.js.map +1 -1
- package/dist/support/updateNotifier.d.ts +12 -0
- package/dist/support/updateNotifier.d.ts.map +1 -1
- package/dist/support/updateNotifier.js +71 -0
- package/dist/support/updateNotifier.js.map +1 -1
- package/dist/support/web.d.ts.map +1 -1
- package/dist/support/web.js +5 -3
- package/dist/support/web.js.map +1 -1
- package/dist/support/worktreeManager.d.ts +33 -0
- package/dist/support/worktreeManager.d.ts.map +1 -1
- package/dist/support/worktreeManager.js +172 -2
- package/dist/support/worktreeManager.js.map +1 -1
- package/dist/tui/App.js +1 -1
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/components/AuditBoard.d.ts +3 -2
- package/dist/tui/components/AuditBoard.d.ts.map +1 -1
- package/dist/tui/components/AuditBoard.js +13 -4
- package/dist/tui/components/AuditBoard.js.map +1 -1
- package/dist/tui/components/DataTable.d.ts +3 -1
- package/dist/tui/components/DataTable.d.ts.map +1 -1
- package/dist/tui/components/DataTable.js +22 -5
- package/dist/tui/components/DataTable.js.map +1 -1
- package/dist/tui/components/StageTimeline.d.ts +1 -1
- package/dist/tui/components/StageTimeline.d.ts.map +1 -1
- package/dist/tui/components/StageTimeline.js +5 -2
- package/dist/tui/components/StageTimeline.js.map +1 -1
- package/dist/tui/components/SubagentTree.d.ts +6 -6
- package/dist/tui/components/SubagentTree.d.ts.map +1 -1
- package/dist/tui/components/SubagentTree.js +33 -5
- package/dist/tui/components/SubagentTree.js.map +1 -1
- package/dist/tui/eventCoalescer.d.ts +29 -0
- package/dist/tui/eventCoalescer.d.ts.map +1 -0
- package/dist/tui/eventCoalescer.js +56 -0
- package/dist/tui/eventCoalescer.js.map +1 -0
- package/dist/tui/hooks/usePipelineEvents.d.ts +1 -1
- package/dist/tui/hooks/usePipelineEvents.d.ts.map +1 -1
- package/dist/tui/hooks/usePipelineEvents.js +18 -4
- package/dist/tui/hooks/usePipelineEvents.js.map +1 -1
- package/dist/tui/monitorRows.d.ts +41 -2
- package/dist/tui/monitorRows.d.ts.map +1 -1
- package/dist/tui/monitorRows.js +86 -7
- package/dist/tui/monitorRows.js.map +1 -1
- package/dist/tui/panels/MonitorPanel.d.ts +2 -1
- package/dist/tui/panels/MonitorPanel.d.ts.map +1 -1
- package/dist/tui/panels/MonitorPanel.js +2 -2
- package/dist/tui/panels/MonitorPanel.js.map +1 -1
- package/dist/tui/panels/PipelinePanel.d.ts.map +1 -1
- package/dist/tui/panels/PipelinePanel.js +6 -1
- package/dist/tui/panels/PipelinePanel.js.map +1 -1
- package/dist/tui/pipelineEvents.d.ts +14 -0
- package/dist/tui/pipelineEvents.d.ts.map +1 -1
- package/dist/tui/pipelineEvents.js +89 -1
- package/dist/tui/pipelineEvents.js.map +1 -1
- package/dist/tui/subagentTree.d.ts +26 -3
- package/dist/tui/subagentTree.d.ts.map +1 -1
- package/dist/tui/subagentTree.js +89 -14
- package/dist/tui/subagentTree.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,149 +1,19 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import type { TaskItem } from '../orchestration/decisionEngine.js';
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import { type CostInfo } from '../support/costTracker.js';
|
|
10
|
-
import { type GuardsRunResult } from './pipelineGuards.js';
|
|
11
|
-
import { type ReflectionState } from './reflection.js';
|
|
12
|
-
export interface PipelineConfig {
|
|
13
|
-
/** List of active stages (executed in order) */
|
|
14
|
-
stages: PipelineStage[];
|
|
15
|
-
/** Whether to continue on test failure */
|
|
16
|
-
continueOnTestFail?: boolean;
|
|
17
|
-
/** Skip Documenter if no changes */
|
|
18
|
-
skipDocumenterIfNoChange?: boolean;
|
|
19
|
-
/** Max total iterations (one cycle = Worker → Reviewer → Tester) */
|
|
20
|
-
maxIterations?: number;
|
|
21
|
-
/**
|
|
22
|
-
* Max objective self-repair attempts (lint/bs/test failures) before the loop
|
|
23
|
-
* gives up on bad edits. Independent of maxIterations so an operator can cap
|
|
24
|
-
* token burn on reflection without shrinking the reviewer-revise budget.
|
|
25
|
-
* Default: DEFAULT_MAX_REFLECTIONS (3).
|
|
26
|
-
*/
|
|
27
|
-
maxReflections?: number;
|
|
28
|
-
/** Per-role configuration */
|
|
29
|
-
roles?: {
|
|
30
|
-
worker?: RoleConfig;
|
|
31
|
-
reviewer?: RoleConfig;
|
|
32
|
-
tester?: RoleConfig;
|
|
33
|
-
documenter?: RoleConfig;
|
|
34
|
-
auditor?: RoleConfig;
|
|
35
|
-
'skill-documenter'?: RoleConfig;
|
|
36
|
-
};
|
|
37
|
-
/** Pipeline guards configuration */
|
|
38
|
-
guards?: Partial<PipelineGuardsConfig>;
|
|
39
|
-
/** Optional job profiles for model selection */
|
|
40
|
-
jobProfiles?: JobProfile[];
|
|
41
|
-
/** Skip tester if no code files (.ts/.js/.py etc.) changed (default: true) */
|
|
42
|
-
skipTesterIfNoCodeChange?: boolean;
|
|
43
|
-
/** Skip auditor if fewer than N files changed (default: 3) */
|
|
44
|
-
skipAuditorUnderFileCount?: number;
|
|
45
|
-
/** Enable verbose logging (detailed stage info, agent decisions, timing) */
|
|
46
|
-
verbose?: boolean;
|
|
47
|
-
/** Draft Analyzer 사전 분석 결과 (Haiku) — Worker/Planner에 주입 */
|
|
48
|
-
draftAnalysis?: {
|
|
49
|
-
taskType: string;
|
|
50
|
-
intentSummary: string;
|
|
51
|
-
relevantFiles: string[];
|
|
52
|
-
suggestedApproach: string;
|
|
53
|
-
projectStats?: string;
|
|
54
|
-
completionCriteria?: string[];
|
|
55
|
-
sufficient?: boolean;
|
|
56
|
-
impactAnalysis?: import('../knowledge/types.js').ImpactAnalysis;
|
|
57
|
-
registrySnapshot?: Array<{
|
|
58
|
-
filePath: string;
|
|
59
|
-
summary: string;
|
|
60
|
-
highlights: string[];
|
|
61
|
-
}>;
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
export interface StageResult {
|
|
65
|
-
stage: PipelineStage;
|
|
66
|
-
success: boolean;
|
|
67
|
-
result: WorkerResult | ReviewResult | TesterResult | DocumenterResult | AuditorResult | SkillDocumenterResult | {
|
|
68
|
-
success: false;
|
|
69
|
-
error: string;
|
|
70
|
-
};
|
|
71
|
-
duration: number;
|
|
72
|
-
/** Stage start time (epoch ms) */
|
|
73
|
-
startedAt: number;
|
|
74
|
-
/** Stage completion time (epoch ms) */
|
|
75
|
-
completedAt: number;
|
|
76
|
-
}
|
|
77
|
-
export interface PipelineResult {
|
|
78
|
-
success: boolean;
|
|
79
|
-
sessionId: string;
|
|
80
|
-
stages: StageResult[];
|
|
81
|
-
finalStatus: 'approved' | 'rejected' | 'failed' | 'cancelled' | 'decomposed' | 'rate_limited' | 'infra_error';
|
|
82
|
-
/** Unix timestamp (ms) when the rate-limit quota resets — set when finalStatus is 'rate_limited'. */
|
|
83
|
-
rateLimitResetsAt?: number;
|
|
84
|
-
totalDuration: number;
|
|
85
|
-
/** Total number of completed iterations */
|
|
86
|
-
iterations: number;
|
|
87
|
-
workerResult?: WorkerResult;
|
|
88
|
-
reviewResult?: ReviewResult;
|
|
89
|
-
testerResult?: TesterResult;
|
|
90
|
-
documenterResult?: DocumenterResult;
|
|
91
|
-
auditorResult?: AuditorResult;
|
|
92
|
-
skillDocumenterResult?: SkillDocumenterResult;
|
|
93
|
-
/** Task context (for reporting) */
|
|
94
|
-
taskContext?: {
|
|
95
|
-
issueIdentifier?: string;
|
|
96
|
-
projectName?: string;
|
|
97
|
-
projectPath?: string;
|
|
98
|
-
taskTitle?: string;
|
|
99
|
-
};
|
|
100
|
-
/** PR URL (auto-created PR in worktree mode) */
|
|
101
|
-
prUrl?: string;
|
|
102
|
-
/** Total cost across all stages */
|
|
103
|
-
totalCost?: CostInfo;
|
|
104
|
-
}
|
|
105
|
-
export interface PipelineContext {
|
|
106
|
-
task: TaskItem;
|
|
107
|
-
projectPath: string;
|
|
108
|
-
session: PairSession;
|
|
109
|
-
config: PipelineConfig;
|
|
110
|
-
/** Current iteration number (1-based) */
|
|
111
|
-
currentIteration: number;
|
|
112
|
-
/** Formatted task prefix for consistent logging (e.g., "OpenSwarm | INT-1171 | worktree/abc123") */
|
|
113
|
-
taskPrefix: string;
|
|
114
|
-
workerResult?: WorkerResult;
|
|
115
|
-
reviewResult?: ReviewResult;
|
|
116
|
-
testerResult?: TesterResult;
|
|
117
|
-
documenterResult?: DocumenterResult;
|
|
118
|
-
auditorResult?: AuditorResult;
|
|
119
|
-
skillDocumenterResult?: SkillDocumenterResult;
|
|
120
|
-
guardsResult?: GuardsRunResult;
|
|
121
|
-
/** Accumulated objective (lint/bs/test) errors for self-repair reflection */
|
|
122
|
-
reflection: ReflectionState;
|
|
123
|
-
/**
|
|
124
|
-
* Source of the latest revise feedback. 'objective' failures (lint/bs/test)
|
|
125
|
-
* flow through the reflection trail and are preserved across fresh-context
|
|
126
|
-
* resets; 'review' feedback (reviewer/halt) is subjective and dropped on a
|
|
127
|
-
* fresh-context retry.
|
|
128
|
-
*/
|
|
129
|
-
feedbackSource?: 'objective' | 'review';
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Build a consistent task prefix for logging across all pipeline stages.
|
|
133
|
-
* Format: "ProjectName | INT-XXX | worktree/abc123" or "ProjectName | INT-XXX"
|
|
134
|
-
*/
|
|
135
|
-
export declare function buildTaskPrefix(task: TaskItem, projectPath: string): string;
|
|
136
|
-
export type PipelineEventType = 'stage:start' | 'stage:complete' | 'stage:fail' | 'iteration:start' | 'iteration:complete' | 'iteration:fail' | 'pipeline:complete' | 'pipeline:fail' | 'halt';
|
|
137
|
-
/** Thrown when the pipeline is cancelled mid-run (project disable / manual stop). */
|
|
138
|
-
export declare class PipelineCancelledError extends Error {
|
|
139
|
-
constructor();
|
|
140
|
-
}
|
|
3
|
+
import type { PipelineGuardsConfig, JobProfile } from '../core/types.js';
|
|
4
|
+
import type { PipelineConfig, PipelineResult, PipelineRunMetadata } from './pairPipelineTypes.js';
|
|
5
|
+
import { PipelineCancelledError } from './stageErrorClassification.js';
|
|
6
|
+
export { PipelineCancelledError };
|
|
7
|
+
export type { PipelineConfig, PipelineContext, PipelineEventType, PipelineResult, PipelineRunMetadata, StageResult, } from './pairPipelineTypes.js';
|
|
8
|
+
export { buildTaskPrefix } from './pipelineTaskPrefix.js';
|
|
141
9
|
export declare class PairPipeline extends EventEmitter {
|
|
142
10
|
private config;
|
|
143
11
|
private stuckDetector;
|
|
144
12
|
private jobProfiles;
|
|
145
13
|
/** Set per run() — aborts the pipeline + in-flight adapter call on cancel/disable. */
|
|
146
14
|
private abortSignal?;
|
|
15
|
+
/** Cache of adapter default models (heavy: OAuth + live catalog) keyed by adapter name. (INT-2393) */
|
|
16
|
+
private defaultModelCache;
|
|
147
17
|
/** Throw if this run has been cancelled. Called at iteration/stage boundaries. */
|
|
148
18
|
private throwIfAborted;
|
|
149
19
|
constructor(config: PipelineConfig);
|
|
@@ -174,6 +44,7 @@ export declare class PairPipeline extends EventEmitter {
|
|
|
174
44
|
* Run a single stage
|
|
175
45
|
*/
|
|
176
46
|
private runStage;
|
|
47
|
+
private stageMetadata;
|
|
177
48
|
/**
|
|
178
49
|
* Determine stage success
|
|
179
50
|
*/
|
|
@@ -210,6 +81,6 @@ export declare function createFullPipeline(config?: Partial<PipelineConfig>): Pa
|
|
|
210
81
|
/**
|
|
211
82
|
* Create pipeline from configuration
|
|
212
83
|
*/
|
|
213
|
-
export declare function createPipelineFromConfig(roles: PipelineConfig['roles'], maxIterations?: number, guards?: Partial<PipelineGuardsConfig>, jobProfiles?: JobProfile[], draftAnalysis?: PipelineConfig['draftAnalysis'], maxReflections?: number): PairPipeline;
|
|
84
|
+
export declare function createPipelineFromConfig(roles: PipelineConfig['roles'], maxIterations?: number, guards?: Partial<PipelineGuardsConfig>, jobProfiles?: JobProfile[], draftAnalysis?: PipelineConfig['draftAnalysis'], maxReflections?: number, runMetadata?: PipelineRunMetadata): PairPipeline;
|
|
214
85
|
export { formatPipelineResult, formatPipelineResultEmbed } from './pipelineFormat.js';
|
|
215
86
|
//# sourceMappingURL=pairPipeline.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pairPipeline.d.ts","sourceRoot":"","sources":["../../src/agents/pairPipeline.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"pairPipeline.d.ts","sourceRoot":"","sources":["../../src/agents/pairPipeline.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAMnE,OAAO,KAAK,EAAiB,oBAAoB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAwBxF,OAAO,KAAK,EACV,cAAc,EAEd,cAAc,EACd,mBAAmB,EAEpB,MAAM,wBAAwB,CAAC;AAUhC,OAAO,EAA2E,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAOhJ,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAClC,YAAY,EACV,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI1D,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,WAAW,CAAe;IAClC,sFAAsF;IACtF,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,sGAAsG;IACtG,OAAO,CAAC,iBAAiB,CAAkD;IAE3E,kFAAkF;IAClF,OAAO,CAAC,cAAc;gBAIV,MAAM,EAAE,cAAc;IAiBlC,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,eAAe;IAMvB,gFAAgF;IAChF,OAAO,CAAC,gBAAgB;IAQxB;;;;;OAKG;IACG,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IA8IxG;;;OAGG;YACW,oBAAoB;IAuGlC;;OAEG;IACH,OAAO,CAAC,QAAQ;IAIhB;;OAEG;YACW,QAAQ;IAkVtB,OAAO,CAAC,aAAa;IAarB;;OAEG;IACH,OAAO,CAAC,cAAc;IA4BtB;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IA4B7B;;;;;;OAMG;YACW,oBAAoB;IAwZlC;;OAEG;IACH,OAAO,CAAC,WAAW;CAyDpB;AAID;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,SAAI,GAAG,YAAY,CAKrE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAC/B,YAAY,CAQd;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,EAC9B,aAAa,SAAI,EACjB,MAAM,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,EACtC,WAAW,CAAC,EAAE,UAAU,EAAE,EAC1B,aAAa,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,EAC/C,cAAc,CAAC,EAAE,MAAM,EACvB,WAAW,CAAC,EAAE,mBAAmB,GAChC,YAAY,CAgCd;AAgHD,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -8,11 +8,13 @@ import { broadcastEvent } from '../core/eventHub.js';
|
|
|
8
8
|
import { CONFIDENCE_THRESHOLDS } from './agentPair.js';
|
|
9
9
|
import * as agentPair from './agentPair.js';
|
|
10
10
|
import { runGuards } from './pipelineGuards.js';
|
|
11
|
-
import { createReflectionState, recordReflection, shouldStopReflecting, buildReflectionFeedback, DEFAULT_MAX_REFLECTIONS, } from './reflection.js';
|
|
11
|
+
import { createReflectionState, recordReflection, shouldStopReflecting, buildReflectionFeedback, similarReviewFeedback, DEFAULT_MAX_REFLECTIONS, } from './reflection.js';
|
|
12
12
|
import { hasRepoSnapshot, scanAndCache, analyzeIssue } from '../knowledge/index.js';
|
|
13
13
|
import { getRegistryStore } from '../registry/sqliteStore.js';
|
|
14
14
|
import { recallRepoKnowledge } from '../memory/repoKnowledge.js';
|
|
15
15
|
import * as workerAgent from './worker.js';
|
|
16
|
+
import { buildTaskPrefix } from './pipelineTaskPrefix.js';
|
|
17
|
+
import { emitWorkerFanoutGateDecision, evaluateWorkerFanoutGate, runWorkerWithOptionalFanout } from './workerFanoutGate.js';
|
|
16
18
|
import * as reviewerAgent from './reviewer.js';
|
|
17
19
|
import * as testerAgent from './tester.js';
|
|
18
20
|
import * as documenterAgent from './documenter.js';
|
|
@@ -21,41 +23,20 @@ import * as skillDocumenterAgent from './skillDocumenter.js';
|
|
|
21
23
|
import { createStuckDetector } from '../support/stuckDetector.js';
|
|
22
24
|
import { RateLimitError } from '../adapters/rateLimitError.js';
|
|
23
25
|
import { isInfraError } from '../adapters/errorClassification.js';
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
export
|
|
29
|
-
const parts = [];
|
|
30
|
-
const projectName = task.linearProject?.name || projectPath.split('/').pop() || 'unknown';
|
|
31
|
-
parts.push(projectName);
|
|
32
|
-
if (task.issueIdentifier) {
|
|
33
|
-
parts.push(task.issueIdentifier);
|
|
34
|
-
}
|
|
35
|
-
else if (task.issueId) {
|
|
36
|
-
parts.push(task.issueId.slice(0, 8));
|
|
37
|
-
}
|
|
38
|
-
// Detect worktree path
|
|
39
|
-
const worktreeMatch = projectPath.match(/worktree\/([a-f0-9-]+)/);
|
|
40
|
-
if (worktreeMatch) {
|
|
41
|
-
parts.push(`worktree/${worktreeMatch[1].slice(0, 8)}`);
|
|
42
|
-
}
|
|
43
|
-
return parts.join(' | ');
|
|
44
|
-
}
|
|
26
|
+
import { resolveAdapterDefaultModel } from './stageModelResolver.js';
|
|
27
|
+
import { isClassifiedStageError, rethrowClassified, extractClassifiedStageResult, PipelineCancelledError } from './stageErrorClassification.js';
|
|
28
|
+
import { isTesterCodeFile, missingWorkerValidationIssues, testerWouldRunForWorkerResult, } from './workerValidationEvidence.js';
|
|
29
|
+
export { PipelineCancelledError };
|
|
30
|
+
export { buildTaskPrefix } from './pipelineTaskPrefix.js';
|
|
45
31
|
// Pair Pipeline
|
|
46
|
-
/** Thrown when the pipeline is cancelled mid-run (project disable / manual stop). */
|
|
47
|
-
export class PipelineCancelledError extends Error {
|
|
48
|
-
constructor() {
|
|
49
|
-
super('Pipeline cancelled');
|
|
50
|
-
this.name = 'PipelineCancelledError';
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
32
|
export class PairPipeline extends EventEmitter {
|
|
54
33
|
config;
|
|
55
34
|
stuckDetector;
|
|
56
35
|
jobProfiles;
|
|
57
36
|
/** Set per run() — aborts the pipeline + in-flight adapter call on cancel/disable. */
|
|
58
37
|
abortSignal;
|
|
38
|
+
/** Cache of adapter default models (heavy: OAuth + live catalog) keyed by adapter name. (INT-2393) */
|
|
39
|
+
defaultModelCache = new Map();
|
|
59
40
|
/** Throw if this run has been cancelled. Called at iteration/stage boundaries. */
|
|
60
41
|
throwIfAborted() {
|
|
61
42
|
if (this.abortSignal?.aborted)
|
|
@@ -201,6 +182,9 @@ export class PairPipeline extends EventEmitter {
|
|
|
201
182
|
// spawn, timeout) is not a task failure — surface it distinctly so the
|
|
202
183
|
// runner does a backoff retry instead of counting it toward STUCK. (INT-2010)
|
|
203
184
|
const infra = !cancelled && !rateLimited && isInfraError(error);
|
|
185
|
+
const classifiedStage = extractClassifiedStageResult(error); // INT-2424
|
|
186
|
+
if (classifiedStage)
|
|
187
|
+
stages.push(classifiedStage);
|
|
204
188
|
if (cancelled) {
|
|
205
189
|
console.log(`[${context.taskPrefix}] Pipeline cancelled`);
|
|
206
190
|
}
|
|
@@ -346,11 +330,16 @@ export class PairPipeline extends EventEmitter {
|
|
|
346
330
|
*/
|
|
347
331
|
async runStage(stage, context, overrides) {
|
|
348
332
|
const startTime = Date.now();
|
|
349
|
-
|
|
333
|
+
// Display model: explicit override → configured (jobProfile/role) → adapter
|
|
334
|
+
// default (so the TUI/dashboard aren't blank when config omits it). (INT-2393)
|
|
335
|
+
const stageModel = overrides?.model
|
|
336
|
+
?? this.getModelForRole(stage, context.task)
|
|
337
|
+
?? await resolveAdapterDefaultModel(this.config.roles?.[stage]?.adapter, this.defaultModelCache);
|
|
350
338
|
const prefix = context.taskPrefix;
|
|
339
|
+
const metadata = this.stageMetadata(context);
|
|
351
340
|
console.log(`[${prefix}] Stage starting: ${stage}`);
|
|
352
341
|
this.emit('stage:start', { stage, context, model: stageModel });
|
|
353
|
-
broadcastEvent({ type: 'pipeline:stage', data: { taskId: context.task.id, stage, status: 'start', model: stageModel } });
|
|
342
|
+
broadcastEvent({ type: 'pipeline:stage', data: { taskId: context.task.id, stage, status: 'start', model: stageModel, ...metadata } });
|
|
354
343
|
if (this.config.verbose) {
|
|
355
344
|
this.emit('log', { line: `[verbose] Stage: ${stage} | model: ${stageModel ?? 'default'} | iteration: ${context.currentIteration}` });
|
|
356
345
|
}
|
|
@@ -389,8 +378,18 @@ export class PairPipeline extends EventEmitter {
|
|
|
389
378
|
const reviewPart = includeReview
|
|
390
379
|
? reviewerAgent.buildRevisionPrompt(context.reviewResult)
|
|
391
380
|
: undefined;
|
|
392
|
-
|
|
393
|
-
|
|
381
|
+
// Cross-SESSION feedback: a re-picked task that failed/was rejected
|
|
382
|
+
// before carries the last reviewer feedback (persisted in task state).
|
|
383
|
+
// Without this the new session starts blind and repeats the exact
|
|
384
|
+
// mistake the reviewer already called out (INT-2474). First iteration
|
|
385
|
+
// only — later iterations have fresher in-session feedback above.
|
|
386
|
+
const priorSessionPart = context.currentIteration === 1 && context.task.priorAttemptFeedback
|
|
387
|
+
? '## Previous attempt failed (feedback from an earlier session)\n'
|
|
388
|
+
+ 'A prior run of this task did not pass. Address these points first and do not repeat them:\n'
|
|
389
|
+
+ context.task.priorAttemptFeedback
|
|
390
|
+
: undefined;
|
|
391
|
+
const combinedFeedback = [priorSessionPart, reflectionPart, reviewPart].filter(Boolean).join('\n\n') || undefined;
|
|
392
|
+
const workerOptions = {
|
|
394
393
|
taskTitle: context.task.title,
|
|
395
394
|
taskDescription: context.task.description || '',
|
|
396
395
|
projectPath: context.projectPath,
|
|
@@ -404,6 +403,7 @@ export class PairPipeline extends EventEmitter {
|
|
|
404
403
|
maxTurns: this.config.roles?.worker?.maxTurns,
|
|
405
404
|
adapterName: this.config.roles?.worker?.adapter,
|
|
406
405
|
reasoningEffort: this.getEffortForTask(context.task),
|
|
406
|
+
bashTimeoutMs: await workerAgent.resolveWorkerBashTimeout(context.projectPath, this.getEffortForTask(context.task)), // INT-2415
|
|
407
407
|
// No-edit guard (re-applied from stranded feat/v0.7.0 commit 2eea3bc):
|
|
408
408
|
// reasoning workers frequently end with analysis only and never call
|
|
409
409
|
// edit_file. Without this the guard defaults to 0 (disabled) — measured:
|
|
@@ -416,6 +416,15 @@ export class PairPipeline extends EventEmitter {
|
|
|
416
416
|
processContext: { taskId: context.task.id, stage: 'worker' },
|
|
417
417
|
workerContext,
|
|
418
418
|
signal: this.abortSignal,
|
|
419
|
+
};
|
|
420
|
+
result = await runWorkerWithOptionalFanout({
|
|
421
|
+
projectPath: context.projectPath,
|
|
422
|
+
workerOptions,
|
|
423
|
+
fanoutDecision: context.workerFanoutDecision,
|
|
424
|
+
fanoutConfig: this.config.roles?.worker?.fanout,
|
|
425
|
+
guards: this.config.guards,
|
|
426
|
+
onLog,
|
|
427
|
+
runWorker: workerAgent.runWorker,
|
|
419
428
|
});
|
|
420
429
|
agentPair.saveWorkerResult(context.session.id, result);
|
|
421
430
|
context.workerResult = result;
|
|
@@ -471,6 +480,11 @@ export class PairPipeline extends EventEmitter {
|
|
|
471
480
|
adapterName: this.config.roles?.reviewer?.adapter,
|
|
472
481
|
reasoningEffort: this.getEffortForTask(context.task),
|
|
473
482
|
completionCriteria: this.config.draftAnalysis?.completionCriteria,
|
|
483
|
+
// Surface non-blocking guard warnings (dead-module, reformat/scope)
|
|
484
|
+
// so the reviewer verifies them instead of them dying in a log. (INT-2388)
|
|
485
|
+
guardWarnings: context.guardsResult?.results
|
|
486
|
+
.filter(r => !r.passed && !r.blocking)
|
|
487
|
+
.flatMap(r => r.issues),
|
|
474
488
|
processContext: { taskId: context.task.id, stage: 'reviewer' },
|
|
475
489
|
signal: this.abortSignal,
|
|
476
490
|
};
|
|
@@ -579,7 +593,8 @@ export class PairPipeline extends EventEmitter {
|
|
|
579
593
|
}
|
|
580
594
|
broadcastEvent({ type: 'pipeline:stage', data: {
|
|
581
595
|
taskId: context.task.id, stage, status: 'complete',
|
|
582
|
-
|
|
596
|
+
...metadata,
|
|
597
|
+
model: costInfo?.model ?? stageModel,
|
|
583
598
|
inputTokens: costInfo?.inputTokens,
|
|
584
599
|
outputTokens: costInfo?.outputTokens,
|
|
585
600
|
costUsd: costInfo?.costUsd,
|
|
@@ -605,12 +620,29 @@ export class PairPipeline extends EventEmitter {
|
|
|
605
620
|
this.emit('stage:fail', { stage, result: stageResult, context, error });
|
|
606
621
|
broadcastEvent({ type: 'pipeline:stage', data: {
|
|
607
622
|
taskId: context.task.id, stage, status: 'fail',
|
|
623
|
+
...metadata,
|
|
624
|
+
model: stageModel,
|
|
608
625
|
durationMs: stageResult.duration,
|
|
626
|
+
rateLimitResetsAt: error instanceof RateLimitError && error.resetsAt ? error.resetsAt * 1000 : undefined,
|
|
609
627
|
error: error instanceof Error ? error.message : String(error),
|
|
610
628
|
} });
|
|
629
|
+
if (isClassifiedStageError(error))
|
|
630
|
+
rethrowClassified(error, stageResult); // INT-2424
|
|
611
631
|
return stageResult;
|
|
612
632
|
}
|
|
613
633
|
}
|
|
634
|
+
stageMetadata(context) {
|
|
635
|
+
const configured = this.config.runMetadata ?? {};
|
|
636
|
+
const projectPath = configured.projectPath ?? context.projectPath;
|
|
637
|
+
return {
|
|
638
|
+
repository: configured.repository ?? context.task.linearProject?.name ?? repoNameFromPath(projectPath),
|
|
639
|
+
projectPath,
|
|
640
|
+
worktree: configured.worktree ?? worktreeNameFromPath(projectPath),
|
|
641
|
+
branch: configured.branch,
|
|
642
|
+
issueIdentifier: configured.issueIdentifier ?? context.task.issueIdentifier ?? context.task.issueId,
|
|
643
|
+
title: configured.title ?? context.task.title,
|
|
644
|
+
};
|
|
645
|
+
}
|
|
614
646
|
/**
|
|
615
647
|
* Determine stage success
|
|
616
648
|
*/
|
|
@@ -719,6 +751,21 @@ export class PairPipeline extends EventEmitter {
|
|
|
719
751
|
toModel: escalateModel,
|
|
720
752
|
} });
|
|
721
753
|
}
|
|
754
|
+
const fanoutDecision = evaluateWorkerFanoutGate({
|
|
755
|
+
task: context.task,
|
|
756
|
+
draftAnalysis: this.config.draftAnalysis,
|
|
757
|
+
iteration: context.currentIteration,
|
|
758
|
+
feedbackSource: context.feedbackSource,
|
|
759
|
+
effort: this.getEffortForTask(context.task),
|
|
760
|
+
config: this.config.roles?.worker?.fanout,
|
|
761
|
+
});
|
|
762
|
+
context.workerFanoutDecision = fanoutDecision;
|
|
763
|
+
emitWorkerFanoutGateDecision({
|
|
764
|
+
context,
|
|
765
|
+
decision: fanoutDecision,
|
|
766
|
+
verbose: this.config.verbose,
|
|
767
|
+
emit: (event, payload) => this.emit(event, payload),
|
|
768
|
+
});
|
|
722
769
|
agentPair.updateSessionStatus(context.session.id, 'working');
|
|
723
770
|
const workerResult = await this.runStage('worker', context, workerOverrides);
|
|
724
771
|
stages.push(workerResult);
|
|
@@ -786,6 +833,52 @@ export class PairPipeline extends EventEmitter {
|
|
|
786
833
|
});
|
|
787
834
|
}
|
|
788
835
|
}
|
|
836
|
+
// A code-changing worker that reports no commands is usually a low-accuracy
|
|
837
|
+
// partial implementation: the reviewer then spends a full pass rediscovering
|
|
838
|
+
// that nothing was built, tested, or smoke-checked. When there is no tester
|
|
839
|
+
// stage to provide objective evidence, bounce it back immediately with a
|
|
840
|
+
// ground-truth validation reflection.
|
|
841
|
+
if (hasReviewer && context.workerResult && !testerWouldRunForWorkerResult(context.workerResult, hasTester, this.config.skipTesterIfNoCodeChange ?? true)) {
|
|
842
|
+
const validationIssues = missingWorkerValidationIssues(context.workerResult);
|
|
843
|
+
if (validationIssues.length > 0) {
|
|
844
|
+
const { progressed } = recordReflection(context.reflection, {
|
|
845
|
+
iteration: context.currentIteration,
|
|
846
|
+
source: 'validation',
|
|
847
|
+
errors: validationIssues,
|
|
848
|
+
});
|
|
849
|
+
// Missing validation evidence is a nudge, not a verdict: the worker may
|
|
850
|
+
// simply be unable to self-report its commands (e.g. git-detected
|
|
851
|
+
// changes with no JSON block — worker.ts promotes those to success with
|
|
852
|
+
// commands=[]). Bounce it back to re-run with validation while that can
|
|
853
|
+
// still make progress; once it stagnates or the reflection budget is
|
|
854
|
+
// spent, DEFER to the reviewer (pre-gate behavior) rather than
|
|
855
|
+
// hard-failing the whole task. This is a pure predicate — do NOT reuse
|
|
856
|
+
// shouldAbortSelfRepair here: it marks the session 'failed' as a side
|
|
857
|
+
// effect (see ~L795), which would sink an otherwise-approvable task.
|
|
858
|
+
const reflectionBudget = this.config.maxReflections ?? DEFAULT_MAX_REFLECTIONS;
|
|
859
|
+
const canRetryForValidation = progressed && !shouldStopReflecting(context.reflection, reflectionBudget);
|
|
860
|
+
if (canRetryForValidation) {
|
|
861
|
+
console.log(`[${context.taskPrefix}] Missing worker validation evidence: ${validationIssues.join('; ')}`);
|
|
862
|
+
context.reviewResult = {
|
|
863
|
+
decision: 'revise',
|
|
864
|
+
feedback: `Worker validation evidence missing: ${validationIssues.join('; ')}`,
|
|
865
|
+
issues: validationIssues,
|
|
866
|
+
suggestions: ['Run a relevant validation command before asking for review'],
|
|
867
|
+
};
|
|
868
|
+
context.feedbackSource = 'objective';
|
|
869
|
+
agentPair.trackFailure(context.session.id);
|
|
870
|
+
this.emit('iteration:fail', {
|
|
871
|
+
iteration: context.currentIteration,
|
|
872
|
+
stage: 'worker',
|
|
873
|
+
context,
|
|
874
|
+
});
|
|
875
|
+
agentPair.updateSessionStatus(context.session.id, 'revising');
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
878
|
+
console.log(`[${context.taskPrefix}] Validation evidence still missing after retries — deferring to reviewer`);
|
|
879
|
+
this.emit('log', { line: '⚠️ Validation evidence missing; deferring to reviewer' });
|
|
880
|
+
}
|
|
881
|
+
}
|
|
789
882
|
// ========== HALT CHECK (confidence too low) ==========
|
|
790
883
|
if (context.workerResult) {
|
|
791
884
|
const confidence = agentPair.calculateConfidence(context.workerResult);
|
|
@@ -826,9 +919,8 @@ export class PairPipeline extends EventEmitter {
|
|
|
826
919
|
if (hasTester) {
|
|
827
920
|
// Skip tester if no code files changed (configurable, default true)
|
|
828
921
|
const skipIfNoCode = this.config.skipTesterIfNoCodeChange ?? true;
|
|
829
|
-
const codeExtensions = /\.(ts|tsx|js|jsx|py|rs|go|java|rb|c|cpp|h|hpp)$/;
|
|
830
922
|
const changedFiles = context.workerResult?.filesChanged || [];
|
|
831
|
-
const hasCodeChange = changedFiles.some(
|
|
923
|
+
const hasCodeChange = changedFiles.some(isTesterCodeFile);
|
|
832
924
|
if (skipIfNoCode && !hasCodeChange) {
|
|
833
925
|
console.log(`[${context.taskPrefix}] Skipping tester: no code files changed (${changedFiles.length} files: ${changedFiles.join(', ') || 'none'})`);
|
|
834
926
|
}
|
|
@@ -906,6 +998,28 @@ export class PairPipeline extends EventEmitter {
|
|
|
906
998
|
return { success: false };
|
|
907
999
|
}
|
|
908
1000
|
if (decision === 'revise') {
|
|
1001
|
+
const reviseFeedback = reviewerResult.result.feedback ?? '';
|
|
1002
|
+
// The reflection stagnation detector only counts OBJECTIVE sources, so
|
|
1003
|
+
// a reviewer that keeps saying the same thing never trips it — failing
|
|
1004
|
+
// sessions used to burn every remaining iteration on feedback the
|
|
1005
|
+
// worker demonstrably isn't absorbing (measured: 146 max-iteration
|
|
1006
|
+
// exhaustions vs 21 objective aborts). Two consecutive near-identical
|
|
1007
|
+
// revise feedbacks → end the session now; the runner persists this
|
|
1008
|
+
// feedback and the NEXT attempt starts with it injected (INT-2474).
|
|
1009
|
+
if (context.lastReviseFeedback
|
|
1010
|
+
&& similarReviewFeedback(context.lastReviseFeedback, reviseFeedback)) {
|
|
1011
|
+
const reason = 'reviewer repeated the same revise feedback — worker is not absorbing it';
|
|
1012
|
+
console.log(`[${context.taskPrefix}] Aborting session early: ${reason}`);
|
|
1013
|
+
this.emit('log', { line: `🛑 ${reason}` });
|
|
1014
|
+
this.emit('iteration:fail', {
|
|
1015
|
+
iteration: context.currentIteration,
|
|
1016
|
+
stage: 'reviewer',
|
|
1017
|
+
context,
|
|
1018
|
+
});
|
|
1019
|
+
agentPair.updateSessionStatus(context.session.id, 'failed');
|
|
1020
|
+
return { success: false };
|
|
1021
|
+
}
|
|
1022
|
+
context.lastReviseFeedback = reviseFeedback;
|
|
909
1023
|
// revise = next iteration. Reviewer feedback is subjective → it travels
|
|
910
1024
|
// through the reviewer channel and is dropped on a fresh-context reset.
|
|
911
1025
|
console.log(`[${context.taskPrefix}] Reviewer requested revision`);
|
|
@@ -1022,7 +1136,7 @@ export function createFullPipeline(config) {
|
|
|
1022
1136
|
/**
|
|
1023
1137
|
* Create pipeline from configuration
|
|
1024
1138
|
*/
|
|
1025
|
-
export function createPipelineFromConfig(roles, maxIterations = 3, guards, jobProfiles, draftAnalysis, maxReflections) {
|
|
1139
|
+
export function createPipelineFromConfig(roles, maxIterations = 3, guards, jobProfiles, draftAnalysis, maxReflections, runMetadata) {
|
|
1026
1140
|
const stages = [];
|
|
1027
1141
|
if (roles?.worker?.enabled !== false) {
|
|
1028
1142
|
stages.push('worker');
|
|
@@ -1050,8 +1164,18 @@ export function createPipelineFromConfig(roles, maxIterations = 3, guards, jobPr
|
|
|
1050
1164
|
guards,
|
|
1051
1165
|
jobProfiles,
|
|
1052
1166
|
draftAnalysis,
|
|
1167
|
+
runMetadata,
|
|
1053
1168
|
});
|
|
1054
1169
|
}
|
|
1170
|
+
function repoNameFromPath(projectPath) {
|
|
1171
|
+
if (!projectPath)
|
|
1172
|
+
return undefined;
|
|
1173
|
+
const normalized = projectPath.replace(/\/+$/, '').replace(/\/worktree\/[^/]+$/, '');
|
|
1174
|
+
return normalized.split('/').pop();
|
|
1175
|
+
}
|
|
1176
|
+
function worktreeNameFromPath(projectPath) {
|
|
1177
|
+
return projectPath?.match(/\/worktree\/([^/]+)\/?$/)?.[1];
|
|
1178
|
+
}
|
|
1055
1179
|
// Helpers
|
|
1056
1180
|
/**
|
|
1057
1181
|
* Extract a worker-readable summary of what the agent did during a stage so
|