Skip to content

/v1/messages does not apply request.param_constraints temperature clamp (override block silently no-ops) #335

Description

@moonming

Repro (source-blind, from AISIX-Cloud #302 D3.3 E2E coverage)

  1. Dashboard → Provider Keys → New → Anthropic. Save with requestOverrides.param_constraints.temperature_max = 0.5.
  2. Create a Model on this PK with upstream id claude-3-5-sonnet-20241022.
  3. Issue API key with the model allowlisted.
  4. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions