Skip to content

fix(ts): refuse a temperature that is not a list of 3 at construction, as Python does (#502 parity) - #712

Merged
NandhaKishorM merged 1 commit into
NandhaKishorM:mainfrom
Divit-aggarwal:fix/ts-temperature-list-of-three
Sep 29, 2026
Merged

NandhaKishorM merged 1 commit into
NandhaKishorM:mainfrom
Divit-aggarwal:fix/ts-temperature-list-of-three

Conversation

@Divit-aggarwal

Copy link
Copy Markdown
Contributor

What

The TypeScript Agent constructor now throws Incompatible model: temperature must be a list of 3 floats, got … when the temperature, from the temperature option or from cfg, is not a list of exactly 3. Python's Agent has 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.0 for 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:

new Agent({ provider, temperature: [1.3, 0.9] });
// before: constructs; score/noul silently decode at temperature 1.0 for the missing entry
// after:  Incompatible model: temperature must be a list of 3 floats, got [1.3,0.9]

The rawList[i] ?? 1.0 fallbacks, 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's config.json carries a list of 3.

How it was verified

cd laya-ts
npx tsc -p tsconfig.json --noEmit   # exit 0
npm test -- --run                   # 23 files, all tests passed
npm run test:package                # package test passed
cd ..
ruff check laya/ --select=E9,F63,F7,F82,F401,F811 --line-length=120   # All checks passed
python -m compileall -q laya/ tests/                                   # exit 0

The two Python commands are the CI gates; no Python was changed. The new test fails on main and passes with this change.

Scope

  • TypeScript only: the constructor check and one test in lang-temperature.test.ts
  • A list of 3 is clamped exactly as before
  • Parity fix only. No prediction-accuracy claim is made

Related: #502 (the Python change).

Written with Claude Code; I've reviewed the change and re-run the verification myself.

🤖 Generated with Claude Code

…, 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 Bruce-Yii left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@NandhaKishorM
NandhaKishorM merged commit cac6312 into NandhaKishorM:main Sep 29, 2026
20 of 21 checks passed
@NandhaKishorM

Copy link
Copy Markdown
Owner

Passed checks and merged. Thank you @Divit-aggarwal! It ships in 0.3.22.

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.

3 participants