Repository navigation
fix(ts): refuse a temperature that is not a list of 3 at construction, as Python does (#502 parity) - #712
Conversation
…, as Python does (NandhaKishorM#502 parity) The decode indexes the temperature by question type. Python's Agent refuses any other shape when it loads (NandhaKishorM#502), naming the value it got. The TypeScript Agent filled a short list with 1.0 per missing type and broadcast a bare number to all three, so a malformed config loaded cleanly and answered with a temperature the checkpoint never shipped, with no warning. Throw "Incompatible model: temperature must be a list of 3 floats" for a list of any other length or a non-list, from the constructor option and from cfg alike. A list of 3 is clamped exactly as before. Passing a bare number was never documented, but it did work before, and it now throws. This is a parity fix; it makes no prediction-accuracy claim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bruce-Yii
left a comment
There was a problem hiding this comment.
The arity-3 check is the right contract. laya/agent.py:451 refuses anything that is not a list or tuple of exactly 3, and 3 is what _decode_answers indexes, so this is parity rather than a new restriction on the TS side. I confirmed the default, the cfg path and the clamp ([100, 0, "2"] → [5, 0.5, 2]) are unchanged, that all four rejection cases in the new test fail on main, and that tsc --noEmit and the full suite are clean.
Two things to settle.
The error message does not match the Python it cites. Python raises:
Incompatible model: '/models/laya-english' temperature must be a list of 3 floats, got [1.3, 0.9]
and this raises:
Incompatible model: temperature must be a list of 3 floats, got [1.3,0.9]
The test asserts "Incompatible model: temperature must be a list of 3 floats" as a substring, but the model path sits between model: and temperature in the Python string, so that substring is not in it. The test therefore pins a message Python never emits. If the model id genuinely is not reachable from the constructor — it takes a provider, not a path — that is a fair reason not to match exactly, and providers.ts:308 and agent.ts:625 both interpolate one, so there may be an id within reach. Otherwise the assertion should be adjusted to the message this actually throws.
rawList.map reintroduces holes. Replacing [0, 1, 2].map((i) => clampTemperature(rawList[i] ?? 1.0)) with rawList.map(...) drops the guarantee that the result is dense, because Array.prototype.map skips holes. With temperature: new Array(3):
main: length=3 hasOwnProperty(2)=true temperature[2]=1 serialises [1,1,1]
this: length=3 hasOwnProperty(2)=false temperature[2]=undefined serialises [null,null,null]
Such a value passes the new arity check and then feeds undefined into the decode — the shape of failure #502 exists to prevent, arriving by a different route. It is not reachable from JSON, so it is narrow, but keeping the indexed form costs nothing:
this.temperature = [0, 1, 2].map((i) => clampTemperature(rawList[i]));Worth noting that #710 and #711, from the same batch, take the opposite position on sparse holes and say so explicitly. This one moves the other way on the same hazard, which suggests it was not a deliberate choice.
Unrelated, but relevant to the parity claim: laya/onnx_agent.py:179 has no base-length check, only the language-override one at :190, so the two Python backends currently disagree with each other on this. Not a blocker here since the PR cites laya/agent.py and that is canonical — but "as Python does" is true of one backend and not yet of the other.
|
Passed checks and merged. Thank you @Divit-aggarwal! It ships in 0.3.22. |
What
The TypeScript
Agentconstructor now throwsIncompatible model: temperature must be a list of 3 floats, got …when the temperature, from thetemperatureoption or fromcfg, is not a list of exactly 3. Python'sAgenthas done this at load since #502.Why
The decode indexes the temperature by question type. Before this change, TS filled a short list with
1.0for each missing type and broadcast a bare number to all three. A malformed config therefore loaded cleanly and answered with a temperature the checkpoint never shipped, with no warning:The
rawList[i] ?? 1.0fallbacks, now unreachable, are removed.Behaviour change to note: a bare number (
temperature: 1.2) used to be broadcast. It was never documented, and Python rejects it, so it now throws too. Every shipped checkpoint'sconfig.jsoncarries a list of 3.How it was verified
The two Python commands are the CI gates; no Python was changed. The new test fails on
mainand passes with this change.Scope
lang-temperature.test.tsRelated: #502 (the Python change).
Written with Claude Code; I've reviewed the change and re-run the verification myself.
🤖 Generated with Claude Code