File size: 8,061 Bytes
c9fbed3
 
cfc4380
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c9fbed3
cfc4380
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161d54d
 
cfc4380
 
 
 
 
161d54d
 
 
cfc4380
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161d54d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cfc4380
 
 
 
 
 
161d54d
 
 
 
 
 
 
 
cfc4380
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
---
license: apache-2.0
base_model: cklxx/laya-browser
tags:
- laya
- system-1
- browser-agent
- web-navigation
- decision-model
- modernbert
- finetuned
- done-judgment
- noul
library_name: safetensors
language:
- en
pipeline_tag: text-classification
---

# laya-browser-v32b (v32b-b15)

A 322M-parameter browser-agent decision model, fine-tuned from
[`cklxx/laya-browser`](https://huggingface.co/cklxx/laya-browser) (which fine-tuned
[`convaiinnovations/laya`](https://huggingface.co/convaiinnovations/laya) for browser
decisions). Fully Apache-2.0 upstream; this checkpoint keeps the same license.

**What it is:** a System-1 decision head for browser agents. It never writes text β€”
it answers *typed questions* about a page state (which operation? which element?
does the goal-holding statement hold?) and returns **calibrated probabilities**.
That makes it safe to put in front of a browser: it can only choose from what it
was shown.

**Headline numbers** (all measured 2026-09-25, same fixtures for every model):

| Benchmark | **v32b-b15** | official laya-browser (td) | hosted Jev API |
|---|---:|---:|---:|
| recovery2-holdout (240) | **0.7125** | 0.425 | β€” |
| browser-suite v5 (110) | 0.5636 | **0.5818** | β€” |
| browser-suite v4 (70) | **0.5143** | 0.500 | β€” |
| MiniWoB-116 | **0.9138** | 0.6638 | β€” |
| JevBench hard (111) | **0.4144** | 0.243 | 0.7207 |
| JevBench easy (48) | 0.8542 | 0.979 | 1.0000 |
| decision latency (p50) | **27 ms** (RTX 3080) | β€” | 854 ms (network) |

vs the official browser-tuned checkpoint: **wins holdout (+28.8pp), MiniWoB (+25pp),
suite v4 (+1.4pp), JevBench hard (+17.1pp), injection_safety (0.75 vs 0.50)**; loses
suite v5 by 2 items. vs the hosted Jev API: lower absolute accuracy but **$0 cost,
fully private, offline, 31x faster** β€” and it *beats* Jev on `score` questions
(0.667 vs 0.333) and `temporal_numeric` (0.33 vs 0.20) on JevBench hard.

## What was trained

Starting from the official `v10s`-lineage browser checkpoint, this model adds
(v17β†’v32 recipe, frozen encoder + head-only training throughout):

1. **SCROLL_UP + recovery data** β€” the official checkpoint had a 0/203 hit rate on
   scroll-up; this one is 193/203 with no loss of general accuracy.
2. **Counterfactual ranking pairs** β€” Sharper target choice among similar candidates.
3. **Noul (statement-holds) training** β€” the upstream training pipeline never
   produced `noul` items (yes/no judgment questions), leaving done_judgment at
   0.615. A purpose-built 8k-item noul corpus (8 patterns Γ— 320, balanced
   yes/no) raised probe accuracy from **37% β†’ 100%** and done_judgment to 0.769
   (probability-averaged with the choice specialist).
4. **Head blending** β€” capability heads are blended into the champion at low
   weight (6–15%) so new skills arrive with zero regression elsewhere.

The encoder (134 tensors) is byte-identical to upstream; only the 36-tensor
decision head was trained.

## Usage

Requires [`laya`](https://pypi.org/project/laya/) (`pip install laya`) or
[`laya-mlx`](https://pypi.org/project/laya-mlx/) on Apple Silicon.

```python
import laya

agent = laya.load("ichenney/laya-browser-v32b", subfolder="v32b", device="cuda")
state = {...}  # page state: url, title, text, elements table
questions = {
    "operation": {"type": "choice",
                  "instructions": "Pick the operation that achieves the goal.",
                  "criteria": {"0": "CLICK", "1": "TYPE_TEXT", "2": "SCROLL_DOWN",
                               "3": "SCROLL_UP", "4": "SELECT_OPTION", "5": "WAIT",
                               "6": "DONE", "7": "BLOCKED"}},
}
answers = agent.predict(state, questions)["answers"]
print(answers["operation"]["choice"], answers["operation"]["probabilities"])
```

Or through the **`localdecide`** harness (recommended β€” it adds element-table
building, coarse-to-fine chunking, and guards). v32b is the harness's
**default** model β€” `model="browser"` loads this repo automatically:

```python
from localdecide import BrowserDecider
from localdecide.backends import LayaTorchBackend

backend = LayaTorchBackend()          # model="browser" β†’ this checkpoint
# to stay on the upstream cklxx v10s instead:
# backend = LayaTorchBackend(model="browser-legacy")
decider = BrowserDecider(backend=backend)
```

## Checkpoint contents

```
v32b/
β”œβ”€β”€ model.safetensors      # full model: frozen encoder (134 tensors) + trained head (36)
β”œβ”€β”€ rl_agent_config.json   # laya agent config (max_len 1024, head_max_len 768, v1 format)
β”œβ”€β”€ encoder/config.json    # ModernBERT-style encoder architecture config
└── tokenizer/             # tokenizer.json + config (same vocab as upstream)
```

## Training details

- **Base**: [`cklxx/laya-browser`](https://huggingface.co/cklxx/laya-browser)
  (frozen encoder β€” 134 tensors untouched, byte-identical), head-only fine-tune (36 tensors)
- **Data** (each family generated synthetically from real page fixtures, no user data):
  | corpus | items | purpose |
  |---|---:|---|
  | general browser decisions (v10s-lineage mix) | ~11,800 | retain upstream competence |
  | targeted 6-family patch (op-choice / state-reason / multistep / surface-trap / injection / filter-first, 8 languages) | 9,600 | v20: fix known failure axes |
  | counterfactual ranking pairs | 11,200 | v21: sharper target choice (blend-only) |
  | SCROLL_UP + recovery | 6,972 | v23: upstream had 0/203 scroll-up probe |
  | multistep replanning | 5,600 | v25: proved harmful, archived |
  | 22-failure-mode patch | 6,300 | v29: evidence for the noul investigation |
  | **noul statement-holds** | **8,000** (3,200 yes / 4,800 no) | **v31: the root-cause fix** β€” 8 patterns Γ— 320, no-heavy to counter the model's yes-bias (probe NOUL_NO was 37%) |
- **Optimization**: head LR 1e-4, bf16 autocast, batch 8, GRPO-style grouped
  advantages (group 4, w_sph 0.75 / w_rps 1.0), 1–3 epochs per stage
- **Cost**: ~3 minutes per training run on one RTX 3080; the entire 15-version
  campaign totals under 2 GPU-hours
- **Method**: single-variable iterations β€” change one thing, run the full eval
  battery (browser-suite v4/v5 + recovery2-holdout, ~90 min), keep or discard on
  data. New capabilities are trained as separate heads and blended into the
  champion at 6–15% weight, which transfers skills with zero measured regression.
- **Champion selection**: highest held-out mean across the 3 suites; the final
  ensemble (v36) probability-averages v32b-b15 with the v31a noul specialist at
  w=0.4
- **Evaluation**: 3 suites Γ— 3 official baselines + hosted Jev API (fresh
  231-item run), all JSONs published in the
  [training log](https://github.com/ChenneyZhuang/laya-training-log)

## Limitations

- 322M parameters: complex multi-hop reasoning (JevBench `multi_hop` 0.22 vs
  hosted Jev 0.89) is beyond current capacity β€” this is a capacity, not a
  recipe, gap
- English-dominant training data (the synthetic fixtures cover 8 languages, but
  natural-page diversity is English-heavy)
- Safety-adjacent judgments (phishing, abuse) should be guarded by harness
  rules, not trusted to the head alone β€” the v10s phishing analysis in the
  [harness README](https://github.com/ChenneyZhuang/laya-browser-agent#head-to-head-vs-hosted-jev-measured-not-claimed-v10s-era-kept-for-provenance)
  applies to v32b too
- FP32 weights: 1.3 GB on disk. An FP16/BF16 export would halve that; the
  MLX runtime loads it fine on 8 GB Apple Silicon but the torch path wants ~2 GB resident

## License

Apache-2.0 (inherited from both upstream checkpoints). The companion harness is
[github.com/ChenneyZhuang/laya-browser-agent](https://github.com/ChenneyZhuang/laya-browser-agent).

## Citation

```bibtex
@misc{laya-browser-v32b,
  title  = {laya-browser-v32b: a noul-capable browser decision model},
  author = {Chenney Zhuang},
  year   = {2026},
  url    = {https://huggingface.co/ichenney/laya-browser-v32b},
  note   = {Fine-tuned from cklxx/laya-browser (Apache-2.0), frozen-encoder head training with noul corpus injection}
}
```