Module: Legion::Extensions::Llm::Bedrock::ThinkingModes
- Defined in:
- lib/legion/extensions/llm/bedrock/thinking_modes.rb
Overview
Single source of truth for how each Bedrock model expresses extended thinking on the wire. Shared by both the Provider (invoke_model / converse paths) and the Translator (canonical render path) so the two never diverge.
Bedrock supports exactly one thinking wire shape for Anthropic Claude:
{ type: 'enabled', budget_tokens: N } (native Anthropic Messages API)
There is NO Bedrock Claude model that accepts { type: 'adaptive' } —
sending adaptive raises ValidationException: adaptive thinking is not supported on this model (observed live on opus-4-5) and surfaces as an
HTTP 500. So a model either supports budgeted thinking (emit enabled)
or it does not (OMIT the thinking field entirely — never adaptive).
Budgeted extended thinking arrived with Claude 3.7 Sonnet and is
supported across the entire Claude 4 family (sonnet-4, opus-4.x,
haiku-4.5). The match is a substring so it tolerates the many Bedrock
model-id decorations (geo prefixes us./eu./ap., anthropic.
provider prefix, -vN:0 version suffixes, :200k context suffixes).
Constant Summary collapse
- BUDGETED_THINKING_FRAGMENTS =
Model-id fragments for Claude families that support explicit budgeted extended thinking via { type: 'enabled', budget_tokens: N }.
%w[ claude-3-7-sonnet claude-sonnet-4 claude-opus-4 claude-haiku-4 ].freeze
Class Method Summary collapse
-
.budgeted_thinking?(model_id) ⇒ Boolean
True when the model supports { type: 'enabled', budget_tokens: N }.
-
.known_non_thinking?(model_id) ⇒ Boolean
Distinct from
!budgeted_thinking?: a nil/blank/unknown model id is NOT known-unsupported — we then honor an explicit thinking request and emit the (safe)enabledshape rather than dropping it.
Class Method Details
.budgeted_thinking?(model_id) ⇒ Boolean
Returns true when the model supports { type: 'enabled', budget_tokens: N }.
39 40 41 42 43 44 45 46 |
# File 'lib/legion/extensions/llm/bedrock/thinking_modes.rb', line 39 def budgeted_thinking?(model_id) return false if model_id.nil? || model_id.to_s.strip.empty? mid = model_id.to_s # Substring scan (String#include?), NOT array intersection: intersect? # raises TypeError on a String argument. BUDGETED_THINKING_FRAGMENTS.any? { |fragment| mid.include?(fragment) } end |
.known_non_thinking?(model_id) ⇒ Boolean
Distinct from !budgeted_thinking?: a nil/blank/unknown model id is
NOT known-unsupported — we then honor an explicit thinking request and
emit the (safe) enabled shape rather than dropping it. The router's
capability filter (fed by the shared catalog) is the real guard that
keeps thinking requests off non-thinking models; this method only
strips thinking for a positively-identified non-thinking Claude model
so we never emit an unsupported shape and 500.
56 57 58 59 60 |
# File 'lib/legion/extensions/llm/bedrock/thinking_modes.rb', line 56 def known_non_thinking?(model_id) return false if model_id.nil? || model_id.to_s.strip.empty? !budgeted_thinking?(model_id) end |