fix: drop deprecated sampling params and response_format from Anthropic provider config - #377
fix: drop deprecated sampling params and response_format from Anthropic provider config#377ayo0la wants to merge 2 commits into
Conversation
The shipped anthropic provider entry cannot complete a single request
against the real API. Two independent problems, both in providers.json:
1. temperature and top_p were removed on Claude Opus 4.7 and later.
Sending either returns 400 "`temperature` is deprecated for this
model". This affected claude-opus-4-8 and claude-sonnet-5.
claude-haiku-4-5 still accepts both, so it keeps them.
2. response_format {"type": "json_object"} is rejected by the endpoint,
which accepts only "json_schema" — and that in turn requires a strict
flag plus additionalProperties: false set recursively, which
EvaluationData.model_json_schema() does not emit. Setting
structured_output to "none" sends no response_format at all; the
prompt-level JSON instructions and extract_json_from_response's
fence stripping already cover this path.
No code change is needed. OpenAICompatibleProvider.chat() adds
temperature and top_p only when present in options, and skips
response_format when structured_output is "none", so both fixes are
declarative. The per-model keys are kept (as empty objects) rather than
removed because pdf.py and github.py fall back to a hardcoded
{"temperature": 0.1, "top_p": 0.9} when a model is absent from
MODEL_PARAMETERS, which would reintroduce the same 400.
Verified by capturing the outgoing request body for every configured
model: claude-opus-4-8 and claude-sonnet-5 now send neither sampling
parameter nor response_format, claude-haiku-4-5 still sends both
sampling parameters, and the gemini and ollama entries are byte-for-byte
unchanged.
Diagnosis and the live 400 traces are from @sahiee-dev in interviewstreet#373.
Fixes interviewstreet#373
There was a problem hiding this comment.
Thanks for picking this up quickly. The providers.json change is the right direction, but I don't think it's sufficient on its own, the two call sites that actually build the request options don't read the config the same way, so this doesn't fully fix the bug. (Both lines below are outside this diff, which is why I can't leave inline comments on them, flagging here instead.)
pdf.py:94-95 (_call_llm_for_section), indexes directly instead of using .get():
"temperature": model_params["temperature"],
"top_p": model_params["top_p"],With "claude-opus-4-8": {} / "claude-sonnet-5": {} in this PR, MODEL_PARAMETERS["claude-sonnet-5"] is {}, and indexing a missing key on an empty dict raises KeyError. Every per-section PDF extraction call (basics/work/education/skills/projects/awards) would crash locally before it even reaches the API, for exactly the two models this PR targets.
evaluator.py:68-69 (evaluate_resume : the final scoring call, arguably the most important one):
"temperature": self.model_params.get("temperature", 0.5),
"top_p": self.model_params.get("top_p", 0.9),Both .get() calls fall back to non-empty defaults when the key is missing. Since self.model_params is {} for the two affected models, options still ends up with temperature: 0.5, top_p: 0.9 no matter what providers.json says, and OpenAICompatibleProvider.chat() forwards them into the body regardless. I'd expect this to reproduce the exact `temperature` is deprecated for this model 400 on the evaluation call itself.
github.py's generate_projects_json (~line 458) passes model_params straight through as options, so that one call site is correctly fixed by this PR, it's just the other two that don't share that pattern.
Given three call sites read providers.json three different ways (direct index, .get-with-default, passthrough), I'd lean toward moving the guard into OpenAICompatibleProvider.chat() itself in models.py, one choke point where the HTTP body is actually built, so it can't be defeated by whatever a given call site happens to default to upstream. Happy to be wrong if I'm missing something in how MODEL_PARAMETERS gets consumed elsewhere, but the pdf.py crash in particular seems straightforward to repro.
|
Re-verified against the live API today (2026-08-08), in case it helps triage. Native Messages API, sending
OpenAI-compatible endpoint (
One note on why this sets So getting Anthropic onto structured outputs needs a schema-normalisation pass, which seemed like a separate change from this config fix. Glad to open that as a follow-up if you would rather go that route. |
|
Hi I have an Anthropic key so I ran the branch's config on current master (actual @sahiee-dev's review is right on both of his claims. On an uncached resume every section extraction dies immediately with Also found something not mentioned yet: the haiku entry this PR keeps is broken too. haiku does still accept sampling params, but only one at a time, when I sent both, this was the outcome:
Tried all four combinations on FWIW I also tried the chokepoint idea from the review, skip |
The providers.json-only change was not sufficient. Three call sites read MODEL_PARAMETERS three different ways, so config alone cannot fix this: - pdf.py:94-95 indexed model_params directly, raising KeyError for any model with no sampling params configured. Every per-section extraction crashed before reaching the API. - evaluator.py:68-69 used .get() with non-empty defaults, re-adding temperature 0.5 and top_p 0.9 regardless of what providers.json said, so the scoring call still 400d. - github.py passed model_params straight through and was already correct. Move the guard into OpenAICompatibleProvider.chat(), the one chokepoint where the HTTP body is assembled, so no call site can reintroduce the pair by defaulting. top_p is dropped rather than temperature because temperature is what keeps scoring runs reproducible. Non-Anthropic providers are untouched and still receive both. claude-haiku-4-5 shipped both params too and 400s the same way, so all three Anthropic entries now carry temperature only. Verified against the live API by @baghdme: both -> 400, either alone -> 200. Also fixes the two call sites so they forward only configured keys, which removes the KeyError independently of provider choice.
Summary
The shipped
anthropicentry inproviders.jsoncannot complete a single request against the real API. Two independent problems, both config-level:temperature/top_pwere removed on Claude Opus 4.7 and later. Sending either returns400 "temperatureis deprecated for this model". This affectsclaude-opus-4-8andclaude-sonnet-5.claude-haiku-4-5predates the removal and still accepts both, so it keeps them.response_format: {"type": "json_object"}is rejected by the endpoint, which accepts only"json_schema"— and that in turn requires astrictflag plusadditionalProperties: falseset recursively, whichEvaluationData.model_json_schema()does not emit.Fix
Four lines in
providers.json. No code change is needed:OpenAICompatibleProvider.chat()addstemperature/top_ponly when they are present inoptions, so omitting them from the per-model config omits them from the request body.response_formatentirely whenstructured_outputis"none". The prompt-level JSON instructions plusextract_json_from_response's fence stripping already cover that path.Keeping the fix declarative avoids threading a new provider-level boolean through
config.provider_for()→llm_utils.initialize_llm_provider()→OpenAICompatibleProvider.The per-model keys are kept as empty objects rather than deleted.
pdf.py:73andgithub.py:377fall back to a hardcoded{"temperature": 0.1, "top_p": 0.9}when a model is absent fromMODEL_PARAMETERS, so removing the entries would reintroduce the identical 400.Testing
Captured the outgoing
chat/completionsbody for every configured model by stubbingrequests.post, so the request shape is observed rather than inferred:claude-opus-4-8claude-sonnet-5claude-haiku-4-5gemini-2.5-flashjson_schemagemma3:4bjson_schemaThe
geminiandollamaentries are unchanged, confirming no regression to the working providers.providers.jsonvalidates as JSON.I do not have an Anthropic key to run
score.pyend to end; @sahiee-dev confirmed in #373 that a full run completes against realclaude-sonnet-5once these two changes are in place.Credit
Diagnosis, the live 400 traces, and the end-to-end confirmation are @sahiee-dev's in #373. I confirmed the sampling-parameter half independently and implemented it as a config-only change. Claimed in this comment before starting.
Fixes #373