Skip to content

feat(libsy-llm-client): strip rejected extra_body keys on retry #260

Description

@gburachas

Problem

Per-target extra_body keys are merged into the outbound request body in
crates/libsy-llm-client/src/client.rs at a point that sits outside the retry loop, so the merge
happens once, before any attempt.

When an upstream rejects the request because of one of those keys — a 400/422 naming an unknown or
unexpected parameter — every retry re-sends the same rejected key. The retry cannot succeed, and
there is no way for a caller to say "drop this knob and try again".

The case we hit in practice: reasoning-control knobs (chat_template_kwargs, enable_thinking) that
some OpenAI-compatible servers accept and others reject outright. A call carrying the knob fails
permanently against a rejecting server, even though the identical call without it would succeed.

Proposal

Move the extra_body merge inside the retry loop and allow named keys to be dropped after a
parameter rejection. Roughly 20 lines.

Deliberately narrow:

  • Only a 400/422 whose body names the parameter, or an unknown/extra-parameter condition,
    qualifies. A 429 or 5xx must surface as-is — silently stripping a knob and re-firing on a
    rate limit would double the load and mask the real failure.
  • Retry exactly once without the knob. No escalation ladder, no second strip.

Scope

crates/libsy-llm-client/ only. Benefits every route that configures extra_body, which is why it
seems worth doing as its own change rather than inside a feature PR.

Notes

Happy to open the PR. Wanted to check the direction first, since it moves an existing statement
across the retry boundary rather than adding alongside it — if you'd prefer a different shape (e.g.
an explicit per-target "droppable keys" list instead of inferring from the reject), that's easy to
adjust.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions