diff --git a/apps/cli/src/commands.test.ts b/apps/cli/src/commands.test.ts index deced6c..6c1d04f 100644 --- a/apps/cli/src/commands.test.ts +++ b/apps/cli/src/commands.test.ts @@ -117,6 +117,20 @@ describe('built-in command behavior', () => { expect(ctx.effort).toBe('high'); }); + it('/effort table reflects core EFFORT_PARAMS (single source of truth)', async () => { + const { EFFORT_PARAMS } = await import('@deepcode/core'); + const reg = new CommandRegistry(); + const out = (await reg.match('/effort')!.cmd.run([], makeContext())).join('\n'); + // Every tier renders the maxTokens/temperature the provider actually uses. + for (const tier of ['low', 'medium', 'high', 'xhigh', 'max'] as const) { + expect(out).toContain(String(EFFORT_PARAMS[tier].maxTokens)); + expect(out).toContain(EFFORT_PARAMS[tier].temperature.toFixed(1)); + } + // The old divergent hardcoded numbers must never resurface. + expect(out).not.toContain('32768'); + expect(out).not.toContain('16384'); + }); + it('/status emits session info', async () => { const reg = new CommandRegistry(); const ctx = makeContext({ sessions: new SessionManager({ root: sessRoot }) }); diff --git a/apps/cli/src/commands.ts b/apps/cli/src/commands.ts index b6eb0fb..8707b1c 100644 --- a/apps/cli/src/commands.ts +++ b/apps/cli/src/commands.ts @@ -9,7 +9,13 @@ import type { SessionMeta, StoredMessage, } from '@deepcode/core'; -import { contextWindowFor, redact, type Credentials } from '@deepcode/core'; +import { + contextWindowFor, + redact, + EFFORT_PARAMS, + type Credentials, + type Effort, +} from '@deepcode/core'; export interface SessionContext { cwd: string; @@ -147,19 +153,34 @@ export const ModeCommand: SlashCommand = { }, }; -// Effort tier UI metadata — surfaced by `/effort` with no args. +// Effort tier UI metadata surfaced by `/effort` with no args. +// why: the maxTokens/temperature numbers are NOT defined here — they are read +// from EFFORT_PARAMS in @deepcode/core, the single source of truth the REPL and +// headless paths actually send to the provider. A divergent hardcoded table +// here previously told users "max = 32768 tokens, temp 0.7" while the provider +// sent max_tokens=8192, temp=0.8 — pure misinformation. Only the human-readable +// use-case hint is CLI-local; everything quantitative is derived. +const EFFORT_ORDER: Effort[] = ['low', 'medium', 'high', 'xhigh', 'max']; + +const EFFORT_USE: Record = { + low: 'Quick targeted fixes. Cheap.', + medium: 'Default. Most tasks.', + high: 'Multi-step refactors.', + xhigh: 'Plans, architecture decisions.', + max: 'Open-ended exploration. Burns tokens.', +}; + const EFFORT_TIERS: Array<{ - name: string; + name: Effort; maxTokens: number; temperature: number; use: string; -}> = [ - { name: 'low', maxTokens: 1024, temperature: 0.0, use: 'Quick targeted fixes. Cheap.' }, - { name: 'medium', maxTokens: 4096, temperature: 0.3, use: 'Default. Most tasks.' }, - { name: 'high', maxTokens: 8192, temperature: 0.5, use: 'Multi-step refactors.' }, - { name: 'xhigh', maxTokens: 16384, temperature: 0.6, use: 'Plans, architecture decisions.' }, - { name: 'max', maxTokens: 32768, temperature: 0.7, use: 'Open-ended exploration. Burns tokens.' }, -]; +}> = EFFORT_ORDER.map((name) => ({ + name, + maxTokens: EFFORT_PARAMS[name].maxTokens, + temperature: EFFORT_PARAMS[name].temperature, + use: EFFORT_USE[name], +})); export const EffortCommand: SlashCommand = { name: '/effort',