, "action": {...}}` |
+| `noul` | `{"type": "noul", "noul": , "confidence": , "action": {...}}` |
+
+(来源:`https://raw.githubusercontent.com/NandhaKishorM/laya/main/laya/agent.py`,2026-09-23;`confidence_from_probs`、`action` 均为额外字段。)
+
+对 `skills/jev-browser/lib/typesafe.mjs::normalizeAnswers` 的逐项判定:
+
+| 我们的检查 | Laya 是否满足 | 说明 |
+|---|---|---|
+| `answers[id].type === questions[id].type` | ✅ | 三种类型都带 `type` |
+| `noul` 为 0..1 的数 | ✅ | `noul` 字段是 P(yes);我们自行补 `probabilities:{true,false}`,Laya 不返回该 map 也没关系 |
+| `choice` 的 `probabilities` 覆盖 `criteria` 的所有 key | ✅ | 按 `q["crit"]` 的原 key 输出;缺失 key 我们本来就会补 0 |
+| `choice.choice` / `confidence` | ✅ | 两者都在 |
+| `score` 的 `probabilities` 键为 `"0".."n-1"` | ✅ | Laya 用 `str(i)`,与我们 `criteria.map((_, i) => String(i))` 完全一致 |
+| `score.score` / `legend` | ✅ | 都在(`legend` 我们不强制读) |
+| 多余字段(`action`、`routing`) | ✅ | 我们只挑已知键,忽略其余(Laya 自述其 Haskell 客户端 `hs-jev` 同样「ignores the rest」) |
+| 概率归一化 | ⚠️ 无需处理 | Laya 把概率**四舍五入到 4 位小数**,和不一定精确为 1;我们的客户端不做归一化、也不因为和不等于 1 抛错,所以可接受(不要在此之上再加「概率和必须为 1」的断言) |
+| 空 `questions` | ⚠️ 不会发生 | Laya 对空问题集返回空 answers 而不报错;我们本地已先在 `validateQuestions` 拦掉空问题集 |
+| 鉴权 | ✅ | `LAYA_API_KEY` 未设置时不校验,我们照发 `Authorization: Bearer `;设置后也匹配 |
+| `model` 字段 | ✅ | 我们默认发 `jev-latest`;Laya 的 `_resolve_model` 对未知名字**当作「未指定」并自动路由**(源码注释明说 Jev 客户端的 model 字段预期 miss),不会 400 |
+| 错误码 | ✅ | body 非对象或缺 `questions` → 400;模型/tokenizer 异常 → 422(我们视为不可重试的 `TypeSafeError`) |
+
+**结论:`laya-serve` 的响应可以不改我们任何客户端代码直接用。** 接入成本不在 schema,而在「Mac 实测延迟 + 在真实 state 上的答案一致率」——见 9.4。
+
+### 9.2 Open-Jev(`github.com/Zefan-Cai/Open-Jev`,权重 Apache-2.0 / 代码 MIT)
+
+#### 9.2.1 它是什么
+
+独立复现(自述 `Independent implementation inspired by TypeSafe's Jev. It does not reproduce proprietary RLCD, private weights or training data`)。技术形态:**LoRA adapter + 训练出来的 scalar decision head + 保存的校准温度**,跑在 pinned 的上游 Qwen 上;**base 权重不打包**,且**必须用 Open-Jev 自己的 loader**(`AutoPeftModel generation alone does not implement these decisions`)。[Open-Jev README, 2026-09-23;`ZefanCai/Open-Jev-2B` 的 `package/README.md`]
+
+关键实现细节(2B 包):`Yes-minus-No-initialized scalar head`;训练 20,204 steps × global batch 4 = **80,816 行**;**temperature = 1.5187963**(512 行 calibration 记录);27B v1.1 的温度是 **2.5343690298472983**、LoRA rank 8。[`package/README.md`, 2026-09-20;`docs/jevbench-public.md`, 2026-09-23]
+
+#### 9.2.2 checkpoint 与许可
+
+| checkpoint | base(需自行 pin) | HF 包体积(usedStorage) | 温度 | 权重 license | 状态 |
+|---|---|---|---|---|---|
+| Open-Jev-2B | `Qwen/Qwen3.5-2B` @ `15852e8c16360a2fea060d615a32b45270f8a8fc` | 10,052,477 B(≈10 MB) | 1.5187963 | apache-2.0 | 已发布(`package/` 内含 adapter / head.pt / temperature.json / manifest) |
+| Open-Jev-9B | `Qwen/Qwen3.5-9B` @ `c202236235762e1c871ad0ccb60c8ee5ba337b9a` | 23,632,005 B(≈23.6 MB) | 未在卡片列出 | apache-2.0 | 已发布,「new 9B training did not start」 |
+| Open-Jev-27B-v1.1 | `Qwen/Qwen3.8-27B` | 61,930,165 B(≈62 MB) | 2.5343690298472983 | apache-2.0 | 2026-09-22 发布;**训练用四卡 FSDP2,未起过 HTTP 服务** |
+
+许可口径:`Weights use Apache-2.0; Open-Jev source code remains MIT.`(每个 HF 仓库同时带 `LICENSE` 与 `LICENSE-CODE`)[`package/README.md`]。上游 Qwen 权重保留其自身条款;`Qwen/Qwen3.8-27B` 的许可证本次未核。
+
+#### 9.2.3 安装 / 服务 / 文档化的限制
+
+```bash
+# 从源码起(Python 3.10+,需要 GPU)
+python3 -m venv .venv && source .venv/bin/activate
+python -m pip install -e '.[train]'
+python -m jev.server --model Qwen/Qwen3.5-2B --revision 15852e8c16360a2fea060d615a32b45270f8a8fc --max-length 4096
+# 或用发布的包
+python -m jev.server --checkpoint /path/to/package/checkpoint --device cuda:0 --max-length 4096 --batch-size 1 --host 127.0.0.1 --port 8791
+
+# Docker
+docker compose up -d --build # NVIDIA GPU;首次构建下载约 4.6 GB,镜像约 12 GB
+docker compose up -d --build open-jev-cpu # 纯 CPU(much slower,首次加载给 15 分钟启动期)
+curl -s http://127.0.0.1:8791/health
+```
+
+服务路由:`GET /health`(`{status:"ready", model, method}`)、`GET /v1/models`(**`aliases: ["open-jev", "jev-latest"]`**)、`POST /v1/systemone`,另有内置 workbench / task lab / painting 静态页。[`jev/server.py` + `docker/README.md`, 2026-09-23]
+
+「partial API compatibility, not the full hosted service」具体落在哪(文档里能确证的全部条目):
+
+| 项 | 文档化事实 |
+|---|---|
+| 请求/响应形状 | `Official /v1/systemone request/answer shape`(README 任务覆盖表);response metadata 带 `checkpoint_sha256` |
+| 服务实现 | 自己的 **stdlib `ThreadingHTTPServer`**(不是 FastAPI/uvicorn),socket timeout 30 s,请求体上限 4 MiB |
+| 并发 | `Requests are serialised by a lock in the server, so one container answers one request at a time regardless of JEV_BATCH_SIZE` |
+| 鉴权 / 限流 | `The server has no authentication and applies no rate limiting`(compose 只发布到 loopback) |
+| 长度处理 | `JEV_MAX_LENGTH` 默认 4096;**超长直接拒绝而非截断**(`longer inputs are rejected rather than truncated`) |
+| 加速路径 | `JEV_PREFIX_CACHE` 默认 off(`it exceeded the probability tolerance on 9 of 11 measured workloads`) |
+| 元数据 | `code_commit: null`(镜像不含 git 历史);27B v1.1 **没有 HTTP 服务**(FSDP2 四卡直算) |
+| 未覆盖 | 官方托管的计费/多租户/并发/完整评测口径;2B/9B 的公开数字只基于 **512 行**抽样(非全量 26,452 held-out) |
+
+仓库**没有**发布逐字段的兼容性 diff,因此「partial」的边界只能以上表为准;`[INFERENCE]` 就我们使用的三种问题类型而言,未见文档化缺口,真正的风险是「2B 起、需自家 loader 与 pinned base、Mac 无路径」。
+
+#### 9.2.4 JevBench public(231 题,六条独立审计过的流)
+
+| Model | Correct / 231 | Accuracy | Hard / 111 | Brier ↓ | Top-label ECE ↓ | p50(口径各异) |
+|---|---|---|---|---|---|---|
+| Released Open-Jev 2B | 150 | 64.94% | 46 | 0.4751 | 0.1274 | 138.0 ms(本地 H100,loopback HTTP) |
+| Released Open-Jev 9B | 179 | 77.49% | 66 | 0.3219 | 0.0858 | 189.2 ms(同上) |
+| Open-Jev 27B v1.1 | 197 | 85.28% | 80 | 0.2420 | 未报告 | 无 HTTP(FSDP2,不计入延迟表) |
+| **Jev 1.13.0** | **200** | **86.58%** | **81** | **0.1811** | **0.0318** | 291.3 ms(托管 HTTPS) |
+| GPT-5.6 Luna | 206 | 89.18% | 89 | 0.2074 | 0.0932 | 953.8 ms |
+| GPT-6 Astra | 231 | 100.00% | 111 | 0.0085 | 0.0149 | 2206.4 ms |
+
+(来源:`docs/jevbench-public.md`, 2026-09-23。作者同时声明:native 概率与 GPT 的「口头化概率」不可直接比;139 个 Choice 里有 119 个的候选顺序不同,所以这不是 fully order-controlled 的对比。)
+另一个内部口径(512 行抽样,非全量):2B 在 `calibrated_test` 上 hard-label 0.917021 / ECE 0.0203,`calibrated_ood` 0.878099 / 0.0785。[`package/README.md`, 2026-09-20]
+
+### 9.3 SemIf 与 kev-agent-kit 各一行
+
+- **SemIf(MIT)**:**是模型引擎,不是模型**——它把「渲染 prompt + 读选项 logits」这套逻辑做成 Python 包与 `semif-score` CLI,**在进程内加载模型**(PyTorch/CUDA、`--device mps`、`--backend mlx`、或 `--backend llamacpp --gguf …` 走本地 GGUF);没有 HTTP 服务、没有 `/v1/systemone`,所以**不能**用 baseUrl 指过去,但它可以做我们要自己写的那层 adapter 的参考实现与校准脚本(per-workload 温度拟合)。运行时:Python 3.10+,`pip install -e '.[test,mlx]'` 或 `.[test,llamacpp]`。[SemIf README, 2026-09-23]
+- **kev-agent-kit / kev-mcp(Apache-2.0,Busy-Office)**:也不实现模型——它把上游 `kev.serve` 装进 Docker(`Dockerfile.cpu` + `compose.yaml`),再提供一个 **stdio MCP server**(`integrations/kev-mcp`,3 个 MCP 工具)去查询**本地 Kev API(默认 `http://127.0.0.1:8008`)**,并附带把配置写进 `~/.codex/config.toml`、`~/.claude.json`、`~/.gemini/config/mcp_config.json` 的全局安装器;运行时要求 Docker Compose + uv + Python 3.12+ + Node 20+,首次启动下载 **0.5B** checkpoint,其徽章与卡片覆盖 0.5b/0.6b/4b/8b(即绑定的是 Qwen3 世代)。[repo README, 2026-09-23;glama.ai 的 kev-mcp 条目]
+ 可复用点:要么直接用它那套 compose 作为 Kev 宿主,要么(更干净)继续用上游 `kev.serve`——两者都是同一个 HTTP 契约,我们的客户端只看 baseUrl。
+
+### 9.4 裁定表
+
+| | Kev-0.8B | Laya-421M(`laya` / `laya-typed-decisions`) | Open-Jev-2B | SemIf |
+|---|---|---|---|---|
+| **sub-1B?** | ✅ 873M base + 43 MB adapter | ✅ 421M(多语档 322M) | ❌ 2B 起(另有 9B / 27B) | —(不是模型;默认 4B 基线) |
+| **license** | Apache-2.0(+ Qwen base Apache-2.0) | Apache-2.0(标签含 `commercial-use`) | 权重 Apache-2.0 / 代码 MIT(base 需 pin 上游) | MIT(代码;权重不含) |
+| **说 `/v1/systemone`?** | ✅ 官方声明并作为主契约 | ✅ 源码级实现(`laya/serve.py`),响应与 Jev 字段同形 | ✅ 但仅「partial」:无鉴权/限流、串行锁、超长拒绝、自有 stdlib server | ❌ 只有 CLI/库 |
+| **Mac 无 GPU 可跑?** | ✅(Qwen3.5 系自动走 MLX;Qwen3 世代走 MPS);延迟口径待自测 | ⚠️ 理论上可以(Python+torch,CPU 预加载 193–464 ms/问),但 **Mac/MPS 无官方数据**,必须实测 | ⚠️ 仅 Docker CPU 变体,作者标 `much slower`(15 min 启动期);实用前提是有 NVIDIA GPU | ✅(`--backend mlx` / `--device mps` / llamacpp CPU) |
+| **质量 vs Jev** | 域外 0.652/0.684,Brier 0.499/0.460,coverage@5% 仅 0.23(Jev 0.857 / 0.211 / 0.70);第三方 900 张工单上 Kev-9B 反超 Jev | typed-decisions 0.766 vs Jev 0.727(**其自身训练 split**);banking77 0.492 vs 0.870;多语 0.366 macro;出厂过度自信(ECE 0.314–0.466) | JevBench 150/231(64.94%)vs Jev 200/231;Brier 0.4751 vs 0.1811 | 见 §3 表(4B:authored 0.813 / WANLI 0.637 / TypeSafe 子集 0.845 vs Jev 0.883) |
+| **接成第二后端?** | **默认后端(已选定)** | **值得接**:schema 已确认可直接吃,且能补 Kev 的短板(多语、低延迟、无 GPU 档、option 数 ≤20 的短选项场景);前置条件=在 Mac 与我们的真实 state 上各跑一批,确认「延迟 + 与 Kev/Jev 的 top 答案一致率」 | **不建议**:2B 起、需自家 loader 与 pinned base、Mac 无实用路径;保留为协议/质量对照物 | **不接线**;复用其方法(选项槽单 token 校验、per-workload 温度拟合)与脚本 |
diff --git a/experiments/gguf-provider/RESULTS.md b/experiments/gguf-provider/RESULTS.md
new file mode 100644
index 0000000..cb0ae34
--- /dev/null
+++ b/experiments/gguf-provider/RESULTS.md
@@ -0,0 +1,99 @@
+# Local GGUF backend — measured results
+
+First-token logprob readout on top of `llama.cpp`: the question is rendered with labelled options,
+exactly one token is generated, and the probability mass on each option label at that position is
+the answer. No training, no text generation, no output parsing, no API key.
+
+Default model is now **Qwen3.5-4B Q4_K_M**; the 0.8B stays as a selectable, faster/weaker entry.
+Full ranking and caveats: `results/local-models-4b.md`.
+
+- Machine: Apple M3 Max / 48 GB / macOS 25.6.0 arm64, Node 26.9.0 (no Python involved).
+- Ship model: `Qwen3.5-4B-Q4_K_M.gguf` — 2,740,937,888 B, sha256 `00fe7986ff5f6b463e62455821146049db6f9313603938a70800d1fb69ef11a4`,
+ from `unsloth/Qwen3.5-4B-GGUF` (`llama-server /props` reports `model_ftype = Q4_K - Medium`, arch `qwen35`).
+- Reference model: `Qwen3.5-0.8B-Q8_0.gguf` — 811,843,840 B, sha256
+ `0ad885ffd4bb022fc4f0d33a3308fa108ef8613159d3b3a67e23abca056b7a6c`, from `unsloth/Qwen3.5-0.8B-GGUF`.
+- Server: `llama-server` (Homebrew `llama.cpp` 0.4.0, Metal via MPS), **`-c 16384`** — see *Context size*.
+- Product copy of this provider: `skills/jev-browser/lib/local.mjs`, one command in
+ `skills/jev-browser/bin/jev-local.mjs`. The code here and the code there are the same algorithm.
+
+## Accuracy — 20 graded items (ground truth known by construction)
+
+| model | all (20) | browser (15) | noul (5) | action + click_target (5) |
+| --- | --- | --- | --- | --- |
+| **Qwen3.5-4B Q4_K_M (ships)** | **16 · 0.800** | 12 · 0.800 | 4 · 0.800 | 2 · 0.400 |
+| Qwen3.5-0.8B Q8_0 (reference) | 10 · 0.500 | 7 · 0.467 | 3 · 0.600 | 1 · 0.200 |
+| "always answer the option listed first" | 11 · 0.550 | 9 · 0.600 | 2 · 0.400 | 2 · 0.400 |
+| hosted Jev (ceiling, same items) | 19 · 0.950 | 14 · 0.933 | 5 · 1.000 | 5 · 1.000 |
+
+The 4B is the first local candidate to clear the positional prior (+5 items) and to be close enough
+to hosted Jev to be useful for short decisions. Its errors on the graded set: `ddg-click-target-aapl`
+(see caveats), `ddg-typed-action`, `github-login-action`, `bq-penguins`.
+
+Readout quality on the 4B: captured label mass **mean 0.9407 / min 0.7958**, **0 non-single-token
+labels** (the alphabet verification skipped everything the tokenizer splits). One 100-option item
+lost 32 tail labels outside the 512-candidate window.
+
+**Rotation (text, not position).** Rotating the option list while keeping the labels: on the
+100-option `wiki-login-click-target` the 4B hit the exact expected element at every rotation
+(k=0/3/7 → `e8`/`e5`/`e1`, P≈0.99). The 0.8B instead kept answering inside the first few slots
+(`e1`/`e2`/`e4`/`e6`) — i.e. the 4B reads the option text, the 0.8B reads position.
+
+**Confidence is usable as an abstention signal on the 4B** (it was not on the 0.8B): 12 choice/score
+answers, mean confidence 0.516; wrong answers average 0.233 (most confident wrong: 0.598). Filtering
+at `confidence ≥ 0.5` keeps 8/12 answers with 7/8 correct; at `≥ 0.7`, 4/12 with 4/4.
+
+## Latency — one real browser step, 5 questions
+
+State 16,111 B — the skill's own first-step question set (`goal_done` noul, `blocker` 6 options,
+`action` 5, `click_target` 55, `select_target` 3); 13,729 prompt tokens cold, 6,859 warm. Numbers
+below are from a clean re-run with nothing else running (a concurrent-download run produced the same
+answers, 13.8 s wall).
+
+| model | cold | warm (prefix cache hot) | RSS |
+| --- | --- | --- | --- |
+| **Qwen3.5-4B Q4_K_M** | **18,298 ms** | **9,002 ms** | 3,362 MiB |
+| Qwen3.5-0.8B Q8_0 | 2,933 ms | 1,745 ms | not measured |
+
+Per question, 4B warm: `goal_done` 703 ms · `blocker` 815 ms · `action` 705 ms ·
+**`click_target` 6,135 ms** · `select_target` 630 ms. Per question, 0.8B warm: 151 / 159 / 127 /
+1,165 / 132 ms. The whole step is the repeated prefill of the state per question, and `click_target`
+dominates because it lists 55–100 options. The 0.8B through the skill itself
+(`jev-browser judge` against `TYPESAFE_BASE_URL`) was 2,673 ms wall for the same questions with
+`normalizeAnswers` consuming the answers unchanged (27/27 checks); local tokens cost **$0**.
+
+## Context size
+
+A rendered prompt is dominated by the option list: with the skill's default
+`observation.maxCandidates` of 100, `click_target` is about **11.7k tokens** (11,748 measured on the
+55-option fixture step). The launcher now spawns `llama.cpp` with **`-c 16384`** (its `--ctx`
+default) for that reason; at `-c 8192` llama.cpp hard-fails the request with
+`400 request (11748 tokens) exceeds the available context size (8192 tokens)`
+(`exceed_context_size_error`), so 8192 is not usable with the default candidate count. Starting
+`llama-server` by hand is no longer required.
+
+## Where it breaks
+
+- Long element lists stay the weak spot: even at 4B, `click_target` costs ~6 s and the `action`
+ slice is 2/5 — it is the question that also dominates latency.
+- Free-form `type_value` and pass-`goal_done` judgments on long states were the 0.8B's worst cases;
+ the 4B reads both correctly on the fixtures (goal_done 0.006 for an unmet goal) but they remain
+ the least tested.
+- Anything visual: the state is text only.
+- Product guard: when the readout cannot find the option labels at all (label not a single token,
+ candidates truncated) the mass drops and the server answers HTTP 422 `LOW_LABEL_MASS` naming the
+ question instead of guessing.
+
+## Ranking and what is still unmeasured
+
+`results/local-models-4b.md` is the full ranking. Two caveats from it are load-bearing:
+
+- Candidates 2 and 3 (`Qwen3-4B-Instruct-2507`, `gemma-3-4b-it`) never finished downloading — the
+ link collapsed to ~10–25 KB/s with bursts — so their accuracy **and** their drivability through
+ the render path (chat template via `/apply-template`) are unexercised. No download is running now;
+ the retry script is `/tmp/jev-ceiling/fetch-4b.sh` (start with `hub`, then
+ `bash /tmp/jev-ceiling/run-candidate.sh 8100`).
+- `ddg-click-target-aapl`'s ground-truth label is debatable: the hand label is `e1` (investing.com,
+ `in_viewport=false`), while hosted Jev and the 4B both pick `e15` (Yahoo Finance AAPL quote page,
+ in viewport). Every model is therefore scored down by up to one item on that question.
+
+`Qwen3-0.6B` (11/20 on the same set, slower than the 0.8B) is not shipped.
diff --git a/experiments/gguf-provider/cli.mjs b/experiments/gguf-provider/cli.mjs
new file mode 100755
index 0000000..2982747
--- /dev/null
+++ b/experiments/gguf-provider/cli.mjs
@@ -0,0 +1,51 @@
+#!/usr/bin/env node
+// EXPERIMENTAL — not part of the jev-browser skill.
+// Run one `/v1/systemone` request (or a captured `--dry-run` fixture) through the
+// local GGUF provider and print the Jev-shaped response.
+//
+// node experiments/gguf-provider/cli.mjs --fixture experiments/gguf-provider/fixtures/raw_duckduckgo.txt
+// node experiments/gguf-provider/cli.mjs --request request.json --url http://127.0.0.1:8090
+// node experiments/gguf-provider/cli.mjs --fixture ... --normalize (also runs the skill's normalizeAnswers)
+import { readFileSync } from "node:fs";
+import { GgufProvider } from "./lib/provider.mjs";
+
+const arg = (name, fallback = undefined) => (process.argv.includes(name) ? process.argv[process.argv.indexOf(name) + 1] : fallback);
+const flag = (name) => process.argv.includes(name);
+
+/** A `--dry-run` capture has a human preamble before the JSON body. */
+export function loadRequest({ fixture, request }) {
+ if (request) return JSON.parse(readFileSync(request, "utf8"));
+ const raw = readFileSync(fixture, "utf8");
+ const start = raw.indexOf("{");
+ if (start < 0) throw new Error(`no JSON object found in ${fixture}`);
+ const parsed = JSON.parse(raw.slice(start));
+ if (!parsed.questions) throw new Error(`${fixture} does not contain a question set`);
+ return { state: parsed.state, questions: parsed.questions, model: parsed.model };
+}
+
+if (import.meta.url === `file://${process.argv[1]}`) {
+ const fixture = arg("--fixture");
+ const request = arg("--request");
+ if (!fixture && !request) {
+ console.error("usage: cli.mjs --fixture | --request ");
+ process.exit(2);
+ }
+ const body = loadRequest({ fixture, request });
+ const provider = new GgufProvider({
+ url: arg("--url", "http://127.0.0.1:8090"),
+ model: arg("--model", "gguf-local"),
+ ending: arg("--ending", "answer"),
+ nProbs: Number(arg("--n-probs", 512)),
+ verbose: flag("--verbose"),
+ });
+ const t0 = performance.now();
+ const response = await provider.systemOne(body);
+ const wallMs = performance.now() - t0;
+ const out = { ...response, usage: { ...response.usage, wall_ms: Math.round(wallMs) } };
+
+ if (flag("--normalize")) {
+ const { normalizeAnswers } = await import("../../skills/jev-browser/lib/typesafe.mjs");
+ out.normalized = normalizeAnswers(response.answers, body.questions);
+ }
+ process.stdout.write(`${JSON.stringify(out, null, 2)}\n`);
+}
diff --git a/experiments/gguf-provider/eval/items.mjs b/experiments/gguf-provider/eval/items.mjs
new file mode 100644
index 0000000..f228f6c
--- /dev/null
+++ b/experiments/gguf-provider/eval/items.mjs
@@ -0,0 +1,207 @@
+// EXPERIMENTAL — not part of the jev-browser skill.
+// The eval set: items whose ground truth is known BY CONSTRUCTION.
+//
+// Two families:
+// - browser: a REAL page state captured with `jev-browser run --dry-run` (the fixture
+// files in ../fixtures/), with the correct answer read off the state by hand and
+// recorded in `why`. No synthetic element lists.
+// - noul: short passage + yes/no question, answer obvious from the passage.
+
+import { readFileSync } from "node:fs";
+import { fileURLToPath } from "node:url";
+import { dirname, join } from "node:path";
+
+const FIXTURES = join(dirname(fileURLToPath(import.meta.url)), "..", "fixtures");
+
+export function loadFixture(file) {
+ const raw = readFileSync(join(FIXTURES, file), "utf8");
+ return JSON.parse(raw.slice(raw.indexOf("{")));
+}
+
+const DDG = "raw_duckduckgo_com_html__q_apple_stock_price.txt";
+const DDG_TYPED = "raw_ddg_typed.txt";
+const WIKI = "raw_en_wikipedia_org_wiki_Main_Page.txt";
+const WIKI_TYPED = "raw_wiki_typed.txt";
+const GITHUB = "raw_github_login.txt";
+
+/** Browser-decision items. `expect` is keyed by question id. */
+export const BROWSER_ITEMS = [
+ {
+ id: "ddg-click-target-aapl",
+ fixture: DDG,
+ state: { goal: "find today's price of AAPL" },
+ expect: { click_target: "e1" },
+ why: "e1 is the only organic result actually about the AAPL quote ('View today's Apple Inc stock price and latest AAPL news and analysis' -> investing.com); e2/e4 are DuckDuckGo chrome and e7.. are ads.",
+ },
+ {
+ id: "ddg-action-aapl",
+ fixture: DDG,
+ state: { goal: "find today's price of AAPL" },
+ expect: { action: "click" },
+ why: "Allowed actions are click/select/scroll_down/wait/stop; the next step is opening the quote page, so click.",
+ },
+ {
+ id: "ddg-blocker-aapl",
+ fixture: DDG,
+ state: { goal: "find today's price of AAPL" },
+ expect: { blocker: "none" },
+ why: "No login wall, CAPTCHA, consent modal or error page is present.",
+ },
+ {
+ id: "ddg-goal-done-aapl",
+ fixture: DDG,
+ state: { goal: "find today's price of AAPL" },
+ expect: { goal_done: false },
+ why: "visible_text contains no price and the title is 'apple stock price at DuckDuckGo' - a results page only OFFERS a way to reach the price, which the question rules exclude.",
+ },
+ {
+ id: "ddg-typed-action",
+ fixture: DDG_TYPED,
+ state: { goal: "search for the nvidia stock price" },
+ expect: { action: "type" },
+ why: "inputs.query is provided and the page has a text field (e3), so typing is the next step.",
+ },
+ {
+ id: "ddg-typed-type-target",
+ fixture: DDG_TYPED,
+ state: { goal: "search for the nvidia stock price" },
+ expect: { type_target: "e3" },
+ why: "e3 is the search field 'q' (currently holding the previous query); there is no other text field.",
+ },
+ {
+ id: "ddg-typed-submit",
+ fixture: DDG_TYPED,
+ state: { goal: "search for the nvidia stock price" },
+ expect: { submit_after_type: true },
+ why: "A single search box submits on Enter (the page also has a Search button, but pressing Enter is the natural way to submit this field).",
+ },
+ {
+ id: "wiki-login-click-target",
+ fixture: WIKI,
+ state: { goal: "log in to Wikipedia" },
+ expect: { click_target: "e9" },
+ why: "e9 is the only 'Log in' link on the page.",
+ },
+ {
+ id: "wiki-typed-type-target",
+ fixture: WIKI_TYPED,
+ state: { goal: "search Wikipedia for the article about bacteria" },
+ expect: { type_target: "e1" },
+ why: "e1 is the only text field ('Search Wikipedia'); e3 is a link named 'bacteria', not a field.",
+ },
+ {
+ id: "github-login-type-target",
+ fixture: GITHUB,
+ state: { goal: "sign in to GitHub" },
+ expect: { type_target: "e3" },
+ why: "e3 is the empty required 'Username or email address' field; e5 is the password field that comes after it.",
+ },
+ {
+ id: "github-login-type-value",
+ fixture: GITHUB,
+ state: { goal: "sign in to GitHub" },
+ expect: { type_value: "username" },
+ why: "The chosen field is the username field, and inputs.username is the matching (non-secret) input.",
+ },
+ {
+ id: "github-login-submit",
+ fixture: GITHUB,
+ state: { goal: "sign in to GitHub" },
+ expect: { submit_after_type: false },
+ why: "The password field is still empty, so Enter must not be pressed yet.",
+ },
+ {
+ id: "github-login-action",
+ fixture: GITHUB,
+ state: { goal: "sign in to GitHub" },
+ expect: { action: "type" },
+ why: "Both credentials are in inputs and both required fields are listed, so typing is the next step.",
+ },
+ {
+ id: "github-login-blocker",
+ fixture: GITHUB,
+ state: { goal: "sign in to GitHub" },
+ expect: { blocker: "none" },
+ why: "The login form is fillable with the provided inputs, so it is explicitly not an obstacle.",
+ },
+];
+
+/** Questions the controller only consumes conditionally; reported separately. */
+export const SPECULATIVE_ITEMS = [
+ {
+ id: "ddg-typed-select-target",
+ fixture: DDG_TYPED,
+ state: { goal: "search for the nvidia stock price" },
+ expect: { select_target: "none" },
+ why: "Searching does not require changing the region or time dropdown.",
+ },
+];
+
+const T = "The passage states this.";
+const F = "The passage does not state this.";
+
+const noulQuestion = (question, trueDesc, falseDesc) => ({
+ type: "noul",
+ instructions: { question, rules: ["Answer only from the passage in the state."] },
+ criteria: { true: trueDesc, false: falseDesc },
+});
+
+/**
+ * The score question (`progress`) only exists from the second step on, because it needs
+ * a `previous_page` and a `last_action`. Both come from real captures: the previous page
+ * is the captured Wikipedia main page, the current page is the captured Special:UserLogin
+ * page reached by clicking its 'Log in' link.
+ */
+export const PROGRESS_ITEM = {
+ id: "wiki-progress-after-login-click",
+ fixture: "raw_wiki_loginpage.txt",
+ state: {
+ goal: "log in to Wikipedia",
+ previous_page: null, // filled in by the eval from the main-page fixture
+ last_action: "click e9 'Log in'",
+ },
+ question: {
+ type: "score",
+ instructions: { question: "Compared with `previous_page`, how did `last_action` change progress toward `goal`, judging by `page`?" },
+ criteria: [
+ "`page` moved away from `goal`: a wrong page, an error, or lost progress compared with `previous_page`.",
+ "No meaningful change toward `goal` compared with `previous_page`.",
+ "`page` is closer to `goal` than `previous_page` was.",
+ "`page` now shows `goal` accomplished.",
+ ],
+ },
+ expect: { progress: 2 },
+ why: "Clicking 'Log in' replaced the encyclopedia main page with the real login form: closer to the goal than before, but the goal (being signed in) is not accomplished.",
+};
+
+export const NOUL_ITEMS = [
+ { id: "bq-paris", passage: "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France. It was completed in 1889 and is 330 metres tall.", question: "Is the Eiffel Tower located in Paris?", expect: true, why: "Passage says Paris." },
+ { id: "bq-penguins", passage: "Penguins are flightless seabirds. Their wings have evolved into flippers, so they cannot fly.", question: "Can penguins fly?", expect: false, why: "Passage says they are flightless." },
+ { id: "bq-python", passage: "Python is a high-level, interpreted programming language created by Guido van Rossum and first released in 1991.", question: "Was Python created before 1990?", expect: false, why: "Passage gives 1991." },
+ { id: "bq-everest", passage: "Mount Everest is Earth's highest mountain above sea level, at 8,849 metres, in the Mahalangur Himal sub-range of the Himalayas.", question: "Is Mount Everest taller than 8,000 metres?", expect: true, why: "8,849 > 8,000." },
+ { id: "bq-trap-failed", passage: "The passage records that the experiment failed and the team stopped the run early.", question: "Did the experiment succeed?", expect: false, why: "Explicitly failed - a polarity trap.", trap: true },
+];
+
+/** Build the provider request for one item. */
+export function requestFor(item, fixtureCache) {
+ if (item.passage !== undefined) {
+ const state = { passage: item.passage, question: item.question };
+ const questions = { answer: noulQuestion(item.question, T, F) };
+ return { state, questions, graded: "answer", expect: item.expect };
+ }
+ const fixture = fixtureCache[item.fixture] ?? (fixtureCache[item.fixture] = loadFixture(item.fixture));
+ const state = structuredClone(fixture.state);
+ Object.assign(state, item.state);
+ if (item.id === PROGRESS_ITEM.id) {
+ const wiki = fixtureCache[WIKI] ?? (fixtureCache[WIKI] = loadFixture(WIKI));
+ state.previous_page = {
+ url: wiki.state.page.url,
+ title: wiki.state.page.title,
+ text_excerpt: wiki.state.page.visible_text.slice(0, 600),
+ element_count: wiki.state.page.elements.length,
+ };
+ }
+ const graded = Object.keys(item.expect)[0];
+ const question = item.question ?? fixture.questions[graded];
+ return { state, questions: { [graded]: structuredClone(question) }, graded, expect: item.expect[graded] };
+}
diff --git a/experiments/gguf-provider/eval/run.mjs b/experiments/gguf-provider/eval/run.mjs
new file mode 100755
index 0000000..23bf2cf
--- /dev/null
+++ b/experiments/gguf-provider/eval/run.mjs
@@ -0,0 +1,152 @@
+#!/usr/bin/env node
+// EXPERIMENTAL — not part of the jev-browser skill.
+// Honest accuracy eval of the local GGUF readout provider on items whose ground truth
+// is known by construction (see items.mjs).
+//
+// node experiments/gguf-provider/eval/run.mjs # all graded items
+// node experiments/gguf-provider/eval/run.mjs --set noul
+// node experiments/gguf-provider/eval/run.mjs --rotate # label-permutation test
+// node experiments/gguf-provider/eval/run.mjs --json > result.json
+import { BROWSER_ITEMS, NOUL_ITEMS, SPECULATIVE_ITEMS, PROGRESS_ITEM, requestFor } from "./items.mjs";
+import { GgufProvider } from "../lib/provider.mjs";
+
+const arg = (name, fallback) => (process.argv.includes(name) ? process.argv[process.argv.indexOf(name) + 1] : fallback);
+const flag = (name) => process.argv.includes(name);
+
+const SET = arg("--set", "all");
+const ROTATE_KS = arg("--rotate-ks", "0,3,7").split(",").map(Number);
+const ROTATE_ONLY = arg("--rotate-only", null); // restrict to one item id, and skip graded rows
+const provider = new GgufProvider({
+ url: arg("--url", "http://127.0.0.1:8090"),
+ model: arg("--model", "gguf-local"),
+ ending: arg("--ending", "answer"),
+ verbose: flag("--verbose"),
+});
+
+const fixtures = {};
+
+/**
+ * Rotate a choice question's option list (content moves, labels stay) and rebuild the
+ * state's element list to match — the check for "did it read the option, or just the label A".
+ */
+function rotateRequest(item, k) {
+ const { state, questions, graded } = requestFor(item, fixtures);
+ const question = questions[graded];
+ if (question.type !== "choice") throw new Error(`rotation only applies to choice questions (${item.id})`);
+ const entries = Object.entries(question.criteria);
+ const options = entries.filter(([key]) => key !== "none");
+ const tail = entries.filter(([key]) => key === "none");
+ const shift = ((k % options.length) + options.length) % options.length;
+ const ordered = [...options.slice(shift), ...options.slice(0, shift), ...tail];
+
+ const criteria = {};
+ const keyMap = new Map();
+ ordered.forEach(([oldKey, description], i) => {
+ const key = `e${i + 1}`;
+ criteria[key] = description;
+ keyMap.set(oldKey, key);
+ });
+ const elements = ordered
+ .filter(([oldKey]) => oldKey !== "none")
+ .map(([, description], i) => ({ id: `e${i + 1}`, description, in_viewport: true }));
+
+ return {
+ state: { ...state, page: { ...state.page, elements } },
+ questions: { [graded]: { ...question, criteria } },
+ graded,
+ expect: keyMap.get(item.expect[graded]) ?? item.expect[graded],
+ };
+}
+
+function grade(answer, expected) {
+ if (typeof expected === "boolean") {
+ const predicted = answer.noul >= 0.5;
+ return { predicted, correct: predicted === expected, detail: `P(yes)=${answer.noul.toFixed(4)}` };
+ }
+ if (typeof expected === "number") {
+ const probs = Object.values(answer.probabilities).map((p) => p.toFixed(2)).join(",");
+ return { predicted: answer.score, correct: Math.abs(answer.score - expected) <= 0.5, detail: `score=${answer.score.toFixed(3)} p=[${probs}]` };
+ }
+ return { predicted: answer.choice, correct: answer.choice === expected, detail: `choice=${answer.choice} P(correct)=${(answer.probabilities[expected] ?? 0).toFixed(4)}` };
+}
+
+const items = [];
+if (SET === "all" || SET === "browser") items.push(...BROWSER_ITEMS.map((i) => ({ ...i, kind: "browser" })), { ...PROGRESS_ITEM, kind: "browser" });
+if (SET === "all" || SET === "noul") items.push(...NOUL_ITEMS.map((i) => ({ ...i, kind: "noul" })));
+if (SET === "speculative") items.push(...SPECULATIVE_ITEMS.map((i) => ({ ...i, kind: "speculative" })));
+
+const rows = [];
+for (const item of ROTATE_ONLY ? [] : items) {
+ const { state, questions, graded, expect } = requestFor(item, fixtures);
+ const t0 = performance.now();
+ const response = await provider.systemOne({ state, questions });
+ const ms = performance.now() - t0;
+ const answer = response.answers[graded];
+ const expected = expect;
+ const { predicted, correct, detail } = grade(answer, expected);
+ const detailRow = response.usage.per_question[graded];
+ rows.push({
+ id: item.id,
+ kind: item.kind,
+ question: graded,
+ type: questions[graded].type,
+ expected: String(expected),
+ predicted: String(predicted),
+ got: detail,
+ correct,
+ ms: Math.round(ms),
+ label_mass: detailRow.label_mass,
+ multi_token_labels: detailRow.multi_token_labels,
+ missing_labels: detailRow.missing_labels,
+ confidence: answer.confidence ?? null,
+ });
+ process.stderr.write(`${correct ? "ok " : "MISS"} ${item.id} (${graded}) ${detail} ${Math.round(ms)}ms\n`);
+}
+
+let rotations = null;
+if (flag("--rotate")) {
+ rotations = [];
+ const rotateItems = items.filter((i) => Object.keys(i.expect)[0] === "click_target" && (!ROTATE_ONLY || i.id === ROTATE_ONLY));
+ for (const item of rotateItems) {
+ for (const k of ROTATE_KS) {
+ const r = rotateRequest(item, k);
+ const response = await provider.systemOne({ state: r.state, questions: r.questions });
+ const answer = response.answers[r.graded];
+ const correct = answer.choice === r.expect;
+ rotations.push({ id: item.id, rotation: k, expected: r.expect, got: answer.choice, correct, p_correct: answer.probabilities[r.expect] ?? 0 });
+ process.stderr.write(`${correct ? "ok " : "MISS"} rotate ${item.id} k=${k} -> ${answer.choice} (want ${r.expect})\n`);
+ }
+ }
+}
+
+const summary = (list) => ({ n: list.length, correct: list.filter((r) => r.correct).length, accuracy: list.length ? Number((list.filter((r) => r.correct).length / list.length).toFixed(3)) : null });
+const by = (key) => Object.fromEntries([...new Set(rows.map((r) => r[key]))].map((k) => [k, summary(rows.filter((r) => r[key] === k))]));
+const latencies = rows.map((r) => r.ms).sort((a, b) => a - b);
+
+const result = {
+ model: provider.model,
+ ending: provider.ending,
+ items: rows.length,
+ overall: summary(rows),
+ by_question: by("question"),
+ by_kind: by("kind"),
+ latency_ms: {
+ total: latencies.reduce((a, b) => a + b, 0),
+ mean: Math.round(latencies.reduce((a, b) => a + b, 0) / Math.max(1, latencies.length)),
+ median: latencies[Math.floor(latencies.length / 2)] ?? null,
+ max: latencies[latencies.length - 1] ?? null,
+ },
+ rows,
+ rotations,
+};
+
+if (flag("--json")) {
+ console.log(JSON.stringify(result, null, 2));
+} else {
+ for (const r of rows) console.log(`${r.correct ? "PASS" : "FAIL"} ${r.id.padEnd(30)} ${r.question.padEnd(18)} want=${r.expected.padEnd(6)} got=${r.predicted.padEnd(6)} ${r.got}`);
+ console.log(`\noverall: ${result.overall.correct}/${result.overall.n} = ${result.overall.accuracy}`);
+ console.log(`by kind: ${JSON.stringify(result.by_kind)}`);
+ console.log(`by question: ${JSON.stringify(result.by_question)}`);
+ console.log(`latency ms: ${JSON.stringify(result.latency_ms)}`);
+ if (rotations) console.log(`rotations: ${rotations.filter((r) => r.correct).length}/${rotations.length} followed the content`);
+}
diff --git a/experiments/gguf-provider/fixtures/judge-questions.json b/experiments/gguf-provider/fixtures/judge-questions.json
new file mode 100644
index 0000000..0613064
--- /dev/null
+++ b/experiments/gguf-provider/fixtures/judge-questions.json
@@ -0,0 +1,148 @@
+{
+ "goal_done": {
+ "type": "noul",
+ "instructions": {
+ "question": "Is `goal` already fully accomplished according to what `page` shows right now?",
+ "rules": [
+ "Judge only from `page` (its url, title, headings, visible_text, dialog and elements).",
+ "A page that merely offers a way to accomplish `goal` does not count as accomplished.",
+ "If `goal` asks to open or view something, it is accomplished when that thing is what `page` shows.",
+ "If `goal` asks to perform an action (submit, add, sign in, start), it is accomplished only when `page` shows the result or confirmation of that action."
+ ]
+ },
+ "criteria": {
+ "true": "`page` shows the end result that `goal` asks for.",
+ "false": "At least one more action is needed, `page` shows something else, or it is unclear."
+ }
+ },
+ "blocker": {
+ "type": "choice",
+ "instructions": {
+ "question": "Does `page` present an obstacle that an automated browser agent cannot resolve with the listed elements and `inputs`, stopping progress toward `goal`?",
+ "rules": [
+ "Pick `none` unless the obstacle is clearly visible in `page`.",
+ "Cookie banners or dialogs that have a listed button to dismiss them are not obstacles."
+ ]
+ },
+ "criteria": {
+ "none": "No obstacle: the page can be operated normally (a login form that can be filled with provided `inputs` is not an obstacle).",
+ "login_required": "The page requires signing in and `inputs` does not provide the credentials needed to sign in.",
+ "verification_challenge": "A CAPTCHA, one-time code, two-factor prompt, or similar human verification is shown.",
+ "consent_or_permission_dialog": "A modal dialog demanding consent, permissions, or a choice from the user blocks the content and nothing listed dismisses it.",
+ "error_page": "The page shows an error (not found, access denied, server error, network failure) instead of the expected content.",
+ "missing_information": "Progress requires information (an account, payment details, a value) that is neither on the page nor in `inputs`."
+ }
+ },
+ "action": {
+ "type": "choice",
+ "instructions": {
+ "question": "Which single browser action should be performed next to make progress toward `goal` from the current `page`?",
+ "rules": [
+ "Every element in `page.elements` can be clicked, filled or selected right now, even when its in_viewport is false (the browser scrolls to it). Scroll only when the needed element or text is not listed at all.",
+ "Use `type` only when a value in `inputs` belongs in a listed text field.",
+ "Use `stop` when `goal` is already accomplished or nothing listed can help.",
+ "Consider `last_action` and `history`: do not repeat an action that produced no change."
+ ]
+ },
+ "criteria": {
+ "click": {
+ "what": "Click one element listed in `page.elements` (a link, button, checkbox, radio, tab, menu item, or similar).",
+ "use_when": "The next step toward `goal` is to open, choose, submit, toggle, or confirm something that is listed."
+ },
+ "select": {
+ "what": "Choose an option in a dropdown listed in `page.elements`.",
+ "use_when": "A dropdown must be set to a value implied by `goal` or `inputs`."
+ },
+ "scroll_down": {
+ "what": "Scroll down to reveal content that is not listed in `page.elements` and not in `page.visible_text`.",
+ "use_when": "Nothing listed can serve `goal` and more content probably exists further down. Never needed to reach an element that is already listed: clicking scrolls to it automatically."
+ },
+ "wait": {
+ "what": "Do nothing for a moment because the page is still loading or a result is still pending.",
+ "use_when": "The visible text or a dialog indicates loading, processing, or a countdown."
+ },
+ "stop": {
+ "what": "Stop: no listed action can make progress toward `goal`.",
+ "use_when": "`goal` is already accomplished as shown by `page`, or it is impossible from here with the listed actions."
+ }
+ }
+ },
+ "click_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is a click, which element in `page.elements` should be clicked to make progress toward `goal`?",
+ "rules": [
+ "Choose `none` if no listed element helps.",
+ "Each option id refers to `page.elements[].id`."
+ ]
+ },
+ "criteria": {
+ "e1": "link 'View today's Apple Inc stock price and latest AAPL news and analysis. Create re…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "e2": "link 'DuckDuckGo' → /html/",
+ "e4": "button 'Search'",
+ "e5": "dropdown 'All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgar…' (nothing selected yet; options: All Regions | Argentina | Australia | Austria | Belgium (fr) | Belgium (nl) | Brazil | Bulgaria | Canada (en) | Canada (fr) | Catalonia | Chile | …)",
+ "e6": "dropdown 'Any Time Past Day Past Week Past Month Past Year' (nothing selected yet; options: Any Time | Past Day | Past Week | Past Month | Past Year)",
+ "e7": "link 'Plus500™ Trade Stocks CFDs - 24/7 Support' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dplus500.com%26ad_provider%3Dbingv7aa%26ad_ty…",
+ "e8": "button 'AD'",
+ "e9": "link 'plus500.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dplus500.com%26ad_provider%3Dbingv7aa%26ad_ty…",
+ "e10": "link 'CFD Trading. Access the Stock Market via CFDs. Free Demo. Capital at risk. Trad…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dplus500.com%26ad_provider%3Dbingv7aa%26ad_ty…",
+ "e11": "link 'Lightspeed Trading Platform - Online Stock Trading' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "e12": "button 'AD'",
+ "e13": "link 'lightspeed.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "e14": "link 'Open an Account Today with a Brokerage Firm Designed for Active Traders. Trade …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "e15": "link 'Apple Inc. (AAPL) Stock Price, News, Quote & History - Yahoo Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "e16": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "e17": "link 'finance.yahoo.com/quote/AAPL/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "e18": "link 'Find the latest Apple Inc. (AAPL) stock quote, history, news and other vital in…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "e19": "link 'Stock Price - Apple' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "e20": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdef…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "e21": "link 'investor.apple.com/stock-price/default.aspx' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "e22": "link 'The stock information provided is for informational purposes only and is not in…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "e23": "link 'Apple Inc (AAPL) Stock Price & News - Google Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "e24": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "e25": "link 'www.google.com/finance/quote/AAPL:NASDAQ' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "e26": "link 'Get real-time stock quotes, news, financial details, and analytics for Apple In…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "e27": "link 'Apple (AAPL) Stock Price & Overview' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "e28": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "e29": "link 'stockanalysis.com/stocks/aapl/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "e30": "link 'A detailed overview of Apple Inc. (AAPL) stock, including real-time price, char…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "e31": "link 'AAPL Stock Price | Apple Inc. Stock Quote (U.S.: Nasdaq) | MarketWatch' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "e32": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "e33": "link 'www.marketwatch.com/investing/stock/aapl' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "e34": "link 'AAPL | Complete Apple Inc. stock news by MarketWatch. View real-time stock pric…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "e35": "link 'Apple Stock Price Today | NASDAQ: AAPL Live - Investing.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "e36": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dc…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "e37": "link 'www.investing.com/equities/apple-computer-inc' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "e38": "link 'AAPL: Apple Inc. - Stock Price, Quote and News - CNBC' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "e39": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "e40": "link 'www.cnbc.com/quotes/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "e41": "link 'Get Apple Inc. (AAPL:NASDAQ) real-time stock quotes, news, price and financial …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "e42": "link 'Apple Inc. (AAPL) Stock Historical Prices & Data - Yahoo Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "e43": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhisto…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "e44": "link 'finance.yahoo.com/quote/AAPL/history/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "e45": "link 'Discover historical prices for AAPL stock on Yahoo Finance. View daily, weekly …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "e46": "link 'Apple Inc - AAPL - Stock Price & Analysis | Finbox' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "e47": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dk…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "e48": "link 'finbox.com/NASDAQGS:AAPL/?ai=kuy15sh&pi=mfnbx' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "e49": "link 'Get real-time Apple (AAPL) stock price quotes, analyst insights, forecasts, new…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "e50": "link 'AAPL Stock Quote Price and Forecast | CNN' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "e51": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&ru…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "e52": "link 'www.cnn.com/markets/stocks/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "e53": "link 'View Apple Inc. AAPL stock quote prices, financial information, real-time forec…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "e54": "button 'Next'",
+ "e55": "link 'Feedback' → //duckduckgo.com/feedback.html",
+ "none": "No listed element should be clicked."
+ }
+ },
+ "select_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is choosing a dropdown option, which dropdown in `page.elements` should be changed to make progress toward `goal`?"
+ },
+ "criteria": {
+ "e5": "dropdown 'All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgar…' (nothing selected yet; options: All Regions | Argentina | Australia | Austria | Belgium (fr) | Belgium (nl) | Brazil | Bulgaria | Canada (en) | Canada (fr) | Catalonia | Chile | …)",
+ "e6": "dropdown 'Any Time Past Day Past Week Past Month Past Year' (nothing selected yet; options: Any Time | Past Day | Past Week | Past Month | Past Year)",
+ "none": "No listed dropdown needs changing."
+ }
+ }
+}
\ No newline at end of file
diff --git a/experiments/gguf-provider/fixtures/judge-state.json b/experiments/gguf-provider/fixtures/judge-state.json
new file mode 100644
index 0000000..043f5d0
--- /dev/null
+++ b/experiments/gguf-provider/fixtures/judge-state.json
@@ -0,0 +1,309 @@
+{
+ "goal": "find today's price of AAPL",
+ "inputs": "none provided",
+ "page": {
+ "url": "https://html.duckduckgo.com/html/?q=apple+stock+price",
+ "title": "apple stock price at DuckDuckGo",
+ "headings": [
+ "## Plus500™ Trade Stocks CFDs - 24/7 Support AD",
+ "## Lightspeed Trading Platform - Online Stock Trading AD",
+ "## Apple Inc. (AAPL) Stock Price, News, Quote & History - Yahoo Finance",
+ "## Stock Price - Apple",
+ "## Apple Inc (AAPL) Stock Price & News - Google Finance",
+ "## Apple (AAPL) Stock Price & Overview",
+ "## AAPL Stock Price | Apple Inc. Stock Quote (U.S.: Nasdaq) | MarketWatch",
+ "## Apple Stock Price Today | NASDAQ: AAPL Live - Investing.com",
+ "## AAPL: Apple Inc. - Stock Price, Quote and News - CNBC",
+ "## Apple Inc. (AAPL) Stock Historical Prices & Data - Yahoo Finance",
+ "## Apple Inc - AAPL - Stock Price & Analysis | Finbox",
+ "## AAPL Stock Quote Price and Forecast | CNN"
+ ],
+ "dialog": null,
+ "scroll_position": "at the top; more content below",
+ "visible_text": "All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgaria Canada (en) Canada (fr) Catalonia Chile China Colombia Croatia Czech Republic Denmark Estonia Finland France Germany Greece Hong Kong Hungary Iceland India (en) Indonesia (en) Ireland Israel (en) Italy Japan Korea Latvia Lithuania Malaysia (en) Mexico Netherlands New Zealand Norway Pakistan (en) Peru Philippines (en) Poland Portugal Romania Russia Saudi Arabia Singapore Slovakia Slovenia South Africa Spain (ca) Spain (es) Sweden Switzerland (de) Switzerland (fr) Taiwan Thailand (en) Turkey US (English) US (Spanish) Ukraine United Kingdom Vietnam (en) Any Time Past Day Past Week Past Month Past Year Plus500™ Trade Stocks CFDs - 24/7 Support AD plus500.com CFD Trading. Access the Stock Market via CFDs. Free Demo. Capital at risk. Trade CFDs: Stocks, Forex, Options, Commodities, ETFs, Indexes & more. Tight Spreads. Lightspeed Trading Platform - Online Stock Trading AD lightspeed.com Open an Account Today with a Brokerage Firm Designed for Active Traders. Trade with Confidence When the Market Moves Fast with Stable and Reliable Technology. Apple Inc. (AAPL) Stock Price, News, Quote & History - Yahoo Finance finance.yahoo.com/quote/AAPL/ Find the latest Apple Inc. (AAPL) stock quote, history, news and other vital information to help you with your stock trading and investing. Stock Price - Apple investor.apple.com/stock-price/default.aspx 2026-09-22T20:00:00.0000000 The stock information provided is for informational purposes only and is not intended for trading purposes. The stock information and charts are provided by Tickertech, a third party service, and Apple does not provide information to this service. Apple Inc (AAPL) Stock Price & News - Google Finance www.google.com/finance/quote/AAPL:NASDAQ Get real-time stock quotes, news, financial details, and analytics for Apple Inc from Google Finance. Apple (AAPL) Stock Price & Overview stockanalysis.com/stocks/aapl/ 2026-09-22T20:00:00.0000000 A detailed overview of Apple Inc. (AAPL) stock, including real-time price, chart, key statistics, news, and more. AAPL Stock Price | Apple Inc. Stock Quote (U.S.: Nasdaq) | MarketWatch www.marketwatch.com/investing/stock/aapl 2026-09-23T00:00:00.0000000 AAPL | Complete Apple Inc. stock news by MarketWatch. View real-time stock prices and stock quotes for a full financial overview. Apple Stock Price Today | NASDAQ: AAPL Live - Investing.com www.investing.com/equities/apple-computer-inc View today's Apple Inc stock price and latest AAPL news and analysis. Create real-time notifications to follow any changes in the live stock price. AAPL: Apple Inc. - Stock Price, Quote and News - CNBC www.cnbc.com/quotes/AAPL Get Apple Inc. (AAPL:NASDAQ) real-time stock quotes, news, price and financial information from CNBC. Apple Inc. (AAPL) Stock Historical Prices & Data - Yahoo Finance finance.yahoo.com/quote/AAPL/history/ Discover historical prices for AAPL stock on Yahoo Finance. View daily, w…",
+ "elements": [
+ {
+ "id": "e1",
+ "description": "link 'View today's Apple Inc stock price and latest AAPL news and analysis. Create re…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "in_viewport": false
+ },
+ {
+ "id": "e2",
+ "description": "link 'DuckDuckGo' → /html/",
+ "in_viewport": true
+ },
+ {
+ "id": "e3",
+ "description": "text field 'q' (current value \"apple stock price\")",
+ "in_viewport": true
+ },
+ {
+ "id": "e4",
+ "description": "button 'Search'",
+ "in_viewport": true
+ },
+ {
+ "id": "e5",
+ "description": "dropdown 'All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgar…' (nothing selected yet; options: All Regions | Argentina | Australia | Austria | Belgium (fr) | Belgium (nl) | Brazil | Bulgaria | Canada (en) | Canada (fr) | Catalonia | Chile | …)",
+ "in_viewport": true
+ },
+ {
+ "id": "e6",
+ "description": "dropdown 'Any Time Past Day Past Week Past Month Past Year' (nothing selected yet; options: Any Time | Past Day | Past Week | Past Month | Past Year)",
+ "in_viewport": true
+ },
+ {
+ "id": "e7",
+ "description": "link 'Plus500™ Trade Stocks CFDs - 24/7 Support' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dplus500.com%26ad_provider%3Dbingv7aa%26ad_ty…",
+ "in_viewport": true
+ },
+ {
+ "id": "e8",
+ "description": "button 'AD'",
+ "in_viewport": true
+ },
+ {
+ "id": "e9",
+ "description": "link 'plus500.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dplus500.com%26ad_provider%3Dbingv7aa%26ad_ty…",
+ "in_viewport": true
+ },
+ {
+ "id": "e10",
+ "description": "link 'CFD Trading. Access the Stock Market via CFDs. Free Demo. Capital at risk. Trad…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dplus500.com%26ad_provider%3Dbingv7aa%26ad_ty…",
+ "in_viewport": true
+ },
+ {
+ "id": "e11",
+ "description": "link 'Lightspeed Trading Platform - Online Stock Trading' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "in_viewport": true
+ },
+ {
+ "id": "e12",
+ "description": "button 'AD'",
+ "in_viewport": true
+ },
+ {
+ "id": "e13",
+ "description": "link 'lightspeed.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "in_viewport": true
+ },
+ {
+ "id": "e14",
+ "description": "link 'Open an Account Today with a Brokerage Firm Designed for Active Traders. Trade …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "in_viewport": true
+ },
+ {
+ "id": "e15",
+ "description": "link 'Apple Inc. (AAPL) Stock Price, News, Quote & History - Yahoo Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "in_viewport": true
+ },
+ {
+ "id": "e16",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "in_viewport": true
+ },
+ {
+ "id": "e17",
+ "description": "link 'finance.yahoo.com/quote/AAPL/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "in_viewport": true
+ },
+ {
+ "id": "e18",
+ "description": "link 'Find the latest Apple Inc. (AAPL) stock quote, history, news and other vital in…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "in_viewport": true
+ },
+ {
+ "id": "e19",
+ "description": "link 'Stock Price - Apple' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "in_viewport": true
+ },
+ {
+ "id": "e20",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdef…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "in_viewport": true
+ },
+ {
+ "id": "e21",
+ "description": "link 'investor.apple.com/stock-price/default.aspx' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "in_viewport": true
+ },
+ {
+ "id": "e22",
+ "description": "link 'The stock information provided is for informational purposes only and is not in…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "in_viewport": true
+ },
+ {
+ "id": "e23",
+ "description": "link 'Apple Inc (AAPL) Stock Price & News - Google Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "in_viewport": true
+ },
+ {
+ "id": "e24",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "in_viewport": true
+ },
+ {
+ "id": "e25",
+ "description": "link 'www.google.com/finance/quote/AAPL:NASDAQ' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "in_viewport": true
+ },
+ {
+ "id": "e26",
+ "description": "link 'Get real-time stock quotes, news, financial details, and analytics for Apple In…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "in_viewport": true
+ },
+ {
+ "id": "e27",
+ "description": "link 'Apple (AAPL) Stock Price & Overview' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "in_viewport": true
+ },
+ {
+ "id": "e28",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "in_viewport": true
+ },
+ {
+ "id": "e29",
+ "description": "link 'stockanalysis.com/stocks/aapl/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "in_viewport": true
+ },
+ {
+ "id": "e30",
+ "description": "link 'A detailed overview of Apple Inc. (AAPL) stock, including real-time price, char…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "in_viewport": false
+ },
+ {
+ "id": "e31",
+ "description": "link 'AAPL Stock Price | Apple Inc. Stock Quote (U.S.: Nasdaq) | MarketWatch' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "in_viewport": false
+ },
+ {
+ "id": "e32",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "in_viewport": false
+ },
+ {
+ "id": "e33",
+ "description": "link 'www.marketwatch.com/investing/stock/aapl' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "in_viewport": false
+ },
+ {
+ "id": "e34",
+ "description": "link 'AAPL | Complete Apple Inc. stock news by MarketWatch. View real-time stock pric…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "in_viewport": false
+ },
+ {
+ "id": "e35",
+ "description": "link 'Apple Stock Price Today | NASDAQ: AAPL Live - Investing.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "in_viewport": false
+ },
+ {
+ "id": "e36",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dc…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "in_viewport": false
+ },
+ {
+ "id": "e37",
+ "description": "link 'www.investing.com/equities/apple-computer-inc' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "in_viewport": false
+ },
+ {
+ "id": "e38",
+ "description": "link 'AAPL: Apple Inc. - Stock Price, Quote and News - CNBC' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "in_viewport": false
+ },
+ {
+ "id": "e39",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "in_viewport": false
+ },
+ {
+ "id": "e40",
+ "description": "link 'www.cnbc.com/quotes/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "in_viewport": false
+ },
+ {
+ "id": "e41",
+ "description": "link 'Get Apple Inc. (AAPL:NASDAQ) real-time stock quotes, news, price and financial …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "in_viewport": false
+ },
+ {
+ "id": "e42",
+ "description": "link 'Apple Inc. (AAPL) Stock Historical Prices & Data - Yahoo Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "in_viewport": false
+ },
+ {
+ "id": "e43",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhisto…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "in_viewport": false
+ },
+ {
+ "id": "e44",
+ "description": "link 'finance.yahoo.com/quote/AAPL/history/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "in_viewport": false
+ },
+ {
+ "id": "e45",
+ "description": "link 'Discover historical prices for AAPL stock on Yahoo Finance. View daily, weekly …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "in_viewport": false
+ },
+ {
+ "id": "e46",
+ "description": "link 'Apple Inc - AAPL - Stock Price & Analysis | Finbox' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "in_viewport": false
+ },
+ {
+ "id": "e47",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dk…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "in_viewport": false
+ },
+ {
+ "id": "e48",
+ "description": "link 'finbox.com/NASDAQGS:AAPL/?ai=kuy15sh&pi=mfnbx' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "in_viewport": false
+ },
+ {
+ "id": "e49",
+ "description": "link 'Get real-time Apple (AAPL) stock price quotes, analyst insights, forecasts, new…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "in_viewport": false
+ },
+ {
+ "id": "e50",
+ "description": "link 'AAPL Stock Quote Price and Forecast | CNN' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "in_viewport": false
+ },
+ {
+ "id": "e51",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&ru…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "in_viewport": false
+ },
+ {
+ "id": "e52",
+ "description": "link 'www.cnn.com/markets/stocks/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "in_viewport": false
+ },
+ {
+ "id": "e53",
+ "description": "link 'View Apple Inc. AAPL stock quote prices, financial information, real-time forec…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "in_viewport": false
+ },
+ {
+ "id": "e54",
+ "description": "button 'Next'",
+ "in_viewport": false
+ },
+ {
+ "id": "e55",
+ "description": "link 'Feedback' → //duckduckgo.com/feedback.html",
+ "in_viewport": false
+ }
+ ],
+ "omitted_elements": 0
+ },
+ "previous_page": null,
+ "last_action": null,
+ "history": {
+ "steps_taken": 0,
+ "recent_urls": []
+ }
+}
\ No newline at end of file
diff --git a/experiments/gguf-provider/fixtures/raw_ddg_typed.txt b/experiments/gguf-provider/fixtures/raw_ddg_typed.txt
new file mode 100644
index 0000000..88c3f0f
--- /dev/null
+++ b/experiments/gguf-provider/fixtures/raw_ddg_typed.txt
@@ -0,0 +1,562 @@
+backend=ego model=jev-latest maxSteps=25 budget=$0.25
+ego task space 24, page p1
+{
+ "mode": "dry-run",
+ "backend": "ego",
+ "state": {
+ "goal": "search for the nvidia stock price",
+ "inputs": {
+ "query": "nvidia stock price"
+ },
+ "page": {
+ "url": "https://html.duckduckgo.com/html/?q=apple+stock+price",
+ "title": "apple stock price at DuckDuckGo",
+ "headings": [
+ "## Lightspeed Trading Platform - Online Stock Trading AD",
+ "## Apple Inc. (AAPL) Stock Price, News, Quote & History - Yahoo Finance",
+ "## Stock Price - Apple",
+ "## Apple Inc (AAPL) Stock Price & News - Google Finance",
+ "## Apple (AAPL) Stock Price & Overview",
+ "## AAPL Stock Price | Apple Inc. Stock Quote (U.S.: Nasdaq) | MarketWatch",
+ "## Apple Inc - AAPL - Stock Price & Analysis | Finbox",
+ "## Apple Stock Price Today | NASDAQ: AAPL Live - Investing.com",
+ "## AAPL: Apple Inc. - Stock Price, Quote and News - CNBC",
+ "## AAPL Stock Quote Price and Forecast | CNN",
+ "## AAPL Interactive Stock Chart | Apple Inc. Stock - Yahoo Finance"
+ ],
+ "dialog": null,
+ "scroll_position": "at the top; more content below",
+ "visible_text": "All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgaria Canada (en) Canada (fr) Catalonia Chile China Colombia Croatia Czech Republic Denmark Estonia Finland France Germany Greece Hong Kong Hungary Iceland India (en) Indonesia (en) Ireland Israel (en) Italy Japan Korea Latvia Lithuania Malaysia (en) Mexico Netherlands New Zealand Norway Pakistan (en) Peru Philippines (en) Poland Portugal Romania Russia Saudi Arabia Singapore Slovakia Slovenia South Africa Spain (ca) Spain (es) Sweden Switzerland (de) Switzerland (fr) Taiwan Thailand (en) Turkey US (English) US (Spanish) Ukraine United Kingdom Vietnam (en) Any Time Past Day Past Week Past Month Past Year Lightspeed Trading Platform - Online Stock Trading AD lightspeed.com Open an Account Today with a Brokerage Firm Designed for Active Traders. Earn Unlimited Cash Back on a 50% Commission Rebate for Your First 3 Months. Apple Inc. (AAPL) Stock Price, News, Quote & History - Yahoo Finance finance.yahoo.com/quote/AAPL/ Find the latest Apple Inc. (AAPL) stock quote, history, news and other vital information to help you with your stock trading and investing. Stock Price - Apple investor.apple.com/stock-price/default.aspx 2026-09-22T20:00:00.0000000 The stock information provided is for informational purposes only and is not intended for trading purposes. The stock information and charts are provided by Tickertech, a third party service, and Apple does not provide information to this service. Apple Inc (AAPL) Stock Price & News - Google Finance www.google.com/finance/quote/AAPL:NASDAQ Get real-time stock quotes, news, financial details, and analytics for Apple Inc from Google Finance. Apple (AAPL) Stock Price & Overview stockanalysis.com/stocks/aapl/ 2026-09-22T20:00:00.0000000 A detailed overview of Apple Inc. (AAPL) stock, including real-time price, chart, key statistics, news, and more. AAPL Stock Price | Apple Inc. Stock Quote (U.S.: Nasdaq) | MarketWatch www.marketwatch.com/investing/stock/aapl 2026-09-23T00:00:00.0000000 AAPL | Complete Apple Inc. stock news by MarketWatch. View real-time stock prices and stock quotes for a full financial overview. Apple Inc - AAPL - Stock Price & Analysis | Finbox finbox.com/NASDAQGS:AAPL/?ai=kuy15sh&pi=mfnbx 2026-06-27T00:00:00.0000000 Get real-time Apple (AAPL) stock price quotes, analyst insights, forecasts, news, and information you need to help your stock trading and investing. Apple Stock Price Today | NASDAQ: AAPL Live - Investing.com www.investing.com/equities/apple-computer-inc View today's Apple Inc stock price and latest AAPL news and analysis. Create real-time notifications to follow any changes in the live stock price. AAPL: Apple Inc. - Stock Price, Quote and News - CNBC www.cnbc.com/quotes/AAPL Get Apple Inc. (AAPL:NASDAQ) real-time stock quotes, news, price and financial information from CNBC. AAPL Stock Quote Price and Forecast | CNN www.cnn.com/markets/stocks/AAPL View Apple Inc. AAPL stock quote prices, financial info…",
+ "elements": [
+ {
+ "id": "e1",
+ "description": "button 'Search'",
+ "in_viewport": true
+ },
+ {
+ "id": "e2",
+ "description": "link 'DuckDuckGo' → /html/",
+ "in_viewport": true
+ },
+ {
+ "id": "e3",
+ "description": "text field 'q' (current value \"apple stock price\")",
+ "in_viewport": true
+ },
+ {
+ "id": "e4",
+ "description": "dropdown 'All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgar…' (nothing selected yet; options: All Regions | Argentina | Australia | Austria | Belgium (fr) | Belgium (nl) | Brazil | Bulgaria | Canada (en) | Canada (fr) | Catalonia | Chile | …)",
+ "in_viewport": true
+ },
+ {
+ "id": "e5",
+ "description": "dropdown 'Any Time Past Day Past Week Past Month Past Year' (nothing selected yet; options: Any Time | Past Day | Past Week | Past Month | Past Year)",
+ "in_viewport": true
+ },
+ {
+ "id": "e6",
+ "description": "link 'Lightspeed Trading Platform - Online Stock Trading' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "in_viewport": true
+ },
+ {
+ "id": "e7",
+ "description": "button 'AD'",
+ "in_viewport": true
+ },
+ {
+ "id": "e8",
+ "description": "link 'lightspeed.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "in_viewport": true
+ },
+ {
+ "id": "e9",
+ "description": "link 'Open an Account Today with a Brokerage Firm Designed for Active Traders. Earn U…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "in_viewport": true
+ },
+ {
+ "id": "e10",
+ "description": "link 'Apple Inc. (AAPL) Stock Price, News, Quote & History - Yahoo Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "in_viewport": true
+ },
+ {
+ "id": "e11",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "in_viewport": true
+ },
+ {
+ "id": "e12",
+ "description": "link 'finance.yahoo.com/quote/AAPL/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "in_viewport": true
+ },
+ {
+ "id": "e13",
+ "description": "link 'Find the latest Apple Inc. (AAPL) stock quote, history, news and other vital in…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "in_viewport": true
+ },
+ {
+ "id": "e14",
+ "description": "link 'Stock Price - Apple' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "in_viewport": true
+ },
+ {
+ "id": "e15",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdef…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "in_viewport": true
+ },
+ {
+ "id": "e16",
+ "description": "link 'investor.apple.com/stock-price/default.aspx' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "in_viewport": true
+ },
+ {
+ "id": "e17",
+ "description": "link 'The stock information provided is for informational purposes only and is not in…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "in_viewport": true
+ },
+ {
+ "id": "e18",
+ "description": "link 'Apple Inc (AAPL) Stock Price & News - Google Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "in_viewport": true
+ },
+ {
+ "id": "e19",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "in_viewport": true
+ },
+ {
+ "id": "e20",
+ "description": "link 'www.google.com/finance/quote/AAPL:NASDAQ' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "in_viewport": true
+ },
+ {
+ "id": "e21",
+ "description": "link 'Get real-time stock quotes, news, financial details, and analytics for Apple In…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "in_viewport": true
+ },
+ {
+ "id": "e22",
+ "description": "link 'Apple (AAPL) Stock Price & Overview' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "in_viewport": true
+ },
+ {
+ "id": "e23",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "in_viewport": true
+ },
+ {
+ "id": "e24",
+ "description": "link 'stockanalysis.com/stocks/aapl/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "in_viewport": true
+ },
+ {
+ "id": "e25",
+ "description": "link 'A detailed overview of Apple Inc. (AAPL) stock, including real-time price, char…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "in_viewport": true
+ },
+ {
+ "id": "e26",
+ "description": "link 'AAPL Stock Price | Apple Inc. Stock Quote (U.S.: Nasdaq) | MarketWatch' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "in_viewport": false
+ },
+ {
+ "id": "e27",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "in_viewport": false
+ },
+ {
+ "id": "e28",
+ "description": "link 'www.marketwatch.com/investing/stock/aapl' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "in_viewport": false
+ },
+ {
+ "id": "e29",
+ "description": "link 'AAPL | Complete Apple Inc. stock news by MarketWatch. View real-time stock pric…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "in_viewport": false
+ },
+ {
+ "id": "e30",
+ "description": "link 'Apple Inc - AAPL - Stock Price & Analysis | Finbox' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "in_viewport": false
+ },
+ {
+ "id": "e31",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dk…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "in_viewport": false
+ },
+ {
+ "id": "e32",
+ "description": "link 'finbox.com/NASDAQGS:AAPL/?ai=kuy15sh&pi=mfnbx' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "in_viewport": false
+ },
+ {
+ "id": "e33",
+ "description": "link 'Get real-time Apple (AAPL) stock price quotes, analyst insights, forecasts, new…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "in_viewport": false
+ },
+ {
+ "id": "e34",
+ "description": "link 'Apple Stock Price Today | NASDAQ: AAPL Live - Investing.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "in_viewport": false
+ },
+ {
+ "id": "e35",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dc…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "in_viewport": false
+ },
+ {
+ "id": "e36",
+ "description": "link 'www.investing.com/equities/apple-computer-inc' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "in_viewport": false
+ },
+ {
+ "id": "e37",
+ "description": "link 'View today's Apple Inc stock price and latest AAPL news and analysis. Create re…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "in_viewport": false
+ },
+ {
+ "id": "e38",
+ "description": "link 'AAPL: Apple Inc. - Stock Price, Quote and News - CNBC' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "in_viewport": false
+ },
+ {
+ "id": "e39",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "in_viewport": false
+ },
+ {
+ "id": "e40",
+ "description": "link 'www.cnbc.com/quotes/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "in_viewport": false
+ },
+ {
+ "id": "e41",
+ "description": "link 'Get Apple Inc. (AAPL:NASDAQ) real-time stock quotes, news, price and financial …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "in_viewport": false
+ },
+ {
+ "id": "e42",
+ "description": "link 'AAPL Stock Quote Price and Forecast | CNN' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "in_viewport": false
+ },
+ {
+ "id": "e43",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&ru…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "in_viewport": false
+ },
+ {
+ "id": "e44",
+ "description": "link 'www.cnn.com/markets/stocks/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "in_viewport": false
+ },
+ {
+ "id": "e45",
+ "description": "link 'View Apple Inc. AAPL stock quote prices, financial information, real-time forec…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "in_viewport": false
+ },
+ {
+ "id": "e46",
+ "description": "link 'AAPL Interactive Stock Chart | Apple Inc. Stock - Yahoo Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fchart%2FAAPL&rut=214f360bebd2cb7a4ec2c7bce2ba334a22b97c43a86…",
+ "in_viewport": false
+ },
+ {
+ "id": "e47",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fchart%2FAAPL&rut=214…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fchart%2FAAPL&rut=214f360bebd2cb7a4ec2c7bce2ba334a22b97c43a86…",
+ "in_viewport": false
+ },
+ {
+ "id": "e48",
+ "description": "link 'finance.yahoo.com/chart/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fchart%2FAAPL&rut=214f360bebd2cb7a4ec2c7bce2ba334a22b97c43a86…",
+ "in_viewport": false
+ },
+ {
+ "id": "e49",
+ "description": "link 'At Yahoo Finance, you get free stock quotes, up-to-date news, portfolio managem…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fchart%2FAAPL&rut=214f360bebd2cb7a4ec2c7bce2ba334a22b97c43a86…",
+ "in_viewport": false
+ },
+ {
+ "id": "e50",
+ "description": "button 'Next'",
+ "in_viewport": false
+ },
+ {
+ "id": "e51",
+ "description": "link 'Feedback' → //duckduckgo.com/feedback.html",
+ "in_viewport": false
+ }
+ ],
+ "omitted_elements": 0
+ },
+ "previous_page": null,
+ "last_action": null,
+ "history": {
+ "steps_taken": 0,
+ "recent_urls": []
+ }
+ },
+ "questions": {
+ "goal_done": {
+ "type": "noul",
+ "instructions": {
+ "question": "Is `goal` already fully accomplished according to what `page` shows right now?",
+ "rules": [
+ "Judge only from `page` (its url, title, headings, visible_text, dialog and elements).",
+ "A page that merely offers a way to accomplish `goal` does not count as accomplished.",
+ "If `goal` asks to open or view something, it is accomplished when that thing is what `page` shows.",
+ "If `goal` asks to perform an action (submit, add, sign in, start), it is accomplished only when `page` shows the result or confirmation of that action."
+ ]
+ },
+ "criteria": {
+ "true": "`page` shows the end result that `goal` asks for.",
+ "false": "At least one more action is needed, `page` shows something else, or it is unclear."
+ }
+ },
+ "blocker": {
+ "type": "choice",
+ "instructions": {
+ "question": "Does `page` present an obstacle that an automated browser agent cannot resolve with the listed elements and `inputs`, stopping progress toward `goal`?",
+ "rules": [
+ "Pick `none` unless the obstacle is clearly visible in `page`.",
+ "Cookie banners or dialogs that have a listed button to dismiss them are not obstacles."
+ ]
+ },
+ "criteria": {
+ "none": "No obstacle: the page can be operated normally (a login form that can be filled with provided `inputs` is not an obstacle).",
+ "login_required": "The page requires signing in and `inputs` does not provide the credentials needed to sign in.",
+ "verification_challenge": "A CAPTCHA, one-time code, two-factor prompt, or similar human verification is shown.",
+ "consent_or_permission_dialog": "A modal dialog demanding consent, permissions, or a choice from the user blocks the content and nothing listed dismisses it.",
+ "error_page": "The page shows an error (not found, access denied, server error, network failure) instead of the expected content.",
+ "missing_information": "Progress requires information (an account, payment details, a value) that is neither on the page nor in `inputs`."
+ }
+ },
+ "action": {
+ "type": "choice",
+ "instructions": {
+ "question": "Which single browser action should be performed next to make progress toward `goal` from the current `page`?",
+ "rules": [
+ "Every element in `page.elements` can be clicked, filled or selected right now, even when its in_viewport is false (the browser scrolls to it). Scroll only when the needed element or text is not listed at all.",
+ "Use `type` only when a value in `inputs` belongs in a listed text field.",
+ "Use `stop` when `goal` is already accomplished or nothing listed can help.",
+ "Consider `last_action` and `history`: do not repeat an action that produced no change."
+ ]
+ },
+ "criteria": {
+ "click": {
+ "what": "Click one element listed in `page.elements` (a link, button, checkbox, radio, tab, menu item, or similar).",
+ "use_when": "The next step toward `goal` is to open, choose, submit, toggle, or confirm something that is listed."
+ },
+ "type": {
+ "what": "Type one of the provided `inputs` values into a text field listed in `page.elements`.",
+ "use_when": "A form field or search box must be filled before progress is possible, and a suitable value exists in `inputs`."
+ },
+ "select": {
+ "what": "Choose an option in a dropdown listed in `page.elements`.",
+ "use_when": "A dropdown must be set to a value implied by `goal` or `inputs`."
+ },
+ "scroll_down": {
+ "what": "Scroll down to reveal content that is not listed in `page.elements` and not in `page.visible_text`.",
+ "use_when": "Nothing listed can serve `goal` and more content probably exists further down. Never needed to reach an element that is already listed: clicking scrolls to it automatically."
+ },
+ "wait": {
+ "what": "Do nothing for a moment because the page is still loading or a result is still pending.",
+ "use_when": "The visible text or a dialog indicates loading, processing, or a countdown."
+ },
+ "stop": {
+ "what": "Stop: no listed action can make progress toward `goal`.",
+ "use_when": "`goal` is already accomplished as shown by `page`, or it is impossible from here with the listed actions."
+ }
+ }
+ },
+ "click_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is a click, which element in `page.elements` should be clicked to make progress toward `goal`?",
+ "rules": [
+ "Choose `none` if no listed element helps.",
+ "Each option id refers to `page.elements[].id`."
+ ]
+ },
+ "criteria": {
+ "e1": "button 'Search'",
+ "e2": "link 'DuckDuckGo' → /html/",
+ "e4": "dropdown 'All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgar…' (nothing selected yet; options: All Regions | Argentina | Australia | Austria | Belgium (fr) | Belgium (nl) | Brazil | Bulgaria | Canada (en) | Canada (fr) | Catalonia | Chile | …)",
+ "e5": "dropdown 'Any Time Past Day Past Week Past Month Past Year' (nothing selected yet; options: Any Time | Past Day | Past Week | Past Month | Past Year)",
+ "e6": "link 'Lightspeed Trading Platform - Online Stock Trading' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "e7": "button 'AD'",
+ "e8": "link 'lightspeed.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "e9": "link 'Open an Account Today with a Brokerage Firm Designed for Active Traders. Earn U…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "e10": "link 'Apple Inc. (AAPL) Stock Price, News, Quote & History - Yahoo Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "e11": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "e12": "link 'finance.yahoo.com/quote/AAPL/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "e13": "link 'Find the latest Apple Inc. (AAPL) stock quote, history, news and other vital in…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "e14": "link 'Stock Price - Apple' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "e15": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdef…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "e16": "link 'investor.apple.com/stock-price/default.aspx' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "e17": "link 'The stock information provided is for informational purposes only and is not in…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "e18": "link 'Apple Inc (AAPL) Stock Price & News - Google Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "e19": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "e20": "link 'www.google.com/finance/quote/AAPL:NASDAQ' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "e21": "link 'Get real-time stock quotes, news, financial details, and analytics for Apple In…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "e22": "link 'Apple (AAPL) Stock Price & Overview' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "e23": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "e24": "link 'stockanalysis.com/stocks/aapl/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "e25": "link 'A detailed overview of Apple Inc. (AAPL) stock, including real-time price, char…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "e26": "link 'AAPL Stock Price | Apple Inc. Stock Quote (U.S.: Nasdaq) | MarketWatch' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "e27": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "e28": "link 'www.marketwatch.com/investing/stock/aapl' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "e29": "link 'AAPL | Complete Apple Inc. stock news by MarketWatch. View real-time stock pric…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "e30": "link 'Apple Inc - AAPL - Stock Price & Analysis | Finbox' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "e31": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dk…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "e32": "link 'finbox.com/NASDAQGS:AAPL/?ai=kuy15sh&pi=mfnbx' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "e33": "link 'Get real-time Apple (AAPL) stock price quotes, analyst insights, forecasts, new…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "e34": "link 'Apple Stock Price Today | NASDAQ: AAPL Live - Investing.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "e35": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dc…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "e36": "link 'www.investing.com/equities/apple-computer-inc' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "e37": "link 'View today's Apple Inc stock price and latest AAPL news and analysis. Create re…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "e38": "link 'AAPL: Apple Inc. - Stock Price, Quote and News - CNBC' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "e39": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "e40": "link 'www.cnbc.com/quotes/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "e41": "link 'Get Apple Inc. (AAPL:NASDAQ) real-time stock quotes, news, price and financial …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "e42": "link 'AAPL Stock Quote Price and Forecast | CNN' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "e43": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&ru…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "e44": "link 'www.cnn.com/markets/stocks/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "e45": "link 'View Apple Inc. AAPL stock quote prices, financial information, real-time forec…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "e46": "link 'AAPL Interactive Stock Chart | Apple Inc. Stock - Yahoo Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fchart%2FAAPL&rut=214f360bebd2cb7a4ec2c7bce2ba334a22b97c43a86…",
+ "e47": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fchart%2FAAPL&rut=214…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fchart%2FAAPL&rut=214f360bebd2cb7a4ec2c7bce2ba334a22b97c43a86…",
+ "e48": "link 'finance.yahoo.com/chart/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fchart%2FAAPL&rut=214f360bebd2cb7a4ec2c7bce2ba334a22b97c43a86…",
+ "e49": "link 'At Yahoo Finance, you get free stock quotes, up-to-date news, portfolio managem…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fchart%2FAAPL&rut=214f360bebd2cb7a4ec2c7bce2ba334a22b97c43a86…",
+ "e50": "button 'Next'",
+ "e51": "link 'Feedback' → //duckduckgo.com/feedback.html",
+ "none": "No listed element should be clicked."
+ }
+ },
+ "type_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is typing, which text field in `page.elements` should receive a value from `inputs` to make progress toward `goal`?",
+ "rules": [
+ "Prefer empty fields over fields that already contain the right value.",
+ "Choose `none` if no listed field should be filled now."
+ ]
+ },
+ "criteria": {
+ "e3": "text field 'q' (current value \"apple stock price\")",
+ "none": "No listed text field should be filled now."
+ }
+ },
+ "type_value": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is typing, which entry of `inputs` belongs in the text field that should be filled next?",
+ "rules": [
+ "Match the field's label, placeholder and type to the meaning of the input key.",
+ "Choose `none` if no provided input belongs there."
+ ]
+ },
+ "criteria": {
+ "query": "inputs.query = \"nvidia stock price\"",
+ "none": "No provided input belongs in the field."
+ }
+ },
+ "submit_after_type": {
+ "type": "noul",
+ "instructions": {
+ "question": "After typing the value into the chosen text field, should the Enter key be pressed immediately to submit (as with a search box or a single-field form)?",
+ "rules": [
+ "Answer no when other fields still need values or when a separate submit button must be clicked after all fields are filled."
+ ]
+ },
+ "criteria": {
+ "true": "Pressing Enter right after typing is the natural way to submit this field (search boxes, single-field forms, the last field of a form).",
+ "false": "More fields must be filled first, or a separate button should be clicked, or Enter would do nothing useful."
+ }
+ },
+ "select_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is choosing a dropdown option, which dropdown in `page.elements` should be changed to make progress toward `goal`?"
+ },
+ "criteria": {
+ "e4": "dropdown 'All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgar…' (nothing selected yet; options: All Regions | Argentina | Australia | Austria | Belgium (fr) | Belgium (nl) | Brazil | Bulgaria | Canada (en) | Canada (fr) | Catalonia | Chile | …)",
+ "e5": "dropdown 'Any Time Past Day Past Week Past Month Past Year' (nothing selected yet; options: Any Time | Past Day | Past Week | Past Month | Past Year)",
+ "none": "No listed dropdown needs changing."
+ }
+ }
+ },
+ "meta": {
+ "allowedActions": [
+ "click",
+ "type",
+ "select",
+ "scroll_down",
+ "wait",
+ "stop"
+ ],
+ "clickableIds": [
+ "e1",
+ "e2",
+ "e4",
+ "e5",
+ "e6",
+ "e7",
+ "e8",
+ "e9",
+ "e10",
+ "e11",
+ "e12",
+ "e13",
+ "e14",
+ "e15",
+ "e16",
+ "e17",
+ "e18",
+ "e19",
+ "e20",
+ "e21",
+ "e22",
+ "e23",
+ "e24",
+ "e25",
+ "e26",
+ "e27",
+ "e28",
+ "e29",
+ "e30",
+ "e31",
+ "e32",
+ "e33",
+ "e34",
+ "e35",
+ "e36",
+ "e37",
+ "e38",
+ "e39",
+ "e40",
+ "e41",
+ "e42",
+ "e43",
+ "e44",
+ "e45",
+ "e46",
+ "e47",
+ "e48",
+ "e49",
+ "e50",
+ "e51"
+ ],
+ "editableIds": [
+ "e3"
+ ],
+ "selectIds": [
+ "e4",
+ "e5"
+ ],
+ "inputKeys": [
+ "query"
+ ],
+ "urlInputKeys": [],
+ "questionCount": 8,
+ "candidateCount": 53
+ },
+ "estimatedInputTokens": 8601,
+ "estimatedCostUsd": 0.000361242
+}
diff --git a/experiments/gguf-provider/fixtures/raw_duckduckgo_com_html__q_apple_stock_price.txt b/experiments/gguf-provider/fixtures/raw_duckduckgo_com_html__q_apple_stock_price.txt
new file mode 100644
index 0000000..f926b70
--- /dev/null
+++ b/experiments/gguf-provider/fixtures/raw_duckduckgo_com_html__q_apple_stock_price.txt
@@ -0,0 +1,541 @@
+backend=ego model=jev-latest maxSteps=25 budget=$0.25
+ego task space 16, page p1
+{
+ "mode": "dry-run",
+ "backend": "ego",
+ "state": {
+ "goal": "find today's price of AAPL",
+ "inputs": "none provided",
+ "page": {
+ "url": "https://html.duckduckgo.com/html/?q=apple+stock+price",
+ "title": "apple stock price at DuckDuckGo",
+ "headings": [
+ "## Plus500™ Trade Stocks CFDs - 24/7 Support AD",
+ "## Lightspeed Trading Platform - Online Stock Trading AD",
+ "## Apple Inc. (AAPL) Stock Price, News, Quote & History - Yahoo Finance",
+ "## Stock Price - Apple",
+ "## Apple Inc (AAPL) Stock Price & News - Google Finance",
+ "## Apple (AAPL) Stock Price & Overview",
+ "## AAPL Stock Price | Apple Inc. Stock Quote (U.S.: Nasdaq) | MarketWatch",
+ "## Apple Stock Price Today | NASDAQ: AAPL Live - Investing.com",
+ "## AAPL: Apple Inc. - Stock Price, Quote and News - CNBC",
+ "## Apple Inc. (AAPL) Stock Historical Prices & Data - Yahoo Finance",
+ "## Apple Inc - AAPL - Stock Price & Analysis | Finbox",
+ "## AAPL Stock Quote Price and Forecast | CNN"
+ ],
+ "dialog": null,
+ "scroll_position": "at the top; more content below",
+ "visible_text": "All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgaria Canada (en) Canada (fr) Catalonia Chile China Colombia Croatia Czech Republic Denmark Estonia Finland France Germany Greece Hong Kong Hungary Iceland India (en) Indonesia (en) Ireland Israel (en) Italy Japan Korea Latvia Lithuania Malaysia (en) Mexico Netherlands New Zealand Norway Pakistan (en) Peru Philippines (en) Poland Portugal Romania Russia Saudi Arabia Singapore Slovakia Slovenia South Africa Spain (ca) Spain (es) Sweden Switzerland (de) Switzerland (fr) Taiwan Thailand (en) Turkey US (English) US (Spanish) Ukraine United Kingdom Vietnam (en) Any Time Past Day Past Week Past Month Past Year Plus500™ Trade Stocks CFDs - 24/7 Support AD plus500.com CFD Trading. Access the Stock Market via CFDs. Free Demo. Capital at risk. Trade CFDs: Stocks, Forex, Options, Commodities, ETFs, Indexes & more. Tight Spreads. Lightspeed Trading Platform - Online Stock Trading AD lightspeed.com Open an Account Today with a Brokerage Firm Designed for Active Traders. Trade with Confidence When the Market Moves Fast with Stable and Reliable Technology. Apple Inc. (AAPL) Stock Price, News, Quote & History - Yahoo Finance finance.yahoo.com/quote/AAPL/ Find the latest Apple Inc. (AAPL) stock quote, history, news and other vital information to help you with your stock trading and investing. Stock Price - Apple investor.apple.com/stock-price/default.aspx 2026-09-22T20:00:00.0000000 The stock information provided is for informational purposes only and is not intended for trading purposes. The stock information and charts are provided by Tickertech, a third party service, and Apple does not provide information to this service. Apple Inc (AAPL) Stock Price & News - Google Finance www.google.com/finance/quote/AAPL:NASDAQ Get real-time stock quotes, news, financial details, and analytics for Apple Inc from Google Finance. Apple (AAPL) Stock Price & Overview stockanalysis.com/stocks/aapl/ 2026-09-22T20:00:00.0000000 A detailed overview of Apple Inc. (AAPL) stock, including real-time price, chart, key statistics, news, and more. AAPL Stock Price | Apple Inc. Stock Quote (U.S.: Nasdaq) | MarketWatch www.marketwatch.com/investing/stock/aapl 2026-09-23T00:00:00.0000000 AAPL | Complete Apple Inc. stock news by MarketWatch. View real-time stock prices and stock quotes for a full financial overview. Apple Stock Price Today | NASDAQ: AAPL Live - Investing.com www.investing.com/equities/apple-computer-inc View today's Apple Inc stock price and latest AAPL news and analysis. Create real-time notifications to follow any changes in the live stock price. AAPL: Apple Inc. - Stock Price, Quote and News - CNBC www.cnbc.com/quotes/AAPL Get Apple Inc. (AAPL:NASDAQ) real-time stock quotes, news, price and financial information from CNBC. Apple Inc. (AAPL) Stock Historical Prices & Data - Yahoo Finance finance.yahoo.com/quote/AAPL/history/ Discover historical prices for AAPL stock on Yahoo Finance. View daily, w…",
+ "elements": [
+ {
+ "id": "e1",
+ "description": "link 'View today's Apple Inc stock price and latest AAPL news and analysis. Create re…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "in_viewport": false
+ },
+ {
+ "id": "e2",
+ "description": "link 'DuckDuckGo' → /html/",
+ "in_viewport": true
+ },
+ {
+ "id": "e3",
+ "description": "text field 'q' (current value \"apple stock price\")",
+ "in_viewport": true
+ },
+ {
+ "id": "e4",
+ "description": "button 'Search'",
+ "in_viewport": true
+ },
+ {
+ "id": "e5",
+ "description": "dropdown 'All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgar…' (nothing selected yet; options: All Regions | Argentina | Australia | Austria | Belgium (fr) | Belgium (nl) | Brazil | Bulgaria | Canada (en) | Canada (fr) | Catalonia | Chile | …)",
+ "in_viewport": true
+ },
+ {
+ "id": "e6",
+ "description": "dropdown 'Any Time Past Day Past Week Past Month Past Year' (nothing selected yet; options: Any Time | Past Day | Past Week | Past Month | Past Year)",
+ "in_viewport": true
+ },
+ {
+ "id": "e7",
+ "description": "link 'Plus500™ Trade Stocks CFDs - 24/7 Support' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dplus500.com%26ad_provider%3Dbingv7aa%26ad_ty…",
+ "in_viewport": true
+ },
+ {
+ "id": "e8",
+ "description": "button 'AD'",
+ "in_viewport": true
+ },
+ {
+ "id": "e9",
+ "description": "link 'plus500.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dplus500.com%26ad_provider%3Dbingv7aa%26ad_ty…",
+ "in_viewport": true
+ },
+ {
+ "id": "e10",
+ "description": "link 'CFD Trading. Access the Stock Market via CFDs. Free Demo. Capital at risk. Trad…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dplus500.com%26ad_provider%3Dbingv7aa%26ad_ty…",
+ "in_viewport": true
+ },
+ {
+ "id": "e11",
+ "description": "link 'Lightspeed Trading Platform - Online Stock Trading' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "in_viewport": true
+ },
+ {
+ "id": "e12",
+ "description": "button 'AD'",
+ "in_viewport": true
+ },
+ {
+ "id": "e13",
+ "description": "link 'lightspeed.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "in_viewport": true
+ },
+ {
+ "id": "e14",
+ "description": "link 'Open an Account Today with a Brokerage Firm Designed for Active Traders. Trade …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "in_viewport": true
+ },
+ {
+ "id": "e15",
+ "description": "link 'Apple Inc. (AAPL) Stock Price, News, Quote & History - Yahoo Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "in_viewport": true
+ },
+ {
+ "id": "e16",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "in_viewport": true
+ },
+ {
+ "id": "e17",
+ "description": "link 'finance.yahoo.com/quote/AAPL/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "in_viewport": true
+ },
+ {
+ "id": "e18",
+ "description": "link 'Find the latest Apple Inc. (AAPL) stock quote, history, news and other vital in…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "in_viewport": true
+ },
+ {
+ "id": "e19",
+ "description": "link 'Stock Price - Apple' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "in_viewport": true
+ },
+ {
+ "id": "e20",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdef…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "in_viewport": true
+ },
+ {
+ "id": "e21",
+ "description": "link 'investor.apple.com/stock-price/default.aspx' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "in_viewport": true
+ },
+ {
+ "id": "e22",
+ "description": "link 'The stock information provided is for informational purposes only and is not in…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "in_viewport": true
+ },
+ {
+ "id": "e23",
+ "description": "link 'Apple Inc (AAPL) Stock Price & News - Google Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "in_viewport": true
+ },
+ {
+ "id": "e24",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "in_viewport": true
+ },
+ {
+ "id": "e25",
+ "description": "link 'www.google.com/finance/quote/AAPL:NASDAQ' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "in_viewport": true
+ },
+ {
+ "id": "e26",
+ "description": "link 'Get real-time stock quotes, news, financial details, and analytics for Apple In…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "in_viewport": true
+ },
+ {
+ "id": "e27",
+ "description": "link 'Apple (AAPL) Stock Price & Overview' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "in_viewport": true
+ },
+ {
+ "id": "e28",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "in_viewport": true
+ },
+ {
+ "id": "e29",
+ "description": "link 'stockanalysis.com/stocks/aapl/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "in_viewport": true
+ },
+ {
+ "id": "e30",
+ "description": "link 'A detailed overview of Apple Inc. (AAPL) stock, including real-time price, char…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "in_viewport": false
+ },
+ {
+ "id": "e31",
+ "description": "link 'AAPL Stock Price | Apple Inc. Stock Quote (U.S.: Nasdaq) | MarketWatch' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "in_viewport": false
+ },
+ {
+ "id": "e32",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "in_viewport": false
+ },
+ {
+ "id": "e33",
+ "description": "link 'www.marketwatch.com/investing/stock/aapl' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "in_viewport": false
+ },
+ {
+ "id": "e34",
+ "description": "link 'AAPL | Complete Apple Inc. stock news by MarketWatch. View real-time stock pric…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "in_viewport": false
+ },
+ {
+ "id": "e35",
+ "description": "link 'Apple Stock Price Today | NASDAQ: AAPL Live - Investing.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "in_viewport": false
+ },
+ {
+ "id": "e36",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dc…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "in_viewport": false
+ },
+ {
+ "id": "e37",
+ "description": "link 'www.investing.com/equities/apple-computer-inc' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "in_viewport": false
+ },
+ {
+ "id": "e38",
+ "description": "link 'AAPL: Apple Inc. - Stock Price, Quote and News - CNBC' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "in_viewport": false
+ },
+ {
+ "id": "e39",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "in_viewport": false
+ },
+ {
+ "id": "e40",
+ "description": "link 'www.cnbc.com/quotes/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "in_viewport": false
+ },
+ {
+ "id": "e41",
+ "description": "link 'Get Apple Inc. (AAPL:NASDAQ) real-time stock quotes, news, price and financial …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "in_viewport": false
+ },
+ {
+ "id": "e42",
+ "description": "link 'Apple Inc. (AAPL) Stock Historical Prices & Data - Yahoo Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "in_viewport": false
+ },
+ {
+ "id": "e43",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhisto…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "in_viewport": false
+ },
+ {
+ "id": "e44",
+ "description": "link 'finance.yahoo.com/quote/AAPL/history/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "in_viewport": false
+ },
+ {
+ "id": "e45",
+ "description": "link 'Discover historical prices for AAPL stock on Yahoo Finance. View daily, weekly …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "in_viewport": false
+ },
+ {
+ "id": "e46",
+ "description": "link 'Apple Inc - AAPL - Stock Price & Analysis | Finbox' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "in_viewport": false
+ },
+ {
+ "id": "e47",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dk…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "in_viewport": false
+ },
+ {
+ "id": "e48",
+ "description": "link 'finbox.com/NASDAQGS:AAPL/?ai=kuy15sh&pi=mfnbx' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "in_viewport": false
+ },
+ {
+ "id": "e49",
+ "description": "link 'Get real-time Apple (AAPL) stock price quotes, analyst insights, forecasts, new…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "in_viewport": false
+ },
+ {
+ "id": "e50",
+ "description": "link 'AAPL Stock Quote Price and Forecast | CNN' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "in_viewport": false
+ },
+ {
+ "id": "e51",
+ "description": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&ru…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "in_viewport": false
+ },
+ {
+ "id": "e52",
+ "description": "link 'www.cnn.com/markets/stocks/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "in_viewport": false
+ },
+ {
+ "id": "e53",
+ "description": "link 'View Apple Inc. AAPL stock quote prices, financial information, real-time forec…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "in_viewport": false
+ },
+ {
+ "id": "e54",
+ "description": "button 'Next'",
+ "in_viewport": false
+ },
+ {
+ "id": "e55",
+ "description": "link 'Feedback' → //duckduckgo.com/feedback.html",
+ "in_viewport": false
+ }
+ ],
+ "omitted_elements": 0
+ },
+ "previous_page": null,
+ "last_action": null,
+ "history": {
+ "steps_taken": 0,
+ "recent_urls": []
+ }
+ },
+ "questions": {
+ "goal_done": {
+ "type": "noul",
+ "instructions": {
+ "question": "Is `goal` already fully accomplished according to what `page` shows right now?",
+ "rules": [
+ "Judge only from `page` (its url, title, headings, visible_text, dialog and elements).",
+ "A page that merely offers a way to accomplish `goal` does not count as accomplished.",
+ "If `goal` asks to open or view something, it is accomplished when that thing is what `page` shows.",
+ "If `goal` asks to perform an action (submit, add, sign in, start), it is accomplished only when `page` shows the result or confirmation of that action."
+ ]
+ },
+ "criteria": {
+ "true": "`page` shows the end result that `goal` asks for.",
+ "false": "At least one more action is needed, `page` shows something else, or it is unclear."
+ }
+ },
+ "blocker": {
+ "type": "choice",
+ "instructions": {
+ "question": "Does `page` present an obstacle that an automated browser agent cannot resolve with the listed elements and `inputs`, stopping progress toward `goal`?",
+ "rules": [
+ "Pick `none` unless the obstacle is clearly visible in `page`.",
+ "Cookie banners or dialogs that have a listed button to dismiss them are not obstacles."
+ ]
+ },
+ "criteria": {
+ "none": "No obstacle: the page can be operated normally (a login form that can be filled with provided `inputs` is not an obstacle).",
+ "login_required": "The page requires signing in and `inputs` does not provide the credentials needed to sign in.",
+ "verification_challenge": "A CAPTCHA, one-time code, two-factor prompt, or similar human verification is shown.",
+ "consent_or_permission_dialog": "A modal dialog demanding consent, permissions, or a choice from the user blocks the content and nothing listed dismisses it.",
+ "error_page": "The page shows an error (not found, access denied, server error, network failure) instead of the expected content.",
+ "missing_information": "Progress requires information (an account, payment details, a value) that is neither on the page nor in `inputs`."
+ }
+ },
+ "action": {
+ "type": "choice",
+ "instructions": {
+ "question": "Which single browser action should be performed next to make progress toward `goal` from the current `page`?",
+ "rules": [
+ "Every element in `page.elements` can be clicked, filled or selected right now, even when its in_viewport is false (the browser scrolls to it). Scroll only when the needed element or text is not listed at all.",
+ "Use `type` only when a value in `inputs` belongs in a listed text field.",
+ "Use `stop` when `goal` is already accomplished or nothing listed can help.",
+ "Consider `last_action` and `history`: do not repeat an action that produced no change."
+ ]
+ },
+ "criteria": {
+ "click": {
+ "what": "Click one element listed in `page.elements` (a link, button, checkbox, radio, tab, menu item, or similar).",
+ "use_when": "The next step toward `goal` is to open, choose, submit, toggle, or confirm something that is listed."
+ },
+ "select": {
+ "what": "Choose an option in a dropdown listed in `page.elements`.",
+ "use_when": "A dropdown must be set to a value implied by `goal` or `inputs`."
+ },
+ "scroll_down": {
+ "what": "Scroll down to reveal content that is not listed in `page.elements` and not in `page.visible_text`.",
+ "use_when": "Nothing listed can serve `goal` and more content probably exists further down. Never needed to reach an element that is already listed: clicking scrolls to it automatically."
+ },
+ "wait": {
+ "what": "Do nothing for a moment because the page is still loading or a result is still pending.",
+ "use_when": "The visible text or a dialog indicates loading, processing, or a countdown."
+ },
+ "stop": {
+ "what": "Stop: no listed action can make progress toward `goal`.",
+ "use_when": "`goal` is already accomplished as shown by `page`, or it is impossible from here with the listed actions."
+ }
+ }
+ },
+ "click_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is a click, which element in `page.elements` should be clicked to make progress toward `goal`?",
+ "rules": [
+ "Choose `none` if no listed element helps.",
+ "Each option id refers to `page.elements[].id`."
+ ]
+ },
+ "criteria": {
+ "e1": "link 'View today's Apple Inc stock price and latest AAPL news and analysis. Create re…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "e2": "link 'DuckDuckGo' → /html/",
+ "e4": "button 'Search'",
+ "e5": "dropdown 'All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgar…' (nothing selected yet; options: All Regions | Argentina | Australia | Austria | Belgium (fr) | Belgium (nl) | Brazil | Bulgaria | Canada (en) | Canada (fr) | Catalonia | Chile | …)",
+ "e6": "dropdown 'Any Time Past Day Past Week Past Month Past Year' (nothing selected yet; options: Any Time | Past Day | Past Week | Past Month | Past Year)",
+ "e7": "link 'Plus500™ Trade Stocks CFDs - 24/7 Support' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dplus500.com%26ad_provider%3Dbingv7aa%26ad_ty…",
+ "e8": "button 'AD'",
+ "e9": "link 'plus500.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dplus500.com%26ad_provider%3Dbingv7aa%26ad_ty…",
+ "e10": "link 'CFD Trading. Access the Stock Market via CFDs. Free Demo. Capital at risk. Trad…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dplus500.com%26ad_provider%3Dbingv7aa%26ad_ty…",
+ "e11": "link 'Lightspeed Trading Platform - Online Stock Trading' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "e12": "button 'AD'",
+ "e13": "link 'lightspeed.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "e14": "link 'Open an Account Today with a Brokerage Firm Designed for Active Traders. Trade …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fduckduckgo.com%2Fy.js%3Fad_domain%3Dlightspeed.com%26ad_provider%3Dbingv7aa%26ad…",
+ "e15": "link 'Apple Inc. (AAPL) Stock Price, News, Quote & History - Yahoo Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "e16": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "e17": "link 'finance.yahoo.com/quote/AAPL/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "e18": "link 'Find the latest Apple Inc. (AAPL) stock quote, history, news and other vital in…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2F&rut=925d117f51b2d2c549bcef4bb77bffae9afc4460…",
+ "e19": "link 'Stock Price - Apple' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "e20": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdef…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "e21": "link 'investor.apple.com/stock-price/default.aspx' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "e22": "link 'The stock information provided is for informational purposes only and is not in…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Finvestor.apple.com%2Fstock%2Dprice%2Fdefault.aspx&rut=93af5b4e40dd2273d259cb9444…",
+ "e23": "link 'Apple Inc (AAPL) Stock Price & News - Google Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "e24": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "e25": "link 'www.google.com/finance/quote/AAPL:NASDAQ' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "e26": "link 'Get real-time stock quotes, news, financial details, and analytics for Apple In…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.google.com%2Ffinance%2Fquote%2FAAPL%3ANASDAQ&rut=99ed6a80895b304658b97cbadae…",
+ "e27": "link 'Apple (AAPL) Stock Price & Overview' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "e28": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "e29": "link 'stockanalysis.com/stocks/aapl/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "e30": "link 'A detailed overview of Apple Inc. (AAPL) stock, including real-time price, char…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fstockanalysis.com%2Fstocks%2Faapl%2F&rut=c49c036905cbe6eeb9e4eba2ce486e27df27b04…",
+ "e31": "link 'AAPL Stock Price | Apple Inc. Stock Quote (U.S.: Nasdaq) | MarketWatch' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "e32": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "e33": "link 'www.marketwatch.com/investing/stock/aapl' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "e34": "link 'AAPL | Complete Apple Inc. stock news by MarketWatch. View real-time stock pric…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.marketwatch.com%2Finvesting%2Fstock%2Faapl&rut=a975440bcf4c749c2e44e0f226f07…",
+ "e35": "link 'Apple Stock Price Today | NASDAQ: AAPL Live - Investing.com' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "e36": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dc…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "e37": "link 'www.investing.com/equities/apple-computer-inc' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.investing.com%2Fequities%2Fapple%2Dcomputer%2Dinc&rut=17856eb98fb1220a5fdc8f…",
+ "e38": "link 'AAPL: Apple Inc. - Stock Price, Quote and News - CNBC' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "e39": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "e40": "link 'www.cnbc.com/quotes/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "e41": "link 'Get Apple Inc. (AAPL:NASDAQ) real-time stock quotes, news, price and financial …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnbc.com%2Fquotes%2FAAPL&rut=3b031a9b3e5a0b19c668563be2ef460a4704e1d15fd04a4…",
+ "e42": "link 'Apple Inc. (AAPL) Stock Historical Prices & Data - Yahoo Finance' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "e43": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhisto…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "e44": "link 'finance.yahoo.com/quote/AAPL/history/' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "e45": "link 'Discover historical prices for AAPL stock on Yahoo Finance. View daily, weekly …' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinance.yahoo.com%2Fquote%2FAAPL%2Fhistory%2F&rut=bfee86f6722c9d4e1633b5411cd3e1…",
+ "e46": "link 'Apple Inc - AAPL - Stock Price & Analysis | Finbox' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "e47": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dk…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "e48": "link 'finbox.com/NASDAQGS:AAPL/?ai=kuy15sh&pi=mfnbx' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "e49": "link 'Get real-time Apple (AAPL) stock price quotes, analyst insights, forecasts, new…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Ffinbox.com%2FNASDAQGS%3AAAPL%2F%3Fai%3Dkuy15sh%26pi%3Dmfnbx&rut=83e76c56e0f88e1d…",
+ "e50": "link 'AAPL Stock Quote Price and Forecast | CNN' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "e51": "link '//duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&ru…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "e52": "link 'www.cnn.com/markets/stocks/AAPL' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "e53": "link 'View Apple Inc. AAPL stock quote prices, financial information, real-time forec…' → //duckduckgo.com/l/?uddg=https%3A%2F%2Fwww.cnn.com%2Fmarkets%2Fstocks%2FAAPL&rut=d671cad119cac68b3c3dc1bd8450e6a92bfb6c…",
+ "e54": "button 'Next'",
+ "e55": "link 'Feedback' → //duckduckgo.com/feedback.html",
+ "none": "No listed element should be clicked."
+ }
+ },
+ "select_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is choosing a dropdown option, which dropdown in `page.elements` should be changed to make progress toward `goal`?"
+ },
+ "criteria": {
+ "e5": "dropdown 'All Regions Argentina Australia Austria Belgium (fr) Belgium (nl) Brazil Bulgar…' (nothing selected yet; options: All Regions | Argentina | Australia | Austria | Belgium (fr) | Belgium (nl) | Brazil | Bulgaria | Canada (en) | Canada (fr) | Catalonia | Chile | …)",
+ "e6": "dropdown 'Any Time Past Day Past Week Past Month Past Year' (nothing selected yet; options: Any Time | Past Day | Past Week | Past Month | Past Year)",
+ "none": "No listed dropdown needs changing."
+ }
+ }
+ },
+ "meta": {
+ "allowedActions": [
+ "click",
+ "select",
+ "scroll_down",
+ "wait",
+ "stop"
+ ],
+ "clickableIds": [
+ "e1",
+ "e2",
+ "e4",
+ "e5",
+ "e6",
+ "e7",
+ "e8",
+ "e9",
+ "e10",
+ "e11",
+ "e12",
+ "e13",
+ "e14",
+ "e15",
+ "e16",
+ "e17",
+ "e18",
+ "e19",
+ "e20",
+ "e21",
+ "e22",
+ "e23",
+ "e24",
+ "e25",
+ "e26",
+ "e27",
+ "e28",
+ "e29",
+ "e30",
+ "e31",
+ "e32",
+ "e33",
+ "e34",
+ "e35",
+ "e36",
+ "e37",
+ "e38",
+ "e39",
+ "e40",
+ "e41",
+ "e42",
+ "e43",
+ "e44",
+ "e45",
+ "e46",
+ "e47",
+ "e48",
+ "e49",
+ "e50",
+ "e51",
+ "e52",
+ "e53",
+ "e54",
+ "e55"
+ ],
+ "editableIds": [
+ "e3"
+ ],
+ "selectIds": [
+ "e5",
+ "e6"
+ ],
+ "inputKeys": [],
+ "urlInputKeys": [],
+ "questionCount": 5,
+ "candidateCount": 57
+ },
+ "estimatedInputTokens": 8492,
+ "estimatedCostUsd": 0.000356664
+}
diff --git a/experiments/gguf-provider/fixtures/raw_en_wikipedia_org_wiki_Main_Page.txt b/experiments/gguf-provider/fixtures/raw_en_wikipedia_org_wiki_Main_Page.txt
new file mode 100644
index 0000000..d8357ad
--- /dev/null
+++ b/experiments/gguf-provider/fixtures/raw_en_wikipedia_org_wiki_Main_Page.txt
@@ -0,0 +1,834 @@
+backend=ego model=jev-latest maxSteps=25 budget=$0.25
+ego task space 15, page p1
+{
+ "mode": "dry-run",
+ "backend": "ego",
+ "state": {
+ "goal": "find today's price of AAPL",
+ "inputs": "none provided",
+ "page": {
+ "url": "https://en.wikipedia.org/wiki/Main_Page",
+ "title": "Wikipedia, the free encyclopedia",
+ "headings": [
+ "# Welcome to Wikipedia",
+ "## From today's featured article",
+ "## Did you know ...",
+ "## In the news",
+ "## On this day",
+ "## From today's featured list",
+ "## Today's featured video",
+ "## Other areas of Wikipedia",
+ "## Wikipedia's sister projects"
+ ],
+ "dialog": null,
+ "scroll_position": "at the top; more content below",
+ "visible_text": "Jump to content Main menu Search Donate Create account Log in Main Page Talk Read View source View history Tools Appearance hide Text Small Standard Large Width Standard Wide Color Automatic Light Dark Welcome to Wikipedia, the free encyclopedia that anyone can edit. 265,014 active editors7,243,180 articles in English From today's featured article Mary Mallon (September 23, 1869 – November 11, 1938), dubbed Typhoid Mary, was an Irish-born cook who lived in the US and is believed to have infected up to 57 people with the bacteria that cause typhoid fever, with three confirmed deaths. Between 1897 and 1907, Mallon worked at several homes; residents at four of them contracted typhoid. In 1907, she was forcibly quarantined at Riverside Hospital, but was freed in 1910, promising not to work as a cook. A further outbreak at the Sloane Maternity Hospital, where she was working, resulted in 25 cases and two deaths in early 1915. She was again confined, remaining so until her death in 1938. Her nickname became a term for anyone who spreads disease. Mallon's case raises questions about the balance between individual liberty and public health. No other carrier of typhoid was confined for as long as she was. Her story has been reevaluated, particularly during outbreaks of HIV/AIDS, tuberculosis, and COVID-19. (Full article...) Recently featured: Alison FrantzEarly Netherlandish paintingMisti ArchiveBy emailMore featured articlesAbout Did you know ... Lotte Rakhat chocolate bar ... that amendments to Kazakhstan's law on state symbols raised concerns over changes to the packaging of one of Lotte Rakhat's most popular products (pictured)? ... that a promotion for the Jackie Robinson commemorative coins included a baseball card issued by the United States government? ... that \"Candidatus Magnetoglobus multicellularis\", unlike almost all other known prokaryotes, spends its entire life cycle as a multicellular organism? ... that Leona E. Prasse's 1972 Feininger catalogue, which involved the help of the subject's widow, was called an improvement over a previous Feininger book from 1959? ... that the dinosaur that laid the eggs identified as Umbellaoolithus is unknown, but it ate plants? ... that only a shoe and a backpack were found after Makan Nasiri was killed in the 2026 Minab school attack? ... that a story in I Became the Main Role of a BL Drama was published as a script because there were not enough pages or time to include it as a full comic? ... that \"Pistol Nell\" earned her nickname by helping to thwart a bank robbery? ... that Billy Bragg ate Joe Hill's ashes? ArchiveStart a new articleNominate an article In the news Tilcayo An attack on a police complex in Kohat, Pakistan, leaves at least 31 people dead. The tilcayo (pictured), a new species of tiger cat, is formally identified. Former leader of Kosovo Hashim Thaçi is sentenced to 25 years in prison for war crimes during his leadership of the Kosovo Liberation Army. At the Primetime Emmy Awards, Widow's…",
+ "elements": [
+ {
+ "id": "e1",
+ "description": "link 'Archive' → https://en.wikipedia.org/wiki/Wikipedia:Today's_featured_article/September_2026",
+ "in_viewport": true
+ },
+ {
+ "id": "e2",
+ "description": "link 'About' → https://en.wikipedia.org/wiki/Wikipedia:About_Today's_featured_article",
+ "in_viewport": true
+ },
+ {
+ "id": "e3",
+ "description": "link 'Archive' → https://en.wikipedia.org/wiki/Wikipedia:Today's_featured_list/September_2026",
+ "in_viewport": false
+ },
+ {
+ "id": "e4",
+ "description": "link '/wiki/Main_Page' → /wiki/Main_Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e5",
+ "description": "text field 'Search Wikipedia' (type search, placeholder \"Search Wikipedia\", empty)",
+ "in_viewport": true
+ },
+ {
+ "id": "e6",
+ "description": "button 'Search'",
+ "in_viewport": true
+ },
+ {
+ "id": "e7",
+ "description": "link 'Donate' → https://donate.wikimedia.org/?wmf_source=donate&wmf_medium=sidebar&wmf_campaign=en.wikipedia.org&uselang=en",
+ "in_viewport": true
+ },
+ {
+ "id": "e8",
+ "description": "link 'Create account' → /w/index.php?title=Special:CreateAccount&returnto=Main+Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e9",
+ "description": "link 'Log in' → /w/index.php?title=Special:UserLogin&returnto=Main+Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e10",
+ "description": "link 'Main Page' → /wiki/Main_Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e11",
+ "description": "link 'Talk' → /wiki/Talk:Main_Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e12",
+ "description": "link 'Read' → /wiki/Main_Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e13",
+ "description": "link 'View source' → /w/index.php?title=Main_Page&action=edit",
+ "in_viewport": true
+ },
+ {
+ "id": "e14",
+ "description": "link 'View history' → /w/index.php?title=Main_Page&action=history",
+ "in_viewport": true
+ },
+ {
+ "id": "e15",
+ "description": "button 'Hide Appearance'",
+ "in_viewport": true
+ },
+ {
+ "id": "e16",
+ "description": "link 'Wikipedia' → https://en.wikipedia.org/wiki/Wikipedia",
+ "in_viewport": true
+ },
+ {
+ "id": "e17",
+ "description": "link 'free' → https://en.wikipedia.org/wiki/Free_content",
+ "in_viewport": true
+ },
+ {
+ "id": "e18",
+ "description": "link 'anyone can edit' → https://en.wikipedia.org/wiki/Help:Introduction_to_Wikipedia",
+ "in_viewport": true
+ },
+ {
+ "id": "e19",
+ "description": "link '265,014' → https://en.wikipedia.org/wiki/Special:Statistics",
+ "in_viewport": true
+ },
+ {
+ "id": "e20",
+ "description": "link '7,243,180' → https://en.wikipedia.org/wiki/Special:Statistics",
+ "in_viewport": true
+ },
+ {
+ "id": "e21",
+ "description": "link 'English' → https://en.wikipedia.org/wiki/English_language",
+ "in_viewport": true
+ },
+ {
+ "id": "e22",
+ "description": "link 'Mary Mallon' → https://en.wikipedia.org/wiki/Mary_Mallon",
+ "in_viewport": true
+ },
+ {
+ "id": "e23",
+ "description": "link 'An attack on a police complex' → https://en.wikipedia.org/wiki/2026_Kohat_attack",
+ "in_viewport": true
+ },
+ {
+ "id": "e24",
+ "description": "link 'Kohat' → https://en.wikipedia.org/wiki/Kohat",
+ "in_viewport": true
+ },
+ {
+ "id": "e25",
+ "description": "link 'Tilcayo' → https://en.wikipedia.org/wiki/File:Leopardus_tilcayo_(5x3_cropped).jpg",
+ "in_viewport": true
+ },
+ {
+ "id": "e26",
+ "description": "link 'bacteria' → https://en.wikipedia.org/wiki/Bacteria",
+ "in_viewport": true
+ },
+ {
+ "id": "e27",
+ "description": "link 'typhoid fever' → https://en.wikipedia.org/wiki/Typhoid_fever",
+ "in_viewport": true
+ },
+ {
+ "id": "e28",
+ "description": "link 'tilcayo' → https://en.wikipedia.org/wiki/Tilcayo",
+ "in_viewport": true
+ },
+ {
+ "id": "e29",
+ "description": "link 'Mary Mallon' → https://en.wikipedia.org/wiki/File:Mary_Mallon,_aka_Typhoid_Mary.jpg",
+ "in_viewport": true
+ },
+ {
+ "id": "e30",
+ "description": "link 'quarantined' → https://en.wikipedia.org/wiki/Quarantine",
+ "in_viewport": true
+ },
+ {
+ "id": "e31",
+ "description": "link 'Hashim Thaçi' → https://en.wikipedia.org/wiki/Hashim_Thaçi",
+ "in_viewport": true
+ },
+ {
+ "id": "e32",
+ "description": "link 'war crimes during his leadership' → https://en.wikipedia.org/wiki/War_crimes_in_the_Kosovo_War#KLA_war_crimes",
+ "in_viewport": true
+ },
+ {
+ "id": "e33",
+ "description": "link 'Sloane Maternity Hospital' → https://en.wikipedia.org/wiki/Sloane_Hospital_for_Women",
+ "in_viewport": true
+ },
+ {
+ "id": "e34",
+ "description": "link 'Kosovo Liberation Army' → https://en.wikipedia.org/wiki/Kosovo_Liberation_Army",
+ "in_viewport": true
+ },
+ {
+ "id": "e35",
+ "description": "link 'the Primetime Emmy Awards' → https://en.wikipedia.org/wiki/78th_Primetime_Emmy_Awards",
+ "in_viewport": true
+ },
+ {
+ "id": "e36",
+ "description": "link 'Widow's Bay' → https://en.wikipedia.org/wiki/Widow's_Bay",
+ "in_viewport": true
+ },
+ {
+ "id": "e37",
+ "description": "link 'Outstanding Comedy Series' → https://en.wikipedia.org/wiki/Primetime_Emmy_Award_for_Outstanding_Comedy_Series",
+ "in_viewport": true
+ },
+ {
+ "id": "e38",
+ "description": "link 'The Pitt' → https://en.wikipedia.org/wiki/The_Pitt",
+ "in_viewport": true
+ },
+ {
+ "id": "e39",
+ "description": "link 'Outstanding Drama Series' → https://en.wikipedia.org/wiki/Primetime_Emmy_Award_for_Outstanding_Drama_Series",
+ "in_viewport": true
+ },
+ {
+ "id": "e40",
+ "description": "link 'public health' → https://en.wikipedia.org/wiki/Public_health",
+ "in_viewport": true
+ },
+ {
+ "id": "e41",
+ "description": "link 'Iran war' → https://en.wikipedia.org/wiki/2026_Iran_war",
+ "in_viewport": true
+ },
+ {
+ "id": "e42",
+ "description": "link 'Lebanon war' → https://en.wikipedia.org/wiki/2026_Lebanon_war",
+ "in_viewport": true
+ },
+ {
+ "id": "e43",
+ "description": "link 'Russo-Ukrainian war' → https://en.wikipedia.org/wiki/Russo-Ukrainian_war_(2022–present)",
+ "in_viewport": true
+ },
+ {
+ "id": "e44",
+ "description": "link 'timeline' → https://en.wikipedia.org/wiki/Timeline_of_the_Russo-Ukrainian_war_(1_September_2026_–_present)",
+ "in_viewport": true
+ },
+ {
+ "id": "e45",
+ "description": "link 'HIV/AIDS' → https://en.wikipedia.org/wiki/HIV/AIDS",
+ "in_viewport": true
+ },
+ {
+ "id": "e46",
+ "description": "link 'tuberculosis' → https://en.wikipedia.org/wiki/Tuberculosis",
+ "in_viewport": true
+ },
+ {
+ "id": "e47",
+ "description": "link 'Recent deaths' → https://en.wikipedia.org/wiki/Deaths_in_2026",
+ "in_viewport": true
+ },
+ {
+ "id": "e48",
+ "description": "link 'Dolores Sibonga' → https://en.wikipedia.org/wiki/Dolores_Sibonga",
+ "in_viewport": true
+ },
+ {
+ "id": "e49",
+ "description": "link 'Aracy Amaral' → https://en.wikipedia.org/wiki/Aracy_Amaral",
+ "in_viewport": true
+ },
+ {
+ "id": "e50",
+ "description": "link 'Bonnie Greer' → https://en.wikipedia.org/wiki/Bonnie_Greer",
+ "in_viewport": true
+ },
+ {
+ "id": "e51",
+ "description": "link 'COVID-19' → https://en.wikipedia.org/wiki/COVID-19",
+ "in_viewport": true
+ },
+ {
+ "id": "e52",
+ "description": "link 'Full article...' → https://en.wikipedia.org/wiki/Mary_Mallon",
+ "in_viewport": true
+ },
+ {
+ "id": "e53",
+ "description": "link 'Peter Max' → https://en.wikipedia.org/wiki/Peter_Max",
+ "in_viewport": true
+ },
+ {
+ "id": "e54",
+ "description": "link 'Chung Ho-yong' → https://en.wikipedia.org/wiki/Chung_Ho-yong",
+ "in_viewport": true
+ },
+ {
+ "id": "e55",
+ "description": "link 'Win Aung' → https://en.wikipedia.org/wiki/Win_Aung_(footballer)",
+ "in_viewport": true
+ },
+ {
+ "id": "e56",
+ "description": "link 'More current events' → https://en.wikipedia.org/wiki/Portal:Current_events",
+ "in_viewport": true
+ },
+ {
+ "id": "e57",
+ "description": "link 'Nominate an article' → https://en.wikipedia.org/wiki/Wikipedia:In_the_news/Candidates",
+ "in_viewport": true
+ },
+ {
+ "id": "e58",
+ "description": "link 'Alison Frantz' → https://en.wikipedia.org/wiki/Alison_Frantz",
+ "in_viewport": true
+ },
+ {
+ "id": "e59",
+ "description": "link 'Early Netherlandish painting' → https://en.wikipedia.org/wiki/Early_Netherlandish_painting",
+ "in_viewport": true
+ },
+ {
+ "id": "e60",
+ "description": "link 'Misti' → https://en.wikipedia.org/wiki/Misti",
+ "in_viewport": true
+ },
+ {
+ "id": "e61",
+ "description": "link 'By email' → https://lists.wikimedia.org/postorius/lists/daily-article-l.lists.wikimedia.org/",
+ "in_viewport": true
+ },
+ {
+ "id": "e62",
+ "description": "link 'More featured articles' → https://en.wikipedia.org/wiki/Wikipedia:Featured_articles_(linked_from_TFAfooter)",
+ "in_viewport": true
+ },
+ {
+ "id": "e63",
+ "description": "link 'September 23' → https://en.wikipedia.org/wiki/September_23",
+ "in_viewport": false
+ },
+ {
+ "id": "e64",
+ "description": "link 'Celebrate Bisexuality Day' → https://en.wikipedia.org/wiki/Celebrate_Bisexuality_Day",
+ "in_viewport": false
+ },
+ {
+ "id": "e65",
+ "description": "link '1803' → https://en.wikipedia.org/wiki/1803",
+ "in_viewport": false
+ },
+ {
+ "id": "e66",
+ "description": "link 'Maratha' → https://en.wikipedia.org/wiki/Maratha_Empire",
+ "in_viewport": false
+ },
+ {
+ "id": "e67",
+ "description": "link 'East India Company' → https://en.wikipedia.org/wiki/East_India_Company",
+ "in_viewport": false
+ },
+ {
+ "id": "e68",
+ "description": "link 'Lotte Rakhat' → https://en.wikipedia.org/wiki/Lotte_Rakhat",
+ "in_viewport": false
+ },
+ {
+ "id": "e69",
+ "description": "link 'Lotte Rakhat chocolate bar' → https://en.wikipedia.org/wiki/File:Rakhat_Kazakhstan_dark_chocolate_bar_(square_crop).jpg",
+ "in_viewport": false
+ },
+ {
+ "id": "e70",
+ "description": "link 'U2 performing in Sarajevo' → https://en.wikipedia.org/wiki/File:U2_performing_in_Sarajevo_on_Sept_23_1997_(11).jpg",
+ "in_viewport": false
+ },
+ {
+ "id": "e71",
+ "description": "link 'Battle of Assaye' → https://en.wikipedia.org/wiki/Battle_of_Assaye",
+ "in_viewport": false
+ },
+ {
+ "id": "e72",
+ "description": "link 'Jackie Robinson commemorative coins' → https://en.wikipedia.org/wiki/Jackie_Robinson_commemorative_coins",
+ "in_viewport": false
+ },
+ {
+ "id": "e73",
+ "description": "link 'Second Anglo-Maratha War' → https://en.wikipedia.org/wiki/Second_Anglo-Maratha_War",
+ "in_viewport": false
+ },
+ {
+ "id": "e74",
+ "description": "link 'baseball card' → https://en.wikipedia.org/wiki/Baseball_card",
+ "in_viewport": false
+ },
+ {
+ "id": "e75",
+ "description": "link '1884' → https://en.wikipedia.org/wiki/1884",
+ "in_viewport": false
+ },
+ {
+ "id": "e76",
+ "description": "link 'Cape Virgenes' → https://en.wikipedia.org/wiki/Cape_Virgenes",
+ "in_viewport": false
+ },
+ {
+ "id": "e77",
+ "description": "link 'Candidatus Magnetoglobus multicellularis' → https://en.wikipedia.org/wiki/Candidatus_Magnetoglobus_multicellularis",
+ "in_viewport": false
+ },
+ {
+ "id": "e78",
+ "description": "link 'prokaryotes' → https://en.wikipedia.org/wiki/Prokaryote",
+ "in_viewport": false
+ },
+ {
+ "id": "e79",
+ "description": "link 'Tierra del Fuego Gold Rush' → https://en.wikipedia.org/wiki/Tierra_del_Fuego_Gold_Rush",
+ "in_viewport": false
+ },
+ {
+ "id": "e80",
+ "description": "link '1983' → https://en.wikipedia.org/wiki/1983",
+ "in_viewport": false
+ },
+ {
+ "id": "e81",
+ "description": "link 'Gulf Air Flight 771' → https://en.wikipedia.org/wiki/Gulf_Air_Flight_771",
+ "in_viewport": false
+ },
+ {
+ "id": "e82",
+ "description": "link 'Leona E. Prasse' → https://en.wikipedia.org/wiki/Leona_E._Prasse",
+ "in_viewport": false
+ },
+ {
+ "id": "e83",
+ "description": "link '1972 Feininger catalogue' → https://en.wikipedia.org/wiki/Lyonel_Feininger:_A_Definitive_Catalogue_of_His_Graphic_Work",
+ "in_viewport": false
+ },
+ {
+ "id": "e84",
+ "description": "link 'Abu Nidal Organization' → https://en.wikipedia.org/wiki/Abu_Nidal_Organization",
+ "in_viewport": false
+ },
+ {
+ "id": "e85",
+ "description": "link 'the subject's widow' → https://en.wikipedia.org/wiki/Julia_Feininger",
+ "in_viewport": false
+ },
+ {
+ "id": "e86",
+ "description": "link 'a previous Feininger book from 1959' → https://en.wikipedia.org/wiki/Lyonel_Feininger_(Hess_book)",
+ "in_viewport": false
+ },
+ {
+ "id": "e87",
+ "description": "link 'United Arab Emirates' → https://en.wikipedia.org/wiki/United_Arab_Emirates",
+ "in_viewport": false
+ },
+ {
+ "id": "e88",
+ "description": "link '1997' → https://en.wikipedia.org/wiki/1997",
+ "in_viewport": false
+ },
+ {
+ "id": "e89",
+ "description": "link 'U2' → https://en.wikipedia.org/wiki/U2",
+ "in_viewport": false
+ },
+ {
+ "id": "e90",
+ "description": "link 'performed' → https://en.wikipedia.org/wiki/U2_concert_in_Sarajevo",
+ "in_viewport": false
+ },
+ {
+ "id": "e91",
+ "description": "link 'Sarajevo' → https://en.wikipedia.org/wiki/Sarajevo",
+ "in_viewport": false
+ },
+ {
+ "id": "e92",
+ "description": "link 'Umbellaoolithus' → https://en.wikipedia.org/wiki/Umbellaoolithus",
+ "in_viewport": false
+ },
+ {
+ "id": "e93",
+ "description": "link 'Bosnian War' → https://en.wikipedia.org/wiki/Bosnian_War",
+ "in_viewport": false
+ },
+ {
+ "id": "e94",
+ "description": "link 'Makan Nasiri' → https://en.wikipedia.org/wiki/Makan_Nasiri",
+ "in_viewport": false
+ },
+ {
+ "id": "e95",
+ "description": "link '2016' → https://en.wikipedia.org/wiki/2016",
+ "in_viewport": false
+ },
+ {
+ "id": "e96",
+ "description": "link '2026 Minab school attack' → https://en.wikipedia.org/wiki/2026_Minab_school_attack",
+ "in_viewport": false
+ },
+ {
+ "id": "e97",
+ "description": "link 'rape in Germany' → https://en.wikipedia.org/wiki/Rape_in_Germany",
+ "in_viewport": false
+ },
+ {
+ "id": "e98",
+ "description": "link 'I Became the Main Role of a BL Drama' → https://en.wikipedia.org/wiki/I_Became_the_Main_Role_of_a_BL_Drama",
+ "in_viewport": false
+ },
+ {
+ "id": "e99",
+ "description": "link 'script' → https://en.wikipedia.org/wiki/Script_(comics)",
+ "in_viewport": false
+ },
+ {
+ "id": "e100",
+ "description": "link 'Eleonora Gonzaga' → https://en.wikipedia.org/wiki/Eleonora_Gonzaga_(born_1598)",
+ "in_viewport": false
+ }
+ ],
+ "omitted_elements": 82
+ },
+ "previous_page": null,
+ "last_action": null,
+ "history": {
+ "steps_taken": 0,
+ "recent_urls": []
+ }
+ },
+ "questions": {
+ "goal_done": {
+ "type": "noul",
+ "instructions": {
+ "question": "Is `goal` already fully accomplished according to what `page` shows right now?",
+ "rules": [
+ "Judge only from `page` (its url, title, headings, visible_text, dialog and elements).",
+ "A page that merely offers a way to accomplish `goal` does not count as accomplished.",
+ "If `goal` asks to open or view something, it is accomplished when that thing is what `page` shows.",
+ "If `goal` asks to perform an action (submit, add, sign in, start), it is accomplished only when `page` shows the result or confirmation of that action."
+ ]
+ },
+ "criteria": {
+ "true": "`page` shows the end result that `goal` asks for.",
+ "false": "At least one more action is needed, `page` shows something else, or it is unclear."
+ }
+ },
+ "blocker": {
+ "type": "choice",
+ "instructions": {
+ "question": "Does `page` present an obstacle that an automated browser agent cannot resolve with the listed elements and `inputs`, stopping progress toward `goal`?",
+ "rules": [
+ "Pick `none` unless the obstacle is clearly visible in `page`.",
+ "Cookie banners or dialogs that have a listed button to dismiss them are not obstacles."
+ ]
+ },
+ "criteria": {
+ "none": "No obstacle: the page can be operated normally (a login form that can be filled with provided `inputs` is not an obstacle).",
+ "login_required": "The page requires signing in and `inputs` does not provide the credentials needed to sign in.",
+ "verification_challenge": "A CAPTCHA, one-time code, two-factor prompt, or similar human verification is shown.",
+ "consent_or_permission_dialog": "A modal dialog demanding consent, permissions, or a choice from the user blocks the content and nothing listed dismisses it.",
+ "error_page": "The page shows an error (not found, access denied, server error, network failure) instead of the expected content.",
+ "missing_information": "Progress requires information (an account, payment details, a value) that is neither on the page nor in `inputs`."
+ }
+ },
+ "action": {
+ "type": "choice",
+ "instructions": {
+ "question": "Which single browser action should be performed next to make progress toward `goal` from the current `page`?",
+ "rules": [
+ "Every element in `page.elements` can be clicked, filled or selected right now, even when its in_viewport is false (the browser scrolls to it). Scroll only when the needed element or text is not listed at all.",
+ "Use `type` only when a value in `inputs` belongs in a listed text field.",
+ "Use `stop` when `goal` is already accomplished or nothing listed can help.",
+ "Consider `last_action` and `history`: do not repeat an action that produced no change."
+ ]
+ },
+ "criteria": {
+ "click": {
+ "what": "Click one element listed in `page.elements` (a link, button, checkbox, radio, tab, menu item, or similar).",
+ "use_when": "The next step toward `goal` is to open, choose, submit, toggle, or confirm something that is listed."
+ },
+ "scroll_down": {
+ "what": "Scroll down to reveal content that is not listed in `page.elements` and not in `page.visible_text`.",
+ "use_when": "Nothing listed can serve `goal` and more content probably exists further down. Never needed to reach an element that is already listed: clicking scrolls to it automatically."
+ },
+ "wait": {
+ "what": "Do nothing for a moment because the page is still loading or a result is still pending.",
+ "use_when": "The visible text or a dialog indicates loading, processing, or a countdown."
+ },
+ "stop": {
+ "what": "Stop: no listed action can make progress toward `goal`.",
+ "use_when": "`goal` is already accomplished as shown by `page`, or it is impossible from here with the listed actions."
+ }
+ }
+ },
+ "click_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is a click, which element in `page.elements` should be clicked to make progress toward `goal`?",
+ "rules": [
+ "Choose `none` if no listed element helps.",
+ "Each option id refers to `page.elements[].id`."
+ ]
+ },
+ "criteria": {
+ "e1": "link 'Archive' → https://en.wikipedia.org/wiki/Wikipedia:Today's_featured_article/September_2026",
+ "e2": "link 'About' → https://en.wikipedia.org/wiki/Wikipedia:About_Today's_featured_article",
+ "e3": "link 'Archive' → https://en.wikipedia.org/wiki/Wikipedia:Today's_featured_list/September_2026",
+ "e4": "link '/wiki/Main_Page' → /wiki/Main_Page",
+ "e6": "button 'Search'",
+ "e7": "link 'Donate' → https://donate.wikimedia.org/?wmf_source=donate&wmf_medium=sidebar&wmf_campaign=en.wikipedia.org&uselang=en",
+ "e8": "link 'Create account' → /w/index.php?title=Special:CreateAccount&returnto=Main+Page",
+ "e9": "link 'Log in' → /w/index.php?title=Special:UserLogin&returnto=Main+Page",
+ "e10": "link 'Main Page' → /wiki/Main_Page",
+ "e11": "link 'Talk' → /wiki/Talk:Main_Page",
+ "e12": "link 'Read' → /wiki/Main_Page",
+ "e13": "link 'View source' → /w/index.php?title=Main_Page&action=edit",
+ "e14": "link 'View history' → /w/index.php?title=Main_Page&action=history",
+ "e15": "button 'Hide Appearance'",
+ "e16": "link 'Wikipedia' → https://en.wikipedia.org/wiki/Wikipedia",
+ "e17": "link 'free' → https://en.wikipedia.org/wiki/Free_content",
+ "e18": "link 'anyone can edit' → https://en.wikipedia.org/wiki/Help:Introduction_to_Wikipedia",
+ "e19": "link '265,014' → https://en.wikipedia.org/wiki/Special:Statistics",
+ "e20": "link '7,243,180' → https://en.wikipedia.org/wiki/Special:Statistics",
+ "e21": "link 'English' → https://en.wikipedia.org/wiki/English_language",
+ "e22": "link 'Mary Mallon' → https://en.wikipedia.org/wiki/Mary_Mallon",
+ "e23": "link 'An attack on a police complex' → https://en.wikipedia.org/wiki/2026_Kohat_attack",
+ "e24": "link 'Kohat' → https://en.wikipedia.org/wiki/Kohat",
+ "e25": "link 'Tilcayo' → https://en.wikipedia.org/wiki/File:Leopardus_tilcayo_(5x3_cropped).jpg",
+ "e26": "link 'bacteria' → https://en.wikipedia.org/wiki/Bacteria",
+ "e27": "link 'typhoid fever' → https://en.wikipedia.org/wiki/Typhoid_fever",
+ "e28": "link 'tilcayo' → https://en.wikipedia.org/wiki/Tilcayo",
+ "e29": "link 'Mary Mallon' → https://en.wikipedia.org/wiki/File:Mary_Mallon,_aka_Typhoid_Mary.jpg",
+ "e30": "link 'quarantined' → https://en.wikipedia.org/wiki/Quarantine",
+ "e31": "link 'Hashim Thaçi' → https://en.wikipedia.org/wiki/Hashim_Thaçi",
+ "e32": "link 'war crimes during his leadership' → https://en.wikipedia.org/wiki/War_crimes_in_the_Kosovo_War#KLA_war_crimes",
+ "e33": "link 'Sloane Maternity Hospital' → https://en.wikipedia.org/wiki/Sloane_Hospital_for_Women",
+ "e34": "link 'Kosovo Liberation Army' → https://en.wikipedia.org/wiki/Kosovo_Liberation_Army",
+ "e35": "link 'the Primetime Emmy Awards' → https://en.wikipedia.org/wiki/78th_Primetime_Emmy_Awards",
+ "e36": "link 'Widow's Bay' → https://en.wikipedia.org/wiki/Widow's_Bay",
+ "e37": "link 'Outstanding Comedy Series' → https://en.wikipedia.org/wiki/Primetime_Emmy_Award_for_Outstanding_Comedy_Series",
+ "e38": "link 'The Pitt' → https://en.wikipedia.org/wiki/The_Pitt",
+ "e39": "link 'Outstanding Drama Series' → https://en.wikipedia.org/wiki/Primetime_Emmy_Award_for_Outstanding_Drama_Series",
+ "e40": "link 'public health' → https://en.wikipedia.org/wiki/Public_health",
+ "e41": "link 'Iran war' → https://en.wikipedia.org/wiki/2026_Iran_war",
+ "e42": "link 'Lebanon war' → https://en.wikipedia.org/wiki/2026_Lebanon_war",
+ "e43": "link 'Russo-Ukrainian war' → https://en.wikipedia.org/wiki/Russo-Ukrainian_war_(2022–present)",
+ "e44": "link 'timeline' → https://en.wikipedia.org/wiki/Timeline_of_the_Russo-Ukrainian_war_(1_September_2026_–_present)",
+ "e45": "link 'HIV/AIDS' → https://en.wikipedia.org/wiki/HIV/AIDS",
+ "e46": "link 'tuberculosis' → https://en.wikipedia.org/wiki/Tuberculosis",
+ "e47": "link 'Recent deaths' → https://en.wikipedia.org/wiki/Deaths_in_2026",
+ "e48": "link 'Dolores Sibonga' → https://en.wikipedia.org/wiki/Dolores_Sibonga",
+ "e49": "link 'Aracy Amaral' → https://en.wikipedia.org/wiki/Aracy_Amaral",
+ "e50": "link 'Bonnie Greer' → https://en.wikipedia.org/wiki/Bonnie_Greer",
+ "e51": "link 'COVID-19' → https://en.wikipedia.org/wiki/COVID-19",
+ "e52": "link 'Full article...' → https://en.wikipedia.org/wiki/Mary_Mallon",
+ "e53": "link 'Peter Max' → https://en.wikipedia.org/wiki/Peter_Max",
+ "e54": "link 'Chung Ho-yong' → https://en.wikipedia.org/wiki/Chung_Ho-yong",
+ "e55": "link 'Win Aung' → https://en.wikipedia.org/wiki/Win_Aung_(footballer)",
+ "e56": "link 'More current events' → https://en.wikipedia.org/wiki/Portal:Current_events",
+ "e57": "link 'Nominate an article' → https://en.wikipedia.org/wiki/Wikipedia:In_the_news/Candidates",
+ "e58": "link 'Alison Frantz' → https://en.wikipedia.org/wiki/Alison_Frantz",
+ "e59": "link 'Early Netherlandish painting' → https://en.wikipedia.org/wiki/Early_Netherlandish_painting",
+ "e60": "link 'Misti' → https://en.wikipedia.org/wiki/Misti",
+ "e61": "link 'By email' → https://lists.wikimedia.org/postorius/lists/daily-article-l.lists.wikimedia.org/",
+ "e62": "link 'More featured articles' → https://en.wikipedia.org/wiki/Wikipedia:Featured_articles_(linked_from_TFAfooter)",
+ "e63": "link 'September 23' → https://en.wikipedia.org/wiki/September_23",
+ "e64": "link 'Celebrate Bisexuality Day' → https://en.wikipedia.org/wiki/Celebrate_Bisexuality_Day",
+ "e65": "link '1803' → https://en.wikipedia.org/wiki/1803",
+ "e66": "link 'Maratha' → https://en.wikipedia.org/wiki/Maratha_Empire",
+ "e67": "link 'East India Company' → https://en.wikipedia.org/wiki/East_India_Company",
+ "e68": "link 'Lotte Rakhat' → https://en.wikipedia.org/wiki/Lotte_Rakhat",
+ "e69": "link 'Lotte Rakhat chocolate bar' → https://en.wikipedia.org/wiki/File:Rakhat_Kazakhstan_dark_chocolate_bar_(square_crop).jpg",
+ "e70": "link 'U2 performing in Sarajevo' → https://en.wikipedia.org/wiki/File:U2_performing_in_Sarajevo_on_Sept_23_1997_(11).jpg",
+ "e71": "link 'Battle of Assaye' → https://en.wikipedia.org/wiki/Battle_of_Assaye",
+ "e72": "link 'Jackie Robinson commemorative coins' → https://en.wikipedia.org/wiki/Jackie_Robinson_commemorative_coins",
+ "e73": "link 'Second Anglo-Maratha War' → https://en.wikipedia.org/wiki/Second_Anglo-Maratha_War",
+ "e74": "link 'baseball card' → https://en.wikipedia.org/wiki/Baseball_card",
+ "e75": "link '1884' → https://en.wikipedia.org/wiki/1884",
+ "e76": "link 'Cape Virgenes' → https://en.wikipedia.org/wiki/Cape_Virgenes",
+ "e77": "link 'Candidatus Magnetoglobus multicellularis' → https://en.wikipedia.org/wiki/Candidatus_Magnetoglobus_multicellularis",
+ "e78": "link 'prokaryotes' → https://en.wikipedia.org/wiki/Prokaryote",
+ "e79": "link 'Tierra del Fuego Gold Rush' → https://en.wikipedia.org/wiki/Tierra_del_Fuego_Gold_Rush",
+ "e80": "link '1983' → https://en.wikipedia.org/wiki/1983",
+ "e81": "link 'Gulf Air Flight 771' → https://en.wikipedia.org/wiki/Gulf_Air_Flight_771",
+ "e82": "link 'Leona E. Prasse' → https://en.wikipedia.org/wiki/Leona_E._Prasse",
+ "e83": "link '1972 Feininger catalogue' → https://en.wikipedia.org/wiki/Lyonel_Feininger:_A_Definitive_Catalogue_of_His_Graphic_Work",
+ "e84": "link 'Abu Nidal Organization' → https://en.wikipedia.org/wiki/Abu_Nidal_Organization",
+ "e85": "link 'the subject's widow' → https://en.wikipedia.org/wiki/Julia_Feininger",
+ "e86": "link 'a previous Feininger book from 1959' → https://en.wikipedia.org/wiki/Lyonel_Feininger_(Hess_book)",
+ "e87": "link 'United Arab Emirates' → https://en.wikipedia.org/wiki/United_Arab_Emirates",
+ "e88": "link '1997' → https://en.wikipedia.org/wiki/1997",
+ "e89": "link 'U2' → https://en.wikipedia.org/wiki/U2",
+ "e90": "link 'performed' → https://en.wikipedia.org/wiki/U2_concert_in_Sarajevo",
+ "e91": "link 'Sarajevo' → https://en.wikipedia.org/wiki/Sarajevo",
+ "e92": "link 'Umbellaoolithus' → https://en.wikipedia.org/wiki/Umbellaoolithus",
+ "e93": "link 'Bosnian War' → https://en.wikipedia.org/wiki/Bosnian_War",
+ "e94": "link 'Makan Nasiri' → https://en.wikipedia.org/wiki/Makan_Nasiri",
+ "e95": "link '2016' → https://en.wikipedia.org/wiki/2016",
+ "e96": "link '2026 Minab school attack' → https://en.wikipedia.org/wiki/2026_Minab_school_attack",
+ "e97": "link 'rape in Germany' → https://en.wikipedia.org/wiki/Rape_in_Germany",
+ "e98": "link 'I Became the Main Role of a BL Drama' → https://en.wikipedia.org/wiki/I_Became_the_Main_Role_of_a_BL_Drama",
+ "e99": "link 'script' → https://en.wikipedia.org/wiki/Script_(comics)",
+ "e100": "link 'Eleonora Gonzaga' → https://en.wikipedia.org/wiki/Eleonora_Gonzaga_(born_1598)",
+ "none": "No listed element should be clicked."
+ }
+ }
+ },
+ "meta": {
+ "allowedActions": [
+ "click",
+ "scroll_down",
+ "wait",
+ "stop"
+ ],
+ "clickableIds": [
+ "e1",
+ "e2",
+ "e3",
+ "e4",
+ "e6",
+ "e7",
+ "e8",
+ "e9",
+ "e10",
+ "e11",
+ "e12",
+ "e13",
+ "e14",
+ "e15",
+ "e16",
+ "e17",
+ "e18",
+ "e19",
+ "e20",
+ "e21",
+ "e22",
+ "e23",
+ "e24",
+ "e25",
+ "e26",
+ "e27",
+ "e28",
+ "e29",
+ "e30",
+ "e31",
+ "e32",
+ "e33",
+ "e34",
+ "e35",
+ "e36",
+ "e37",
+ "e38",
+ "e39",
+ "e40",
+ "e41",
+ "e42",
+ "e43",
+ "e44",
+ "e45",
+ "e46",
+ "e47",
+ "e48",
+ "e49",
+ "e50",
+ "e51",
+ "e52",
+ "e53",
+ "e54",
+ "e55",
+ "e56",
+ "e57",
+ "e58",
+ "e59",
+ "e60",
+ "e61",
+ "e62",
+ "e63",
+ "e64",
+ "e65",
+ "e66",
+ "e67",
+ "e68",
+ "e69",
+ "e70",
+ "e71",
+ "e72",
+ "e73",
+ "e74",
+ "e75",
+ "e76",
+ "e77",
+ "e78",
+ "e79",
+ "e80",
+ "e81",
+ "e82",
+ "e83",
+ "e84",
+ "e85",
+ "e86",
+ "e87",
+ "e88",
+ "e89",
+ "e90",
+ "e91",
+ "e92",
+ "e93",
+ "e94",
+ "e95",
+ "e96",
+ "e97",
+ "e98",
+ "e99",
+ "e100"
+ ],
+ "editableIds": [
+ "e5"
+ ],
+ "selectIds": [],
+ "inputKeys": [],
+ "urlInputKeys": [],
+ "questionCount": 4,
+ "candidateCount": 100
+ },
+ "estimatedInputTokens": 7744,
+ "estimatedCostUsd": 0.00032524800000000004
+}
diff --git a/experiments/gguf-provider/fixtures/raw_example_com.txt b/experiments/gguf-provider/fixtures/raw_example_com.txt
new file mode 100644
index 0000000..6d3cab9
--- /dev/null
+++ b/experiments/gguf-provider/fixtures/raw_example_com.txt
@@ -0,0 +1,128 @@
+backend=ego model=jev-latest maxSteps=25 budget=$0.25
+ego task space 22, page p1
+{
+ "mode": "dry-run",
+ "backend": "ego",
+ "state": {
+ "goal": "find today's price of AAPL",
+ "inputs": "none provided",
+ "page": {
+ "url": "https://example.com/",
+ "title": "Example Domain",
+ "headings": [
+ "# Example Domain"
+ ],
+ "dialog": null,
+ "scroll_position": "page fits in the viewport",
+ "visible_text": "Example Domain This domain is for use in documentation examples without needing permission. Avoid use in operations. Learn more",
+ "elements": [
+ {
+ "id": "e1",
+ "description": "link 'Learn more' → https://iana.org/domains/example",
+ "in_viewport": true
+ }
+ ],
+ "omitted_elements": 0
+ },
+ "previous_page": null,
+ "last_action": null,
+ "history": {
+ "steps_taken": 0,
+ "recent_urls": []
+ }
+ },
+ "questions": {
+ "goal_done": {
+ "type": "noul",
+ "instructions": {
+ "question": "Is `goal` already fully accomplished according to what `page` shows right now?",
+ "rules": [
+ "Judge only from `page` (its url, title, headings, visible_text, dialog and elements).",
+ "A page that merely offers a way to accomplish `goal` does not count as accomplished.",
+ "If `goal` asks to open or view something, it is accomplished when that thing is what `page` shows.",
+ "If `goal` asks to perform an action (submit, add, sign in, start), it is accomplished only when `page` shows the result or confirmation of that action."
+ ]
+ },
+ "criteria": {
+ "true": "`page` shows the end result that `goal` asks for.",
+ "false": "At least one more action is needed, `page` shows something else, or it is unclear."
+ }
+ },
+ "blocker": {
+ "type": "choice",
+ "instructions": {
+ "question": "Does `page` present an obstacle that an automated browser agent cannot resolve with the listed elements and `inputs`, stopping progress toward `goal`?",
+ "rules": [
+ "Pick `none` unless the obstacle is clearly visible in `page`.",
+ "Cookie banners or dialogs that have a listed button to dismiss them are not obstacles."
+ ]
+ },
+ "criteria": {
+ "none": "No obstacle: the page can be operated normally (a login form that can be filled with provided `inputs` is not an obstacle).",
+ "login_required": "The page requires signing in and `inputs` does not provide the credentials needed to sign in.",
+ "verification_challenge": "A CAPTCHA, one-time code, two-factor prompt, or similar human verification is shown.",
+ "consent_or_permission_dialog": "A modal dialog demanding consent, permissions, or a choice from the user blocks the content and nothing listed dismisses it.",
+ "error_page": "The page shows an error (not found, access denied, server error, network failure) instead of the expected content.",
+ "missing_information": "Progress requires information (an account, payment details, a value) that is neither on the page nor in `inputs`."
+ }
+ },
+ "action": {
+ "type": "choice",
+ "instructions": {
+ "question": "Which single browser action should be performed next to make progress toward `goal` from the current `page`?",
+ "rules": [
+ "Every element in `page.elements` can be clicked, filled or selected right now, even when its in_viewport is false (the browser scrolls to it). Scroll only when the needed element or text is not listed at all.",
+ "Use `type` only when a value in `inputs` belongs in a listed text field.",
+ "Use `stop` when `goal` is already accomplished or nothing listed can help.",
+ "Consider `last_action` and `history`: do not repeat an action that produced no change."
+ ]
+ },
+ "criteria": {
+ "click": {
+ "what": "Click one element listed in `page.elements` (a link, button, checkbox, radio, tab, menu item, or similar).",
+ "use_when": "The next step toward `goal` is to open, choose, submit, toggle, or confirm something that is listed."
+ },
+ "wait": {
+ "what": "Do nothing for a moment because the page is still loading or a result is still pending.",
+ "use_when": "The visible text or a dialog indicates loading, processing, or a countdown."
+ },
+ "stop": {
+ "what": "Stop: no listed action can make progress toward `goal`.",
+ "use_when": "`goal` is already accomplished as shown by `page`, or it is impossible from here with the listed actions."
+ }
+ }
+ },
+ "click_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is a click, which element in `page.elements` should be clicked to make progress toward `goal`?",
+ "rules": [
+ "Choose `none` if no listed element helps.",
+ "Each option id refers to `page.elements[].id`."
+ ]
+ },
+ "criteria": {
+ "e1": "link 'Learn more' → https://iana.org/domains/example",
+ "none": "No listed element should be clicked."
+ }
+ }
+ },
+ "meta": {
+ "allowedActions": [
+ "click",
+ "wait",
+ "stop"
+ ],
+ "clickableIds": [
+ "e1"
+ ],
+ "editableIds": [],
+ "selectIds": [],
+ "inputKeys": [],
+ "urlInputKeys": [],
+ "questionCount": 4,
+ "candidateCount": 1
+ },
+ "estimatedInputTokens": 1163,
+ "estimatedCostUsd": 0.000048846000000000006
+}
diff --git a/experiments/gguf-provider/fixtures/raw_github_login.txt b/experiments/gguf-provider/fixtures/raw_github_login.txt
new file mode 100644
index 0000000..a184dfc
--- /dev/null
+++ b/experiments/gguf-provider/fixtures/raw_github_login.txt
@@ -0,0 +1,251 @@
+backend=ego model=jev-latest maxSteps=25 budget=$0.25
+ego task space 25, page p1
+{
+ "mode": "dry-run",
+ "backend": "ego",
+ "state": {
+ "goal": "sign in to GitHub",
+ "inputs": {
+ "username": "octocat",
+ "password": "[secret value: hidden from the model, available to type]"
+ },
+ "page": {
+ "url": "https://github.com/login",
+ "title": "Sign in to GitHub · GitHub",
+ "headings": [
+ "# Sign in to GitHub"
+ ],
+ "dialog": null,
+ "scroll_position": "page fits in the viewport",
+ "visible_text": "Skip to content Sign in to GitHub Username or email address Password Forgot password? New to GitHub? Create an account Terms Privacy Docs Contact GitHub Support Manage cookies Do not share my personal information",
+ "elements": [
+ {
+ "id": "e1",
+ "description": "button 'Sign in'",
+ "in_viewport": true
+ },
+ {
+ "id": "e2",
+ "description": "link 'Create an account' → /signup?source=login",
+ "in_viewport": true
+ },
+ {
+ "id": "e3",
+ "description": "text field 'Username or email address' (empty, required)",
+ "in_viewport": true
+ },
+ {
+ "id": "e4",
+ "description": "link 'Forgot password?' → /password_reset",
+ "in_viewport": true
+ },
+ {
+ "id": "e5",
+ "description": "text field 'Password' (type password, empty, required)",
+ "in_viewport": true
+ },
+ {
+ "id": "e6",
+ "description": "button 'Manage cookies'",
+ "in_viewport": true
+ },
+ {
+ "id": "e7",
+ "description": "button 'Do not share my personal information'",
+ "in_viewport": true
+ },
+ {
+ "id": "e8",
+ "description": "link 'Terms' → https://docs.github.com/site-policy/github-terms/github-terms-of-service",
+ "in_viewport": true
+ },
+ {
+ "id": "e9",
+ "description": "link 'Privacy' → https://docs.github.com/site-policy/privacy-policies/github-privacy-statement",
+ "in_viewport": true
+ },
+ {
+ "id": "e10",
+ "description": "link 'Docs' → https://docs.github.com",
+ "in_viewport": true
+ },
+ {
+ "id": "e11",
+ "description": "link 'Contact GitHub Support' → https://support.github.com",
+ "in_viewport": true
+ }
+ ],
+ "omitted_elements": 0
+ },
+ "previous_page": null,
+ "last_action": null,
+ "history": {
+ "steps_taken": 0,
+ "recent_urls": []
+ }
+ },
+ "questions": {
+ "goal_done": {
+ "type": "noul",
+ "instructions": {
+ "question": "Is `goal` already fully accomplished according to what `page` shows right now?",
+ "rules": [
+ "Judge only from `page` (its url, title, headings, visible_text, dialog and elements).",
+ "A page that merely offers a way to accomplish `goal` does not count as accomplished.",
+ "If `goal` asks to open or view something, it is accomplished when that thing is what `page` shows.",
+ "If `goal` asks to perform an action (submit, add, sign in, start), it is accomplished only when `page` shows the result or confirmation of that action."
+ ]
+ },
+ "criteria": {
+ "true": "`page` shows the end result that `goal` asks for.",
+ "false": "At least one more action is needed, `page` shows something else, or it is unclear."
+ }
+ },
+ "blocker": {
+ "type": "choice",
+ "instructions": {
+ "question": "Does `page` present an obstacle that an automated browser agent cannot resolve with the listed elements and `inputs`, stopping progress toward `goal`?",
+ "rules": [
+ "Pick `none` unless the obstacle is clearly visible in `page`.",
+ "Cookie banners or dialogs that have a listed button to dismiss them are not obstacles."
+ ]
+ },
+ "criteria": {
+ "none": "No obstacle: the page can be operated normally (a login form that can be filled with provided `inputs` is not an obstacle).",
+ "login_required": "The page requires signing in and `inputs` does not provide the credentials needed to sign in.",
+ "verification_challenge": "A CAPTCHA, one-time code, two-factor prompt, or similar human verification is shown.",
+ "consent_or_permission_dialog": "A modal dialog demanding consent, permissions, or a choice from the user blocks the content and nothing listed dismisses it.",
+ "error_page": "The page shows an error (not found, access denied, server error, network failure) instead of the expected content.",
+ "missing_information": "Progress requires information (an account, payment details, a value) that is neither on the page nor in `inputs`."
+ }
+ },
+ "action": {
+ "type": "choice",
+ "instructions": {
+ "question": "Which single browser action should be performed next to make progress toward `goal` from the current `page`?",
+ "rules": [
+ "Every element in `page.elements` can be clicked, filled or selected right now, even when its in_viewport is false (the browser scrolls to it). Scroll only when the needed element or text is not listed at all.",
+ "Use `type` only when a value in `inputs` belongs in a listed text field.",
+ "Use `stop` when `goal` is already accomplished or nothing listed can help.",
+ "Consider `last_action` and `history`: do not repeat an action that produced no change."
+ ]
+ },
+ "criteria": {
+ "click": {
+ "what": "Click one element listed in `page.elements` (a link, button, checkbox, radio, tab, menu item, or similar).",
+ "use_when": "The next step toward `goal` is to open, choose, submit, toggle, or confirm something that is listed."
+ },
+ "type": {
+ "what": "Type one of the provided `inputs` values into a text field listed in `page.elements`.",
+ "use_when": "A form field or search box must be filled before progress is possible, and a suitable value exists in `inputs`."
+ },
+ "wait": {
+ "what": "Do nothing for a moment because the page is still loading or a result is still pending.",
+ "use_when": "The visible text or a dialog indicates loading, processing, or a countdown."
+ },
+ "stop": {
+ "what": "Stop: no listed action can make progress toward `goal`.",
+ "use_when": "`goal` is already accomplished as shown by `page`, or it is impossible from here with the listed actions."
+ }
+ }
+ },
+ "click_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is a click, which element in `page.elements` should be clicked to make progress toward `goal`?",
+ "rules": [
+ "Choose `none` if no listed element helps.",
+ "Each option id refers to `page.elements[].id`."
+ ]
+ },
+ "criteria": {
+ "e1": "button 'Sign in'",
+ "e2": "link 'Create an account' → /signup?source=login",
+ "e4": "link 'Forgot password?' → /password_reset",
+ "e6": "button 'Manage cookies'",
+ "e7": "button 'Do not share my personal information'",
+ "e8": "link 'Terms' → https://docs.github.com/site-policy/github-terms/github-terms-of-service",
+ "e9": "link 'Privacy' → https://docs.github.com/site-policy/privacy-policies/github-privacy-statement",
+ "e10": "link 'Docs' → https://docs.github.com",
+ "e11": "link 'Contact GitHub Support' → https://support.github.com",
+ "none": "No listed element should be clicked."
+ }
+ },
+ "type_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is typing, which text field in `page.elements` should receive a value from `inputs` to make progress toward `goal`?",
+ "rules": [
+ "Prefer empty fields over fields that already contain the right value.",
+ "Choose `none` if no listed field should be filled now."
+ ]
+ },
+ "criteria": {
+ "e3": "text field 'Username or email address' (empty, required)",
+ "e5": "text field 'Password' (type password, empty, required)",
+ "none": "No listed text field should be filled now."
+ }
+ },
+ "type_value": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is typing, which entry of `inputs` belongs in the text field that should be filled next?",
+ "rules": [
+ "Match the field's label, placeholder and type to the meaning of the input key.",
+ "Choose `none` if no provided input belongs there."
+ ]
+ },
+ "criteria": {
+ "username": "inputs.username = \"octocat\"",
+ "password": "inputs.password (a secret value such as a password)",
+ "none": "No provided input belongs in the field."
+ }
+ },
+ "submit_after_type": {
+ "type": "noul",
+ "instructions": {
+ "question": "After typing the value into the chosen text field, should the Enter key be pressed immediately to submit (as with a search box or a single-field form)?",
+ "rules": [
+ "Answer no when other fields still need values or when a separate submit button must be clicked after all fields are filled."
+ ]
+ },
+ "criteria": {
+ "true": "Pressing Enter right after typing is the natural way to submit this field (search boxes, single-field forms, the last field of a form).",
+ "false": "More fields must be filled first, or a separate button should be clicked, or Enter would do nothing useful."
+ }
+ }
+ },
+ "meta": {
+ "allowedActions": [
+ "click",
+ "type",
+ "wait",
+ "stop"
+ ],
+ "clickableIds": [
+ "e1",
+ "e2",
+ "e4",
+ "e6",
+ "e7",
+ "e8",
+ "e9",
+ "e10",
+ "e11"
+ ],
+ "editableIds": [
+ "e3",
+ "e5"
+ ],
+ "selectIds": [],
+ "inputKeys": [
+ "username",
+ "password"
+ ],
+ "urlInputKeys": [],
+ "questionCount": 7,
+ "candidateCount": 11
+ },
+ "estimatedInputTokens": 2132,
+ "estimatedCostUsd": 0.00008954400000000001
+}
diff --git a/experiments/gguf-provider/fixtures/raw_wiki_loginpage.txt b/experiments/gguf-provider/fixtures/raw_wiki_loginpage.txt
new file mode 100644
index 0000000..2319388
--- /dev/null
+++ b/experiments/gguf-provider/fixtures/raw_wiki_loginpage.txt
@@ -0,0 +1,286 @@
+backend=ego model=jev-latest maxSteps=25 budget=$0.25
+ego task space 26, page p1
+{
+ "mode": "dry-run",
+ "backend": "ego",
+ "state": {
+ "goal": "log in to Wikipedia",
+ "inputs": "none provided",
+ "page": {
+ "url": "https://auth.wikimedia.org/enwiki/wiki/Special:UserLogin?useformat=desktop&usesul3=1&returnto=Main+Page¢ralauthLoginToken=8ba9892a14010d510d885378ffc13139",
+ "title": "Log in - Wikipedia",
+ "headings": [
+ "# Log in"
+ ],
+ "dialog": null,
+ "scroll_position": "at the top; more content below",
+ "visible_text": "Jump to content Main menu Donate Create account Log in Log in Tools Appearance hide Text Small Standard Large This page always uses small font size Width Standard Wide Color Automatic Light Dark Username Password Keep me logged in (for up to one year) Log in Help with logging in Forgot your password? Don't have an account?Join Wikipedia Privacy policy About Wikipedia Disclaimers Contact Wikipedia Legal & safety contacts Code of Conduct Developers Statistics Cookie statement Mobile view",
+ "elements": [
+ {
+ "id": "e1",
+ "description": "link 'https://en.wikipedia.org/wiki/Main_Page' → https://en.wikipedia.org/wiki/Main_Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e2",
+ "description": "link 'Donate' → https://donate.wikimedia.org/?wmf_source=donate&wmf_medium=sidebar&wmf_campaign=auth.wikimedia.org&uselang=en",
+ "in_viewport": true
+ },
+ {
+ "id": "e3",
+ "description": "link 'Create account' → /enwiki/w/index.php?title=Special:CreateAccount&returnto=Main+Page¢ralauthLoginToken=8ba9892a14010d510d885378ffc131…",
+ "in_viewport": true
+ },
+ {
+ "id": "e4",
+ "description": "link 'Log in' → /enwiki/w/index.php?title=Special:UserLogin&returnto=Main+Page¢ralauthLoginToken=8ba9892a14010d510d885378ffc13139&u…",
+ "in_viewport": true
+ },
+ {
+ "id": "e5",
+ "description": "button 'Hide Appearance'",
+ "in_viewport": true
+ },
+ {
+ "id": "e6",
+ "description": "text field 'Username' (type input, placeholder \"Enter your username\", empty)",
+ "in_viewport": true
+ },
+ {
+ "id": "e7",
+ "description": "text field 'Password' (type password, placeholder \"Enter your password\", empty)",
+ "in_viewport": true
+ },
+ {
+ "id": "e8",
+ "description": "button 'Log in'",
+ "in_viewport": true
+ },
+ {
+ "id": "e9",
+ "description": "link 'Help with logging in' → https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Logging_in",
+ "in_viewport": true
+ },
+ {
+ "id": "e10",
+ "description": "link 'Forgot your password?' → /enwiki/w/index.php?title=Special:PasswordReset&returnto=Main+Page¢ralauthLoginToken=8ba9892a14010d510d885378ffc131…",
+ "in_viewport": true
+ },
+ {
+ "id": "e11",
+ "description": "link 'Join Wikipedia' → /enwiki/w/index.php?title=Special:CreateAccount&returnto=Main+Page¢ralauthLoginToken=8ba9892a14010d510d885378ffc131…",
+ "in_viewport": true
+ },
+ {
+ "id": "e12",
+ "description": "link 'Wikimedia Foundation' → https://www.wikimedia.org/",
+ "in_viewport": true
+ },
+ {
+ "id": "e13",
+ "description": "link 'Powered by MediaWiki' → https://www.mediawiki.org/",
+ "in_viewport": true
+ },
+ {
+ "id": "e14",
+ "description": "link 'Privacy policy' → https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Privacy_policy",
+ "in_viewport": true
+ },
+ {
+ "id": "e15",
+ "description": "link 'About Wikipedia' → https://en.wikipedia.org/wiki/Wikipedia:About",
+ "in_viewport": true
+ },
+ {
+ "id": "e16",
+ "description": "link 'Disclaimers' → https://en.wikipedia.org/wiki/Wikipedia:General_disclaimer",
+ "in_viewport": true
+ },
+ {
+ "id": "e17",
+ "description": "link 'Contact Wikipedia' → //en.wikipedia.org/wiki/Wikipedia:Contact_us",
+ "in_viewport": true
+ },
+ {
+ "id": "e18",
+ "description": "link 'Legal & safety contacts' → https://foundation.wikimedia.org/wiki/Special:MyLanguage/Legal:Wikimedia_Foundation_Legal_and_Safety_Contact_Information",
+ "in_viewport": true
+ },
+ {
+ "id": "e19",
+ "description": "link 'Code of Conduct' → https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Universal_Code_of_Conduct",
+ "in_viewport": true
+ },
+ {
+ "id": "e20",
+ "description": "link 'Developers' → https://developer.wikimedia.org",
+ "in_viewport": true
+ },
+ {
+ "id": "e21",
+ "description": "link 'Statistics' → https://stats.wikimedia.org/#/en.wikipedia.org",
+ "in_viewport": true
+ },
+ {
+ "id": "e22",
+ "description": "link 'Cookie statement' → https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Cookie_statement",
+ "in_viewport": true
+ },
+ {
+ "id": "e23",
+ "description": "link 'Mobile view' → //auth.wikimedia.org/enwiki/w/index.php?title=Special:UserLogin¢ralauthLoginToken=8ba9892a14010d510d885378ffc13139&…",
+ "in_viewport": true
+ }
+ ],
+ "omitted_elements": 0
+ },
+ "previous_page": null,
+ "last_action": null,
+ "history": {
+ "steps_taken": 0,
+ "recent_urls": []
+ }
+ },
+ "questions": {
+ "goal_done": {
+ "type": "noul",
+ "instructions": {
+ "question": "Is `goal` already fully accomplished according to what `page` shows right now?",
+ "rules": [
+ "Judge only from `page` (its url, title, headings, visible_text, dialog and elements).",
+ "A page that merely offers a way to accomplish `goal` does not count as accomplished.",
+ "If `goal` asks to open or view something, it is accomplished when that thing is what `page` shows.",
+ "If `goal` asks to perform an action (submit, add, sign in, start), it is accomplished only when `page` shows the result or confirmation of that action."
+ ]
+ },
+ "criteria": {
+ "true": "`page` shows the end result that `goal` asks for.",
+ "false": "At least one more action is needed, `page` shows something else, or it is unclear."
+ }
+ },
+ "blocker": {
+ "type": "choice",
+ "instructions": {
+ "question": "Does `page` present an obstacle that an automated browser agent cannot resolve with the listed elements and `inputs`, stopping progress toward `goal`?",
+ "rules": [
+ "Pick `none` unless the obstacle is clearly visible in `page`.",
+ "Cookie banners or dialogs that have a listed button to dismiss them are not obstacles."
+ ]
+ },
+ "criteria": {
+ "none": "No obstacle: the page can be operated normally (a login form that can be filled with provided `inputs` is not an obstacle).",
+ "login_required": "The page requires signing in and `inputs` does not provide the credentials needed to sign in.",
+ "verification_challenge": "A CAPTCHA, one-time code, two-factor prompt, or similar human verification is shown.",
+ "consent_or_permission_dialog": "A modal dialog demanding consent, permissions, or a choice from the user blocks the content and nothing listed dismisses it.",
+ "error_page": "The page shows an error (not found, access denied, server error, network failure) instead of the expected content.",
+ "missing_information": "Progress requires information (an account, payment details, a value) that is neither on the page nor in `inputs`."
+ }
+ },
+ "action": {
+ "type": "choice",
+ "instructions": {
+ "question": "Which single browser action should be performed next to make progress toward `goal` from the current `page`?",
+ "rules": [
+ "Every element in `page.elements` can be clicked, filled or selected right now, even when its in_viewport is false (the browser scrolls to it). Scroll only when the needed element or text is not listed at all.",
+ "Use `type` only when a value in `inputs` belongs in a listed text field.",
+ "Use `stop` when `goal` is already accomplished or nothing listed can help.",
+ "Consider `last_action` and `history`: do not repeat an action that produced no change."
+ ]
+ },
+ "criteria": {
+ "click": {
+ "what": "Click one element listed in `page.elements` (a link, button, checkbox, radio, tab, menu item, or similar).",
+ "use_when": "The next step toward `goal` is to open, choose, submit, toggle, or confirm something that is listed."
+ },
+ "scroll_down": {
+ "what": "Scroll down to reveal content that is not listed in `page.elements` and not in `page.visible_text`.",
+ "use_when": "Nothing listed can serve `goal` and more content probably exists further down. Never needed to reach an element that is already listed: clicking scrolls to it automatically."
+ },
+ "wait": {
+ "what": "Do nothing for a moment because the page is still loading or a result is still pending.",
+ "use_when": "The visible text or a dialog indicates loading, processing, or a countdown."
+ },
+ "stop": {
+ "what": "Stop: no listed action can make progress toward `goal`.",
+ "use_when": "`goal` is already accomplished as shown by `page`, or it is impossible from here with the listed actions."
+ }
+ }
+ },
+ "click_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is a click, which element in `page.elements` should be clicked to make progress toward `goal`?",
+ "rules": [
+ "Choose `none` if no listed element helps.",
+ "Each option id refers to `page.elements[].id`."
+ ]
+ },
+ "criteria": {
+ "e1": "link 'https://en.wikipedia.org/wiki/Main_Page' → https://en.wikipedia.org/wiki/Main_Page",
+ "e2": "link 'Donate' → https://donate.wikimedia.org/?wmf_source=donate&wmf_medium=sidebar&wmf_campaign=auth.wikimedia.org&uselang=en",
+ "e3": "link 'Create account' → /enwiki/w/index.php?title=Special:CreateAccount&returnto=Main+Page¢ralauthLoginToken=8ba9892a14010d510d885378ffc131…",
+ "e4": "link 'Log in' → /enwiki/w/index.php?title=Special:UserLogin&returnto=Main+Page¢ralauthLoginToken=8ba9892a14010d510d885378ffc13139&u…",
+ "e5": "button 'Hide Appearance'",
+ "e8": "button 'Log in'",
+ "e9": "link 'Help with logging in' → https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Logging_in",
+ "e10": "link 'Forgot your password?' → /enwiki/w/index.php?title=Special:PasswordReset&returnto=Main+Page¢ralauthLoginToken=8ba9892a14010d510d885378ffc131…",
+ "e11": "link 'Join Wikipedia' → /enwiki/w/index.php?title=Special:CreateAccount&returnto=Main+Page¢ralauthLoginToken=8ba9892a14010d510d885378ffc131…",
+ "e12": "link 'Wikimedia Foundation' → https://www.wikimedia.org/",
+ "e13": "link 'Powered by MediaWiki' → https://www.mediawiki.org/",
+ "e14": "link 'Privacy policy' → https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Privacy_policy",
+ "e15": "link 'About Wikipedia' → https://en.wikipedia.org/wiki/Wikipedia:About",
+ "e16": "link 'Disclaimers' → https://en.wikipedia.org/wiki/Wikipedia:General_disclaimer",
+ "e17": "link 'Contact Wikipedia' → //en.wikipedia.org/wiki/Wikipedia:Contact_us",
+ "e18": "link 'Legal & safety contacts' → https://foundation.wikimedia.org/wiki/Special:MyLanguage/Legal:Wikimedia_Foundation_Legal_and_Safety_Contact_Information",
+ "e19": "link 'Code of Conduct' → https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Universal_Code_of_Conduct",
+ "e20": "link 'Developers' → https://developer.wikimedia.org",
+ "e21": "link 'Statistics' → https://stats.wikimedia.org/#/en.wikipedia.org",
+ "e22": "link 'Cookie statement' → https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Cookie_statement",
+ "e23": "link 'Mobile view' → //auth.wikimedia.org/enwiki/w/index.php?title=Special:UserLogin¢ralauthLoginToken=8ba9892a14010d510d885378ffc13139&…",
+ "none": "No listed element should be clicked."
+ }
+ }
+ },
+ "meta": {
+ "allowedActions": [
+ "click",
+ "scroll_down",
+ "wait",
+ "stop"
+ ],
+ "clickableIds": [
+ "e1",
+ "e2",
+ "e3",
+ "e4",
+ "e5",
+ "e8",
+ "e9",
+ "e10",
+ "e11",
+ "e12",
+ "e13",
+ "e14",
+ "e15",
+ "e16",
+ "e17",
+ "e18",
+ "e19",
+ "e20",
+ "e21",
+ "e22",
+ "e23"
+ ],
+ "editableIds": [
+ "e6",
+ "e7"
+ ],
+ "selectIds": [],
+ "inputKeys": [],
+ "urlInputKeys": [],
+ "questionCount": 4,
+ "candidateCount": 23
+ },
+ "estimatedInputTokens": 2852,
+ "estimatedCostUsd": 0.000119784
+}
diff --git a/experiments/gguf-provider/fixtures/raw_wiki_typed.txt b/experiments/gguf-provider/fixtures/raw_wiki_typed.txt
new file mode 100644
index 0000000..30cd73d
--- /dev/null
+++ b/experiments/gguf-provider/fixtures/raw_wiki_typed.txt
@@ -0,0 +1,884 @@
+backend=ego model=jev-latest maxSteps=25 budget=$0.25
+ego task space 23, page p1
+{
+ "mode": "dry-run",
+ "backend": "ego",
+ "state": {
+ "goal": "search Wikipedia for the article about bacteria",
+ "inputs": {
+ "query": "bacteria"
+ },
+ "page": {
+ "url": "https://en.wikipedia.org/wiki/Main_Page",
+ "title": "Wikipedia, the free encyclopedia",
+ "headings": [
+ "# Welcome to Wikipedia",
+ "## From today's featured article",
+ "## Did you know ...",
+ "## In the news",
+ "## On this day",
+ "## From today's featured list",
+ "## Today's featured video",
+ "## Other areas of Wikipedia",
+ "## Wikipedia's sister projects"
+ ],
+ "dialog": null,
+ "scroll_position": "at the top; more content below",
+ "visible_text": "Jump to content Main menu Search Donate Create account Log in Main Page Talk Read View source View history Tools Appearance hide Text Small Standard Large Width Standard Wide Color Automatic Light Dark Welcome to Wikipedia, the free encyclopedia that anyone can edit. 265,014 active editors7,243,180 articles in English From today's featured article Mary Mallon (September 23, 1869 – November 11, 1938), dubbed Typhoid Mary, was an Irish-born cook who lived in the US and is believed to have infected up to 57 people with the bacteria that cause typhoid fever, with three confirmed deaths. Between 1897 and 1907, Mallon worked at several homes; residents at four of them contracted typhoid. In 1907, she was forcibly quarantined at Riverside Hospital, but was freed in 1910, promising not to work as a cook. A further outbreak at the Sloane Maternity Hospital, where she was working, resulted in 25 cases and two deaths in early 1915. She was again confined, remaining so until her death in 1938. Her nickname became a term for anyone who spreads disease. Mallon's case raises questions about the balance between individual liberty and public health. No other carrier of typhoid was confined for as long as she was. Her story has been reevaluated, particularly during outbreaks of HIV/AIDS, tuberculosis, and COVID-19. (Full article...) Recently featured: Alison FrantzEarly Netherlandish paintingMisti ArchiveBy emailMore featured articlesAbout Did you know ... Lotte Rakhat chocolate bar ... that amendments to Kazakhstan's law on state symbols raised concerns over changes to the packaging of one of Lotte Rakhat's most popular products (pictured)? ... that a promotion for the Jackie Robinson commemorative coins included a baseball card issued by the United States government? ... that \"Candidatus Magnetoglobus multicellularis\", unlike almost all other known prokaryotes, spends its entire life cycle as a multicellular organism? ... that Leona E. Prasse's 1972 Feininger catalogue, which involved the help of the subject's widow, was called an improvement over a previous Feininger book from 1959? ... that the dinosaur that laid the eggs identified as Umbellaoolithus is unknown, but it ate plants? ... that only a shoe and a backpack were found after Makan Nasiri was killed in the 2026 Minab school attack? ... that a story in I Became the Main Role of a BL Drama was published as a script because there were not enough pages or time to include it as a full comic? ... that \"Pistol Nell\" earned her nickname by helping to thwart a bank robbery? ... that Billy Bragg ate Joe Hill's ashes? ArchiveStart a new articleNominate an article In the news Tilcayo An attack on a police complex in Kohat, Pakistan, leaves at least 31 people dead. The tilcayo (pictured), a new species of tiger cat, is formally identified. Former leader of Kosovo Hashim Thaçi is sentenced to 25 years in prison for war crimes during his leadership of the Kosovo Liberation Army. At the Primetime Emmy Awards, Widow's…",
+ "elements": [
+ {
+ "id": "e1",
+ "description": "text field 'Search Wikipedia' (type search, placeholder \"Search Wikipedia\", empty)",
+ "in_viewport": true
+ },
+ {
+ "id": "e2",
+ "description": "button 'Search'",
+ "in_viewport": true
+ },
+ {
+ "id": "e3",
+ "description": "link 'bacteria' → https://en.wikipedia.org/wiki/Bacteria",
+ "in_viewport": true
+ },
+ {
+ "id": "e4",
+ "description": "link 'Full article...' → https://en.wikipedia.org/wiki/Mary_Mallon",
+ "in_viewport": true
+ },
+ {
+ "id": "e5",
+ "description": "link 'Nominate an article' → https://en.wikipedia.org/wiki/Wikipedia:In_the_news/Candidates",
+ "in_viewport": true
+ },
+ {
+ "id": "e6",
+ "description": "link 'Archive' → https://en.wikipedia.org/wiki/Wikipedia:Today's_featured_article/September_2026",
+ "in_viewport": true
+ },
+ {
+ "id": "e7",
+ "description": "link 'By email' → https://lists.wikimedia.org/postorius/lists/daily-article-l.lists.wikimedia.org/",
+ "in_viewport": true
+ },
+ {
+ "id": "e8",
+ "description": "link 'More featured articles' → https://en.wikipedia.org/wiki/Wikipedia:Featured_articles_(linked_from_TFAfooter)",
+ "in_viewport": true
+ },
+ {
+ "id": "e9",
+ "description": "link 'About' → https://en.wikipedia.org/wiki/Wikipedia:About_Today's_featured_article",
+ "in_viewport": true
+ },
+ {
+ "id": "e10",
+ "description": "link 'By email' → https://lists.wikimedia.org/postorius/lists/daily-article-l.lists.wikimedia.org/",
+ "in_viewport": false
+ },
+ {
+ "id": "e11",
+ "description": "link 'Start a new article' → https://en.wikipedia.org/wiki/Help:Your_first_article",
+ "in_viewport": false
+ },
+ {
+ "id": "e12",
+ "description": "link 'Nominate an article' → https://en.wikipedia.org/wiki/Template_talk:Did_you_know",
+ "in_viewport": false
+ },
+ {
+ "id": "e13",
+ "description": "link '/wiki/Main_Page' → /wiki/Main_Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e14",
+ "description": "link 'Donate' → https://donate.wikimedia.org/?wmf_source=donate&wmf_medium=sidebar&wmf_campaign=en.wikipedia.org&uselang=en",
+ "in_viewport": true
+ },
+ {
+ "id": "e15",
+ "description": "link 'Create account' → /w/index.php?title=Special:CreateAccount&returnto=Main+Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e16",
+ "description": "link 'Log in' → /w/index.php?title=Special:UserLogin&returnto=Main+Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e17",
+ "description": "link 'Main Page' → /wiki/Main_Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e18",
+ "description": "link 'Talk' → /wiki/Talk:Main_Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e19",
+ "description": "link 'Read' → /wiki/Main_Page",
+ "in_viewport": true
+ },
+ {
+ "id": "e20",
+ "description": "link 'View source' → /w/index.php?title=Main_Page&action=edit",
+ "in_viewport": true
+ },
+ {
+ "id": "e21",
+ "description": "link 'View history' → /w/index.php?title=Main_Page&action=history",
+ "in_viewport": true
+ },
+ {
+ "id": "e22",
+ "description": "button 'Hide Appearance'",
+ "in_viewport": true
+ },
+ {
+ "id": "e23",
+ "description": "link 'Wikipedia' → https://en.wikipedia.org/wiki/Wikipedia",
+ "in_viewport": true
+ },
+ {
+ "id": "e24",
+ "description": "link 'free' → https://en.wikipedia.org/wiki/Free_content",
+ "in_viewport": true
+ },
+ {
+ "id": "e25",
+ "description": "link 'anyone can edit' → https://en.wikipedia.org/wiki/Help:Introduction_to_Wikipedia",
+ "in_viewport": true
+ },
+ {
+ "id": "e26",
+ "description": "link '265,014' → https://en.wikipedia.org/wiki/Special:Statistics",
+ "in_viewport": true
+ },
+ {
+ "id": "e27",
+ "description": "link '7,243,180' → https://en.wikipedia.org/wiki/Special:Statistics",
+ "in_viewport": true
+ },
+ {
+ "id": "e28",
+ "description": "link 'English' → https://en.wikipedia.org/wiki/English_language",
+ "in_viewport": true
+ },
+ {
+ "id": "e29",
+ "description": "link 'Mary Mallon' → https://en.wikipedia.org/wiki/Mary_Mallon",
+ "in_viewport": true
+ },
+ {
+ "id": "e30",
+ "description": "link 'An attack on a police complex' → https://en.wikipedia.org/wiki/2026_Kohat_attack",
+ "in_viewport": true
+ },
+ {
+ "id": "e31",
+ "description": "link 'Kohat' → https://en.wikipedia.org/wiki/Kohat",
+ "in_viewport": true
+ },
+ {
+ "id": "e32",
+ "description": "link 'Tilcayo' → https://en.wikipedia.org/wiki/File:Leopardus_tilcayo_(5x3_cropped).jpg",
+ "in_viewport": true
+ },
+ {
+ "id": "e33",
+ "description": "link 'typhoid fever' → https://en.wikipedia.org/wiki/Typhoid_fever",
+ "in_viewport": true
+ },
+ {
+ "id": "e34",
+ "description": "link 'tilcayo' → https://en.wikipedia.org/wiki/Tilcayo",
+ "in_viewport": true
+ },
+ {
+ "id": "e35",
+ "description": "link 'Mary Mallon' → https://en.wikipedia.org/wiki/File:Mary_Mallon,_aka_Typhoid_Mary.jpg",
+ "in_viewport": true
+ },
+ {
+ "id": "e36",
+ "description": "link 'quarantined' → https://en.wikipedia.org/wiki/Quarantine",
+ "in_viewport": true
+ },
+ {
+ "id": "e37",
+ "description": "link 'Hashim Thaçi' → https://en.wikipedia.org/wiki/Hashim_Thaçi",
+ "in_viewport": true
+ },
+ {
+ "id": "e38",
+ "description": "link 'war crimes during his leadership' → https://en.wikipedia.org/wiki/War_crimes_in_the_Kosovo_War#KLA_war_crimes",
+ "in_viewport": true
+ },
+ {
+ "id": "e39",
+ "description": "link 'Sloane Maternity Hospital' → https://en.wikipedia.org/wiki/Sloane_Hospital_for_Women",
+ "in_viewport": true
+ },
+ {
+ "id": "e40",
+ "description": "link 'Kosovo Liberation Army' → https://en.wikipedia.org/wiki/Kosovo_Liberation_Army",
+ "in_viewport": true
+ },
+ {
+ "id": "e41",
+ "description": "link 'the Primetime Emmy Awards' → https://en.wikipedia.org/wiki/78th_Primetime_Emmy_Awards",
+ "in_viewport": true
+ },
+ {
+ "id": "e42",
+ "description": "link 'Widow's Bay' → https://en.wikipedia.org/wiki/Widow's_Bay",
+ "in_viewport": true
+ },
+ {
+ "id": "e43",
+ "description": "link 'Outstanding Comedy Series' → https://en.wikipedia.org/wiki/Primetime_Emmy_Award_for_Outstanding_Comedy_Series",
+ "in_viewport": true
+ },
+ {
+ "id": "e44",
+ "description": "link 'The Pitt' → https://en.wikipedia.org/wiki/The_Pitt",
+ "in_viewport": true
+ },
+ {
+ "id": "e45",
+ "description": "link 'Outstanding Drama Series' → https://en.wikipedia.org/wiki/Primetime_Emmy_Award_for_Outstanding_Drama_Series",
+ "in_viewport": true
+ },
+ {
+ "id": "e46",
+ "description": "link 'public health' → https://en.wikipedia.org/wiki/Public_health",
+ "in_viewport": true
+ },
+ {
+ "id": "e47",
+ "description": "link 'Iran war' → https://en.wikipedia.org/wiki/2026_Iran_war",
+ "in_viewport": true
+ },
+ {
+ "id": "e48",
+ "description": "link 'Lebanon war' → https://en.wikipedia.org/wiki/2026_Lebanon_war",
+ "in_viewport": true
+ },
+ {
+ "id": "e49",
+ "description": "link 'Russo-Ukrainian war' → https://en.wikipedia.org/wiki/Russo-Ukrainian_war_(2022–present)",
+ "in_viewport": true
+ },
+ {
+ "id": "e50",
+ "description": "link 'timeline' → https://en.wikipedia.org/wiki/Timeline_of_the_Russo-Ukrainian_war_(1_September_2026_–_present)",
+ "in_viewport": true
+ },
+ {
+ "id": "e51",
+ "description": "link 'HIV/AIDS' → https://en.wikipedia.org/wiki/HIV/AIDS",
+ "in_viewport": true
+ },
+ {
+ "id": "e52",
+ "description": "link 'tuberculosis' → https://en.wikipedia.org/wiki/Tuberculosis",
+ "in_viewport": true
+ },
+ {
+ "id": "e53",
+ "description": "link 'Recent deaths' → https://en.wikipedia.org/wiki/Deaths_in_2026",
+ "in_viewport": true
+ },
+ {
+ "id": "e54",
+ "description": "link 'Dolores Sibonga' → https://en.wikipedia.org/wiki/Dolores_Sibonga",
+ "in_viewport": true
+ },
+ {
+ "id": "e55",
+ "description": "link 'Aracy Amaral' → https://en.wikipedia.org/wiki/Aracy_Amaral",
+ "in_viewport": true
+ },
+ {
+ "id": "e56",
+ "description": "link 'Bonnie Greer' → https://en.wikipedia.org/wiki/Bonnie_Greer",
+ "in_viewport": true
+ },
+ {
+ "id": "e57",
+ "description": "link 'COVID-19' → https://en.wikipedia.org/wiki/COVID-19",
+ "in_viewport": true
+ },
+ {
+ "id": "e58",
+ "description": "link 'Peter Max' → https://en.wikipedia.org/wiki/Peter_Max",
+ "in_viewport": true
+ },
+ {
+ "id": "e59",
+ "description": "link 'Chung Ho-yong' → https://en.wikipedia.org/wiki/Chung_Ho-yong",
+ "in_viewport": true
+ },
+ {
+ "id": "e60",
+ "description": "link 'Win Aung' → https://en.wikipedia.org/wiki/Win_Aung_(footballer)",
+ "in_viewport": true
+ },
+ {
+ "id": "e61",
+ "description": "link 'More current events' → https://en.wikipedia.org/wiki/Portal:Current_events",
+ "in_viewport": true
+ },
+ {
+ "id": "e62",
+ "description": "link 'Alison Frantz' → https://en.wikipedia.org/wiki/Alison_Frantz",
+ "in_viewport": true
+ },
+ {
+ "id": "e63",
+ "description": "link 'Early Netherlandish painting' → https://en.wikipedia.org/wiki/Early_Netherlandish_painting",
+ "in_viewport": true
+ },
+ {
+ "id": "e64",
+ "description": "link 'Misti' → https://en.wikipedia.org/wiki/Misti",
+ "in_viewport": true
+ },
+ {
+ "id": "e65",
+ "description": "link 'September 23' → https://en.wikipedia.org/wiki/September_23",
+ "in_viewport": false
+ },
+ {
+ "id": "e66",
+ "description": "link 'Celebrate Bisexuality Day' → https://en.wikipedia.org/wiki/Celebrate_Bisexuality_Day",
+ "in_viewport": false
+ },
+ {
+ "id": "e67",
+ "description": "link '1803' → https://en.wikipedia.org/wiki/1803",
+ "in_viewport": false
+ },
+ {
+ "id": "e68",
+ "description": "link 'Maratha' → https://en.wikipedia.org/wiki/Maratha_Empire",
+ "in_viewport": false
+ },
+ {
+ "id": "e69",
+ "description": "link 'East India Company' → https://en.wikipedia.org/wiki/East_India_Company",
+ "in_viewport": false
+ },
+ {
+ "id": "e70",
+ "description": "link 'Lotte Rakhat' → https://en.wikipedia.org/wiki/Lotte_Rakhat",
+ "in_viewport": false
+ },
+ {
+ "id": "e71",
+ "description": "link 'Lotte Rakhat chocolate bar' → https://en.wikipedia.org/wiki/File:Rakhat_Kazakhstan_dark_chocolate_bar_(square_crop).jpg",
+ "in_viewport": false
+ },
+ {
+ "id": "e72",
+ "description": "link 'U2 performing in Sarajevo' → https://en.wikipedia.org/wiki/File:U2_performing_in_Sarajevo_on_Sept_23_1997_(11).jpg",
+ "in_viewport": false
+ },
+ {
+ "id": "e73",
+ "description": "link 'Battle of Assaye' → https://en.wikipedia.org/wiki/Battle_of_Assaye",
+ "in_viewport": false
+ },
+ {
+ "id": "e74",
+ "description": "link 'Jackie Robinson commemorative coins' → https://en.wikipedia.org/wiki/Jackie_Robinson_commemorative_coins",
+ "in_viewport": false
+ },
+ {
+ "id": "e75",
+ "description": "link 'Second Anglo-Maratha War' → https://en.wikipedia.org/wiki/Second_Anglo-Maratha_War",
+ "in_viewport": false
+ },
+ {
+ "id": "e76",
+ "description": "link 'baseball card' → https://en.wikipedia.org/wiki/Baseball_card",
+ "in_viewport": false
+ },
+ {
+ "id": "e77",
+ "description": "link '1884' → https://en.wikipedia.org/wiki/1884",
+ "in_viewport": false
+ },
+ {
+ "id": "e78",
+ "description": "link 'Cape Virgenes' → https://en.wikipedia.org/wiki/Cape_Virgenes",
+ "in_viewport": false
+ },
+ {
+ "id": "e79",
+ "description": "link 'Candidatus Magnetoglobus multicellularis' → https://en.wikipedia.org/wiki/Candidatus_Magnetoglobus_multicellularis",
+ "in_viewport": false
+ },
+ {
+ "id": "e80",
+ "description": "link 'prokaryotes' → https://en.wikipedia.org/wiki/Prokaryote",
+ "in_viewport": false
+ },
+ {
+ "id": "e81",
+ "description": "link 'Tierra del Fuego Gold Rush' → https://en.wikipedia.org/wiki/Tierra_del_Fuego_Gold_Rush",
+ "in_viewport": false
+ },
+ {
+ "id": "e82",
+ "description": "link '1983' → https://en.wikipedia.org/wiki/1983",
+ "in_viewport": false
+ },
+ {
+ "id": "e83",
+ "description": "link 'Gulf Air Flight 771' → https://en.wikipedia.org/wiki/Gulf_Air_Flight_771",
+ "in_viewport": false
+ },
+ {
+ "id": "e84",
+ "description": "link 'Leona E. Prasse' → https://en.wikipedia.org/wiki/Leona_E._Prasse",
+ "in_viewport": false
+ },
+ {
+ "id": "e85",
+ "description": "link '1972 Feininger catalogue' → https://en.wikipedia.org/wiki/Lyonel_Feininger:_A_Definitive_Catalogue_of_His_Graphic_Work",
+ "in_viewport": false
+ },
+ {
+ "id": "e86",
+ "description": "link 'Abu Nidal Organization' → https://en.wikipedia.org/wiki/Abu_Nidal_Organization",
+ "in_viewport": false
+ },
+ {
+ "id": "e87",
+ "description": "link 'the subject's widow' → https://en.wikipedia.org/wiki/Julia_Feininger",
+ "in_viewport": false
+ },
+ {
+ "id": "e88",
+ "description": "link 'a previous Feininger book from 1959' → https://en.wikipedia.org/wiki/Lyonel_Feininger_(Hess_book)",
+ "in_viewport": false
+ },
+ {
+ "id": "e89",
+ "description": "link 'United Arab Emirates' → https://en.wikipedia.org/wiki/United_Arab_Emirates",
+ "in_viewport": false
+ },
+ {
+ "id": "e90",
+ "description": "link '1997' → https://en.wikipedia.org/wiki/1997",
+ "in_viewport": false
+ },
+ {
+ "id": "e91",
+ "description": "link 'U2' → https://en.wikipedia.org/wiki/U2",
+ "in_viewport": false
+ },
+ {
+ "id": "e92",
+ "description": "link 'performed' → https://en.wikipedia.org/wiki/U2_concert_in_Sarajevo",
+ "in_viewport": false
+ },
+ {
+ "id": "e93",
+ "description": "link 'Sarajevo' → https://en.wikipedia.org/wiki/Sarajevo",
+ "in_viewport": false
+ },
+ {
+ "id": "e94",
+ "description": "link 'Umbellaoolithus' → https://en.wikipedia.org/wiki/Umbellaoolithus",
+ "in_viewport": false
+ },
+ {
+ "id": "e95",
+ "description": "link 'Bosnian War' → https://en.wikipedia.org/wiki/Bosnian_War",
+ "in_viewport": false
+ },
+ {
+ "id": "e96",
+ "description": "link 'Makan Nasiri' → https://en.wikipedia.org/wiki/Makan_Nasiri",
+ "in_viewport": false
+ },
+ {
+ "id": "e97",
+ "description": "link '2016' → https://en.wikipedia.org/wiki/2016",
+ "in_viewport": false
+ },
+ {
+ "id": "e98",
+ "description": "link '2026 Minab school attack' → https://en.wikipedia.org/wiki/2026_Minab_school_attack",
+ "in_viewport": false
+ },
+ {
+ "id": "e99",
+ "description": "link 'rape in Germany' → https://en.wikipedia.org/wiki/Rape_in_Germany",
+ "in_viewport": false
+ },
+ {
+ "id": "e100",
+ "description": "link 'I Became the Main Role of a BL Drama' → https://en.wikipedia.org/wiki/I_Became_the_Main_Role_of_a_BL_Drama",
+ "in_viewport": false
+ }
+ ],
+ "omitted_elements": 82
+ },
+ "previous_page": null,
+ "last_action": null,
+ "history": {
+ "steps_taken": 0,
+ "recent_urls": []
+ }
+ },
+ "questions": {
+ "goal_done": {
+ "type": "noul",
+ "instructions": {
+ "question": "Is `goal` already fully accomplished according to what `page` shows right now?",
+ "rules": [
+ "Judge only from `page` (its url, title, headings, visible_text, dialog and elements).",
+ "A page that merely offers a way to accomplish `goal` does not count as accomplished.",
+ "If `goal` asks to open or view something, it is accomplished when that thing is what `page` shows.",
+ "If `goal` asks to perform an action (submit, add, sign in, start), it is accomplished only when `page` shows the result or confirmation of that action."
+ ]
+ },
+ "criteria": {
+ "true": "`page` shows the end result that `goal` asks for.",
+ "false": "At least one more action is needed, `page` shows something else, or it is unclear."
+ }
+ },
+ "blocker": {
+ "type": "choice",
+ "instructions": {
+ "question": "Does `page` present an obstacle that an automated browser agent cannot resolve with the listed elements and `inputs`, stopping progress toward `goal`?",
+ "rules": [
+ "Pick `none` unless the obstacle is clearly visible in `page`.",
+ "Cookie banners or dialogs that have a listed button to dismiss them are not obstacles."
+ ]
+ },
+ "criteria": {
+ "none": "No obstacle: the page can be operated normally (a login form that can be filled with provided `inputs` is not an obstacle).",
+ "login_required": "The page requires signing in and `inputs` does not provide the credentials needed to sign in.",
+ "verification_challenge": "A CAPTCHA, one-time code, two-factor prompt, or similar human verification is shown.",
+ "consent_or_permission_dialog": "A modal dialog demanding consent, permissions, or a choice from the user blocks the content and nothing listed dismisses it.",
+ "error_page": "The page shows an error (not found, access denied, server error, network failure) instead of the expected content.",
+ "missing_information": "Progress requires information (an account, payment details, a value) that is neither on the page nor in `inputs`."
+ }
+ },
+ "action": {
+ "type": "choice",
+ "instructions": {
+ "question": "Which single browser action should be performed next to make progress toward `goal` from the current `page`?",
+ "rules": [
+ "Every element in `page.elements` can be clicked, filled or selected right now, even when its in_viewport is false (the browser scrolls to it). Scroll only when the needed element or text is not listed at all.",
+ "Use `type` only when a value in `inputs` belongs in a listed text field.",
+ "Use `stop` when `goal` is already accomplished or nothing listed can help.",
+ "Consider `last_action` and `history`: do not repeat an action that produced no change."
+ ]
+ },
+ "criteria": {
+ "click": {
+ "what": "Click one element listed in `page.elements` (a link, button, checkbox, radio, tab, menu item, or similar).",
+ "use_when": "The next step toward `goal` is to open, choose, submit, toggle, or confirm something that is listed."
+ },
+ "type": {
+ "what": "Type one of the provided `inputs` values into a text field listed in `page.elements`.",
+ "use_when": "A form field or search box must be filled before progress is possible, and a suitable value exists in `inputs`."
+ },
+ "scroll_down": {
+ "what": "Scroll down to reveal content that is not listed in `page.elements` and not in `page.visible_text`.",
+ "use_when": "Nothing listed can serve `goal` and more content probably exists further down. Never needed to reach an element that is already listed: clicking scrolls to it automatically."
+ },
+ "wait": {
+ "what": "Do nothing for a moment because the page is still loading or a result is still pending.",
+ "use_when": "The visible text or a dialog indicates loading, processing, or a countdown."
+ },
+ "stop": {
+ "what": "Stop: no listed action can make progress toward `goal`.",
+ "use_when": "`goal` is already accomplished as shown by `page`, or it is impossible from here with the listed actions."
+ }
+ }
+ },
+ "click_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is a click, which element in `page.elements` should be clicked to make progress toward `goal`?",
+ "rules": [
+ "Choose `none` if no listed element helps.",
+ "Each option id refers to `page.elements[].id`."
+ ]
+ },
+ "criteria": {
+ "e2": "button 'Search'",
+ "e3": "link 'bacteria' → https://en.wikipedia.org/wiki/Bacteria",
+ "e4": "link 'Full article...' → https://en.wikipedia.org/wiki/Mary_Mallon",
+ "e5": "link 'Nominate an article' → https://en.wikipedia.org/wiki/Wikipedia:In_the_news/Candidates",
+ "e6": "link 'Archive' → https://en.wikipedia.org/wiki/Wikipedia:Today's_featured_article/September_2026",
+ "e7": "link 'By email' → https://lists.wikimedia.org/postorius/lists/daily-article-l.lists.wikimedia.org/",
+ "e8": "link 'More featured articles' → https://en.wikipedia.org/wiki/Wikipedia:Featured_articles_(linked_from_TFAfooter)",
+ "e9": "link 'About' → https://en.wikipedia.org/wiki/Wikipedia:About_Today's_featured_article",
+ "e10": "link 'By email' → https://lists.wikimedia.org/postorius/lists/daily-article-l.lists.wikimedia.org/",
+ "e11": "link 'Start a new article' → https://en.wikipedia.org/wiki/Help:Your_first_article",
+ "e12": "link 'Nominate an article' → https://en.wikipedia.org/wiki/Template_talk:Did_you_know",
+ "e13": "link '/wiki/Main_Page' → /wiki/Main_Page",
+ "e14": "link 'Donate' → https://donate.wikimedia.org/?wmf_source=donate&wmf_medium=sidebar&wmf_campaign=en.wikipedia.org&uselang=en",
+ "e15": "link 'Create account' → /w/index.php?title=Special:CreateAccount&returnto=Main+Page",
+ "e16": "link 'Log in' → /w/index.php?title=Special:UserLogin&returnto=Main+Page",
+ "e17": "link 'Main Page' → /wiki/Main_Page",
+ "e18": "link 'Talk' → /wiki/Talk:Main_Page",
+ "e19": "link 'Read' → /wiki/Main_Page",
+ "e20": "link 'View source' → /w/index.php?title=Main_Page&action=edit",
+ "e21": "link 'View history' → /w/index.php?title=Main_Page&action=history",
+ "e22": "button 'Hide Appearance'",
+ "e23": "link 'Wikipedia' → https://en.wikipedia.org/wiki/Wikipedia",
+ "e24": "link 'free' → https://en.wikipedia.org/wiki/Free_content",
+ "e25": "link 'anyone can edit' → https://en.wikipedia.org/wiki/Help:Introduction_to_Wikipedia",
+ "e26": "link '265,014' → https://en.wikipedia.org/wiki/Special:Statistics",
+ "e27": "link '7,243,180' → https://en.wikipedia.org/wiki/Special:Statistics",
+ "e28": "link 'English' → https://en.wikipedia.org/wiki/English_language",
+ "e29": "link 'Mary Mallon' → https://en.wikipedia.org/wiki/Mary_Mallon",
+ "e30": "link 'An attack on a police complex' → https://en.wikipedia.org/wiki/2026_Kohat_attack",
+ "e31": "link 'Kohat' → https://en.wikipedia.org/wiki/Kohat",
+ "e32": "link 'Tilcayo' → https://en.wikipedia.org/wiki/File:Leopardus_tilcayo_(5x3_cropped).jpg",
+ "e33": "link 'typhoid fever' → https://en.wikipedia.org/wiki/Typhoid_fever",
+ "e34": "link 'tilcayo' → https://en.wikipedia.org/wiki/Tilcayo",
+ "e35": "link 'Mary Mallon' → https://en.wikipedia.org/wiki/File:Mary_Mallon,_aka_Typhoid_Mary.jpg",
+ "e36": "link 'quarantined' → https://en.wikipedia.org/wiki/Quarantine",
+ "e37": "link 'Hashim Thaçi' → https://en.wikipedia.org/wiki/Hashim_Thaçi",
+ "e38": "link 'war crimes during his leadership' → https://en.wikipedia.org/wiki/War_crimes_in_the_Kosovo_War#KLA_war_crimes",
+ "e39": "link 'Sloane Maternity Hospital' → https://en.wikipedia.org/wiki/Sloane_Hospital_for_Women",
+ "e40": "link 'Kosovo Liberation Army' → https://en.wikipedia.org/wiki/Kosovo_Liberation_Army",
+ "e41": "link 'the Primetime Emmy Awards' → https://en.wikipedia.org/wiki/78th_Primetime_Emmy_Awards",
+ "e42": "link 'Widow's Bay' → https://en.wikipedia.org/wiki/Widow's_Bay",
+ "e43": "link 'Outstanding Comedy Series' → https://en.wikipedia.org/wiki/Primetime_Emmy_Award_for_Outstanding_Comedy_Series",
+ "e44": "link 'The Pitt' → https://en.wikipedia.org/wiki/The_Pitt",
+ "e45": "link 'Outstanding Drama Series' → https://en.wikipedia.org/wiki/Primetime_Emmy_Award_for_Outstanding_Drama_Series",
+ "e46": "link 'public health' → https://en.wikipedia.org/wiki/Public_health",
+ "e47": "link 'Iran war' → https://en.wikipedia.org/wiki/2026_Iran_war",
+ "e48": "link 'Lebanon war' → https://en.wikipedia.org/wiki/2026_Lebanon_war",
+ "e49": "link 'Russo-Ukrainian war' → https://en.wikipedia.org/wiki/Russo-Ukrainian_war_(2022–present)",
+ "e50": "link 'timeline' → https://en.wikipedia.org/wiki/Timeline_of_the_Russo-Ukrainian_war_(1_September_2026_–_present)",
+ "e51": "link 'HIV/AIDS' → https://en.wikipedia.org/wiki/HIV/AIDS",
+ "e52": "link 'tuberculosis' → https://en.wikipedia.org/wiki/Tuberculosis",
+ "e53": "link 'Recent deaths' → https://en.wikipedia.org/wiki/Deaths_in_2026",
+ "e54": "link 'Dolores Sibonga' → https://en.wikipedia.org/wiki/Dolores_Sibonga",
+ "e55": "link 'Aracy Amaral' → https://en.wikipedia.org/wiki/Aracy_Amaral",
+ "e56": "link 'Bonnie Greer' → https://en.wikipedia.org/wiki/Bonnie_Greer",
+ "e57": "link 'COVID-19' → https://en.wikipedia.org/wiki/COVID-19",
+ "e58": "link 'Peter Max' → https://en.wikipedia.org/wiki/Peter_Max",
+ "e59": "link 'Chung Ho-yong' → https://en.wikipedia.org/wiki/Chung_Ho-yong",
+ "e60": "link 'Win Aung' → https://en.wikipedia.org/wiki/Win_Aung_(footballer)",
+ "e61": "link 'More current events' → https://en.wikipedia.org/wiki/Portal:Current_events",
+ "e62": "link 'Alison Frantz' → https://en.wikipedia.org/wiki/Alison_Frantz",
+ "e63": "link 'Early Netherlandish painting' → https://en.wikipedia.org/wiki/Early_Netherlandish_painting",
+ "e64": "link 'Misti' → https://en.wikipedia.org/wiki/Misti",
+ "e65": "link 'September 23' → https://en.wikipedia.org/wiki/September_23",
+ "e66": "link 'Celebrate Bisexuality Day' → https://en.wikipedia.org/wiki/Celebrate_Bisexuality_Day",
+ "e67": "link '1803' → https://en.wikipedia.org/wiki/1803",
+ "e68": "link 'Maratha' → https://en.wikipedia.org/wiki/Maratha_Empire",
+ "e69": "link 'East India Company' → https://en.wikipedia.org/wiki/East_India_Company",
+ "e70": "link 'Lotte Rakhat' → https://en.wikipedia.org/wiki/Lotte_Rakhat",
+ "e71": "link 'Lotte Rakhat chocolate bar' → https://en.wikipedia.org/wiki/File:Rakhat_Kazakhstan_dark_chocolate_bar_(square_crop).jpg",
+ "e72": "link 'U2 performing in Sarajevo' → https://en.wikipedia.org/wiki/File:U2_performing_in_Sarajevo_on_Sept_23_1997_(11).jpg",
+ "e73": "link 'Battle of Assaye' → https://en.wikipedia.org/wiki/Battle_of_Assaye",
+ "e74": "link 'Jackie Robinson commemorative coins' → https://en.wikipedia.org/wiki/Jackie_Robinson_commemorative_coins",
+ "e75": "link 'Second Anglo-Maratha War' → https://en.wikipedia.org/wiki/Second_Anglo-Maratha_War",
+ "e76": "link 'baseball card' → https://en.wikipedia.org/wiki/Baseball_card",
+ "e77": "link '1884' → https://en.wikipedia.org/wiki/1884",
+ "e78": "link 'Cape Virgenes' → https://en.wikipedia.org/wiki/Cape_Virgenes",
+ "e79": "link 'Candidatus Magnetoglobus multicellularis' → https://en.wikipedia.org/wiki/Candidatus_Magnetoglobus_multicellularis",
+ "e80": "link 'prokaryotes' → https://en.wikipedia.org/wiki/Prokaryote",
+ "e81": "link 'Tierra del Fuego Gold Rush' → https://en.wikipedia.org/wiki/Tierra_del_Fuego_Gold_Rush",
+ "e82": "link '1983' → https://en.wikipedia.org/wiki/1983",
+ "e83": "link 'Gulf Air Flight 771' → https://en.wikipedia.org/wiki/Gulf_Air_Flight_771",
+ "e84": "link 'Leona E. Prasse' → https://en.wikipedia.org/wiki/Leona_E._Prasse",
+ "e85": "link '1972 Feininger catalogue' → https://en.wikipedia.org/wiki/Lyonel_Feininger:_A_Definitive_Catalogue_of_His_Graphic_Work",
+ "e86": "link 'Abu Nidal Organization' → https://en.wikipedia.org/wiki/Abu_Nidal_Organization",
+ "e87": "link 'the subject's widow' → https://en.wikipedia.org/wiki/Julia_Feininger",
+ "e88": "link 'a previous Feininger book from 1959' → https://en.wikipedia.org/wiki/Lyonel_Feininger_(Hess_book)",
+ "e89": "link 'United Arab Emirates' → https://en.wikipedia.org/wiki/United_Arab_Emirates",
+ "e90": "link '1997' → https://en.wikipedia.org/wiki/1997",
+ "e91": "link 'U2' → https://en.wikipedia.org/wiki/U2",
+ "e92": "link 'performed' → https://en.wikipedia.org/wiki/U2_concert_in_Sarajevo",
+ "e93": "link 'Sarajevo' → https://en.wikipedia.org/wiki/Sarajevo",
+ "e94": "link 'Umbellaoolithus' → https://en.wikipedia.org/wiki/Umbellaoolithus",
+ "e95": "link 'Bosnian War' → https://en.wikipedia.org/wiki/Bosnian_War",
+ "e96": "link 'Makan Nasiri' → https://en.wikipedia.org/wiki/Makan_Nasiri",
+ "e97": "link '2016' → https://en.wikipedia.org/wiki/2016",
+ "e98": "link '2026 Minab school attack' → https://en.wikipedia.org/wiki/2026_Minab_school_attack",
+ "e99": "link 'rape in Germany' → https://en.wikipedia.org/wiki/Rape_in_Germany",
+ "e100": "link 'I Became the Main Role of a BL Drama' → https://en.wikipedia.org/wiki/I_Became_the_Main_Role_of_a_BL_Drama",
+ "none": "No listed element should be clicked."
+ }
+ },
+ "type_target": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is typing, which text field in `page.elements` should receive a value from `inputs` to make progress toward `goal`?",
+ "rules": [
+ "Prefer empty fields over fields that already contain the right value.",
+ "Choose `none` if no listed field should be filled now."
+ ]
+ },
+ "criteria": {
+ "e1": "text field 'Search Wikipedia' (type search, placeholder \"Search Wikipedia\", empty)",
+ "none": "No listed text field should be filled now."
+ }
+ },
+ "type_value": {
+ "type": "choice",
+ "instructions": {
+ "question": "If the next action is typing, which entry of `inputs` belongs in the text field that should be filled next?",
+ "rules": [
+ "Match the field's label, placeholder and type to the meaning of the input key.",
+ "Choose `none` if no provided input belongs there."
+ ]
+ },
+ "criteria": {
+ "query": "inputs.query = \"bacteria\"",
+ "none": "No provided input belongs in the field."
+ }
+ },
+ "submit_after_type": {
+ "type": "noul",
+ "instructions": {
+ "question": "After typing the value into the chosen text field, should the Enter key be pressed immediately to submit (as with a search box or a single-field form)?",
+ "rules": [
+ "Answer no when other fields still need values or when a separate submit button must be clicked after all fields are filled."
+ ]
+ },
+ "criteria": {
+ "true": "Pressing Enter right after typing is the natural way to submit this field (search boxes, single-field forms, the last field of a form).",
+ "false": "More fields must be filled first, or a separate button should be clicked, or Enter would do nothing useful."
+ }
+ }
+ },
+ "meta": {
+ "allowedActions": [
+ "click",
+ "type",
+ "scroll_down",
+ "wait",
+ "stop"
+ ],
+ "clickableIds": [
+ "e2",
+ "e3",
+ "e4",
+ "e5",
+ "e6",
+ "e7",
+ "e8",
+ "e9",
+ "e10",
+ "e11",
+ "e12",
+ "e13",
+ "e14",
+ "e15",
+ "e16",
+ "e17",
+ "e18",
+ "e19",
+ "e20",
+ "e21",
+ "e22",
+ "e23",
+ "e24",
+ "e25",
+ "e26",
+ "e27",
+ "e28",
+ "e29",
+ "e30",
+ "e31",
+ "e32",
+ "e33",
+ "e34",
+ "e35",
+ "e36",
+ "e37",
+ "e38",
+ "e39",
+ "e40",
+ "e41",
+ "e42",
+ "e43",
+ "e44",
+ "e45",
+ "e46",
+ "e47",
+ "e48",
+ "e49",
+ "e50",
+ "e51",
+ "e52",
+ "e53",
+ "e54",
+ "e55",
+ "e56",
+ "e57",
+ "e58",
+ "e59",
+ "e60",
+ "e61",
+ "e62",
+ "e63",
+ "e64",
+ "e65",
+ "e66",
+ "e67",
+ "e68",
+ "e69",
+ "e70",
+ "e71",
+ "e72",
+ "e73",
+ "e74",
+ "e75",
+ "e76",
+ "e77",
+ "e78",
+ "e79",
+ "e80",
+ "e81",
+ "e82",
+ "e83",
+ "e84",
+ "e85",
+ "e86",
+ "e87",
+ "e88",
+ "e89",
+ "e90",
+ "e91",
+ "e92",
+ "e93",
+ "e94",
+ "e95",
+ "e96",
+ "e97",
+ "e98",
+ "e99",
+ "e100"
+ ],
+ "editableIds": [
+ "e1"
+ ],
+ "selectIds": [],
+ "inputKeys": [
+ "query"
+ ],
+ "urlInputKeys": [],
+ "questionCount": 7,
+ "candidateCount": 100
+ },
+ "estimatedInputTokens": 8256,
+ "estimatedCostUsd": 0.00034675200000000003
+}
diff --git a/experiments/gguf-provider/lab/check-normalize.mjs b/experiments/gguf-provider/lab/check-normalize.mjs
new file mode 100755
index 0000000..0a106c3
--- /dev/null
+++ b/experiments/gguf-provider/lab/check-normalize.mjs
@@ -0,0 +1,72 @@
+#!/usr/bin/env node
+// EXPERIMENTAL — not part of the jev-browser skill.
+// PROOF that a response produced by the local GGUF provider survives the skill's own
+// contract check (`validateQuestions` + `normalizeAnswers` from lib/typesafe.mjs)
+// UNCHANGED — no adapting, no re-shaping, no shim.
+//
+// node experiments/gguf-provider/lab/check-normalize.mjs [--fixture ...] [--url ...]
+import { PROGRESS_LEVELS } from "../../../skills/jev-browser/lib/questions.mjs";
+import { validateQuestions, normalizeAnswers } from "../../../skills/jev-browser/lib/typesafe.mjs";
+import { fileURLToPath } from "node:url";
+import { GgufProvider } from "../lib/provider.mjs";
+import { loadRequest } from "../cli.mjs";
+
+const arg = (name, fallback) => (process.argv.includes(name) ? process.argv[process.argv.indexOf(name) + 1] : fallback);
+const fixture = arg("--fixture", fileURLToPath(new URL("../fixtures/raw_duckduckgo_com_html__q_apple_stock_price.txt", import.meta.url)));
+
+// A real captured step, plus the one question type the first step never asks:
+// `progress` (score with PROGRESS_LEVELS) only appears once previous+lastAction exist.
+const captured = loadRequest({ fixture });
+const questions = {
+ goal_done: captured.questions.goal_done,
+ blocker: captured.questions.blocker,
+ click_target: captured.questions.click_target,
+ progress: {
+ type: "score",
+ instructions: { question: "Compared with `previous_page`, how did `last_action` change progress toward `goal`, judging by `page`?" },
+ criteria: [...PROGRESS_LEVELS],
+ },
+};
+const request = { state: captured.state, questions };
+
+validateQuestions(questions); // throws if the question set itself violates the contract
+console.log(`question set validated: ${Object.entries(questions).map(([id, q]) => `${id}[${q.type}]`).join(", ")}`);
+
+const provider = new GgufProvider({ url: arg("--url", "http://127.0.0.1:8090"), model: arg("--model", "gguf-local") });
+const response = await provider.systemOne(request);
+
+console.log("\n--- raw provider response (answers only) ---");
+console.log(JSON.stringify(response.answers, null, 2).slice(0, 3000));
+
+const normalized = normalizeAnswers(response.answers, questions);
+console.log("\n--- normalizeAnswers(...) output ---");
+console.log(JSON.stringify(normalized, null, 2).slice(0, 3000));
+
+// Invariants the controller relies on.
+const checks = [];
+for (const [id, q] of Object.entries(questions)) {
+ const n = normalized[id];
+ checks.push([`${id}: present`, !!n]);
+ checks.push([`${id}: type === ${q.type}`, n?.type === q.type]);
+ if (q.type === "noul") {
+ checks.push([`${id}: 0<=noul<=1`, n.noul >= 0 && n.noul <= 1]);
+ checks.push([`${id}: top is true|false`, n.top === "true" || n.top === "false"]);
+ checks.push([`${id}: probabilities sum 1`, Math.abs(n.probabilities.true + n.probabilities.false - 1) < 1e-9]);
+ } else {
+ const expected = q.type === "choice" ? Object.keys(q.criteria) : q.criteria.map((_, i) => String(i));
+ checks.push([`${id}: has every expected key`, expected.every((k) => k in n.probabilities)]);
+ const sum = Object.values(n.probabilities).reduce((a, b) => a + b, 0);
+ checks.push([`${id}: probabilities sum ~1 (${sum.toFixed(6)})`, Math.abs(sum - 1) < 1e-6]);
+ checks.push([`${id}: ranked non-empty + sorted`, n.ranked.length > 0 && n.ranked.every((r, i, a) => i === 0 || a[i - 1][1] >= r[1])]);
+ checks.push([`${id}: top === ranked[0][0]`, n.top === n.ranked[0][0]]);
+ }
+ if (q.type === "choice") checks.push([`${id}: choice is an option key`, Object.keys(q.criteria).includes(n.choice)]);
+ if (q.type === "score") {
+ checks.push([`${id}: score in [0, ${q.criteria.length - 1}]`, n.score >= 0 && n.score <= q.criteria.length - 1]);
+ checks.push([`${id}: legend equals criteria`, JSON.stringify(n.legend) === JSON.stringify(q.criteria)]);
+ }
+}
+const failed = checks.filter(([, ok]) => !ok);
+for (const [label, ok] of checks) console.log(`${ok ? "PASS" : "FAIL"} ${label}`);
+console.log(`\n${failed.length === 0 ? "ALL PASS" : `${failed.length} FAILED`} (${checks.length} checks)`);
+process.exit(failed.length === 0 ? 0 : 1);
diff --git a/experiments/gguf-provider/lab/fetch.mjs b/experiments/gguf-provider/lab/fetch.mjs
new file mode 100755
index 0000000..bf51b0c
--- /dev/null
+++ b/experiments/gguf-provider/lab/fetch.mjs
@@ -0,0 +1,170 @@
+#!/usr/bin/env node
+// Supervised, resumable, checksum-verified GGUF fetcher for the 4B candidates.
+//
+// Transfer engine is `curl`, not node fetch: measured on this link, undici holds
+// ~0.35 MB/s where curl holds ~0.72-0.93 MB/s (same window, same URL, shared
+// link) -- and curl is what the throughput numbers in results/ were measured
+// with, so ETAs stay comparable. curl also owns byte-level resume via -C -.
+//
+// The supervisor adds what plain `hf download`/curl alone do not give:
+// (a) the brief's abort rule enforced mechanically -- stop for good if a
+// 10-minute rolling window sits under 0.3 MB/s (no retry loop),
+// (b) stall detection (no bytes for 3 min) with bounded reconnects,
+// (c) mandatory size+sha256 verification before the file may reach
+// llama-server. A truncated GGUF must never land in the model dir.
+//
+// It resumes the partial that `hf download` already left in
+// /.cache/huggingface/download/*.incomplete (a contiguous byte prefix) by
+// matching the upstream LFS sha256 embedded in the blob filename.
+//
+// usage:
+// node fetch.mjs --label --repo --file [--dest ] [--log ]
+//
+// exit codes: 0 ok+verified · 3 ABORT (sustained <0.3 MB/s) · 4 verify failed · 5 exhausted retries
+// stdout: one JSON verdict object. progress JSON-lines go to --log (and stdout).
+import { statSync, existsSync, readdirSync, renameSync, rmSync, mkdirSync, appendFileSync, createReadStream } from 'node:fs'
+import { createHash } from 'node:crypto'
+import { spawn } from 'node:child_process'
+import { join } from 'node:path'
+import { homedir } from 'node:os'
+
+const argv = process.argv.slice(2)
+const opt = {}
+for (let i = 0; i < argv.length; i += 2) opt[argv[i].replace(/^--/, '')] = argv[i + 1]
+
+const { repo, file } = opt
+const label = opt.label ?? file
+const dest = opt.dest ?? join(homedir(), '.jev-browser', 'models')
+const logPath = opt.log
+if (!repo || !file) {
+ console.error('usage: fetch.mjs --label --repo --file [--dest ] [--log ]')
+ process.exit(2)
+}
+
+const ABORT_MBPS = 0.3 // brief: sustained floor
+const ABORT_WINDOW_MS = 600_000 // ...over a 10-minute rolling window
+const STALL_MS = 180_000 // no bytes for 3 min -> reconnect
+const MAX_ATTEMPTS = 10
+const SAMPLE_MS = 5_000
+
+const log = (obj) => {
+ const line = JSON.stringify({ t: new Date().toISOString(), label, ...obj })
+ console.log(line)
+ if (logPath) appendFileSync(logPath, line + '\n')
+}
+const mb = (b) => Number((b / 1e6).toFixed(1))
+
+// ---- upstream metadata -------------------------------------------------------
+const meta = await (await fetch(`https://huggingface.co/api/models/${repo}?blobs=true`)).json()
+const sib = (meta.siblings ?? []).find((s) => s.rfilename === file)
+if (!sib?.lfs?.sha256) throw new Error(`no LFS metadata for ${repo}/${file}`)
+const size = sib.size
+const sha256 = sib.lfs.sha256
+log({ event: 'meta', repo, file, size, sha256 })
+
+// ---- locate the existing partial --------------------------------------------
+const blobDir = join(dest, '.cache', 'huggingface', 'download')
+mkdirSync(blobDir, { recursive: true })
+const cands = readdirSync(blobDir)
+ .filter((n) => n.endsWith('.incomplete') && n.includes(sha256))
+ .map((n) => join(blobDir, n))
+ .filter((p) => statSync(p).size > 0)
+ .sort((a, b) => statSync(b).size - statSync(a).size)
+const target = cands[0] ?? join(blobDir, `${file}.resume`)
+let offset = existsSync(target) ? statSync(target).size : 0
+log({ event: 'partial', path: target, bytes: offset, resumed: cands.length > 0 })
+
+const url = `https://huggingface.co/${repo}/resolve/main/${file}`
+
+// ---- transfer loop -----------------------------------------------------------
+let attempts = 0
+while (offset < size && attempts < MAX_ATTEMPTS) {
+ attempts++
+ const attemptStart = Date.now()
+ const startBytes = offset // measured against attempt start, not the trimmed rolling window
+ const history = [{ ms: attemptStart, bytes: offset }] // rolling window for the abort rule
+ let lastProgress = Date.now()
+ let lastSeen = offset
+ let stop = null
+ let stderr = ''
+
+ log({ event: 'attempt', attempt: attempts, offset, via: 'curl -C -' })
+ const child = spawn('curl', [
+ '-sSL', '-C', '-', '-o', target,
+ '--max-time', '2700',
+ '--speed-limit', '40000', '--speed-time', '90', // curl gives up on its own if a single socket dies
+ url,
+ ], { stdio: ['ignore', 'ignore', 'pipe'] })
+ child.stderr.on('data', (d) => { stderr += d })
+
+ const stopChild = (why) => {
+ if (stop) return
+ stop = why
+ log({ event: 'stopping-child', why })
+ child.kill('SIGKILL')
+ }
+
+ const tick = setInterval(() => {
+ const now = Date.now()
+ const cur = existsSync(target) ? statSync(target).size : lastSeen
+ if (cur > lastSeen) { lastSeen = cur; lastProgress = now }
+ history.push({ ms: now, bytes: cur })
+ while (history.length > 2 && history[0].ms < now - ABORT_WINDOW_MS - 60_000) history.shift()
+
+ if (now - lastProgress > STALL_MS) return stopChild('stall')
+ const win = history[0]
+ const elapsed = now - win.ms
+ if (elapsed >= ABORT_WINDOW_MS) {
+ const rate = (cur - win.bytes) / 1e6 / (elapsed / 1000)
+ if (rate < ABORT_MBPS) stopChild(`abort:${rate.toFixed(3)}`)
+ }
+ }, SAMPLE_MS)
+
+ const code = await new Promise((r) => child.on('close', r))
+ clearInterval(tick)
+ offset = existsSync(target) ? statSync(target).size : offset
+ const seconds = (Date.now() - attemptStart) / 1000
+ const attemptRate = (offset - startBytes) / 1e6 / seconds
+
+ if (stop?.startsWith('abort')) {
+ const rate = Number(stop.split(':')[1])
+ log({ event: 'abort', reason: 'sustained-below-floor', window_s: ABORT_WINDOW_MS / 1000, rolling_mb_s: rate, bytes: offset, remaining: size - offset })
+ console.log(JSON.stringify({ label, verdict: 'ABORT', bytes: offset, size, mb_s: rate, sha256_prefix: sha256.slice(0, 12) }))
+ process.exit(3)
+ }
+
+ log({ event: 'attempt-ended', attempt: attempts, exit: code, stopped: stop, offset, of: size, mb_s: Number(attemptRate.toFixed(3)), got_mb: mb(offset - startBytes), seconds: Math.round(seconds), stderr: stderr.trim().slice(-200) || undefined })
+
+ if (offset < size) {
+ // bounded reconnect: brief says do not retry in a loop, so attempts are capped and only
+ // made after a real interruption (stall / socket death), never on a slow-but-moving link
+ await new Promise((r) => setTimeout(r, stop === 'stall' ? 5_000 : 20_000))
+ }
+}
+
+if (offset !== size) {
+ log({ event: 'incomplete', bytes: offset, size, attempts })
+ console.log(JSON.stringify({ label, verdict: 'INCOMPLETE', bytes: offset, size, attempts }))
+ process.exit(5)
+}
+
+// ---- mandatory size + sha256 verification ------------------------------------
+const actualSize = statSync(target).size
+if (actualSize !== size) {
+ console.log(JSON.stringify({ label, verdict: 'VERIFY-FAIL', reason: 'size', bytes: actualSize, size, path: target }))
+ process.exit(4)
+}
+const hash = createHash('sha256')
+for await (const c of createReadStream(target)) hash.update(c)
+const digest = hash.digest('hex')
+if (digest !== sha256) {
+ log({ event: 'verify-fail', reason: 'sha256', digest, expected: sha256 })
+ console.log(JSON.stringify({ label, verdict: 'VERIFY-FAIL', reason: 'sha256', bytes: actualSize, sha256: digest, path: target }))
+ process.exit(4)
+}
+
+const finalPath = join(dest, file)
+renameSync(target, finalPath)
+rmSync(join(blobDir, `${file}.lock`), { force: true })
+log({ event: 'installed', path: finalPath, bytes: actualSize, sha256 })
+console.log(JSON.stringify({ label, verdict: 'OK', path: finalPath, bytes: actualSize, sha256, sha256_prefix: digest.slice(0, 12) }))
diff --git a/experiments/gguf-provider/lab/latency.mjs b/experiments/gguf-provider/lab/latency.mjs
new file mode 100755
index 0000000..cff1b59
--- /dev/null
+++ b/experiments/gguf-provider/lab/latency.mjs
@@ -0,0 +1,44 @@
+#!/usr/bin/env node
+// EXPERIMENTAL — not part of the jev-browser skill.
+// Latency of one realistic controller step: the captured DuckDuckGo search page
+// (5 questions, click_target has 55 options) through the local GGUF provider.
+//
+// Reports cold (first request: full prefill + alphabet verification) and warm runs,
+// plus per-question readout time and the prefix-cache reuse llama.cpp reports.
+//
+// node experiments/gguf-provider/lab/latency.mjs [--repeat 3] [--url http://127.0.0.1:8090]
+import { GgufProvider } from "../lib/provider.mjs";
+import { loadFixture } from "../eval/items.mjs";
+
+const arg = (name, fallback) => (process.argv.includes(name) ? process.argv[process.argv.indexOf(name) + 1] : fallback);
+const repeat = Number(arg("--repeat", 3));
+const fixture = loadFixture(arg("--fixture", "raw_duckduckgo_com_html__q_apple_stock_price.txt"));
+const provider = new GgufProvider({ url: arg("--url", "http://127.0.0.1:8090"), model: arg("--model", "gguf-local"), nProbs: Number(arg("--n-probs", 512)) });
+
+const questionList = Object.keys(fixture.questions);
+console.log(`# latency - ${fixture.state.page.url}`);
+console.log(`questions: ${questionList.map((id) => `${id}(${fixture.questions[id].type === "choice" ? Object.keys(fixture.questions[id].criteria).length : fixture.questions[id].type})`).join(" ")}`);
+console.log(`state bytes: ${JSON.stringify(fixture.state).length}`);
+
+const runs = [];
+for (let i = 0; i < repeat; i++) {
+ const t0 = performance.now();
+ const response = await provider.systemOne({ state: fixture.state, questions: fixture.questions });
+ const wall = performance.now() - t0;
+ const per = response.usage.per_question;
+ runs.push({ run: i, wall_ms: Math.round(wall), ms_alpha: response.usage.ms_alpha, ms_readout: response.usage.ms_readout, input_tokens: response.usage.input_tokens, per });
+ console.log(`\nrun ${i}${i === 0 ? " (cold: alphabet verification + full prefill)" : " (warm)"}: wall ${Math.round(wall)}ms readout ${response.usage.ms_readout}ms alphabet+render ${response.usage.ms_alpha + response.usage.ms_render}ms input_tokens ${response.usage.input_tokens}`);
+ for (const id of questionList) {
+ const p = per[id];
+ console.log(` ${id.padEnd(14)} ${String(p.ms).padStart(6)}ms new_tokens=${String(p.prompt_tokens).padStart(5)} cached=${String(p.cached_tokens).padStart(5)} labels=${p.multi_token_labels.length ? `multi=${p.multi_token_labels}` : "all-single-token"}`);
+ }
+}
+
+const warm = runs.slice(1);
+if (warm.length) {
+ const mean = (xs) => Math.round(xs.reduce((a, b) => a + b, 0) / xs.length);
+ console.log(`\nwarm mean wall: ${mean(warm.map((r) => r.wall_ms))}ms over ${warm.length} runs (cold included above for comparison)`);
+ const tokens = runs[0].input_tokens;
+ console.log(`input tokens per step: ${tokens}; cold wall ${runs[0].wall_ms}ms -> ${Math.round(tokens / (runs[0].wall_ms / 1000))} tok/s end-to-end`);
+}
+console.log(`\nprovider totals: ${JSON.stringify(provider.server.stats)}`);
diff --git a/experiments/gguf-provider/lab/probe-ending.mjs b/experiments/gguf-provider/lab/probe-ending.mjs
new file mode 100644
index 0000000..86195c4
--- /dev/null
+++ b/experiments/gguf-provider/lab/probe-ending.mjs
@@ -0,0 +1,50 @@
+// EXPERIMENTAL — not part of the jev-browser skill.
+// Which prompt ending puts the option label at the readout position?
+// Prints the tail of each rendered prompt and the model's top tokens there.
+//
+// node experiments/gguf-provider/lab/probe-ending.mjs [--url http://127.0.0.1:8090]
+import { LlamaServer } from "../lib/readout.mjs";
+import { renderPrompts } from "../lib/render.mjs";
+
+const arg = (name, fallback) => (process.argv.includes(name) ? process.argv[process.argv.indexOf(name) + 1] : fallback);
+const server = new LlamaServer({ url: arg("--url", "http://127.0.0.1:8090"), nProbs: 20 });
+
+const state = {
+ goal: "find today's price of AAPL",
+ inputs: "none provided",
+ page: {
+ url: "https://example.com/",
+ title: "Example Domain",
+ headings: ["# Example Domain"],
+ dialog: null,
+ scroll_position: "page fits in the viewport",
+ visible_text: "Example Domain This domain is for use in documentation examples without needing permission.",
+ elements: [{ id: "e1", description: "link 'Learn more' -> https://iana.org/domains/example", in_viewport: true }],
+ omitted_elements: 0,
+ },
+ previous_page: null,
+ last_action: null,
+ history: { steps_taken: 0, recent_urls: [] },
+};
+
+const questions = {
+ goal_done: {
+ type: "noul",
+ instructions: {
+ question: "Is `goal` already fully accomplished according to what `page` shows right now?",
+ rules: ["Judge only from `page`.", "A page that merely offers a way to accomplish `goal` does not count."],
+ },
+ criteria: { true: "`page` shows the end result that `goal` asks for.", false: "At least one more action is needed." },
+ },
+};
+
+const labels = ["A", "B", "C", "D", "E", "F", "G", "H"];
+for (const ending of ["answer", "answer-space", "chat"]) {
+ const { prompts } = await renderPrompts({ server, state, questions, labels, ending });
+ const dist = await server.firstTokenDistribution(prompts.goal_done);
+ console.log(`\n=== ending: ${ending} ===`);
+ console.log(`prompt tail: ${JSON.stringify(prompts.goal_done.slice(-120))}`);
+ console.log(`prompt tokens: ${dist.usage.prompt_tokens}`);
+ console.log(`top tokens at readout position:`);
+ for (const c of dist.candidates.slice(0, 12)) console.log(` ${JSON.stringify(c.token).padEnd(16)} id=${String(c.id).padEnd(7)} p=${Math.exp(c.logprob).toFixed(4)}`);
+}
diff --git a/experiments/gguf-provider/lab/probe-noul-bias.mjs b/experiments/gguf-provider/lab/probe-noul-bias.mjs
new file mode 100755
index 0000000..426fae5
--- /dev/null
+++ b/experiments/gguf-provider/lab/probe-noul-bias.mjs
@@ -0,0 +1,87 @@
+#!/usr/bin/env node
+// EXPERIMENTAL — not part of the jev-browser skill.
+// Is the noul readout reading the state, or just picking label A?
+//
+// Each item is run under several prompt variants. If a variant answers the same label
+// whatever the item says — and in particular if swapping which option text sits under
+// label A does not move the answer — that variant is measuring a label prior, not
+// comprehension.
+//
+// node experiments/gguf-provider/lab/probe-noul-bias.mjs
+import { LlamaServer, readoutLabels } from "../lib/readout.mjs";
+import { renderPrompts, labelTokenIds, optionsFor } from "../lib/render.mjs";
+import { NOUL_ITEMS, loadFixture } from "../eval/items.mjs";
+
+const arg = (name, fallback) => (process.argv.includes(name) ? process.argv[process.argv.indexOf(name) + 1] : fallback);
+const server = new LlamaServer({ url: arg("--url", "http://127.0.0.1:8090"), nProbs: 512 });
+const labels = ["A", "B"];
+const tokenIds = await labelTokenIds(server, labels, { surface: "spaced" });
+
+const POS = "The passage states this.";
+const NEG = "The passage does not state this.";
+
+const STRICT_SYSTEM =
+ "You are an expert classification model. You read a state carefully and answer one question about it. " +
+ "You never answer by position or habit: you compare the option texts against the state and choose the option whose text is actually true. " +
+ "You always answer with the label letter of exactly one option, and nothing else.";
+
+const FEW_SHOT = [
+ "Worked example (different state, different question, different answer):",
+ 'State: {"passage": "Cats are mammals."}',
+ "Question: Are cats reptiles?",
+ "The passage speaks of mammals and does not speak of reptiles, so the correct option is the one saying the state does not say this.",
+ "Correct choice: the option whose text is 'The passage does not state this.'",
+].join("\n");
+
+// A real browser state, with two noul questions whose answers are known by inspection:
+// the DuckDuckGo results page shows no price, and it does have a search field.
+const ddg = loadFixture("raw_duckduckgo_com_html__q_apple_stock_price.txt");
+const BROWSER_NOUL = [
+ { id: "ddg-shows-price?", state: ddg.state, question: "Does `page` show the price of AAPL?", expect: false, why: "visible_text of the captured state contains no price at all." },
+ { id: "ddg-has-textbox?", state: ddg.state, question: "Does `page` contain a text field?", expect: true, why: "e3 is the search field 'q'." },
+];
+
+const variants = [
+ { name: "v1-baseline", swap: false, system: undefined, fewShot: null },
+ { name: "v2-Atext-swapped", swap: true, system: undefined, fewShot: null },
+ { name: "v3-strict-system", swap: false, system: STRICT_SYSTEM, fewShot: null },
+ { name: "v4-strict+fewshot", swap: false, system: STRICT_SYSTEM, fewShot: FEW_SHOT },
+ { name: "v5-fewshot-only", swap: false, system: undefined, fewShot: FEW_SHOT },
+];
+
+const summary = [];
+for (const variant of variants) {
+ const rows = [];
+ for (const item of [...NOUL_ITEMS, ...BROWSER_NOUL]) {
+ const state = item.passage !== undefined ? { passage: item.passage } : item.state;
+ const question = {
+ type: "noul",
+ instructions: { question: item.question, rules: ["Answer only from the state."] },
+ criteria: variant.swap ? { true: NEG, false: POS } : { true: POS, false: NEG },
+ };
+ const { prompts } = await renderPrompts({ server, state, questions: { answer: question }, labels, ending: "answer", system: variant.system, fewShot: variant.fewShot });
+ const dist = await server.firstTokenDistribution(prompts.answer);
+ const read = readoutLabels(dist.candidates, labels, tokenIds);
+ const options = optionsFor(question); // label order: options[0] is label A
+ const pickedIndex = read.probabilities.A >= read.probabilities.B ? 0 : 1;
+ const pickedText = options[pickedIndex].text;
+ const predicted = pickedText === POS; // does the model say "the state states this"?
+ rows.push({
+ id: item.id,
+ kind: item.passage !== undefined ? "passage" : "browser",
+ expect: item.expect,
+ pickedLabel: labels[pickedIndex],
+ pickedText: pickedText === POS ? "STATES" : "NOT-STATE",
+ predicted,
+ correct: predicted === item.expect,
+ pA: Number(read.probabilities.A.toFixed(4)),
+ ms: Math.round(dist.ms),
+ });
+ }
+ const correct = rows.filter((r) => r.correct).length;
+ const aPicks = rows.filter((r) => r.pickedLabel === "A").length;
+ summary.push({ variant: variant.name, correct, n: rows.length, labelA_picks: aPicks });
+ console.log(`\n=== ${variant.name}: ${correct}/${rows.length} correct, picked label A ${aPicks}/${rows.length} times ===`);
+ for (const r of rows) console.log(` ${r.correct ? "ok " : "MISS"} ${r.id.padEnd(18)} [${r.kind.padEnd(7)}] expect=${String(r.expect).padEnd(6)} picked=${r.pickedLabel}(${r.pickedText}) P(A)=${r.pA} ${r.ms}ms`);
+}
+console.log("\nsummary:", JSON.stringify(summary, null, 1));
diff --git a/experiments/gguf-provider/lab/ramp.mjs b/experiments/gguf-provider/lab/ramp.mjs
new file mode 100755
index 0000000..3cae3b3
--- /dev/null
+++ b/experiments/gguf-provider/lab/ramp.mjs
@@ -0,0 +1,83 @@
+#!/usr/bin/env node
+// Sampled transfer-rate ramp probe.
+//
+// Fetches a bounded byte range and records the instantaneous rate over each
+// sampling interval, so a uniformly slow link can be told apart from a fast one
+// that merely starts slow (TCP slow start / CDN burst throttling). A single
+// short window cannot distinguish the two; this can.
+//
+// usage: node ramp.mjs