fix(worker): cap completion budget by model context window
max_tokens=16384 caused HTTP 400 on small-context models (e.g. 16k-window models); budget is now min(16384, context_length - 4096) with a 2048 floor. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Showing 1 changed file with +7 and −2
modified
apps/worker/src/eval-runner.ts
+7 −2
@@ -118,6 +118,11 @@ export async function runEvalBatch(opts: EvalBatchOptions): Promise<{ runId: str | ||
| 118 | 118 | const client = new OpenRouterClient(); |
| 119 | 119 | let failures = 0; |
| 120 | 120 | let completedCalls = 0; |
| 121 | + // Small-context models reject max_tokens near/above their window (HTTP 400): | |
| 122 | + // cap the completion budget by the context length, keeping prompt headroom. | |
| 123 | + const maxTokens = model.contextLength | |
| 124 | + ? Math.min(MAX_COMPLETION_TOKENS, Math.max(2048, model.contextLength - 4096)) | |
| 125 | + : MAX_COMPLETION_TOKENS; | |
| 121 | 126 | |
| 122 | 127 | interface Call { |
| 123 | 128 | itemIdx: number; |
@@ -150,8 +155,8 @@ export async function runEvalBatch(opts: EvalBatchOptions): Promise<{ runId: str | ||
| 150 | 155 | // Scored sample: temperature 0. Consistency samples: model default temperature (§6). |
| 151 | 156 | const requestParams = |
| 152 | 157 | sampleIndex === 0 |
| 153 | − ? { model: model.slug, messages, temperature: 0, max_tokens: MAX_COMPLETION_TOKENS } | |
| 154 | − : { model: model.slug, messages, max_tokens: MAX_COMPLETION_TOKENS }; | |
| 158 | + ? { model: model.slug, messages, temperature: 0, max_tokens: maxTokens } | |
| 159 | + : { model: model.slug, messages, max_tokens: maxTokens }; | |
| 155 | 160 | // Audit copy: keep exact params but elide the base64 image payload (the |
| 156 | 161 | // scene is reproducible from the item's stored SVG/perturb seed). |
| 157 | 162 | const auditParams = item.svg |
| 158 | 163 | |