@@ -127,26 +127,51 @@ def model_supports_top_k?(model)
127127 # Returns true if the InvokeModel protocol should be used for this model.
128128 # `bedrock_use_invoke_model` can be:
129129 # - false / nil → always Converse (default)
130- # - true → InvokeModel for all Anthropic models
130+ # - true → InvokeModel for all verifiably Anthropic models
131131 # - Array → InvokeModel when model.id is in the list
132132 # - Proc/lambda → InvokeModel when the callable returns truthy for model
133+ #
134+ # Vendor verification interacts with the selector in two tiers:
135+ # - Ids that are provably non-Anthropic (a known vendor prefix like amazon./meta.,
136+ # with or without a cross-region geo prefix) are never routed, under any selector —
137+ # the InvokeModel payload is Anthropic Messages format and would be rejected.
138+ # - Ids that cannot be verified either way — chiefly application-inference-profile
139+ # ARNs, whose Model::Info carries no provider_name metadata on the
140+ # assume_model_exists path — are routed when the selector opts in explicitly
141+ # (Array or Proc). An operator naming the exact id IS the verification. Only the
142+ # blanket `true` selector requires positive verification via anthropic_model?,
143+ # because it expresses "all Anthropic models", not "this specific model".
133144 def invoke_model? ( model )
134145 selector = @config . bedrock_use_invoke_model
135146 return false unless selector
136- return false unless anthropic_model ?( model )
147+ return false if non_anthropic_model ?( model )
137148
138149 case selector
139150 when true
140- true
151+ anthropic_model? ( model )
141152 when Array
142153 selector . include? ( model . id )
143154 else
144155 selector . respond_to? ( :call ) ? selector . call ( model ) : false
145156 end
146157 end
147158
148- NON_ANTHROPIC_PREFIXES = %w[ amazon. meta. ai21. cohere. mistral. writer. stability. ] . freeze
149- private_constant :NON_ANTHROPIC_PREFIXES
159+ NON_ANTHROPIC_VENDORS = %w[ amazon meta ai21 cohere mistral writer stability ] . freeze
160+ private_constant :NON_ANTHROPIC_VENDORS
161+
162+ # Matches known non-Anthropic vendor ids in both bare ("amazon.nova-pro-v1:0") and
163+ # cross-region ("us.amazon.nova-pro-v1:0") forms.
164+ NON_ANTHROPIC_PATTERN = /\A (?:[a-z0-9-]+\. )?(?:#{ NON_ANTHROPIC_VENDORS . join ( '|' ) } )\. /
165+ private_constant :NON_ANTHROPIC_PATTERN
166+
167+ # True only when the id provably belongs to a non-Anthropic vendor. ARNs return false:
168+ # they don't encode the vendor, so they are "unverifiable", not "non-Anthropic".
169+ def non_anthropic_model? ( model )
170+ id = model . id . to_s
171+ return false if id . start_with? ( 'arn:' )
172+
173+ NON_ANTHROPIC_PATTERN . match? ( id )
174+ end
150175
151176 def anthropic_model? ( model )
152177 id = model . id . to_s
@@ -163,13 +188,15 @@ def anthropic_model?(model)
163188 # Application-inference-profile ARNs do not encode the underlying vendor in the ARN
164189 # string itself. When available, consult model.metadata[:provider_name] (populated
165190 # by Bedrock::Models for registered foundation models) to confirm the profile is
166- # Anthropic-backed. If that field is absent (e.g. a runtime-only ARN the registry
167- # has never seen), log a warning and refuse to route rather than silently forwarding
168- # an incompatible payload to a non-Anthropic model.
191+ # Anthropic-backed. If that field is absent (e.g. an assume_model_exists chat, whose
192+ # Model::Info carries no registry metadata), log a warning and refuse to route rather
193+ # than silently forwarding an incompatible payload to a non-Anthropic model — the
194+ # operator can still opt in explicitly via an Array or Proc selector (see
195+ # invoke_model?).
169196 return arn_anthropic_model? ( model , id ) if id . start_with? ( 'arn:' )
170197
171198 # Block known non-Anthropic Bedrock vendor prefixes (Nova, Llama, Jurassic, etc.).
172- return false if NON_ANTHROPIC_PREFIXES . any? { | pfx | id . start_with? ( pfx ) }
199+ return false if NON_ANTHROPIC_PATTERN . match? ( id )
173200
174201 provider = model . respond_to? ( :provider ) ? model . provider : nil
175202 provider . to_s == 'anthropic'
0 commit comments