{"record":{"id":"da303e2acf305ff9","repo":"JuliusBrussee/caveman","slug":"cave-claude-reasoning-capability-unknown-model","errorCode":null,"errorMessage":"cave_claude_reasoning_capability_unknown:${model}","messagePattern":"cave_claude_reasoning_capability_unknown:(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/claude-runtime.ts","lineNumber":518,"sourceCode":"  reasoning: AgentDefinition[\"reasoning\"],\n  outputMaxTokens: number | undefined,\n): Pick<ClaudeSDKOptions, \"thinking\" | \"effort\"> {\n  if (reasoning === \"off\") return { thinking: { type: \"disabled\" } };\n  const capability = claudeThinkingCapability(model);\n  if (capability === \"adaptive\") {\n    return {\n      thinking: { type: \"adaptive\" },\n      effort: claudeEffort(reasoning),\n    };\n  }\n  if (capability === \"manual\") {\n    const budgetTokens = reasoning === \"high\" ? 8_192 : reasoning === \"medium\" ? 4_096 : 1_024;\n    if (outputMaxTokens !== undefined && outputMaxTokens <= budgetTokens) {\n      throw new Error(\"cave_claude_output_budget_too_small_for_reasoning\");\n    }\n    return { thinking: { type: \"enabled\", budgetTokens } };\n  }\n  throw new Error(`cave_claude_reasoning_capability_unknown:${model}`);\n}\n\nfunction claudeThinkingCapability(model: string): \"adaptive\" | \"manual\" | \"unknown\" {\n  if (/^claude-(?:haiku-4-5|sonnet-4-5|opus-4-(?:1|5))(?:-\\d{8})?$/.test(model)) {\n    return \"manual\";\n  }\n  if (/^claude-(?:sonnet|opus)-4-[678](?:-\\d{8})?$/.test(model) ||\n      /^claude-(?:fable|mythos|sonnet|opus)-5(?:-\\d+)?$/.test(model)) {\n    return \"adaptive\";\n  }\n  return \"unknown\";\n}\n\n// Accepts ANY result subtype: error subtypes (error_max_turns, …) carry the\n// same provider `usage` a success does, so the receipt can be built from a\n// failed run too.\ntype ClaudeCredentialRegime = \"metered\" | \"subscription\" | \"unknown\";\n","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/claude-runtime.ts#L500-L536","documentation":"claudeThinkingCapability() classifies models into \"manual\", \"adaptive\", or \"unknown\" by regex. Reasoning is enabled (not \"off\") but the resolved model matches neither regex, so the framework does not know how to configure thinking for it and fails closed rather than guessing a thinking mode that might error or silently no-op upstream. The model id is embedded in the message.","triggerScenarios":"reasoning != \"off\" with any model outside the known families: e.g. \"claude-3-5-sonnet\", \"claude-opus-4\", a future release like \"claude-sonnet-6-20260101\" before the regexes are updated, or a custom/renamed deployment id. Alias forms that don't match the exact patterns also fall through.","commonSituations":"Anthropic ships a new model generation and the framework pin predates it; user config uses an internal alias or dated snapshot not covered by the (?:-\\d{8})? patterns; typos like \"claude-haiku-45\" (missing dash) classify as unknown.","solutions":["Use a known model family: manual (claude-haiku-4-5, claude-sonnet-4-5, claude-opus-4-1, claude-opus-4-5) or adaptive (claude-sonnet/opus-4-6/4-7/4-8, claude-fable/mythos/sonnet/opus-5).","Check the embedded model id in the message for typos against those exact patterns (note the optional 8-digit date suffix).","If the model is genuinely new, upgrade the caveman agent package so claudeThinkingCapability knows it, or set reasoning: \"off\" until then."],"exampleFix":"// before\nawait run({ prompt, model: \"anthropic/claude-3-5-sonnet\", reasoning: \"medium\" });\n// → cave_claude_reasoning_capability_unknown:claude-3-5-sonnet\n\n// after\nawait run({ prompt, model: \"anthropic/claude-sonnet-4-5\", reasoning: \"medium\" });","handlingStrategy":"validation","validationCode":"const KNOWN_THINKING_MODEL =\n  /^claude-(?:haiku-4-5|sonnet-4-5|opus-4-(?:1|5))(?:-\\d{8})?$/;\nconst KNOWN_ADAPTIVE_MODEL =\n  /^claude-(?:sonnet|opus)-4-[678](?:-\\d{8})?$/ ||\n  /^claude-(?:fable|mythos|sonnet|opus)-5(?:-\\d+)?$/;\nfunction reasoningSupported(model: string): boolean {\n  return KNOWN_THINKING_MODEL.test(model) || KNOWN_ADAPTIVE_MODEL.test(model);\n}","typeGuard":"function supportsReasoning(model: string): boolean {\n  return /^claude-(?:haiku-4-5|sonnet-4-5|opus-4-(?:1|5))(?:-\\d{8})?$/.test(model)\n    || /^claude-(?:sonnet|opus)-4-[678](?:-\\d{8})?$/.test(model)\n    || /^claude-(?:fable|mythos|sonnet|opus)-5(?:-\\d+)?$/.test(model);\n}","tryCatchPattern":"try {\n  await run({ ...options, reasoning: \"medium\" });\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith(\"cave_claude_reasoning_capability_unknown:\")) {\n    const model = error.message.split(\":\")[1];\n    return run({ ...options, reasoning: \"off\" }); // degrade to no thinking\n  }\n  throw error;\n}","preventionTips":["Read the model id out of the error message — it tells you exactly which string failed classification.","Before enabling reasoning on a new model, upgrade the caveman agent package so its capability regexes cover the release.","Prefer exact dated snapshots (claude-sonnet-4-5-20250929) or canonical names that match the documented patterns."],"tags":["model-selection","reasoning","fail-closed","claude-sdk"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}