karajan-code 2.0.0 → 2.0.1
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/package.json
CHANGED
package/src/commands/board.js
CHANGED
|
@@ -34,14 +34,21 @@ export async function startBoard(port = 4000) {
|
|
|
34
34
|
const karajanHome = getKarajanHome();
|
|
35
35
|
fs.mkdirSync(karajanHome, { recursive: true });
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
// Use process.execPath (absolute path to current node binary) instead of "node".
|
|
38
|
+
// Fixes ENOENT on nvm setups where `node` is not in the spawned process's PATH.
|
|
39
|
+
const child = spawn(process.execPath, [serverPath], {
|
|
38
40
|
env: { ...process.env, PORT: String(port) },
|
|
39
41
|
detached: true,
|
|
40
42
|
stdio: "ignore",
|
|
41
43
|
cwd: BOARD_DIR
|
|
42
44
|
});
|
|
45
|
+
// Swallow spawn errors so an HU Board failure never crashes the pipeline.
|
|
46
|
+
child.on("error", () => { /* non-blocking — caller logs via tryAutoStartBoard catch */ });
|
|
43
47
|
child.unref();
|
|
44
48
|
|
|
49
|
+
if (!child.pid) {
|
|
50
|
+
throw new Error("Failed to spawn HU Board server");
|
|
51
|
+
}
|
|
45
52
|
fs.writeFileSync(PID_FILE, String(child.pid));
|
|
46
53
|
return { ok: true, alreadyRunning: false, pid: child.pid, url: `http://localhost:${port}` };
|
|
47
54
|
}
|
package/src/config.js
CHANGED
|
@@ -34,8 +34,15 @@ const DEFAULTS = {
|
|
|
34
34
|
discover: { enabled: false },
|
|
35
35
|
architect: { enabled: false },
|
|
36
36
|
hu_reviewer: { enabled: false },
|
|
37
|
+
brain: { enabled: true },
|
|
37
38
|
auto_simplify: true
|
|
38
39
|
},
|
|
40
|
+
brain: {
|
|
41
|
+
enabled: true,
|
|
42
|
+
provider: "claude",
|
|
43
|
+
bypass_solomon_on_correctness: true,
|
|
44
|
+
max_consecutive_verification_failures: 2
|
|
45
|
+
},
|
|
39
46
|
review_mode: "standard",
|
|
40
47
|
max_iterations: 5,
|
|
41
48
|
max_budget_usd: null,
|
|
@@ -46,6 +46,9 @@ export class PipelineContext {
|
|
|
46
46
|
// Planned task (may differ from original task after planner)
|
|
47
47
|
this.plannedTask = null;
|
|
48
48
|
|
|
49
|
+
// Karajan Brain runtime context (feedback queue, verification tracker, compression stats)
|
|
50
|
+
this.brainCtx = null;
|
|
51
|
+
|
|
49
52
|
// Timing
|
|
50
53
|
this.startedAt = null;
|
|
51
54
|
}
|
|
@@ -16,7 +16,7 @@ import { invokeSolomon } from "../solomon-escalation.js";
|
|
|
16
16
|
import { detectRateLimit } from "../../utils/rate-limit-detector.js";
|
|
17
17
|
import { createStallDetector } from "../../utils/stall-detector.js";
|
|
18
18
|
|
|
19
|
-
export async function runCoderStage({ coderRoleInstance, coderRole, config, logger, emitter, eventBase, session, plannedTask, trackBudget, iteration }) {
|
|
19
|
+
export async function runCoderStage({ coderRoleInstance, coderRole, config, logger, emitter, eventBase, session, plannedTask, trackBudget, iteration, brainCtx }) {
|
|
20
20
|
logger.setContext({ iteration, stage: "coder" });
|
|
21
21
|
emitProgress(
|
|
22
22
|
emitter,
|
|
@@ -26,6 +26,17 @@ export async function runCoderStage({ coderRoleInstance, coderRole, config, logg
|
|
|
26
26
|
})
|
|
27
27
|
);
|
|
28
28
|
|
|
29
|
+
// Brain: if enabled and queue has entries, use enriched feedback instead of flat string
|
|
30
|
+
let reviewerFeedback = session.last_reviewer_feedback;
|
|
31
|
+
if (brainCtx?.enabled) {
|
|
32
|
+
const { buildCoderFeedbackPrompt } = await import("../brain-coordinator.js");
|
|
33
|
+
const enriched = buildCoderFeedbackPrompt(brainCtx);
|
|
34
|
+
if (enriched) {
|
|
35
|
+
reviewerFeedback = enriched;
|
|
36
|
+
logger.info(`Brain: using enriched feedback (${brainCtx.feedbackQueue.entries.length} entries)`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
const coderOnOutput = ({ stream, line }) => {
|
|
30
41
|
emitProgress(emitter, makeEvent("agent:output", { ...eventBase, stage: "coder" }, {
|
|
31
42
|
message: line,
|
|
@@ -40,7 +51,7 @@ export async function runCoderStage({ coderRoleInstance, coderRole, config, logg
|
|
|
40
51
|
try {
|
|
41
52
|
coderExecResult = await coderRoleInstance.execute({
|
|
42
53
|
task: plannedTask,
|
|
43
|
-
reviewerFeedback
|
|
54
|
+
reviewerFeedback,
|
|
44
55
|
sonarSummary: session.last_sonar_summary,
|
|
45
56
|
deferredContext: buildDeferredContext(session.deferred_issues),
|
|
46
57
|
onOutput: coderStall.onOutput
|
|
@@ -123,14 +134,48 @@ export async function runCoderStage({ coderRoleInstance, coderRole, config, logg
|
|
|
123
134
|
throw new Error(`Coder failed: ${details}`);
|
|
124
135
|
}
|
|
125
136
|
|
|
126
|
-
|
|
137
|
+
// Measure files changed so stale detection (solomon-rules) has accurate data
|
|
138
|
+
let filesChanged = 0;
|
|
139
|
+
try {
|
|
140
|
+
const { verifyCoderOutput } = await import("../verification-gate.js");
|
|
141
|
+
const verif = verifyCoderOutput({
|
|
142
|
+
baseRef: session.session_start_sha,
|
|
143
|
+
projectDir: config.projectDir || process.cwd()
|
|
144
|
+
});
|
|
145
|
+
filesChanged = verif.filesChanged || 0;
|
|
146
|
+
} catch { /* ignore verification errors */ }
|
|
147
|
+
|
|
148
|
+
await addCheckpoint(session, { stage: "coder", iteration, note: "Coder applied changes", provider: coderRole.provider, model: coderRole.model || null, filesChanged });
|
|
127
149
|
emitProgress(
|
|
128
150
|
emitter,
|
|
129
151
|
makeEvent("coder:end", { ...eventBase, stage: "coder" }, {
|
|
130
152
|
message: "Coder completed",
|
|
131
|
-
detail: { provider: coderRole.provider, executorType: "agent" }
|
|
153
|
+
detail: { provider: coderRole.provider, executorType: "agent", filesChanged }
|
|
132
154
|
})
|
|
133
155
|
);
|
|
156
|
+
|
|
157
|
+
// Brain: verify coder produced real changes + clear feedback queue (now addressed)
|
|
158
|
+
if (brainCtx?.enabled) {
|
|
159
|
+
const { verifyCoderRan, clearFeedback } = await import("../brain-coordinator.js");
|
|
160
|
+
const result = verifyCoderRan(brainCtx, {
|
|
161
|
+
baseRef: session.session_start_sha,
|
|
162
|
+
projectDir: config.projectDir || process.cwd()
|
|
163
|
+
});
|
|
164
|
+
const maxFailures = config.brain?.max_consecutive_verification_failures ?? 2;
|
|
165
|
+
if (!result.passed) {
|
|
166
|
+
logger.warn(`Brain verification: coder made 0 changes (consecutive failures: ${brainCtx.verificationTracker.consecutiveFailures}/${maxFailures})`);
|
|
167
|
+
emitProgress(emitter, makeEvent("brain:verification", { ...eventBase, stage: "coder" }, {
|
|
168
|
+
message: `Brain: coder produced no changes (${brainCtx.verificationTracker.consecutiveFailures}/${maxFailures} consecutive failures)`,
|
|
169
|
+
detail: { filesChanged: result.filesChanged, consecutiveFailures: brainCtx.verificationTracker.consecutiveFailures }
|
|
170
|
+
}));
|
|
171
|
+
if (brainCtx.verificationTracker.consecutiveFailures >= maxFailures) {
|
|
172
|
+
await markSessionStatus(session, "stalled");
|
|
173
|
+
throw new Error(`Brain: ${maxFailures} consecutive coder iterations with 0 file changes — pipeline stalled`);
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
clearFeedback(brainCtx);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
134
179
|
}
|
|
135
180
|
|
|
136
181
|
export async function runRefactorerStage({ refactorerRole, config, logger, emitter, eventBase, session, plannedTask, trackBudget, iteration }) {
|
|
@@ -117,12 +117,38 @@ async function handleReviewerStalledSolomon({ review, repeatCounts, repeatState,
|
|
|
117
117
|
return { review, stalled: true, stalledResult: { approved: false, sessionId: session.id, reason: "stalled" } };
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
async function handleReviewerRejection({ review, repeatDetector, config, logger, emitter, eventBase, session, iteration, task, askQuestion, budgetSummary }) {
|
|
120
|
+
async function handleReviewerRejection({ review, repeatDetector, config, logger, emitter, eventBase, session, iteration, task, askQuestion, budgetSummary, brainCtx }) {
|
|
121
121
|
repeatDetector.addIteration([], review.blocking_issues);
|
|
122
122
|
const repeatState = repeatDetector.isStalled();
|
|
123
123
|
|
|
124
124
|
const solomonEnabled = Boolean(config.pipeline?.solomon?.enabled);
|
|
125
125
|
|
|
126
|
+
// Brain: if enabled and bypass_solomon_on_correctness, push issues to queue and skip Solomon
|
|
127
|
+
// for non-style rejections. Solomon is still consulted on genuine dilemmas (style-only, deadlock).
|
|
128
|
+
if (brainCtx?.enabled && config.brain?.bypass_solomon_on_correctness !== false) {
|
|
129
|
+
const cats = categorizeIssues(review.blocking_issues);
|
|
130
|
+
const nonStyleIssues = cats.security + cats.correctness + cats.tests;
|
|
131
|
+
const styleIssues = cats.style;
|
|
132
|
+
// Only bypass if there ARE non-style issues (correctness, tests, security, or "other" is correctness)
|
|
133
|
+
// If it's style-only, let Solomon evaluate whether to override
|
|
134
|
+
if (nonStyleIssues > 0 || cats.other > 0) {
|
|
135
|
+
const { processRoleOutput } = await import("../brain-coordinator.js");
|
|
136
|
+
processRoleOutput(brainCtx, { roleName: "reviewer", output: review, iteration });
|
|
137
|
+
logger.info(`Brain: reviewer rejected with ${nonStyleIssues} non-style issue(s) — bypassing Solomon, returning to coder`);
|
|
138
|
+
emitProgress(emitter, makeEvent("brain:bypass-solomon", { ...eventBase, stage: "reviewer" }, {
|
|
139
|
+
message: `Brain: ${nonStyleIssues} non-style issue(s) — sending to coder without Solomon`,
|
|
140
|
+
detail: { categories: cats, queueSize: brainCtx.feedbackQueue.entries.length }
|
|
141
|
+
}));
|
|
142
|
+
// Persist flat feedback for compat with non-Brain flow
|
|
143
|
+
session.last_reviewer_feedback = review.blocking_issues
|
|
144
|
+
.map((x, idx) => `R-${idx + 1} [${x.severity || "medium"}]: ${x.description}`)
|
|
145
|
+
.join("\n");
|
|
146
|
+
await saveSession(session);
|
|
147
|
+
return null; // null = continue to next iteration (coder fixes)
|
|
148
|
+
}
|
|
149
|
+
logger.info("Brain: reviewer rejected with style-only issues — consulting Solomon for dilemma");
|
|
150
|
+
}
|
|
151
|
+
|
|
126
152
|
// When Solomon is disabled, only act on stalls (legacy behavior)
|
|
127
153
|
if (!solomonEnabled) {
|
|
128
154
|
if (!repeatState.stalled) return null;
|
|
@@ -159,7 +185,7 @@ export async function fetchReviewDiff(session, logger) {
|
|
|
159
185
|
return generateDiff({ baseRef: session.session_start_sha, stageNewFiles: true });
|
|
160
186
|
}
|
|
161
187
|
|
|
162
|
-
export async function runReviewerStage({ reviewerRole, config, logger, emitter, eventBase, session, trackBudget, iteration, reviewRules, task, repeatDetector, budgetSummary, askQuestion }) {
|
|
188
|
+
export async function runReviewerStage({ reviewerRole, config, logger, emitter, eventBase, session, trackBudget, iteration, reviewRules, task, repeatDetector, budgetSummary, askQuestion, brainCtx }) {
|
|
163
189
|
logger.setContext({ iteration, stage: "reviewer" });
|
|
164
190
|
emitProgress(
|
|
165
191
|
emitter,
|
|
@@ -326,13 +352,19 @@ export async function runReviewerStage({ reviewerRole, config, logger, emitter,
|
|
|
326
352
|
});
|
|
327
353
|
}
|
|
328
354
|
|
|
355
|
+
// Feedback signature for stale detection: concatenated issue descriptions
|
|
356
|
+
const feedbackSignature = review.blocking_issues
|
|
357
|
+
.map(x => (x.description || "").slice(0, 120))
|
|
358
|
+
.join("|") || "approved";
|
|
359
|
+
|
|
329
360
|
await addCheckpoint(session, {
|
|
330
361
|
stage: "reviewer",
|
|
331
362
|
iteration,
|
|
332
363
|
approved: review.approved,
|
|
333
364
|
blocking_issues: review.blocking_issues.length,
|
|
334
365
|
provider: reviewerRole.provider,
|
|
335
|
-
model: reviewerRole.model || null
|
|
366
|
+
model: reviewerRole.model || null,
|
|
367
|
+
note: feedbackSignature
|
|
336
368
|
});
|
|
337
369
|
|
|
338
370
|
emitProgress(
|
|
@@ -353,7 +385,7 @@ export async function runReviewerStage({ reviewerRole, config, logger, emitter,
|
|
|
353
385
|
);
|
|
354
386
|
|
|
355
387
|
if (!review.approved) {
|
|
356
|
-
const rejectionResult = await handleReviewerRejection({ review, repeatDetector, config, logger, emitter, eventBase, session, iteration, task, askQuestion, budgetSummary });
|
|
388
|
+
const rejectionResult = await handleReviewerRejection({ review, repeatDetector, config, logger, emitter, eventBase, session, iteration, task, askQuestion, budgetSummary, brainCtx });
|
|
357
389
|
if (rejectionResult) return rejectionResult;
|
|
358
390
|
}
|
|
359
391
|
|
package/src/orchestrator.js
CHANGED
|
@@ -210,7 +210,7 @@ function emitSolomonAlerts(alerts, emitter, eventBase, logger) {
|
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
async function handleSolomonCheck({ config, session, emitter, eventBase, logger, task, i, askQuestion, ciEnabled, blockingIssues }) {
|
|
213
|
+
async function handleSolomonCheck({ config, session, emitter, eventBase, logger, task, i, askQuestion, ciEnabled, blockingIssues, brainCtx }) {
|
|
214
214
|
if (config.pipeline?.solomon?.enabled === false) return { action: "continue" };
|
|
215
215
|
|
|
216
216
|
try {
|
|
@@ -220,8 +220,45 @@ async function handleSolomonCheck({ config, session, emitter, eventBase, logger,
|
|
|
220
220
|
|
|
221
221
|
if (rulesResult.alerts.length > 0) {
|
|
222
222
|
emitSolomonAlerts(rulesResult.alerts, emitter, eventBase, logger);
|
|
223
|
-
|
|
224
|
-
|
|
223
|
+
// Brain gateway: when Brain is the orchestrator, rule alerts are telemetry.
|
|
224
|
+
// On critical alerts Brain consults Solomon (AI judge). Only if Solomon can't
|
|
225
|
+
// resolve does Brain escalate to human. Solomon-rules never prompts directly.
|
|
226
|
+
if (!brainCtx?.enabled) {
|
|
227
|
+
const pauseResult = await checkSolomonCriticalAlerts({ rulesResult, askQuestion, session, i });
|
|
228
|
+
if (pauseResult) return pauseResult;
|
|
229
|
+
} else if (rulesResult.hasCritical) {
|
|
230
|
+
const criticalAlerts = rulesResult.alerts.filter(a => a.severity === "critical");
|
|
231
|
+
brainCtx.ruleAlerts = brainCtx.ruleAlerts || [];
|
|
232
|
+
brainCtx.ruleAlerts.push(...criticalAlerts);
|
|
233
|
+
logger.info(`Brain: ${criticalAlerts.length} critical rule alert(s) — consulting Solomon`);
|
|
234
|
+
|
|
235
|
+
const { invokeSolomon } = await import("./orchestrator/solomon-escalation.js");
|
|
236
|
+
const alertSummary = criticalAlerts.map(a => a.message).join("; ");
|
|
237
|
+
const solomonOpinion = await invokeSolomon({
|
|
238
|
+
config, logger, emitter, eventBase, stage: "brain-dilemma", askQuestion, session, iteration: i,
|
|
239
|
+
conflict: {
|
|
240
|
+
stage: "brain-dilemma",
|
|
241
|
+
task,
|
|
242
|
+
iterationCount: i,
|
|
243
|
+
maxIterations: config.max_iterations,
|
|
244
|
+
dilemma: `Brain detected critical rule alerts: ${alertSummary}. Should we continue iterating, pause for human, or stop?`,
|
|
245
|
+
ruleAlerts: criticalAlerts,
|
|
246
|
+
blockingIssues: blockingIssues || [],
|
|
247
|
+
history: (session.checkpoints || []).filter(cp => cp.stage === "reviewer").slice(-5).map(cp => ({ iteration: cp.iteration, feedback: cp.note || "" }))
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
if (solomonOpinion.action === "pause") {
|
|
252
|
+
logger.info("Brain: Solomon advised pause — escalating to human");
|
|
253
|
+
return { action: "return", result: { paused: true, sessionId: session.id, question: solomonOpinion.question || `Brain+Solomon paused: ${alertSummary}`, context: "brain_solomon_dilemma" } };
|
|
254
|
+
}
|
|
255
|
+
if (solomonOpinion.action === "approve") {
|
|
256
|
+
logger.info("Brain: Solomon advised proceeding — treating as approved");
|
|
257
|
+
return { action: "continue", approved: true };
|
|
258
|
+
}
|
|
259
|
+
// action === "continue" | "subtask" | fallback → Brain continues the loop
|
|
260
|
+
logger.info(`Brain: Solomon said '${solomonOpinion.action}' — continuing loop`);
|
|
261
|
+
}
|
|
225
262
|
}
|
|
226
263
|
|
|
227
264
|
if (ciEnabled && session.ci_pr_number) {
|
|
@@ -661,8 +698,8 @@ async function runPreLoopStages({ config, logger, emitter, eventBase, session, f
|
|
|
661
698
|
return { plannedTask, updatedConfig };
|
|
662
699
|
}
|
|
663
700
|
|
|
664
|
-
async function runCoderAndRefactorerStages({ coderRoleInstance, coderRole, refactorerRole, pipelineFlags, config, logger, emitter, eventBase, session, plannedTask, trackBudget, i }) {
|
|
665
|
-
const coderResult = await runCoderStage({ coderRoleInstance, coderRole, config, logger, emitter, eventBase, session, plannedTask, trackBudget, iteration: i });
|
|
701
|
+
async function runCoderAndRefactorerStages({ coderRoleInstance, coderRole, refactorerRole, pipelineFlags, config, logger, emitter, eventBase, session, plannedTask, trackBudget, i, brainCtx }) {
|
|
702
|
+
const coderResult = await runCoderStage({ coderRoleInstance, coderRole, config, logger, emitter, eventBase, session, plannedTask, trackBudget, iteration: i, brainCtx });
|
|
666
703
|
if (coderResult?.action === "pause") return { action: "return", result: coderResult.result };
|
|
667
704
|
const coderStandby = await handleStandbyResult({ stageResult: coderResult, session, emitter, eventBase, i, stage: "coder", logger, config });
|
|
668
705
|
if (coderStandby.handled) {
|
|
@@ -795,7 +832,7 @@ async function runQualityGateStages({ config, logger, emitter, eventBase, sessio
|
|
|
795
832
|
return { action: "ok" };
|
|
796
833
|
}
|
|
797
834
|
|
|
798
|
-
async function runReviewerGateStage({ pipelineFlags, reviewerRole, config, logger, emitter, eventBase, session, trackBudget, i, reviewRules, task, repeatDetector, budgetSummary, askQuestion }) {
|
|
835
|
+
async function runReviewerGateStage({ pipelineFlags, reviewerRole, config, logger, emitter, eventBase, session, trackBudget, i, reviewRules, task, repeatDetector, budgetSummary, askQuestion, brainCtx }) {
|
|
799
836
|
if (!pipelineFlags.reviewerEnabled) {
|
|
800
837
|
return {
|
|
801
838
|
action: "ok",
|
|
@@ -805,7 +842,7 @@ async function runReviewerGateStage({ pipelineFlags, reviewerRole, config, logge
|
|
|
805
842
|
|
|
806
843
|
const reviewerResult = await runReviewerStage({
|
|
807
844
|
reviewerRole, config, logger, emitter, eventBase, session, trackBudget,
|
|
808
|
-
iteration: i, reviewRules, task, repeatDetector, budgetSummary, askQuestion
|
|
845
|
+
iteration: i, reviewRules, task, repeatDetector, budgetSummary, askQuestion, brainCtx
|
|
809
846
|
});
|
|
810
847
|
if (reviewerResult.action === "pause") return { action: "return", result: reviewerResult.result };
|
|
811
848
|
const revStandby = await handleStandbyResult({ stageResult: reviewerResult, session, emitter, eventBase, i, stage: "reviewer", logger, config, askQuestion });
|
|
@@ -1014,6 +1051,13 @@ async function initFlowContext({ task, config, logger, emitter, askQuestion, pgT
|
|
|
1014
1051
|
ctx.session = await initializeSession({ task, config, flags, pgTaskId, pgProject });
|
|
1015
1052
|
ctx.eventBase.sessionId = ctx.session.id;
|
|
1016
1053
|
|
|
1054
|
+
// Karajan Brain: initialize runtime context (opt-in via config.brain.enabled)
|
|
1055
|
+
const { createBrainContext, isBrainEnabled } = await import("./orchestrator/brain-coordinator.js");
|
|
1056
|
+
ctx.brainCtx = createBrainContext({ enabled: isBrainEnabled(config) });
|
|
1057
|
+
if (ctx.brainCtx.enabled) {
|
|
1058
|
+
logger.info("Karajan Brain enabled — feedback queue, verification, compression active");
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1017
1061
|
const { initPgAdapter } = await import("./planning-game/pipeline-adapter.js");
|
|
1018
1062
|
const pgAdapterResult = await initPgAdapter({ session: ctx.session, config, logger, pgTaskId, pgProject });
|
|
1019
1063
|
ctx.pgCard = pgAdapterResult.pgCard;
|
|
@@ -1094,7 +1138,7 @@ async function runSingleIteration(ctx) {
|
|
|
1094
1138
|
const crResult = await runCoderAndRefactorerStages({
|
|
1095
1139
|
coderRoleInstance: ctx.coderRoleInstance, coderRole: ctx.coderRole, refactorerRole: ctx.refactorerRole,
|
|
1096
1140
|
pipelineFlags: ctx.pipelineFlags, config, logger, emitter, eventBase, session,
|
|
1097
|
-
plannedTask: ctx.plannedTask, trackBudget: ctx.trackBudget, i
|
|
1141
|
+
plannedTask: ctx.plannedTask, trackBudget: ctx.trackBudget, i, brainCtx: ctx.brainCtx
|
|
1098
1142
|
});
|
|
1099
1143
|
if (crResult.action === "return" || crResult.action === "retry") return crResult;
|
|
1100
1144
|
|
|
@@ -1117,7 +1161,8 @@ async function runSingleIteration(ctx) {
|
|
|
1117
1161
|
const revResult = await runReviewerGateStage({
|
|
1118
1162
|
pipelineFlags: ctx.pipelineFlags, reviewerRole: ctx.reviewerRole, config, logger, emitter, eventBase,
|
|
1119
1163
|
session, trackBudget: ctx.trackBudget, i, reviewRules: ctx.reviewRules, task,
|
|
1120
|
-
repeatDetector: ctx.repeatDetector, budgetSummary: ctx.budgetSummary, askQuestion: ctx.askQuestion
|
|
1164
|
+
repeatDetector: ctx.repeatDetector, budgetSummary: ctx.budgetSummary, askQuestion: ctx.askQuestion,
|
|
1165
|
+
brainCtx: ctx.brainCtx
|
|
1121
1166
|
});
|
|
1122
1167
|
if (revResult.action === "return" || revResult.action === "retry") return revResult;
|
|
1123
1168
|
const review = revResult.review;
|
|
@@ -1143,7 +1188,7 @@ async function runSingleIteration(ctx) {
|
|
|
1143
1188
|
|
|
1144
1189
|
const solomonResult = await handleSolomonCheck({
|
|
1145
1190
|
config, session, emitter, eventBase, logger, task, i, askQuestion: ctx.askQuestion,
|
|
1146
|
-
ciEnabled, blockingIssues: review?.blocking_issues
|
|
1191
|
+
ciEnabled, blockingIssues: review?.blocking_issues, brainCtx: ctx.brainCtx
|
|
1147
1192
|
});
|
|
1148
1193
|
if (solomonResult.action === "pause") return { action: "return", result: solomonResult.result };
|
|
1149
1194
|
|