How Craft Agents Resolve Adaptive Thinking Models That Reject Disabled Thinking States
Craft Agents detects Mythos-class models using a regex pattern in isAdaptiveThinkingAlwaysOnModel and automatically remaps requests for disabled thinking to the lowest-effort adaptive configuration, ensuring API calls succeed while honoring user intent to minimize reasoning.
The craft-ai-agents/craft-agents-oss repository abstracts LLM reasoning controls behind a unified "thinking level" interface (Off → Low → Medium → High → XHigh → Max). While most Anthropic models support explicit thinking: { type: 'disabled' } requests, the newest Mythos-class models (Claude Fable 5 and Mythos 5) ship with adaptive thinking permanently enabled and reject any payload attempting to disable it. This guide explains how the resolver logic handles these constraints to resolve adaptive thinking models that reject disabled thinking states.
The Mythos-Class Model Constraint
Anthropic’s Mythos-class architecture treats reasoning as a non-disablable core feature. When the Craft Agents UI requests Off or minimizeThinking for these models, sending thinking: { type: 'disabled' } to the Messages API results in a validation error. The system must therefore translate "no reasoning" intent into the lowest possible reasoning intensity that the model accepts.
Detecting Adaptive-Always-On Models
Before resolving thinking options, the system identifies restricted models using the isAdaptiveThinkingAlwaysOnModel helper function defined in packages/shared/src/config/models.ts. This function applies a case-insensitive regex to the model identifier:
// packages/shared/src/config/models.ts
export function isAdaptiveThinkingAlwaysOnModel(modelId: string): boolean {
return /claude-(fable|mythos)/i.test(modelId);
}
Any model ID matching claude-fable or claude-mythos triggers the adaptive-always-on code path, signaling that the resolver cannot emit disabled-thinking directives for these specific backends.
The Resolution Logic in resolveClaudeThinkingOptions
The core resolution happens in packages/shared/src/agent/claude-agent.ts within the resolveClaudeThinkingOptions function. This method accepts a thinkingLevel, model string, and minimizeThinking boolean, then branches based on model capabilities.
When the user requests minimized thinking (or selects "Off"), the resolver checks the adaptiveAlwaysOn flag:
// packages/shared/src/agent/claude-agent.ts (excerpt)
export function resolveClaudeThinkingOptions(args: {
thinkingLevel: ThinkingLevel;
model: string;
providerType?: BackendConfig['providerType'];
minimizeThinking: boolean;
}): Partial<Options> {
const { thinkingLevel, model, minimizeThinking } = args;
const isClaude = isClaudeModel(model);
const effort = THINKING_TO_EFFORT[thinkingLevel];
const isHaiku = model.toLowerCase().includes('haiku');
const supportsAdaptiveThinking = isClaude && !isHaiku;
const adaptiveAlwaysOn = isAdaptiveThinkingAlwaysOnModel(model);
// "Off" or minimizeThinking path
if (minimizeThinking || !isClaude || !effort) {
if (adaptiveAlwaysOn) {
// Mythos-class models cannot accept disabled thinking
return { thinking: { type: 'adaptive' }, effort: 'low' };
}
return supportsAdaptiveThinking
? { thinking: { type: 'disabled' } }
: { maxThinkingTokens: 0 };
}
// Normal adaptive path
if (supportsAdaptiveThinking) {
return { thinking: { type: 'adaptive' }, effort };
}
return { maxThinkingTokens: getThinkingTokens(thinkingLevel, model) };
}
Key insight: When adaptiveAlwaysOn is true, the resolver swaps the disabled-thinking directive for { thinking: { type: 'adaptive' }, effort: 'low' }. This satisfies the API contract while keeping reasoning intensity at its minimum viable level.
Fallback Strategies for Legacy Models
For non-Claude models or legacy Anthropic models that lack adaptive thinking support (such as Haiku variants), the resolver bypasses the thinking object entirely. Instead, it invokes getThinkingTokens() from packages/shared/src/agent/thinking-levels.ts to return a static maxThinkingTokens budget. This ensures consistent behavior across diverse backend providers even when the adaptive thinking paradigm does not apply.
Practical Implementation Examples
Example 1: Mythos-Class Model (Fable 5)
When resolving options for a model that rejects disabled states, the function returns the minimal adaptive configuration:
import { resolveClaudeThinkingOptions } from '@/agent/claude-agent';
const opts = resolveClaudeThinkingOptions({
thinkingLevel: 'off',
model: 'claude-fable-5',
minimizeThinking: true,
});
console.log(opts);
// Output: { thinking: { type: 'adaptive' }, effort: 'low' }
This prevents the API from rejecting the request while respecting the user’s desire to minimize computational overhead.
Example 2: Standard Adaptive Model (Opus 4.8)
For standard models that support explicit disablement, the resolver follows the normal path:
const opts = resolveClaudeThinkingOptions({
thinkingLevel: 'high',
model: 'claude-opus-4-8',
minimizeThinking: false,
});
console.log(opts);
// Output: { thinking: { type: 'adaptive' }, effort: 'high' }
Example 3: Non-Claude Provider (Token Budget Fallback)
When the backend is not Anthropic, the system falls back to token-based controls:
const opts = resolveClaudeThinkingOptions({
thinkingLevel: 'low',
model: 'openai-gpt-4',
minimizeThinking: false,
});
console.log(opts);
// Output: { maxThinkingTokens: 2000 }
Summary
- Mythos-class models (Claude Fable 5 / Mythos 5) require adaptive thinking and reject
type: 'disabled'payloads. - The
isAdaptiveThinkingAlwaysOnModelregex detector inpackages/shared/src/config/models.tsidentifies these models by matching/claude-(fable|mythos)/i. - The
resolveClaudeThinkingOptionsfunction inpackages/shared/src/agent/claude-agent.tsremaps "Off" requests to{ thinking: { type: 'adaptive' }, effort: 'low' }for restricted models. - Legacy and non-Claude models fall back to
maxThinkingTokensvalues defined inpackages/shared/src/agent/thinking-levels.ts. - This resolution strategy is documented in
packages/shared/CLAUDE.mdand ensures API compatibility across the entire model spectrum.
Frequently Asked Questions
Which specific models reject disabled thinking states?
The Claude Fable 5 and Mythos 5 model classes reject explicit disabled thinking requests. According to the source code in packages/shared/src/config/models.ts, any model ID matching the regex /claude-(fable|mythos)/i is flagged as having adaptive thinking always enabled.
What configuration does Craft Agents send when I select "Off" for a Mythos model?
Instead of sending thinking: { type: 'disabled' }, which the API would reject, Craft Agents automatically substitutes low-effort adaptive thinking: { thinking: { type: 'adaptive' }, effort: 'low' }. This configuration satisfies the Messages API requirements while minimizing reasoning intensity.
How does the resolver handle non-Anthropic models?
For models that are not Claude variants or do not support adaptive thinking (such as Haiku models), resolveClaudeThinkingOptions returns a maxThinkingTokens value derived from getThinkingTokens() in packages/shared/src/agent/thinking-levels.ts. This provides a token-budget-based fallback that works across any LLM backend.
Where is the thinking-level mapping documented?
The behavior mapping for adaptive thinking and the special handling for Mythos-class models is documented in packages/shared/CLAUDE.md. This file explains how the UI’s "Off" level translates to API configurations for different model families.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →