fix(dream): gate patterns phase on gateway provider reachability, not ANTHROPIC_API_KEY (takeover of #2279) (#2936)

Absorbs PR #2279's intent (drop the hardcoded ANTHROPIC_API_KEY gate) with
the end-state the gateway world actually wants: the patterns phase now
probes the RESOLVED patterns model through probeChatModel(normalizeModelId)
— the same semantics as think/index.ts and synthesize's makeJudgeClient.

Fixes two misclassifications of the old env gate:
- Non-Anthropic stacks (litellm, deepseek, openrouter, ...) were skipped as
  "no upstream" even though the subagent routes them through the gateway
  (agent.use_gateway_loop). They now pass the gate; their auth is checked
  lazily at dispatch and surfaces in the job outcome.
- Anthropic keys set via `gbrain config set anthropic_api_key` (stdio MCP
  launches without shell env) were treated as missing. hasAnthropicKey
  inside probeChatModel reads both sources.

Skip reason renames no_api_key → no_provider (carrying the probe's detail).
Both pinning tests updated: the structural test asserts the probe wiring;
the PGLite E2E swaps its env-only helper for the shared hermetic
withoutAnthropicKey (env + config file) so it can't flip to a live LLM call
on a dev machine with a config-file key.

Co-authored-by: Sinabina <sinabina@Sinabinas-MacBook-Pro-4.local>
Co-authored-by: brettdavies <brettdavies@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Time Attakc
2026-07-17 14:18:56 -07:00
committed by GitHub
co-authored by Sinabina brettdavies Claude Fable 5
parent bd2ba46a61
commit a0ef951586
3 changed files with 36 additions and 21 deletions
+16 -3
View File
@@ -27,6 +27,8 @@ import { waitForCompletion, TimeoutError } from '../minions/wait-for-completion.
import type { MinionJobInput, SubagentHandlerData } from '../minions/types.ts';
import { serializeMarkdown } from '../markdown.ts';
import type { Page, PageType } from '../types.ts';
import { probeChatModel } from '../ai/gateway.ts';
import { normalizeModelId } from '../model-id.ts';
export interface PatternsPhaseOpts {
brainDir: string;
@@ -63,9 +65,20 @@ export async function runPhasePatterns(
});
}
// Submit one subagent for pattern detection.
if (!process.env.ANTHROPIC_API_KEY) {
return skipped('no_api_key', 'ANTHROPIC_API_KEY unset; pattern detection skipped');
// Submit one subagent for pattern detection. The subagent dispatches via
// the gateway model-tier resolver, so gate on "is the resolved model's
// provider reachable" rather than ANTHROPIC_API_KEY specifically — a
// hardcoded env gate misclassified non-Anthropic stacks (litellm,
// deepseek, openrouter, ...) as "no upstream" even though the subagent
// routes them through the gateway (agent.use_gateway_loop), and it missed
// Anthropic keys set via `gbrain config set anthropic_api_key`. Same
// probe semantics as think/index.ts + synthesize's makeJudgeClient:
// unknown provider/model or Anthropic-without-key skips cheaply; other
// providers' auth is checked lazily at dispatch and surfaces in the job
// outcome. (Takeover of PR #2279's intent by @brettdavies.)
const probe = probeChatModel(normalizeModelId(config.model));
if (!probe.ok) {
return skipped('no_provider', `pattern detection skipped: ${probe.detail}`);
}
const allowedSlugPrefixes = await loadAllowedSlugPrefixes();