/** * buildThinkCandidates — think 재시도 사다리 * * 빈 응답이 오면 다른 think 값으로 재시도한다. glm-5.1:cloud처럼 think를 생략하면 생각만 하고 * content를 안 내놓는 모델을 건지려고 만든 장치다. * * 문제는 `think:false`였다. 2026-08-12 muse-glimmer(생각비중 85%, 체감 3.1 tok/s) 측정 후 * 생각을 끄기로 했는데, 사다리가 빈 응답 한 번에 thinking을 도로 켜버리면 그 결정이 조용히 * 뒤집힌다. 명시적 false는 모델 기본값까지만 물러선다. */ import { test, describe } from 'node:test'; import assert from 'node:assert/strict'; import { buildThinkCandidates } from '../src/providers/ollama-adapter'; describe('think:false는 사다리를 오르지 않는다', () => { test('false → [false, undefined]까지만', () => { assert.deepEqual(buildThinkCandidates(false), [false, undefined]); }); test('생각을 켜는 값이 하나도 없다', () => { const c = buildThinkCandidates(false); for (const v of [true, 'low', 'medium', 'high']) { assert.ok(!c.includes(v as any), `${v}가 포함되면 안 됨`); } }); test('빈 응답이 막다른 길이 되지 않게 기본값 폴백은 남긴다', () => { assert.ok(buildThinkCandidates(false).includes(undefined)); }); }); describe('나머지 경로는 그대로', () => { test('요청값이 맨 앞에 온다', () => { assert.equal(buildThinkCandidates(true)[0], true); assert.equal(buildThinkCandidates('low')[0], 'low'); assert.equal(buildThinkCandidates(undefined)[0], undefined); }); test('true 요청은 여전히 여러 모드로 재시도한다', () => { const c = buildThinkCandidates(true); assert.ok(c.includes('low')); assert.ok(c.includes(undefined)); assert.ok(c.includes('medium')); }); test('중복이 없다', () => { for (const req of [undefined, true, false, 'low', 'medium', 'high'] as const) { const c = buildThinkCandidates(req); assert.equal(new Set(c).size, c.length, `중복 발생: ${JSON.stringify(c)}`); } }); });