Documentation
¶
Overview ¶
Package reasoning provides primitives for working with reasoning content.
This package implements utilities for extracting and processing reasoning (step-by-step thinking) content from language model responses. It operates in two modes:
Streaming mode: Uses a stateful ChunkContentSplitter to process content chunks as they arrive, separating text from reasoning blocks marked with <think> or <thinking> tags. The splitter maintains state between calls to handle cases where reasoning blocks span multiple chunks.
Complete content mode: Uses SplitContent function to separate reasoning content from a complete response, handling cases where the LLM backend hasn't explicitly divided reasoning from regular content.
The package recognizes reasoning content enclosed in <think>...</think> or <thinking>...</thinking> tags, which various LLM providers use to indicate step-by-step thinking processes.
Beyond content splitting, the package is the low-level source of truth for model capabilities, shared by every provider adapter so the wire shape is resolved the same way everywhere. It sits below llms and must not import it. It provides:
- Reasoning-model detection: IsReasoningModel / DefaultIsReasoningModel.
- Per-family capability resolvers keyed by the distinctive part of the model name (so they work with and without an OpenRouter provider prefix): ClaudeReasoningKindFor and the Claude_* helpers (adaptive vs budget thinking, sampling rules, effort-with-budget, structured-output support), OpenAIReasoningCapsFor / ClampEffort, and the Gemini* helpers.
- ResolveOff: the single, provider-aware decision of how to disable thinking (an explicit disable wire, a zero budget, or ErrReasoningOffUnsupported for models that cannot be disabled, e.g. always-on Claude or Bedrock defaults).
Unrecognized models are treated as optimistic pass-through: the provider API, not a local table, is the final arbiter, so a newer model never regresses.
Example usage for streaming mode:
splitter := reasoning.NewChunkContentSplitter()
for chunk := range responseChunks {
text, reasoning := splitter.Split(chunk)
if reasoning != "" {
// Process reasoning content (e.g., display as step-by-step thinking)
fmt.Println("Reasoning:", reasoning)
}
if text != "" {
// Process regular text content
fmt.Println("Content:", text)
}
}
Example usage for complete content mode:
response := "Here's what I found: <thinking>First, I need to analyze the data.
The pattern shows increasing values.</thinking> The trend is clearly upward."
reasoning, content := reasoning.SplitContent(response)
fmt.Println("Reasoning:", reasoning) // "First, I need to analyze the data. The pattern shows increasing values."
fmt.Println("Content:", content) // "Here's what I found: The trend is clearly upward."
See also:
- IsReasoningModel: Checks if a model supports reasoning
- DefaultIsReasoningModel: Provides the default reasoning model detection logic
Index ¶
- Constants
- func AcceptsEffortWire(model string) bool
- func BedrockSupportsStructuredOutput(model string) bool
- func ChatToolsUnsupported(model string) bool
- func ClaudeClampBudget(model string, budget int) int
- func ClaudeClampEffort(model, effort string, p Provider) string
- func ClaudeEffortsFor(model string, p Provider) []string
- func ClaudeInterleavesOnBudget(model string) bool
- func ClaudeKeepsTopPWhileThinking(model string, topP float64) bool
- func ClaudeMaxTokensForBudget(budget, maxTokens int) int
- func ClaudeMutuallyExclusiveSampling(model string) bool
- func ClaudePredatesAdaptive(model string) bool
- func ClaudeRejectsAssistantPrefill(model string) bool
- func ClaudeRejectsSampling(model string) bool
- func ClaudeSpendsThinkingBudget(model string) bool
- func ClaudeSupportsEffortWithBudget(model string, p Provider) bool
- func ClaudeSupportsStructuredOutput(model string) bool
- func ClaudeSupportsStructuredOutputOnBedrock(model string) bool
- func ClaudeSupportsThinking(model string) bool
- func ClaudeThinkingAlwaysOn(model string) bool
- func ClaudeThinkingDefaultsOn(model string) bool
- func ClaudeThinkingObjectRoute(model string) bool
- func DashScopeBudgetSharesAnswerLimit(model string) bool
- func DashScopeGuestThinkingEnabledByFlag(model string) bool
- func DashScopeRoute(model, host string) string
- func DashScopeTakesNoTopK(model string) bool
- func DashScopeTakesThinkingBudget(model string) bool
- func DefaultIsReasoningModel(model string) bool
- func FixesSampling(model string) bool
- func GeminiAcceptsMinimalLevel(model string) bool
- func GeminiBudgetRange(model string) (minimum, maximum int, known bool)
- func GeminiCanDisable(model string) bool
- func GeminiSupportsThinking(model string) bool
- func GeminiThinkingOffByDefault(model string) bool
- func GeminiTogglesThinkingByLevel(model string) bool
- func GeminiUsesThinkingLevel(model string) bool
- func GptOssEffort(effort string) string
- func GptOssEfforts() []string
- func GrokEffort(model, effort string) string
- func GroupByToolCalls(blocks []Block, toolCalls int) [][]Block
- func IsBedrockAlwaysReasoningModel(model string) bool
- func IsBedrockNonReasoningModel(model string) bool
- func IsGptOssModel(model string) bool
- func IsGrokModel(model string) bool
- func IsNovaReasoningModel(model string) bool
- func IsReasoningModel(model string) bool
- func LikelyReasoningModel(model string) bool
- func NovaClearsInferenceConfigAt(effort string) bool
- func NovaEffort(effort string) string
- func NovaEfforts() []string
- func OllamaEffortsFor(model string) []string
- func OpenAIThinkingOptIn(model string) bool
- func QwenThinkingEnabledByFlag(model string) bool
- func QwenThinkingOffByFlag(model string) bool
- func QwenThinkingRequiresStream(model string) bool
- func RejectsMinP(model string) bool
- func RejectsPenalties(model string) bool
- func RejectsRepetitionPenalty(model string) bool
- func RejectsSamplingWhileThinking(model string) bool
- func RejectsTopK(model string) bool
- func ReplaysEmptyReasoning(model string) bool
- func ReplaysReasoningInThinkTags(model string) bool
- func ReplaysReasoningOnEveryTurn(model string) bool
- func ReplaysThinkingInContent(model string) bool
- func ResolveClaudeAdaptive(model string, adaptivePreferred bool) bool
- func ServedByDeepSeek(model, host string) bool
- func ServedByMistral(model string) bool
- func SplitContent(content string) (string, string)
- func TakesNoJSONObject(model string) bool
- func TakesNoJSONSchema(model string) bool
- func TakesNoResponseFormat(model string) bool
- func TakesNoThinkingDepth(model string) bool
- func TakesNoTopK(model string) bool
- func ThinkingMarkedInName(model string) bool
- func ThinkingOptIn(model string) bool
- func UsesLegacyMaxTokens(model string) bool
- type Block
- type ChunkContentSplitter
- type ChunkContentSplitterState
- type ClaudeReasoningKind
- type Collector
- type ContentReasoning
- type EffortToolsRule
- type ErrAssistantPrefillUnsupported
- type ErrChatToolsUnsupported
- type ErrEffortHasNoBudget
- type ErrEffortWithTools
- type ErrForcedToolUseWithThinking
- type ErrReasoningOffUnsupported
- type ErrThinkingBudgetUnsupported
- type ErrThinkingRequiresStream
- type Mechanism
- type OffWire
- type OpenAIReasoningCaps
- type Provider
Constants ¶
const ClaudeMinThinkingBudget = 1024
ClaudeMinThinkingBudget is the smallest budget_tokens Anthropic accepts.
const ClaudeThinkingTopPFloor = 0.95
ClaudeThinkingTopPFloor is the lowest top_p Anthropic accepts while the model is thinking.
const OpenAIDisableEffort = "none"
OpenAIDisableEffort turns thinking off on the wire. It is not llms.ReasoningNone, which is the empty string and instead omits the field.
Variables ¶
This section is empty.
Functions ¶
func AcceptsEffortWire ¶
AcceptsEffortWire reports whether the model's OpenAI-compatible door takes the reasoning_effort field. A door that refuses it fails the whole request, so such a model also has no way to spell "off": the disable token rides on this field.
func BedrockSupportsStructuredOutput ¶
BedrockSupportsStructuredOutput reports whether the AWS model card of a non-Claude Bedrock model lists structured outputs for the bedrock-runtime endpoint. Claude follows ClaudeSupportsStructuredOutputOnBedrock.
func ChatToolsUnsupported ¶
ChatToolsUnsupported reports whether the vendor serves no function tools for the model on /chat/completions. OpenAI states it for GPT-6 Astra: tools ride on the responses API only, and the model has no effort level that turns thinking off to trade for them.
func ClaudeClampBudget ¶
ClaudeClampBudget raises a budget below the vendor floor up to it, and leaves every other model and a zero budget untouched.
func ClaudeClampEffort ¶
ClaudeClampEffort moves an effort the model does not accept on the provider to the nearest one it does: down to the highest accepted level below it, or up to the lowest accepted level when every one of them is higher. An unclassified model and an unknown level pass through unchanged.
func ClaudeEffortsFor ¶
ClaudeEffortsFor returns the effort levels the model's generation accepts on the given provider, or nil for a model this package does not classify.
func ClaudeInterleavesOnBudget ¶
ClaudeInterleavesOnBudget reports whether budget thinking on the model interleaves with tool calls once the interleaved-thinking beta is on.
func ClaudeKeepsTopPWhileThinking ¶
ClaudeKeepsTopPWhileThinking reports whether the caller's top_p survives on the wire once the model is thinking.
func ClaudeMaxTokensForBudget ¶
ClaudeMaxTokensForBudget returns a ceiling that still leaves the answer room once the budget is spent.
func ClaudeMutuallyExclusiveSampling ¶
ClaudeMutuallyExclusiveSampling reports whether the model returns a 400 when temperature and top_p are set together, so the caller must send at most one.
func ClaudePredatesAdaptive ¶
ClaudePredatesAdaptive reports whether the model is a known pre-adaptive Claude generation, so an adaptive request must be gated (not sent verbatim) rather than optimistically forwarded the way a genuinely newer, unclassified model is.
func ClaudeRejectsAssistantPrefill ¶
ClaudeRejectsAssistantPrefill reports whether the model rejects a prefilled assistant response outright, so the request must not be sent.
func ClaudeRejectsSampling ¶
ClaudeRejectsSampling reports whether the model rejects temperature/top_p outright, so sampling params must be dropped even when no thinking is requested.
func ClaudeSpendsThinkingBudget ¶
ClaudeSpendsThinkingBudget reports whether the model pays for thinking out of a budget that the answer limit has to exceed.
func ClaudeSupportsEffortWithBudget ¶
ClaudeSupportsEffortWithBudget reports whether the model accepts output_config.effort together with manual (budget) thinking on the given provider.
func ClaudeSupportsStructuredOutput ¶
ClaudeSupportsStructuredOutput reports whether the model can be asked for schema constrained output. Known-legacy families are rejected; every current model and any unrecognized (newer) name passes through so the provider API stays the final arbiter and the local table never blocks a future model.
func ClaudeSupportsStructuredOutputOnBedrock ¶
ClaudeSupportsStructuredOutputOnBedrock reports whether Amazon Bedrock serves schema constrained output for the Claude model.
func ClaudeSupportsThinking ¶
ClaudeSupportsThinking reports whether the model is a known extended-thinking Claude generation (any tier except Unknown).
func ClaudeThinkingAlwaysOn ¶
ClaudeThinkingAlwaysOn reports whether the model's thinking cannot be disabled, so an explicit disable has to be refused rather than sent.
func ClaudeThinkingDefaultsOn ¶
ClaudeThinkingDefaultsOn reports whether the model thinks when thinking is omitted, so disabling it requires an explicit disable rather than omission.
func ClaudeThinkingObjectRoute ¶
ClaudeThinkingObjectRoute reports whether a Claude name on an OpenAI-shaped door is bare or carries a LiteLLM route that passes Anthropic's thinking object on to a vendor that documents it.
func DashScopeBudgetSharesAnswerLimit ¶
DashScopeBudgetSharesAnswerLimit reports whether the model's thinking budget counts against max_tokens together with the answer.
func DashScopeGuestThinkingEnabledByFlag ¶
DashScopeGuestThinkingEnabledByFlag reports whether a guest model DashScope serves leaves its thinking off until enable_thinking:true asks for it.
func DashScopeRoute ¶
DashScopeRoute returns the name the rules read for a model sent to host: a name sent to Model Studio's own host reads as its dashscope/ route.
func DashScopeTakesNoTopK ¶
DashScopeTakesNoTopK reports whether DashScope serves the model from a family that takes no top_k.
func DashScopeTakesThinkingBudget ¶
DashScopeTakesThinkingBudget reports whether DashScope caps the model's thinking by a token budget.
func DefaultIsReasoningModel ¶
DefaultIsReasoningModel provides the default reasoning model detection logic. This can be used by LLM implementations that want to extend rather than replace the default detection logic.
func FixesSampling ¶
FixesSampling reports whether the model runs on fixed temperature, top_p and penalties, so any value the caller sets for them stays off the wire.
func GeminiAcceptsMinimalLevel ¶
GeminiAcceptsMinimalLevel reports whether the model takes thinking_level MINIMAL. A name this package has not measured reports false and falls back to LOW, so extending this set means measuring first, not guessing.
func GeminiBudgetRange ¶
GeminiBudgetRange returns the thinking_budget bounds the vendor documents for the model. An unknown model reports no bounds.
func GeminiCanDisable ¶
GeminiCanDisable reports whether thinking can be turned off at all; ResolveOff decides the wire. Unclassified Google models are treated as disablable, so a model this package has not seen is attempted rather than refused.
func GeminiSupportsThinking ¶
GeminiSupportsThinking reports whether the model belongs to a Google thinking family: Gemini 2.5, Gemini 3.x, or Gemma 4.
func GeminiThinkingOffByDefault ¶
GeminiThinkingOffByDefault reports whether the model leaves thinking off until asked, so omitting the thinking config already yields "off".
func GeminiTogglesThinkingByLevel ¶
GeminiTogglesThinkingByLevel reports whether the model expresses thinking as on or off through thinking_level alone, with no budget and no level between. Kept apart from GeminiUsesThinkingLevel, which also turns on the Gemini 3 thought-signature placeholder.
func GeminiUsesThinkingLevel ¶
GeminiUsesThinkingLevel reports whether the model uses the qualitative thinking_level control (Gemini 3.x), where thinking_budget is deprecated, instead of a token budget. Gemini 3 also recommends running at temperature 1.0.
func GptOssEffort ¶
func GptOssEfforts ¶
func GptOssEfforts() []string
func GrokEffort ¶
GrokEffort maps a requested effort onto what the model accepts. Only the generations that kept none can carry it; a request to disable a model that always reasons leaves the field off the wire rather than inventing a level.
func GroupByToolCalls ¶
GroupByToolCalls splits blocks by where they sit in a turn with toolCalls tool calls: group 0 opens the turn and group i follows tool call i-1. A block placed past the turn's last tool call closes it.
func IsBedrockAlwaysReasoningModel ¶
IsBedrockAlwaysReasoningModel reports whether the Bedrock family reasons on every request and takes no thinking configuration alongside it.
func IsBedrockNonReasoningModel ¶
IsBedrockNonReasoningModel reports whether the model is in bedrockNonReasoningModels: Bedrock models whose AWS model card lists neither reasoning support nor a request field that controls it.
func IsGptOssModel ¶
IsGptOssModel reports whether the Bedrock model is one of OpenAI's gpt-oss models.
func IsGrokModel ¶
IsGrokModel reports whether the Bedrock model belongs to the xAI Grok family.
func IsNovaReasoningModel ¶
IsNovaReasoningModel reports whether the Bedrock model takes Amazon Nova's reasoningConfig.
func IsReasoningModel ¶
IsReasoningModel returns true if the model is a reasoning/thinking model. This includes OpenAI o1/o3/GPT-5 series, Anthropic Claude 3.7+, DeepSeek reasoner, etc. For runtime checking of LLM instances, use SupportsReasoningModel instead.
func LikelyReasoningModel ¶
LikelyReasoningModel reports whether a model probably reasons: everything IsReasoningModel knows, plus any name from a family whose current generations reason and which is not a known pre-reasoning generation.
For UI hints only. Wire paths keep using IsReasoningModel.
func NovaEffort ¶
func NovaEfforts ¶
func NovaEfforts() []string
func OllamaEffortsFor ¶
OllamaEffortsFor returns the think levels a model takes on the ollama door; nil when Ollama documents no level set for that model.
func OpenAIThinkingOptIn ¶
OpenAIThinkingOptIn reports the generations that reason only when an effort asks them to.
func QwenThinkingEnabledByFlag ¶
QwenThinkingEnabledByFlag reports whether DashScope leaves the model's thinking off until enable_thinking:true asks for it.
func QwenThinkingOffByFlag ¶
QwenThinkingOffByFlag reports whether the model thinks until enable_thinking false asks it to stop.
func QwenThinkingRequiresStream ¶
QwenThinkingRequiresStream reports whether DashScope serves the model's thinking only on a streaming call.
func RejectsMinP ¶
RejectsMinP reports whether min_p must stay off the wire.
func RejectsPenalties ¶
RejectsPenalties reports whether frequency_penalty and presence_penalty must stay off the wire.
func RejectsRepetitionPenalty ¶
RejectsRepetitionPenalty reports whether repetition_penalty must stay off the wire.
func RejectsSamplingWhileThinking ¶
RejectsSamplingWhileThinking reports whether a thinking request must travel without the caller's temperature and top_p.
func RejectsTopK ¶
RejectsTopK reports whether top_k must stay off the wire.
func ReplaysEmptyReasoning ¶
ReplaysEmptyReasoning reports whether an earlier assistant turn with no reasoning to give back still carries reasoning_content, as an empty string. In thinking mode DeepSeek refuses (400) an assistant turn after the last user message that lacks the field, unless the turn's tool call ID is one DeepSeek issued, whose reasoning it then restores on its side. Its own thinking turns can come back with an empty reasoning, and a caller may rewrite the IDs or build the turn. The empty string stops that restore, so a caller that drops the reasoning of such a turn loses it; before the last user message DeepSeek restores nothing.
func ReplaysReasoningOnEveryTurn ¶
ReplaysReasoningOnEveryTurn reports whether reasoning_content goes back on every earlier assistant turn, not only on the turns that called a tool.
func ReplaysThinkingInContent ¶
ReplaysThinkingInContent reports, for a model Mistral serves, whether its earlier assistant turns take their reasoning back, which they take only as a thinking chunk at the head of content, on every turn.
func ResolveClaudeAdaptive ¶
ResolveClaudeAdaptive returns whether to send adaptive thinking (true) or budget thinking (false) for a Claude model, given the caller's preference (adaptivePreferred is true when the caller used WithAdaptiveReasoning).
The rule is deterministic and honors the caller's preference whenever the model supports it, falling back only where the preferred mechanism would be rejected:
- AdaptiveOnly → always adaptive (budget would 400).
- BudgetOnly → always budget (adaptive would 400).
- AdaptiveAndBudget / Unknown → the caller's preference, unchanged.
So a currently-accepted call keeps its mechanism; only a currently-rejected (400) combination is redirected to the mechanism the model accepts.
func ServedByDeepSeek ¶
func ServedByMistral ¶
ServedByMistral reports whether the name is one only Mistral's endpoint uses: a Mistral family, or GLM spelled the way Mistral lists it (glm-5-2, zai-glm-5-2), bare or behind LiteLLM's mistral/ prefix.
func SplitContent ¶
func TakesNoJSONObject ¶
func TakesNoJSONSchema ¶
TakesNoJSONSchema reports whether the vendor's chat completions response_format takes only text and json_object, so a JSON schema cannot be asked for.
func TakesNoResponseFormat ¶
func TakesNoThinkingDepth ¶
TakesNoThinkingDepth reports whether the model's own door takes neither a thinking budget nor an effort level.
func TakesNoTopK ¶
func ThinkingMarkedInName ¶
ThinkingMarkedInName reports whether the model name selects a routing variant that already runs with thinking on, not merely a model capable of thinking.
func ThinkingOptIn ¶
ThinkingOptIn reports whether the model reasons only when a request asks it to.
func UsesLegacyMaxTokens ¶
UsesLegacyMaxTokens reports whether the output limit must travel as max_tokens rather than max_completion_tokens.
Types ¶
type Block ¶
type Block struct {
Text string `json:"text,omitempty"`
Signature []byte `json:"signature,omitempty"`
Redacted []byte `json:"redacted,omitempty"`
// AfterToolCalls counts the tool calls the vendor put ahead of this block in
// the same response.
AfterToolCalls int `json:"after_tool_calls,omitempty"`
}
Block is one reasoning block as the vendor produced it: readable text with the signature that covers it, or encrypted data, never both.
type ChunkContentSplitter ¶
type ChunkContentSplitter interface {
Split(chunk string) (string, string)
GetState() ChunkContentSplitterState
}
func NewChunkContentSplitter ¶
func NewChunkContentSplitter() ChunkContentSplitter
type ChunkContentSplitterState ¶
type ChunkContentSplitterState int
const ( ChunkContentSplitterStateText ChunkContentSplitterState = iota ChunkContentSplitterStateReasoning )
type ClaudeReasoningKind ¶
type ClaudeReasoningKind int
ClaudeReasoningKind classifies how a Claude model accepts extended thinking. It is the single source of truth for adaptive-vs-budget thinking and whether sampling params are permitted, so every provider path resolves the wire shape the same way instead of re-deriving it from scattered model-string checks.
const ( // ClaudeReasoningUnknown is any model not explicitly classified below — a // non-Claude model, a Claude model without extended thinking, or a Claude // generation newer than this table. It is handled as literal pass-through // (the caller's requested mechanism is sent unchanged), preserving prior // behavior so an unclassified model never regresses. ClaudeReasoningUnknown ClaudeReasoningKind = iota // ClaudeReasoningAdaptiveOnly is the newest generation (Opus 4.7/4.8/5, // Sonnet 5, Fable 5, Mythos 5): it is sent thinking.type=adaptive and never // budget_tokens. ClaudeReasoningAdaptiveOnly // ClaudeReasoningAdaptiveAndBudget accepts both adaptive and budget thinking // (Opus 4.6, Sonnet 4.6, Mythos Preview). ClaudeReasoningAdaptiveAndBudget // ClaudeReasoningBudgetOnly is the extended-thinking generation before // adaptive existed (Opus 4.5, Sonnet 4.5, Haiku 4.5): it accepts // thinking.type=enabled + budget_tokens and rejects adaptive. ClaudeReasoningBudgetOnly )
func ClaudeReasoningKindFor ¶
func ClaudeReasoningKindFor(model string) ClaudeReasoningKind
ClaudeReasoningKindFor classifies a Claude model string. Matching is case-insensitive and substring-based so provider/region prefixes and -vN:0 suffixes do not affect the result.
type Collector ¶
type Collector struct {
// contains filtered or unexported fields
}
Collector gathers the reasoning blocks of one response in the vendor's order.
func (*Collector) Reasoning ¶
func (c *Collector) Reasoning() *ContentReasoning
type ContentReasoning ¶
type ContentReasoning struct {
// Content is the reasoning content of the assistant message before the final answer.
Content string `json:"content,omitempty"`
// Signature is the signature of the reasoning contents.
Signature []byte `json:"signature,omitempty"`
// Blocks, when set, is what travels back to the vendor; Content then only
// mirrors their text.
Blocks []Block `json:"blocks,omitempty"`
}
func FromBlocks ¶
func FromBlocks(blocks []Block) *ContentReasoning
FromBlocks builds the reasoning of one response. A lone plain block that no tool call precedes comes back as Content and Signature with no Blocks, so read blocks through Sequence.
func SplitContentWithReasoning ¶
func SplitContentWithReasoning(content string) (*ContentReasoning, string)
func (*ContentReasoning) HasContent ¶
func (r *ContentReasoning) HasContent() bool
HasContent reports whether the model actually reasoned.
func (*ContentReasoning) IsEmpty ¶
func (r *ContentReasoning) IsEmpty() bool
IsEmpty reports whether there is nothing to carry back into the next turn.
func (*ContentReasoning) MarshalJSON ¶
func (r *ContentReasoning) MarshalJSON() ([]byte, error)
func (*ContentReasoning) Sequence ¶
func (r *ContentReasoning) Sequence() []Block
func (*ContentReasoning) String ¶
func (r *ContentReasoning) String() string
func (*ContentReasoning) UnmarshalJSON ¶
func (r *ContentReasoning) UnmarshalJSON(data []byte) error
type EffortToolsRule ¶
type EffortToolsRule int
EffortToolsRule reports what to do with reasoning_effort when function tools ride on the same request.
const ( EffortToolsFree EffortToolsRule = iota EffortToolsOmit EffortToolsDisable )
func EffortWithTools ¶
func EffortWithTools(model string) EffortToolsRule
EffortWithTools reports the rule for a model. An unlisted generation stays free.
type ErrAssistantPrefillUnsupported ¶
type ErrAssistantPrefillUnsupported struct{ Model string }
ErrAssistantPrefillUnsupported reports that the model rejects a conversation ending with an assistant turn.
func (*ErrAssistantPrefillUnsupported) Error ¶
func (e *ErrAssistantPrefillUnsupported) Error() string
type ErrChatToolsUnsupported ¶
type ErrChatToolsUnsupported struct {
Model string
}
ErrChatToolsUnsupported reports a request that carries function tools for a model whose chat completions endpoint does not serve them.
func (*ErrChatToolsUnsupported) Error ¶
func (e *ErrChatToolsUnsupported) Error() string
type ErrEffortHasNoBudget ¶
ErrEffortHasNoBudget reports that reasoning was asked for with an effort that does not map to a token budget, on a model whose only thinking wire is one.
func (*ErrEffortHasNoBudget) Error ¶
func (e *ErrEffortHasNoBudget) Error() string
type ErrEffortWithTools ¶
func (*ErrEffortWithTools) Error ¶
func (e *ErrEffortWithTools) Error() string
type ErrForcedToolUseWithThinking ¶
type ErrForcedToolUseWithThinking struct{ Model string }
ErrForcedToolUseWithThinking reports that a forced tool choice was combined with manual (budget) thinking.
func (*ErrForcedToolUseWithThinking) Error ¶
func (e *ErrForcedToolUseWithThinking) Error() string
type ErrReasoningOffUnsupported ¶
type ErrReasoningOffUnsupported struct{ Model string }
ErrReasoningOffUnsupported is returned when reasoning is explicitly disabled (WithReasoningDisabled) on a model whose thinking cannot be turned off.
func (*ErrReasoningOffUnsupported) Error ¶
func (e *ErrReasoningOffUnsupported) Error() string
type ErrThinkingBudgetUnsupported ¶
type ErrThinkingBudgetUnsupported struct{ Model string }
ErrThinkingBudgetUnsupported reports a thinking budget asked of a model that TakesNoThinkingDepth.
func (*ErrThinkingBudgetUnsupported) Error ¶
func (e *ErrThinkingBudgetUnsupported) Error() string
type ErrThinkingRequiresStream ¶
type ErrThinkingRequiresStream struct{ Model string }
ErrThinkingRequiresStream reports thinking asked of a stream-only model without a stream.
func (*ErrThinkingRequiresStream) Error ¶
func (e *ErrThinkingRequiresStream) Error() string
type Mechanism ¶
type Mechanism int
Mechanism is how a model thinks on one request.
func ResolveMechanism ¶
ResolveMechanism picks the thinking mechanism for a model the caller asked to think. claudeFamily and reasons are the door's own answers: whether the id belongs to Anthropic on that platform, and whether the door treats the model as a reasoning model at all. A family with no mechanism of its own resolves to MechanismNone and the request travels without a thinking configuration.
type OffWire ¶
type OffWire int
OffWire is how a provider expresses "thinking off" for a given model. It is the single decision point shared by every adapter, keyed off the same model tables the enable path uses, so Off and On can never classify a model differently.
const ( // OffOmit sends no reasoning field: the model does not think by default (or the // provider needs no explicit signal), so omitting already yields "off". OffOmit OffWire = iota // OffDisableClaude → Anthropic thinking:{type:"disabled"}. OffDisableClaude // OffZeroBudget → Google thinkingBudget:0. OffZeroBudget // OffMinimalLevel → Google thinking_level:"minimal". OffMinimalLevel // OffEffortNone → OpenAI reasoning_effort:"none". OffEffortNone // OffDisableDashScope → DashScope enable_thinking:false. OffDisableDashScope // OffDisableThinkingObject → thinking:{type:"disabled"} on an OpenAI-shaped door. OffDisableThinkingObject // OffDisableThinkBool → Ollama think:false. OffDisableThinkBool // OffUnsupported: a known mandatory-thinking model that cannot be disabled // (adaptive-only Claude, OpenAI o-series). The adapter returns a typed error. OffUnsupported )
func ResolveOff ¶
ResolveOff decides how to disable thinking for a model on a provider, from the same capability tables the enable path reads. Unknown models get the provider's best-effort disable wire rather than a silent omit, so a caller's explicit "off" is honored wherever the provider can honor it.
type OpenAIReasoningCaps ¶
type OpenAIReasoningCaps struct {
// Known reports whether the model was explicitly classified.
Known bool
// CanDisable reports whether the model accepts reasoning_effort "none".
CanDisable bool
// Efforts are the accepted effort levels in ascending order, excluding "none";
// nil when unknown.
Efforts []string
}
OpenAIReasoningCaps is a best-effort static projection of which reasoning efforts a model reachable on an OpenAI-compatible door accepts, so callers avoid sending a value the API would reject with a 400. It asserts only documented, non-default constraints; every other model returns Known=false and is treated optimistically (send as requested, let the API be the arbiter), preserving prior pass-through behavior.
func OpenAIReasoningCapsFor ¶
func OpenAIReasoningCapsFor(model string) OpenAIReasoningCaps
OpenAIReasoningCapsFor classifies a reasoning model by the effort set its generation accepts on /chat/completions. A model outside the listed generations (including newer ones) returns Known=false so the caller stays optimistic and the API arbitrates.
func (OpenAIReasoningCaps) ClampEffort ¶
func (c OpenAIReasoningCaps) ClampEffort(effort string) string
ClampEffort moves a requested effort to one the model accepts: above the ceiling drops to the ceiling, below the floor rises to the floor, and anything the set does not list steps down to the nearest level it does. Unknown models and efforts outside the scale are returned unchanged.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
cmd/anthropicmodels
command
Command anthropicmodels refreshes the committed Anthropic listing snapshot read by the drift test.
|
Command anthropicmodels refreshes the committed Anthropic listing snapshot read by the drift test. |
|
cmd/mistralmodels
command
Command mistralmodels refreshes the committed Mistral listing snapshot read by the drift test.
|
Command mistralmodels refreshes the committed Mistral listing snapshot read by the drift test. |
|
cmd/modelsdev
command
Command modelsdev refreshes the committed models.dev snapshot read by the drift test.
|
Command modelsdev refreshes the committed models.dev snapshot read by the drift test. |