[decision_models] Compact the browser front's state for Laya's window - #9
Draft
chaimaerachdi wants to merge 1 commit into
Draft
chaimaerachdi wants to merge 1 commit into
chaimaerachdi wants to merge 1 commit into
Conversation
Laya reads a 512 to 1024 token window, but the browser front sends every model the same state it sends Jev: a JSON object per element row, the full page text, and ten actions of history. On a real page that state fills the window well before a single instruction token is spent (docs/benchmarks.md shows 18,785-23,654 input tokens for Jev on the Allrecipes run), which is why `--model laya` routinely raises MODEL_SERVICE_CONFIG_ERROR on the browser front today. laya_state() folds a browser-shaped state before every call to LayaModel._decide: page.text dropped (the choice heads already carry each candidate's own text; the free-form dump is for the chat model's DONE answer, which Laya never writes), each element row rendered as one short line instead of a JSON object, and the last three actions kept instead of ten. On by default; anything that isn't the browser front's shape passes through unchanged (the tool front already fits). LAYA_COMPACT_BROWSER_STATE=0 turns it off. 34 unit tests (tests/test_decision_models_laya.py) cover the compaction itself, its wiring into LayaModel, and the env-var opt-out, all against FakeLayaAgent (no torch/weights needed). Full suite run against main: identical 19 pre-existing failures before and after this change (missing `ty` binary and other env-only gaps in this sandbox, unrelated to decision_models/laya.py). Not done here, and worth flagging: this closes the "state is bigger than the window" gap, not the "is Laya's window, even filled, actually fast enough end to end on a real page" question. That needs the real convaiinnovations/laya checkpoint (uv sync --extra laya), a live browser run, and a real latency number. See the PR description for exact commands. Co-Authored-By: Claude Sonnet 5 <[email protected]>
chaimaerachdi
force-pushed
the
laya-compact-browser-state
branch
from
September 24, 2026 12:38
56eac3a to
36175eb
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The browser front sends every decision model the same state it sends Jev: a JSON object per element row, the
full page text, and ten actions of history.
docs/benchmarks.mdshows that state runs 18,785-23,654 tokenson the Allrecipes run. Laya's window is 512 to 1024 tokens. The state fills the window before a single
instruction token is spent, which is why
--model layaraisesMODEL_SERVICE_CONFIG_ERRORon most realpages today.
What
laya_state()ins1a/decision_models/laya.py, called fromLayaModel._decidebefore every request:page.textdropped. It's for the chat model's DONE answer, which Laya never writes; the choice headsalready carry each candidate's own text.
idx role label =value [flags]) instead of a JSON object withrepeated key names.
recent_actions: last 3 kept instead of 10.already fit the window.
LAYA_COMPACT_BROWSER_STATE=0turns it off.docs/decision-models.md,CHANGELOG.mdupdated.Roughly a tenfold reduction in the JSON-shaped state's size on the fixtures used in the tests below.
What this does not do
This closes the "state is bigger than the window" gap, not the "is a filled window, on the real 0.4B
checkpoint, actually under 7s end to end on a real page" question. That needs
uv sync --extra laya, thereal
convaiinnovations/layaweights, and a live browser run — I don't have a GPU or a live browser sessionin the environment I built this in, so I have not run that. Exact repro:
```
uv sync --extra laya
LAYA_MAX_LEN=1024 uv run s1a run flights --model laya
```
If 1024 still isn't enough on a heavier page,
LAYA_MAX_LENneeds to go up further (2048, 4096); that knobis unchanged by this PR.
Verification
uv run ruff format --check s1a/decision_models/laya.py tests/test_decision_models_laya.pyuv run ruff check s1a/decision_models/laya.py tests/test_decision_models_laya.pyuv run pytest tests/test_decision_models_laya.py -q: 34 passed, 2 skipped, 6 subtests passed(
FakeLayaAgent, no torch/weights needed)uv run pytest tests/ -q --ignore=tests/test_browser_policy.py: same 19 pre-existing failures onmainbefore and after this change (missingtybinary and other environment-only gaps in thesandbox I built this in;
tests/test_browser_policy.pyfails to collect onmaintoo, before thisbranch —
openjiuwen.harness.schema.decision_policyisn't in the pinned[email protected]taginstalled there). Neither is touched by this change.