diff --git a/src/config.js b/src/config.js index b8bb879..9454c7b 100644 --- a/src/config.js +++ b/src/config.js @@ -11,6 +11,8 @@ const DEFAULTS = { webhookSecret: '', routerUrl: 'http://localhost:5497', model: 'anthropic/claude-sonnet-4-6', + agentId: 'code-reviewer', + fallbackAgentId: 'architect', tenantId: 'nirlab', publicBaseUrl: 'http://localhost:5498', dbPath: join(CONFIG_DIR, 'reviews.db'), diff --git a/src/lib/review.js b/src/lib/review.js index 8af01b1..b8cc669 100644 --- a/src/lib/review.js +++ b/src/lib/review.js @@ -71,9 +71,13 @@ export async function runReview({ cfg, gitea, db, job, withGlobal, log }) { await withGlobal(async () => { for (let attempt = 1; attempt <= 2; attempt++) { try { + // Attempt 1 uses the review agent. Attempt 2 falls back to the + // c-suite agent (bypasses the router's domain preflight), covering + // classifier false-positives on diff content: agent_mismatch 400s + // and tool fast-path hijacks that return non-JSON. const out = await chat({ routerUrl: cfg.routerUrl, model: cfg.model, messages, - agentId: 'code-reviewer', + agentId: attempt === 1 ? cfg.agentId : cfg.fallbackAgentId, sessionId: `review-${owner}-${repo}-${sha.slice(0, 12)}-a${attempt}`, tenantId: cfg.tenantId, timeoutMs: cfg.routerTimeoutMs }); diff --git a/src/lib/router.js b/src/lib/router.js index b23de2b..bb65144 100644 --- a/src/lib/router.js +++ b/src/lib/router.js @@ -6,10 +6,14 @@ export async function chat({ routerUrl, model, messages, agentId, sessionId, ten const res = await fetch(`${routerUrl.replace(/\/$/, '')}/v1/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - // tools:false — reviews need pure model reasoning; it also keeps the - // router's tool/skill fast-paths (e.g. current-info briefing) from - // hijacking prompts whose diffs mention GitHub/news-like terms. - body: JSON.stringify({ model, messages, agentId, sessionId, tenantId, stream: false, tools: false }), + // tools:false + raw:true — reviews need pure model reasoning. raw:true is + // the router's sanctioned _bypassToolRouting flag: without it, keyword + // fast-paths (current-info briefing, store-resolver, retail dispatch) + // hijack prompts whose DIFF CONTENT mentions github/sales/store-ish terms + // and return non-review text. The domain preflight (agent_mismatch 400) + // still applies per agent tier; the pipeline's attempt-2 fallback agent + // covers that. + body: JSON.stringify({ model, messages, agentId, sessionId, tenantId, stream: false, tools: false, raw: true }), signal: AbortSignal.timeout(timeoutMs) }); if (!res.ok) {