Skip to content

fix(backend): log the call warnings a Provider raises - #425

Merged
willdady merged 1 commit into
mainfrom
fix/411-provider-call-warnings
Aug 6, 2026
Merged

fix(backend): log the call warnings a Provider raises#425
willdady merged 1 commit into
mainfrom
fix/411-provider-call-warnings

Conversation

@willdady

@willdady willdady commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Closes #411

The problem

The AI SDK reports, per call, that a setting it was handed was not honoured. Nothing in Platypus read the array, so an Operator who set Temperature on an Agent running Bedrock — or on a model that rejects sampling parameters via Anthropic direct — was adjusting a control disconnected at the far end. No error, no log line, nothing in the UI.

Concretely, against the pinned versions: Bedrock drops seed, presencePenalty and frequencyPenalty and clamps temperature into 0–1; Anthropic strips temperature, topP and topK on the models that reject sampling parameters; both warn on a model id they don't recognise.

The change

installProviderWarningLogger() points the SDK's warning hook at pino. Each warning becomes one warn line carrying structured fields — provider, model, warningType, feature/setting, details/message — plus a sentence that stands on its own:

WARN: amazon-bedrock (anthropic.claude-opus-4-5-v1:0) does not support seed, so the value set for it was ignored
WARN: amazon-bedrock (anthropic.claude-opus-4-5-v1:0) did not use temperature as given: 1.5 exceeds bedrock maximum of 1.0. clamped to 1.0

The hook is a process global, which is the reason to use it: one call at startup covers the streaming Chat turn, the unattended run, sub-agent runs, title generation and memory extraction, and a generation call site added later needs no wiring. Assigning it displaces the SDK's own process.emitWarning default, so nothing is logged twice — there's a test for that.

Attribution is provider and model only, which is all the hook carries. Correlating a warning back to a run would mean threading async context through every path, and that is the cost the global avoids.

Notes for review

  • Fields, not a stringified object, so an Operator can filter on feature: "did anything drop my temperature?" is the question this exists to answer.
  • The clamp wording is deliberate. Bedrock reports a clamped temperature under the same unsupported type it uses for a parameter it drops, so "does not support temperature: … clamped to 1.0" would contradict itself. A warning carrying details reads "did not use X as given", and a test pins that.
  • The hook fires per model call, not per turn, so a tool-calling loop repeats its lines once a step. Bounded noise — short, fixed text, only written by Providers that are actually dropping something — but worth a second opinion given Nested ZodError serialization turns one failed turn into thousands of log lines #414 and fix(backend): stop one rejected prompt from filling the log #422.
  • Docs ship with the code: the Agents page callout now names the trap and says what to search the log for.

Testing

14 new tests covering each warning variant, a clamped temperature carrying details, several warnings from one call, a call with no provider or model, and silence when there are no warnings — plus SDK-driven cases through generateText and through a streamed ToolLoopAgent (the sub-agent construction). pnpm typecheck, pnpm lint and pnpm test all pass.

🤖 Generated with Claude Code

The AI SDK reports, per call, that a setting it was handed was not
honoured — Bedrock drops seed, presencePenalty and frequencyPenalty and
clamps temperature into 0-1; Anthropic strips temperature, topP and topK
on the models that reject sampling parameters; both warn on a model id
they don't recognise. Nothing read the array, so an Operator tuning an
Agent's Temperature had no way to learn the control was disconnected at
the far end.

Point the SDK's warning hook at pino. The hook is a process global, so
one call at startup covers every generation path there is — the
streaming Chat turn, the unattended run, sub-agent runs, title
generation and memory extraction — and a call site added later needs no
wiring. Attribution is provider and model only, which is what the hook
carries; correlating a warning back to a run would mean threading async
context through every path, and that is the cost the global avoids.

Closes #411

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@willdady
willdady force-pushed the fix/411-provider-call-warnings branch from caa0c1f to 61e93b1 Compare August 6, 2026 11:08
@willdady
willdady merged commit 733b1b1 into main Aug 6, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provider call warnings are discarded, so silently-ignored sampling parameters look like they work

1 participant