mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-31 04:07:52 +00:00
fix(takes): default takes extraction to the configured chat_model instead of hardcoded cloud Haiku (#2997) (#3021)
extractTakesFromPages hardcoded anthropic:claude-haiku-4-5 as the classifier
model. On an OAuth/local-only install (no ANTHROPIC_API_KEY; chat routed
through a gateway model) every takes extraction died with llm_unavailable —
the takes layer silently never populated and the takes_count health check
stayed red despite a working configured chat_model.
Resolution is now `opts.model || getChatModel()` — the same file-plane
gateway-config idiom enrich.ts uses — NOT engine.getConfig('chat_model')
(the DB config plane), keeping model routing on the single config plane the
rest of the codebase reads. Explicit opts.model still wins; unconfigured
installs fall through to the gateway's DEFAULT_CHAT_MODEL.
Adds a regression test that pins the file-plane read: a conflicting DB-plane
config.chat_model row is ignored, the gateway-configured chat_model is used
when opts.model is unset, and explicit opts.model wins. Verified the
file-plane test fails against the pre-fix code.
Takeover of #2997 by @Nazim22 with the model read moved from the DB config
plane to the file-plane gateway idiom.
Co-authored-by: Garry Tan <garrytan@gmail.com>
Co-authored-by: Nazz <nazim.mj@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Garry Tan
Nazz
Claude Fable 5
parent
9ed53e4e1c
commit
dbf2b3f562
@@ -15,7 +15,7 @@
|
||||
|
||||
import type { BrainEngine } from './engine.ts';
|
||||
import type { TakeBatchInput, TakeKind } from './engine.ts';
|
||||
import { chat, isAvailable } from './ai/gateway.ts';
|
||||
import { chat, getChatModel, isAvailable } from './ai/gateway.ts';
|
||||
|
||||
export const ALLOWED_PAGE_TYPES = [
|
||||
'concept', 'atom', 'lore', 'briefing', 'writing', 'originals',
|
||||
@@ -190,7 +190,11 @@ export async function extractTakesFromPages(
|
||||
let response: { text: string };
|
||||
try {
|
||||
response = await chat({
|
||||
model: opts.model ?? 'anthropic:claude-haiku-4-5',
|
||||
// #2997 — default to the configured chat model (file-plane gateway
|
||||
// config, same idiom as enrich.ts) instead of hardcoded cloud Haiku.
|
||||
// On OAuth/local-only installs the hardcoded model made every takes
|
||||
// extraction die with llm_unavailable despite a working chat_model.
|
||||
model: opts.model || getChatModel(),
|
||||
system: CLASSIFIER_SYSTEM,
|
||||
messages: [
|
||||
{
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Takes-extraction model resolution regression (#2997).
|
||||
*
|
||||
* extractTakesFromPages hardcoded `anthropic:claude-haiku-4-5` as the
|
||||
* classifier model. On OAuth/local-only installs (no ANTHROPIC_API_KEY;
|
||||
* chat routed through a gateway model) every extraction died with
|
||||
* llm_unavailable even though a working chat_model was configured.
|
||||
*
|
||||
* Pins the fix's resolution order AND its config plane:
|
||||
* opts.model → getChatModel() (file-plane gateway config, the enrich.ts
|
||||
* idiom) — NOT the DB config plane (engine.getConfig('chat_model')).
|
||||
*/
|
||||
import { describe, test, expect, beforeAll, afterAll, beforeEach } from 'bun:test';
|
||||
import { PGLiteEngine } from '../src/core/pglite-engine.ts';
|
||||
import {
|
||||
configureGateway,
|
||||
resetGateway,
|
||||
__setChatTransportForTests,
|
||||
} from '../src/core/ai/gateway.ts';
|
||||
import { extractTakesFromPages } from '../src/core/extract-takes-from-pages.ts';
|
||||
|
||||
let engine: PGLiteEngine;
|
||||
const seenModels: string[] = [];
|
||||
let pageN = 0;
|
||||
|
||||
/** Each test seeds a fresh uncovered page so the extraction loop fires. */
|
||||
async function seedPage(): Promise<void> {
|
||||
const body = 'An opinion-bearing body long enough to clear the 200-char eligibility floor. '.repeat(5);
|
||||
await engine.putPage(`concepts/model-resolution-${pageN++}`, {
|
||||
type: 'concept', title: `M${pageN}`, compiled_truth: body, frontmatter: {},
|
||||
});
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
engine = new PGLiteEngine();
|
||||
await engine.connect({});
|
||||
await engine.initSchema();
|
||||
|
||||
__setChatTransportForTests(async (opts) => {
|
||||
seenModels.push(opts.model ?? '(unset)');
|
||||
return {
|
||||
text: '[{"claim":"a stubbed claim","kind":"take","weight":0.7}]',
|
||||
blocks: [{ type: 'text' as const, text: '[{"claim":"a stubbed claim","kind":"take","weight":0.7}]' }],
|
||||
stopReason: 'end' as const,
|
||||
usage: { input_tokens: 1, output_tokens: 1, cache_read_tokens: 0, cache_creation_tokens: 0 },
|
||||
model: opts.model ?? '(unset)',
|
||||
providerId: 'test',
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
__setChatTransportForTests(null);
|
||||
resetGateway();
|
||||
await engine.disconnect();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
seenModels.length = 0;
|
||||
});
|
||||
|
||||
describe('extractTakesFromPages — model resolution (#2997)', () => {
|
||||
test('defaults to the configured chat_model from the file-plane gateway config', async () => {
|
||||
configureGateway({
|
||||
chat_model: 'openai:gpt-config-plane-test',
|
||||
env: { OPENAI_API_KEY: 'sk-test-model-resolution' },
|
||||
});
|
||||
// A conflicting DB-plane value must be IGNORED — model config is the
|
||||
// config-file plane (getChatModel), not the brain DB config table.
|
||||
await engine.setConfig('chat_model', 'wrong:db-plane-model');
|
||||
await seedPage();
|
||||
|
||||
const r = await extractTakesFromPages(engine, { bootstrapEnabled: true, maxPages: 50 });
|
||||
expect(r.pages_scanned).toBe(1);
|
||||
expect(seenModels).toEqual(['openai:gpt-config-plane-test']);
|
||||
});
|
||||
|
||||
test('explicit opts.model wins over the configured chat_model', async () => {
|
||||
configureGateway({
|
||||
chat_model: 'openai:gpt-config-plane-test',
|
||||
env: { OPENAI_API_KEY: 'sk-test-model-resolution' },
|
||||
});
|
||||
await seedPage();
|
||||
|
||||
const r = await extractTakesFromPages(engine, {
|
||||
bootstrapEnabled: true,
|
||||
maxPages: 50,
|
||||
model: 'anthropic:claude-haiku-4-5',
|
||||
});
|
||||
expect(r.pages_scanned).toBe(1);
|
||||
expect(seenModels).toEqual(['anthropic:claude-haiku-4-5']);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user