Repro (source-blind, from AISIX-Cloud #302 D3.3 E2E coverage)
- Dashboard → Provider Keys → New → Anthropic. Save with
requestOverrides.param_constraints.temperature_max = 0.5.
- Create a Model on this PK with upstream id
claude-3-5-sonnet-20241022.
- Issue API key with the model allowlisted.
- POST
/v1/messages to the DP with {model: <alias>, max_tokens: 32, temperature: 0.9, messages:[{role:user, content:'clamp test'}]}.
Expected: outbound HTTP body to Anthropic upstream has temperature: 0.5 (clamped to the configured temperature_max). Same contract as the OpenAI side already pins via adapter-openai-overrides-live.spec.ts:324-343.
Actual: outbound body forwards caller's temperature: 0.9 verbatim. The param_constraints override block validates and persists at cp-api but never applies on outbound for /v1/messages.
Confirmed by audit (independent agent reading ai-gateway source)
crates/aisix-proxy/src/messages.rs lines 138-218 (the Anthropic-upstream dispatch path) builds the outbound req_builder without calling apply_param_constraints on the body.
apply_param_constraints is defined at crates/aisix-provider-openai/src/overrides.rs:95 and IS invoked by the OpenAI chat dispatch path (chat.rs).
- Repo-wide
grep -rn apply_param_constraints aisix-proxy/ returns zero hits.
Impact
Every customer who sets request.param_constraints on an Anthropic ProviderKey expects clamping at the gateway boundary. Today the override is silently dropped on the wire — customers see the same upstream behavior as if the override block didn't exist. This is the same "feature shipped half" pattern as ai-gateway#333 (response.reasoning_field).
Fix scope (DP side, not implementing here)
Mirror the OpenAI dispatch wiring. Roughly:
```rust
// crates/aisix-proxy/src/messages.rs after ~line 196 (before req_builder send):
if let Some(req_overrides) = pk_entry.value.request.as_ref() {
if let Some(constraints) = req_overrides.param_constraints.as_ref() {
aisix_provider_openai::overrides::apply_param_constraints(body, constraints);
}
if let Some(defaults) = req_overrides.default_body_fields.as_ref() {
aisix_provider_openai::overrides::apply_default_body_fields(body, defaults);
}
if let Some(renames) = req_overrides.param_renames.as_ref() {
aisix_provider_openai::overrides::apply_param_renames(body, renames);
}
}
```
(Also extend to apply_default_headers for the header-injection contract — see related issue.)
Audit-suggested: in addition to messages.rs there's likely a parallel call site for responses.rs if the Responses API path is similarly affected.
Related
Repro (source-blind, from AISIX-Cloud #302 D3.3 E2E coverage)
requestOverrides.param_constraints.temperature_max = 0.5.claude-3-5-sonnet-20241022./v1/messagesto the DP with{model: <alias>, max_tokens: 32, temperature: 0.9, messages:[{role:user, content:'clamp test'}]}.Expected: outbound HTTP body to Anthropic upstream has
temperature: 0.5(clamped to the configuredtemperature_max). Same contract as the OpenAI side already pins viaadapter-openai-overrides-live.spec.ts:324-343.Actual: outbound body forwards caller's
temperature: 0.9verbatim. Theparam_constraintsoverride block validates and persists at cp-api but never applies on outbound for/v1/messages.Confirmed by audit (independent agent reading ai-gateway source)
crates/aisix-proxy/src/messages.rslines 138-218 (the Anthropic-upstream dispatch path) builds the outboundreq_builderwithout callingapply_param_constraintson the body.apply_param_constraintsis defined atcrates/aisix-provider-openai/src/overrides.rs:95and IS invoked by the OpenAI chat dispatch path (chat.rs).grep -rn apply_param_constraints aisix-proxy/returns zero hits.Impact
Every customer who sets
request.param_constraintson an Anthropic ProviderKey expects clamping at the gateway boundary. Today the override is silently dropped on the wire — customers see the same upstream behavior as if the override block didn't exist. This is the same "feature shipped half" pattern as ai-gateway#333 (response.reasoning_field).Fix scope (DP side, not implementing here)
Mirror the OpenAI dispatch wiring. Roughly:
```rust
// crates/aisix-proxy/src/messages.rs after ~line 196 (before req_builder send):
if let Some(req_overrides) = pk_entry.value.request.as_ref() {
if let Some(constraints) = req_overrides.param_constraints.as_ref() {
aisix_provider_openai::overrides::apply_param_constraints(body, constraints);
}
if let Some(defaults) = req_overrides.default_body_fields.as_ref() {
aisix_provider_openai::overrides::apply_default_body_fields(body, defaults);
}
if let Some(renames) = req_overrides.param_renames.as_ref() {
aisix_provider_openai::overrides::apply_param_renames(body, renames);
}
}
```
(Also extend to
apply_default_headersfor the header-injection contract — see related issue.)Audit-suggested: in addition to messages.rs there's likely a parallel call site for
responses.rsif the Responses API path is similarly affected.Related
request.param_constraints— RuntimeConfig specresponse.reasoning_field