NAME

Langertha::Role::ReasoningEffort - Role for an engine with a request-side reasoning-effort control

VERSION

version 0.505

reasoning_effort

Normalized request-side reasoning effort. Vocabulary (the OpenAI superset): none, minimal, low, medium, high, xhigh, max. When set, it is translated to the provider-specific wire field via Langertha::Reasoning keyed by "reasoning_wire_format"; values the target wire cannot accept are dropped. When not set, no reasoning field is emitted and the model's own default applies.

Note this is a request-side control, distinct from Langertha::Role::ThinkTag (which filters <think> tags out of responses).

thinking_budget

Optional integer thinking budget, currently consumed only by Gemini 2.5 models (Langertha::Engine::Gemini): on gemini-2.5-* the value is emitted as generationConfig.thinkingConfig.thinkingBudget. On Gemini 3 and Gemini 4 models thinking_budget is rejected — they take thinkingLevel, not the integer budget (Gemini 4 on Vertex answers a budget with HTTP 400); a thinking_budget on such a model croaks before the request is built ("BUILD" in Langertha::Reasoning), and is never sent. When unset, no budget field is emitted. (Anthropic legacy budget_tokens is deliberately not modeled: it 400s on current Claude families.)

thinking_enabled

Optional explicit thinking on/off switch without an effort level (karr k382), for servers whose chat template takes a boolean (enable_thinking on llama.cpp, SGLang and other chat_template_kwargs endpoints). Tri-state: unset (the default, nothing sent), 0 or 1.

0 means the same as reasoning_effort => 'none' on every wire, and so it cannot disable thinking where effort none cannot: Gemini 3/4 raise it to their floor level, OpenAI and Responses models without none (gpt-6, legacy gpt-5) drop it, GPT-OSS on Ollama raises it to low. On a Gemini 2.5 model (thinking budget, no effort) it is dropped with a carp, once per engine; a "thinking_budget" there still goes out.

1 without a "reasoning_effort" is sent only on the chat_template_kwargs wire (enable_thinking => true), on the thinking-toggle endpoints (MiniMax, Kimi: the model's on-type), on DeepSeek V3.x (thinking enabled) and on native Ollama (think => true, not GPT-OSS); on every other wire nothing is sent and the engine carps once.

It is the same concern as "reasoning_effort". Within one layer the two must agree -- thinking_enabled => 0 with an effort other than none, or thinking_enabled => 1 with none, croaks: for the engine attributes at construction, for the per-request controls when the request is built ("assert_switch_agrees" in Langertha::Reasoning). Across layers a per-request control (chat_f) carrying either reasoning_effort or thinking_enabled replaces both engine attributes, so reasoning_effort => 'high' on the engine plus a per-request thinking_enabled => 0 turns thinking off without a croak.

thinking_display

Optional Anthropic thinking-visibility control (summarized | omitted | updates), serialized by "to_anthropic" in Langertha::Reasoning to thinking.display. On every current Claude model the wire default is omitted, which returns an empty $response->thinking; set thinking_display => 'summarized' to get a readable reasoning summary back (it costs summary tokens, so it is opt-in rather than the Langertha default). Ignored on non-Anthropic wires and on Fable-class models (which never carry a thinking block). Like "reasoning_effort", a per-request control (chat_f) beats this attribute.

reasoning_wire_format

reasoning_wire_format => 'anthropic'

The per-engine enum naming which reasoning dialect this engine speaks — openai | anthropic | gemini | responses | chat_template_kwargs (ollama exists on "to" in Langertha::Reasoning but the native Ollama engine calls it directly). Drives the value-object dispatch in "reasoning_kwargs". The default follows the engine base-class hierarchy: OpenAIBase leaves it at openai, AnthropicBase overrides to anthropic, Gemini to gemini, OpenAIResponses to responses, LlamaCpp and SGLang to chat_template_kwargs ("to_chat_template_kwargs" in Langertha::Reasoning).

Any other OpenAI-compatible engine opts in at construction, e.g. for a self-hosted server behind a generic base URL whose chat template reads enable_thinking:

my $engine = Langertha::Engine::OpenAI->new(
    url                   => 'http://gpu-box:8000/v1',
    api_key               => 'unused',
    model                 => 'Qwen/Qwen3-32B',
    reasoning_wire_format => 'chat_template_kwargs',
    reasoning_effort      => 'none',
);

The opt-in stays explicit: api.openai.com rejects request fields it does not know, so chat_template_kwargs is never sent by default.

reasoning_kwargs_for

my %kwargs = $engine->reasoning_kwargs_for( effort => 'high' );
my %kwargs = $engine->reasoning_kwargs_for( %$controls );

Returns the body kwargs to merge into a chat request for the reasoning control, serialized for "reasoning_wire_format" via Langertha::Reasoning. %args may carry effort, thinking_enabled, thinking_budget and/or thinking_display (or the canonical control name reasoning_effort, so the whole controls hash from chat_f can be passed wholesale); keys it does not carry fall back to the engine attributes, so a per-request control (chat_f, karr #46) beats the configured attribute. thinking_budget and thinking_display layer per key; effort and thinking_enabled layer as one concern -- a per-request value for either replaces both attributes (see "thinking_enabled"). A thinking_enabled => 1 without an effort on a wire that cannot carry it is dropped with a carp, once per engine. Empty list when neither a per-request value nor an attribute is set, when the value is unsupported on the engine's wire, or when the engine advertises neither reasoning_effort nor thinking_budget ("supports" in Langertha::Role::Capabilities) -- clearing those flags is how an engine says it takes no reasoning control, and nothing is sent then. Engines override this only to model wire divergence within a shared format (e.g. DeepSeek's model-gated split). An engine whose endpoint speaks the thinking on/off toggle (MiniMax, MiniMaxAnthropic, Moonshot, MoonshotAnthropic) opts in by defining _reasoning_thinking_toggle as true; see "thinking_toggle" in Langertha::Reasoning.

reasoning_kwargs

my %kwargs = $engine->reasoning_kwargs;

Returns the body kwargs to merge into a chat request for the configured reasoning_effort and/or "thinking_budget", serialized for "reasoning_wire_format" via Langertha::Reasoning. Empty list when neither is set, or when the value is unsupported on the engine's wire. Delegates to "reasoning_kwargs_for" with no per-request overrides.

SEE ALSO

SUPPORT

Issues

Please report bugs and feature requests at https://github.com/Getty/langertha/issues.

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <getty@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.