From 683c7c701e756aa41655250424270861c6e68d6b Mon Sep 17 00:00:00 2001 From: "Mr.Dong" <1042542469@qq.com> Date: Fri, 23 Oct 2026 12:49:13 +0800 Subject: [PATCH 01/14] vela: add the 2.0 0.8B hybrid reference worker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Second member of the Vela 2.0 family: a pinned vela2-decoder executor (hybrid.py) with a 10-file gate (shard index and the side-loaded broad head hashed; the 2.02 GB shard by exact size), member-aware response finishing (span_heads with spans, keyed by span question ids), worker member detection from config.json model_type, and the per-member /v1/models entry. compare_reference.py serves either member; the hybrid oracle fixtures export under oracle-hybrid-. Evidence (author-run, x86 WSL2, CPU FP32, no fla — the runtime's CPU path never dispatches to it): nine-case parity vs the pinned upstream server exact-match (four 200s incl. key order, five agreed rejections incl. the 16,384-window 413); 0.3B nine-case regression; live worker smoke with span_heads and per-member thresholds; byte-identical Rust frontend forwarding; 133 CPU contract tests. --- README.md | 8 +- docs/supported-models.md | 10 +- mkdocs.yml | 2 +- recipe/README.md | 2 +- recipe/vela/compare_reference.py | 84 +++-- recipe/vela/reference.md | 144 ++++---- recipe/vela/test_compare_reference.py | 2 +- src/frontend/vela.py | 99 ++++-- src/models/vela/README.md | 122 ++++--- src/models/vela/engine.py | 11 +- src/models/vela/hybrid.py | 241 ++++++++++++++ src/models/vela/postprocess.py | 25 +- src/models/vela/protocol.py | 8 +- .../oracle-hybrid-example-request-cjk.json | 155 +++++++++ .../oracle-hybrid-example-request-score.json | 105 ++++++ ...-hybrid-example-request-set-threshold.json | 81 +++++ .../oracle-hybrid-example-request.json | 183 +++++++++++ tests/vela/test_hybrid.py | 310 ++++++++++++++++++ tests/vela/test_oracle_hybrid_fixtures.py | 64 ++++ tests/vela/test_worker_server.py | 48 +++ 20 files changed, 1528 insertions(+), 176 deletions(-) create mode 100644 src/models/vela/hybrid.py create mode 100644 tests/vela/fixtures/oracle-hybrid-example-request-cjk.json create mode 100644 tests/vela/fixtures/oracle-hybrid-example-request-score.json create mode 100644 tests/vela/fixtures/oracle-hybrid-example-request-set-threshold.json create mode 100644 tests/vela/fixtures/oracle-hybrid-example-request.json create mode 100644 tests/vela/test_hybrid.py create mode 100644 tests/vela/test_oracle_hybrid_fixtures.py diff --git a/README.md b/README.md index b2327ce0..88129980 100644 --- a/README.md +++ b/README.md @@ -164,9 +164,10 @@ Python screenshot worker, Valen-Preview-0923 has a Python reference worker for text and one-image state, CLM has a stub-encoder contract recipe, and OmniJev-4B v1.1 has its checkpoint export and CPU contract, with no worker yet. D3 (Decision 3.0) has a Python reference worker that runs the checkpoint's own -pinned runtime for text state, and Vela 2.0 0.3B has one that serves all five +pinned runtime for text state, and the Vela 2.0 members (0.3B and the 0.8B +hybrid) have one that serves all five SystemOne question kinds (`choice`/`noul`/`score` plus the `span`/`set` -extensions) on the checkpoint's own pinned runtime: +extensions) on each checkpoint's own pinned runtime: | Model | Status | | --- | --- | @@ -180,8 +181,9 @@ extensions) on the checkpoint's own pinned runtime: | CLM-v0.1-8B | [External worker with a CPU stub encoder](recipe/clm/README.md); contract checks only, real Qwen3-8B decisions unverified by this recipe | | LFM2.5-350M | [Transformers worker](recipe/lfm2/README.md); text state and independent choice questions | | OmniJev-4B v1.1 | [Checkpoint export and CPU contract](recipe/omnijev/README.md) only; the native worker is in progress ([#114](https://github.com/ThinkFlowLab/system1-omni/issues/114)) | -| D3 (Decision 3.0) | [Python reference worker](recipe/d3/reference.md) on the checkpoint's pinned runtime; `choice`/`noul`/`score` text state, media refused until stage 2; author-run on A100 (evidence in the integration PR) | +| D3 (Decision 3.0) | [Python reference worker](recipe/d3/reference.md) on the checkpoint's pinned runtime; `choice`/`noul`/`score` text state, media inputs refused; author-run on A100 (evidence in the integration PR) | | Vela 2.0 0.3B | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; all five kinds (`choice`/`noul`/`score`/`span`/`set`) for text state; CPU FP32 validated (author-run, evidence in the integration PR) | +| Vela 2.0 0.8B hybrid | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; same surface plus `span_heads`; CPU FP32 parity recorded in the integration PR | [Supported models and hardware](docs/supported-models.md) lists the devices and where each worker has been run. diff --git a/docs/supported-models.md b/docs/supported-models.md index 2f5967d9..52b31a0b 100644 --- a/docs/supported-models.md +++ b/docs/supported-models.md @@ -25,6 +25,7 @@ Models that are being added are also tracked in issues labeled [new model](https | OmniJev-4B v1.1 | None yet: [checkpoint export and CPU contract](../recipe/omnijev/README.md); the native worker is in progress ([#114](https://github.com/ThinkFlowLab/system1-omni/issues/114)) | Request contract, preparation, heads and finishing checked against the reference ([#120](https://github.com/ThinkFlowLab/system1-omni/pull/120)); no inference | Not yet | Not supported | Python 3.10 reference environment for the export and fixtures | | D3 (Decision 3.0) | [Python reference worker](../recipe/d3/reference.md) running the checkpoint's pinned runtime | Unverified | Author-run on NVIDIA A100 (sm_80): three-kind serving smoke with byte-identical frontend forwarding and reference parity (exact decisions, max delta 0.0, 348 == 348 tokens); evidence in the integration PR. Owner: @MrDongsls. | Unverified | Python 3.12, the [pinned runtime requirements](../recipe/d3/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/d3) (~52 GB) | | Vela 2.0 0.3B | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime | **CPU FP32 validated** (author-run, x86 WSL2, 24 cores): startup with all-kind warmup, the four example requests plus five synthetic rejections, and exact-match reference parity against the pinned upstream server on all nine (four 200s byte-equal incl. key order, agreed 422/413); byte-identical frontend forwarding; evidence in the integration PR. Owner: @MrDongsls. | Unverified (bf16-autocast is an untested deployment option) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.3B) (1.24 GB FP32 weights; ~4.4 GB with ONNX/assets) | +| Vela 2.0 0.8B hybrid | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime (same wire layer as 0.3B) | Same surface as 0.3B plus the `span_heads` field (router/broad dispatch); **CPU FP32 parity** (author-run; evidence in the integration PR) | Unverified (bf16-autocast is the evaluated upstream setting but untested here) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) (2.02 GB shard + 4.5 MB broad head; ~3 GB FP32 parameters) | - **Validated:** covered by the recipe on `main` or by the checks in the linked merged pull request. - **Author-run:** recorded by the recipe author on the stated hardware and not independently reproduced; the row names its owner. @@ -34,10 +35,11 @@ Models that are being added are also tracked in issues labeled [new model](https The Cua-S1 workers answer `choice` questions only. LAYA's English worker, Open-Jev and CLM support `choice`, `score`, and `noul` text questions. D3's reference worker serves the same three kinds for text state; its media -inputs stay refused for now and will be integrated soon. -Vela 2.0 0.3B's reference worker serves all five kinds (`choice`, `noul`, -`score`, plus the `span`/`set` extensions with their Noul views) for text -state on CPU FP32; the hybrid members (0.8B/4B/9B) are separate slices. +inputs stay refused. +Vela 2.0's reference workers (0.3B and the 0.8B hybrid) serve all five +kinds (`choice`, `noul`, `score`, plus the `span`/`set` extensions with +their Noul views, and `span_heads` on the hybrid) for text state on CPU +FP32; the larger hybrid members (4B/9B) are separate slices. CLM has a row per path: the merged `clm-serve` recipe exercises those answer shapes with stub embeddings and says nothing about decision quality, while the native engine's CUDA row is the path through a real Qwen3-8B encoder. Its engine-only figure comes from the same comparison run diff --git a/mkdocs.yml b/mkdocs.yml index 7e912aeb..8f2d39fe 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -76,5 +76,5 @@ nav: - CLM stub-encoder contract: recipe/clm/README.md - LFM2.5-350M choice worker: recipe/lfm2/README.md - D3 reference worker: recipe/d3/reference.md - - Vela 2.0 0.3B reference worker: recipe/vela/reference.md + - Vela 2.0 reference workers: recipe/vela/reference.md - Contributing: CONTRIBUTING.md diff --git a/recipe/README.md b/recipe/README.md index 3950951d..45594959 100644 --- a/recipe/README.md +++ b/recipe/README.md @@ -28,7 +28,7 @@ For a first real decision, follow the [complete CPU walkthrough](../docs/getting - [D3 reference worker](d3/reference.md): download the pinned vllm-sr/d3 package, verify its runtime manifest, and serve `choice`/`noul`/`score` text decisions through the Python worker and the Rust frontend (serving and parity validated on A100). -- [Vela 2.0 0.3B reference worker](vela/reference.md): download the pinned +- [Vela 2.0 reference workers (0.3B and the 0.8B hybrid)](vela/reference.md): download the pinned vllm-sr/Vela-2.0-0.3B package, pass its full-hash package gate, and serve all five SystemOne question kinds (`choice`/`noul`/`score` plus the `span`/`set` extensions) through the Python worker and the Rust frontend on CPU FP32. diff --git a/recipe/vela/compare_reference.py b/recipe/vela/compare_reference.py index fde4cd15..3588e06a 100644 --- a/recipe/vela/compare_reference.py +++ b/recipe/vela/compare_reference.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Compare the Vela 2.0 0.3B worker pipeline against the pinned upstream server. +"""Compare the Vela 2.0 worker pipeline against the pinned upstream server. Runs each fixture request through two paths that share one loaded pinned engine, so the comparison isolates this repository's admission and @@ -13,8 +13,8 @@ finishing). Both paths execute the same verified runtime, and the worker delegates -response construction to the same pinned code — so the criterion is the -charter's reference parity: exact match, including JSON key order, with +response construction to the same pinned code — so the criterion is +reference parity: exact match, including JSON key order, with rejections agreeing on status and body (``{"detail": [{"loc", "msg", "type"}]}``). ``--export`` additionally freezes the oracle fixture — request, SystemOne response and the predict()-level answers — for the @@ -24,11 +24,14 @@ The default fixture set is the recipe's four example requests plus five synthetic rejections: an invalid span question (whole-request -422), a schema that alone exceeds the 8,192-token window (413), and +422), a schema that alone exceeds the member's input window (413), and the three envelope 422s (missing field, extra field, wrong model name) that freeze the worker's preamble admission against the pinned -runtime's. CPU FP32 is the oracle setting; GPU bf16-autocast is a -deployment option, not this tool's default. +runtime's. The example files' ``model`` field is rewritten to the +served member's name, and the hybrid member's oracle fixtures export +under an ``oracle-hybrid-`` prefix, so both members share one tool. +CPU FP32 is the oracle setting; GPU bf16-autocast is a deployment +option, not this tool's default. """ from __future__ import annotations @@ -44,7 +47,7 @@ def parse_args(argv=None): parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) - parser.add_argument("--model", required=True, help="pinned Vela 2.0 0.3B package directory") + parser.add_argument("--model", required=True, help="pinned Vela 2.0 package directory") parser.add_argument("--device", default="cpu", help="torch device (default: the CPU FP32 oracle)") parser.add_argument( "--fixture", @@ -62,8 +65,8 @@ def parse_args(argv=None): return parser.parse_args(argv) -def over_limit_body(): - """A schema that alone cannot fit the 8,192-token window. +def over_limit_body(model=MODEL_NAME): + """A schema that alone cannot fit the member's input window. 255 choice options with ~300-character descriptions: far past ``max_length`` before any state is rendered, which is exactly the @@ -79,7 +82,7 @@ def over_limit_body(): for index in range(255) } return { - "model": MODEL_NAME, + "model": model, "state": "short", "questions": { "big": {"type": "choice", "instructions": "Pick one.", "criteria": criteria} @@ -87,11 +90,11 @@ def over_limit_body(): } -def invalid_span_body(): +def invalid_span_body(model=MODEL_NAME): """A span question whose criteria is a list, not a label mapping.""" return { - "model": MODEL_NAME, + "model": model, "state": "short", "questions": { "bad": { @@ -109,50 +112,63 @@ def missing_model_body(): return {"state": "short", "questions": {"q": {"type": "noul", "instructions": "any?"}}} -def extra_field_body(): +def extra_field_body(model=MODEL_NAME): """An envelope with a field the preamble does not permit ('extra_forbidden').""" return { - "model": MODEL_NAME, + "model": model, "state": "short", "questions": {"q": {"type": "noul", "instructions": "any?"}}, "images": [], } -def wrong_model_body(): +def wrong_model_body(served=MODEL_NAME): """Another member's name on this runtime ('value_error.model' 422).""" + other = "vllm-sr/Vela-2.0-0.3B" if served.endswith("0.8B") else "vllm-sr/Vela-2.0-0.8B" return { - "model": "vllm-sr/Vela-2.0-0.8B", + "model": other, "state": "short", "questions": {"q": {"type": "noul", "instructions": "any?"}}, } -def default_cases(): +def default_cases(served=MODEL_NAME): return [ ("example-request", HERE / "example-request.json"), ("example-request-set-threshold", HERE / "example-request-set-threshold.json"), ("example-request-cjk", HERE / "example-request-cjk.json"), ("example-request-score", HERE / "example-request-score.json"), - ("invalid-span-422", invalid_span_body()), - ("over-limit-413", over_limit_body()), + ("invalid-span-422", invalid_span_body(served)), + ("over-limit-413", over_limit_body(served)), ("missing-model-422", missing_model_body()), - ("extra-field-422", extra_field_body()), - ("wrong-model-422", wrong_model_body()), + ("extra-field-422", extra_field_body(served)), + ("wrong-model-422", wrong_model_body(served)), ] -def load_cases(paths): +def load_cases(paths, served=MODEL_NAME): if not paths: - cases = default_cases() + cases = default_cases(served) else: cases = [(Path(path).name, path) for path in paths] - return [ - (name, body if isinstance(body, dict) else json.loads(Path(body).read_text(encoding="utf-8"))) - for name, body in cases - ] + loaded = [] + for name, source in cases: + body = source if isinstance(source, dict) else json.loads(Path(source).read_text(encoding="utf-8")) + # The example files are member-agnostic apart from their model field; + # serving the other member rewrites it so the case exercises the 200 + # path it was written for, on both compared paths alike. Synthetic + # bodies (including the deliberate wrong-model one) are never touched. + if ( + not isinstance(source, dict) + and isinstance(body, dict) + and body.get("model") != served + and body.get("model") in (MODEL_NAME, "vllm-sr/Vela-2.0-0.8B") + ): + body = {**body, "model": served} + loaded.append((name, body)) + return loaded def reference_response(client, body): @@ -245,10 +261,10 @@ def main(argv=None): sys.path.insert(0, str(HERE.parents[1] / "src")) from fastapi.testclient import TestClient - from frontend.vela import decide - from models.vela.engine import Vela2Executor + from frontend.vela import decide, detect_member - executor = Vela2Executor(args.model, device=args.device) + executor_class, _default_name = detect_member(args.model) + executor = executor_class(args.model, device=args.device) # Both runtime imports stay inside a no-bytecode window: the package # gate refuses existing caches, and vela2_serve is a fresh import that # would otherwise write the __pycache__ the next worker start rejects. @@ -262,11 +278,15 @@ def main(argv=None): app = vela2_serve.create_app(executor.engine, model_name=executor.model_name, api_key=None) client = TestClient(app) + served = executor.model_name + # The hybrid member's oracle fixtures get their own prefix so both + # members' frozen baselines can live in one directory. + prefix = "oracle-hybrid-" if getattr(executor, "is_hybrid", False) else "oracle-" exported = 0 failed = 0 try: - for name, body in load_cases(args.fixture): + for name, body in load_cases(args.fixture, served): raw = json.dumps(body).encode("utf-8") worker = worker_response(raw, executor, decide) reference = reference_response(client, body) @@ -278,7 +298,7 @@ def main(argv=None): req, _plan = vela2_inference.system_one_to_predict(body["state"], body["questions"]) target = Path(args.export) if target.is_dir(): - target = target / f"oracle-{name}.json" + target = target / f"{prefix}{name}.json" export_oracle(name, body, worker[1], executor.engine.predict(req), target) exported += 1 print() diff --git a/recipe/vela/reference.md b/recipe/vela/reference.md index d65a0cda..b6f717fd 100644 --- a/recipe/vela/reference.md +++ b/recipe/vela/reference.md @@ -1,9 +1,13 @@ -# Vela 2.0 0.3B reference worker +# Vela 2.0 reference workers (0.3B, 0.8B hybrid) -This recipe serves Vela 2.0 0.3B through the Python reference worker and -the existing Rust frontend. The model-side implementation is under -[`src/models/vela/`](../../src/models/vela/), and the worker is -[`src/frontend/vela.py`](../../src/frontend/vela.py). +This recipe serves the Vela 2.0 members through the Python reference +worker and the existing Rust frontend: the 0.3B encoder and the 0.8B +hybrid, one pinned member per worker process. The model-side +implementation is under +[`src/models/vela/`](../../src/models/vela/) (0.3B in `engine.py`, the +0.8B hybrid in `hybrid.py`), and the worker is +[`src/frontend/vela.py`](../../src/frontend/vela.py), which picks the +executor from the package's declared `model_type`. Run the commands from the repository root with Python 3.12. The default and evidence-backed setting is CPU FP32 — the reference oracle; a CUDA @@ -14,33 +18,34 @@ description, not here. ## Scope -The slice is: +Scope: -- package: [`vllm-sr/Vela-2.0-0.3B`](https://huggingface.co/vllm-sr/Vela-2.0-0.3B) - at the pinned revision below; -- the Python reference worker behind the Rust frontend, executing the +- packages: [`vllm-sr/Vela-2.0-0.3B`](https://huggingface.co/vllm-sr/Vela-2.0-0.3B) + and [`vllm-sr/Vela-2.0-0.8B`](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) + at the pinned revisions below; +- the Python reference worker behind the Rust frontend, executing each checkpoint's own pinned runtime (`vela2_inference.py` and siblings) after a full-hash package gate; - text/JSON state and all five typed kinds — `choice`, `noul`, `score`, `span`, `set` — in one request, with the span/set response extensions - (`spans`/`sets`/`thresholds` and their Noul views) served - forward-untouched; -- FP32 parameters, one bidirectional forward per assembled sequence, + (`spans`/`sets`/`thresholds`, `span_heads` on the hybrid, and their + Noul views) served forward-untouched; +- FP32 parameters, one bidirectional forward per assembled sequence + (0.3B) or one parts pass with per-question continuation (hybrid), calibrated readouts; zero generated tokens. -Out of scope for this slice: the hybrid members (0.8B/4B/9B — their -reference workers are a separate slice), the ONNX backend, any native -Rust/CUDA executor (the frozen RFC's ModernBERT-profile route), and -`noul_calibration` (a hybrid-only feature that does not exist on 0.3B). +Out of scope: the larger hybrid members (4B/9B), the ONNX backend of +the 0.3B, any native Rust/CUDA executor, and `noul_calibration` (off +by default; documented as a reference-server feature only). ## Architecture and ownership ~~~text Rust frontend - -> Python worker + -> Python worker (executor chosen by config.json model_type) -> admit: JSON transport + upstream envelope preamble (protocol) - -> verify: config identity pin, full SHA-256 of the 7-file table, - exact weights size, then import it (engine) + -> verify: config identity pin, full SHA-256 of the pinned table, + exact weights size, then import it (engine / hybrid) -> execute: the checkpoint's own vela2_inference system_one_request -> finish: response-order/key-set checks + formula mirrors (postprocess) ~~~ @@ -53,28 +58,37 @@ The ownership boundary follows triples; deeper validation (state parts, question semantics, the 413) is the pinned runtime's, verbatim; - `preprocess.py` maps the runtime's `SystemOneError` to 422/413; -- `engine.py` owns the pinned runtime and the package gate; -- `postprocess.py` owns the pure formulas and response finishing; -- `frontend.vela` owns HTTP lifecycle, the single-flight 503 lock, the - `VELA2_API_KEY` 401 gate and warmup-before-readiness; +- `engine.py` owns the 0.3B pinned runtime and its package gate; + `hybrid.py` mirrors it for the 0.8B (a 10-file pin table including + the shard index and the side-loaded `broad_head.safetensors`); +- `postprocess.py` owns the pure formulas and response finishing, + member-aware for the hybrid's `span_heads` field; +- `frontend.vela` owns HTTP lifecycle, member detection, the + single-flight 503 lock, the `VELA2_API_KEY` 401 gate and + warmup-before-readiness; - The Rust frontend forwards `/v1/systemone` and `/health` unchanged. ## Pinned artifacts -| Artifact | Value | -| --- | --- | -| Package | [vllm-sr/Vela-2.0-0.3B](https://huggingface.co/vllm-sr/Vela-2.0-0.3B) | -| Pinned revision | `d6f03aa9baca4f9017fa8f8e9c2764d3bed3f409` | -| Package gate | config structural identity + a 7-file SHA-256 table pinned per revision in `engine.py`, full hash before import, no unlisted importables or `__pycache__` in the package root, exact 1,236,473,252-byte weights check | -| License | Apache-2.0; tokenizer material under Gemma Terms of Use | +| Artifact | 0.3B | 0.8B hybrid | +| --- | --- | --- | +| Package | [vllm-sr/Vela-2.0-0.3B](https://huggingface.co/vllm-sr/Vela-2.0-0.3B) | [vllm-sr/Vela-2.0-0.8B](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) | +| Pinned revision | `d6f03aa9baca4f9017fa8f8e9c2764d3bed3f409` | `326b01d81f61fff7fd4ae570e54b87a49119e490` | +| Package gate | config structural identity + a 7-file SHA-256 table in `engine.py` | config structural identity (incl. `model_name`) + a 10-file SHA-256 table in `hybrid.py`, cross-checked against the package's own SHA256SUMS | +| Weights check | exact 1,236,473,252 bytes | exact 2,022,189,488 bytes + hashed `broad_head.safetensors` | +| Served name | `vllm-sr/Vela-2.0-0.3B` | `vllm-sr/Vela-2.0-0.8B` (from `config.json`) | +| Input window | 8,192 tokens | 16,384 tokens | +| License | Apache-2.0; tokenizer material under Gemma Terms of Use | Apache-2.0; Qwen3.5-0.8B lineage notices in the package | -The gate's file table is checked in (not read from the package, which -ships no manifest), so a later snapshot — self-consistent or not — -cannot pass as the pinned revision. Re-check before changing the pin: +Each gate's file table is checked in (never read from the package), so +a later snapshot — self-consistent or not — cannot pass as the pinned +revision. Re-check before changing a pin: ~~~sh curl -sS "https://huggingface.co/api/models/vllm-sr/Vela-2.0-0.3B/revision/d6f03aa9baca4f9017fa8f8e9c2764d3bed3f409" | jq -r '.sha' sha256sum weights/vela-2.0-0.3b/{vela2_inference.py,modeling_vela2.py,configuration_vela2.py,vela2_serve.py,config.json,calibration.json,tokenizer.json} +curl -sS "https://huggingface.co/api/models/vllm-sr/Vela-2.0-0.8B/revision/326b01d81f61fff7fd4ae570e54b87a49119e490" | jq -r '.sha' +sha256sum weights/vela-2.0-0.8b/{vela2_inference.py,modeling_vela2.py,configuration_vela2.py,vela2_serve.py,config.json,calibration.json,tokenizer.json,tokenizer_config.json,model.safetensors.index.json,broad_head.safetensors} ~~~ ## Install and prepare the artifacts @@ -88,15 +102,21 @@ python3.12 -m venv .venv ~~~sh export VELA_PKG="$PWD/weights/vela-2.0-0.3b" export VELA_REV=d6f03aa9baca4f9017fa8f8e9c2764d3bed3f409 +export VELA_HYBRID_PKG="$PWD/weights/vela-2.0-0.8b" +export VELA_HYBRID_REV=326b01d81f61fff7fd4ae570e54b87a49119e490 mkdir -p weights .venv/bin/hf download vllm-sr/Vela-2.0-0.3B --revision "$VELA_REV" --local-dir "$VELA_PKG" +.venv/bin/hf download vllm-sr/Vela-2.0-0.8B --revision "$VELA_HYBRID_REV" --local-dir "$VELA_HYBRID_PKG" ~~~ -The full package is about 4.4 GB (the 1.24 GB FP32 safetensors, a 34 MB +The 0.3B package is about 4.4 GB (the 1.24 GB FP32 safetensors, a 34 MB tokenizer, the ONNX exports and doc assets); serving needs roughly 2 GB of RAM for the FP32 model plus working memory for the batch rows. -The worker refuses to start when the config is not the pinned member's, -when any of the 7 gated files fails its hash, when the package root +The 0.8B package is about 2.1 GB (a 2.02 GB shard plus the 4.5 MB +broad-head file); FP32 parameters take about 3 GB of RAM on CPU (about +3 GB of GPU memory on CUDA, where the backbone runs under bf16 +autocast). A worker refuses to start when the config is not its pinned +member's, when any gated file fails its hash, when the package root holds an importable entry the table does not name or an existing `__pycache__`, or when the weights file is not the pinned size — that gate runs before any package code is imported. @@ -105,12 +125,15 @@ gate runs before any package code is imported. ~~~sh PYTHONPATH=src .venv/bin/python -m frontend.vela \ - --model "$VELA_PKG" --device cpu --port 8000 + --model "$VELA_PKG" --device cpu --port 8000 # 0.3B +PYTHONPATH=src .venv/bin/python -m frontend.vela \ + --model "$VELA_HYBRID_PKG" --device cpu --port 8001 # 0.8B hybrid ~~~ -The worker verifies the package, loads the FP32 model, runs a real -warmup request covering every question kind, and only then binds the -port: +The worker detects the member from the package's `model_type`, verifies +the package, loads the model, runs a real warmup request covering every +question kind (the hybrid's warmup also drives both span heads), and +only then binds the port: ~~~sh curl -sS -i http://127.0.0.1:8000/health # {"status": "ok"} (upstream verbatim) @@ -198,12 +221,13 @@ the [model contract](../../src/models/vela/README.md). In short: transport errors follow the shared worker discipline; every invalid field rejects the whole request with the upstream 422 `{"detail": [{"loc", "msg", "type"}]}`; 413 `too_long` fires only when -questions plus schema alone exceed 8,192 tokens; and over-limit state -text is **truncated as the reference truncates it** (shrink part first, -floor 64 then 1, then protected parts; windowed re-coverage of cut -labelled parts) — a deliberate, loudly documented divergence from the -repository's no-silent-truncation convention, with the guardrail risk -recorded in the model contract. +questions plus schema alone exceed the member's input window (8,192 on +0.3B, 16,384 on the hybrid); and over-limit state text is **truncated +as the reference truncates it** (shrink part first, floor 64 then 1, +then protected parts; windowed re-coverage of cut labelled parts) — a +deliberate, loudly documented divergence from the repository's +no-silent-truncation convention, with the guardrail risk recorded in +the model contract. ## Repository-side validation @@ -228,26 +252,32 @@ invalid-span 422, an over-limit 413, and the missing-field / extra-field / wrong-model envelope 422s) — through two paths that share one loaded engine: the pinned `vela2_serve.py` app via FastAPI's test client, and the production -`frontend.vela.decide` pipeline. The criterion is the charter's -reference parity: **exact match** including JSON key order for 200s, +`frontend.vela.decide` pipeline. The criterion is reference parity: +**exact match** including JSON key order for 200s, and agreement on status and body for rejections (needs `pip install fastapi uvicorn httpx` on top of the requirements file). `--export tests/vela/fixtures/oracle-.json` freezes each passing 200 case — request, SystemOne response and predict()-level answers — as -the frozen comparison baseline for the frozen RFC's native encoder -slices, and writes it only after a passing comparison. +the frozen comparison baseline, and writes it only after a passing +comparison. ~~~sh PYTHONPATH=src .venv/bin/python recipe/vela/compare_reference.py \ --model "$VELA_PKG" --device cpu \ --export tests/vela/fixtures/ +PYTHONPATH=src .venv/bin/python recipe/vela/compare_reference.py \ + --model "$VELA_HYBRID_PKG" --device cpu \ + --export tests/vela/fixtures/ ~~~ Run it by hand and record the verbatim output, host, package revision and dependency versions in the pull request description. CPU FP32 is the oracle setting; keep flash-linear-attention out of the fixture path -(it does not exist on this encoder member anyway) and do not substitute -GPU bf16-autocast numbers for the baseline. +(it changes the hybrid's numbers and its parity against the fallback +path is not documented upstream) and do not substitute GPU +bf16-autocast numbers for the baseline. The tool rewrites the example +files' `model` field to the served member and exports the hybrid's +oracle fixtures under an `oracle-hybrid-` prefix. ## Troubleshooting and limits @@ -256,15 +286,15 @@ GPU bf16-autocast numbers for the baseline. `__pycache__` bytecode caches and wrong weights sizes at startup, before importing anything. - The 8 MiB body cap is slice-scoped (upstream sets no total-body - limit); a valid request bounded by the 8,192-token window is far - below it. -- `/health` and `/ready` are upstream's minimal bodies on this member, - not the richer shape of some other workers in this repository. + limit); a valid request bounded by either member's input window is + far below it. +- `/health` and `/ready` are upstream's minimal bodies on both + members, not the richer shape of some other workers in this + repository. - Long states are truncated (see Error behavior); if a consumer must never miss tail text, check `usage.input_tokens` against the expected budget or enforce limits upstream of the worker. - GPU bf16-autocast serving (`--device cuda`) is untested in this - slice's evidence; treat it as a deployment option to validate - separately. + evidence; treat it as a deployment option to validate separately. - GPU evidence for the supported-models table is recorded in the integration pull request, not in this recipe. diff --git a/recipe/vela/test_compare_reference.py b/recipe/vela/test_compare_reference.py index d97aaa45..f76fb69d 100644 --- a/recipe/vela/test_compare_reference.py +++ b/recipe/vela/test_compare_reference.py @@ -86,7 +86,7 @@ def check(name: str, condition: bool, detail: str = "") -> None: lines, ok = tool.compare_case("fixture", (200, response()), (422, rejection)) check("worker answering a rejected request fails", not ok, "\n".join(lines)) - # 3. The default case set carries the charter's fixture list shape. + # 3. The default case set carries the fixture list's shape. cases = tool.default_cases() names = [name for name, _ in cases] check( diff --git a/src/frontend/vela.py b/src/frontend/vela.py index c863a018..78f46631 100644 --- a/src/frontend/vela.py +++ b/src/frontend/vela.py @@ -1,10 +1,13 @@ -"""Python reference worker for Vela 2.0 0.3B. +"""Python reference worker for the Vela 2.0 members (0.3B, 0.8B hybrid). The Rust frontend remains the public transport layer. This worker owns only HTTP lifecycle and request orchestration; wire admission lives in models.vela.protocol, the pinned-runtime error mapping in -models.vela.preprocess, the pinned runtime and its package gate in -models.vela.engine, and response finishing in models.vela.postprocess. +models.vela.preprocess, the pinned runtimes and their package gates in +models.vela.engine (0.3B) and models.vela.hybrid (0.8B), and response +finishing in models.vela.postprocess. The executor is chosen by the +package's declared ``model_type``; one worker process serves one pinned +member. The error surface has two layers: transport errors follow the shared Python-worker discipline, and every request rejection the pinned runtime @@ -13,7 +16,8 @@ (or 413 ``too_long``), passed through verbatim. There are no per-question errors. Over-limit state text is truncated exactly as the pinned reference truncates it (see the model contract); only questions plus -schema that cannot fit the 8,192-token window are refused. +schema that cannot fit the member's input window (8,192 or 16,384 +tokens) are refused. """ from __future__ import annotations @@ -26,17 +30,21 @@ import socket import threading from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +from pathlib import Path from typing import Any from models.vela.engine import Vela2Executor +from models.vela.hybrid import EXPECTED_MODEL_NAME as HYBRID_MODEL_NAME, Vela2HybridExecutor from models.vela.postprocess import finish_response from models.vela.preprocess import map_runtime_error, to_request_error from models.vela.protocol import MODEL_NAME, MAX_BODY, RequestError, parse_body, admit_request LOG = logging.getLogger(__name__) -# Upstream vela2_serve.py /v1/models entry, kept verbatim so clients see -# the reference server's description and release date. +# Upstream vela2_serve.py /v1/models entry for the 0.3B member, kept +# verbatim so clients see the reference server's description and release +# date; the hybrid members source their entry from config.json, exactly +# as their vela2_serve.py does. MODELS_ENTRY = { "name": None, # the served model name, filled per request "release_date": "2026-09-29", @@ -48,7 +56,57 @@ UNAUTHORIZED_BODY = {"detail": "Missing or invalid API key"} -def decide(raw: bytes, executor: Vela2Executor) -> dict[str, Any]: +def detect_member(package: str | Path) -> tuple[type, str]: + """Pick the pinned executor for a package's declared member. + + Returns the executor class and the member's default served name; the + structural gate inside the executor is the real authority — this + only routes the right gate to the package. + """ + + config_path = Path(package) / "config.json" + if not config_path.is_file(): + raise ValueError(f"the package is missing config.json: {package}") + try: + config = json.loads(config_path.read_text(encoding="utf-8")) + except (OSError, ValueError) as exc: + raise ValueError(f"config.json in {package} is not readable JSON") from exc + if not isinstance(config, dict): + raise ValueError(f"config.json in {package} is not a JSON object") + model_type = config.get("model_type") + if model_type == "vela2-unified": + return Vela2Executor, MODEL_NAME + if model_type == "vela2-decoder": + return Vela2HybridExecutor, HYBRID_MODEL_NAME + raise ValueError( + f"config.json declares model_type {model_type!r}; this worker serves the " + "vela2-unified (0.3B) and vela2-decoder (0.8B) members of Vela 2.0" + ) + + +def models_entry(executor) -> dict[str, Any]: + """The /v1/models entry, verbatim per member's reference server.""" + + if getattr(executor, "is_hybrid", False): + # Upstream hybrid vela2_serve.py: name/description/release_date + # straight from config.json. + config = getattr(executor, "engine", None) + config = getattr(config, "config", None) if config is not None else None + config = config or {} + return { + "name": executor.model_name, + "release_date": config.get("release_date", ""), + "description": config.get( + "description", + "Vela 2.0: SystemOne Choice / Noul / Score with span and set extensions", + ), + } + entry = dict(MODELS_ENTRY) + entry["name"] = executor.model_name + return entry + + +def decide(raw: bytes, executor) -> dict[str, Any]: """Admit, execute, and finish one complete request.""" body = admit_request(parse_body(raw), executor.served) @@ -62,13 +120,13 @@ def decide(raw: bytes, executor: Vela2Executor) -> dict[str, Any]: # layer cannot foresee (state rendering, question semantics, the # window budget); its rejections are client errors, not failures. raise map_runtime_error(exc) from exc - return finish_response(questions, response) + return finish_response(questions, response, hybrid=getattr(executor, "is_hybrid", False)) class WorkerServer(ThreadingHTTPServer): daemon_threads = False - def __init__(self, address, executor: Vela2Executor, api_key: str | None = None): + def __init__(self, address, executor: Vela2Executor | Vela2HybridExecutor, api_key: str | None = None): self.executor = executor self.api_key = api_key self.inference_lock = threading.Lock() @@ -139,9 +197,7 @@ def do_GET(self): elif path == "/v1/models": if self._unauthorized(): return - entry = dict(MODELS_ENTRY) - entry["name"] = self.server.executor.model_name - self.send_json(200, {"models": [entry]}) + self.send_json(200, {"models": [models_entry(self.server.executor)]}) else: self.send_json(404, {"detail": "unknown route"}) @@ -190,12 +246,16 @@ def do_POST(self): def parse_args(argv=None): - parser = argparse.ArgumentParser(description="Python reference worker for Vela 2.0 0.3B") - parser.add_argument("--model", required=True, help="pinned Vela 2.0 0.3B package directory") - parser.add_argument("--device", default="cpu", help="torch device (reference contract: cpu)") + parser = argparse.ArgumentParser(description="Python reference worker for Vela 2.0 members") + parser.add_argument("--model", required=True, + help="pinned Vela 2.0 package directory (0.3B or the 0.8B hybrid)") + parser.add_argument("--device", default="cpu", + help="torch device (reference contract: cpu; cuda runs the hybrid " + "backbone under bf16 autocast with FP32 heads)") parser.add_argument("--batch-size", type=int, default=None) - parser.add_argument("--name", default=os.environ.get("VELA2_MODEL_NAME", MODEL_NAME), - help="model name accepted in the request's model field") + parser.add_argument("--name", default=os.environ.get("VELA2_MODEL_NAME"), + help="model name accepted in the request's model field " + "(default: the pinned member's served name)") parser.add_argument("--host", default="127.0.0.1") parser.add_argument("--port", type=int, default=8000) return parser.parse_args(argv) @@ -204,10 +264,11 @@ def parse_args(argv=None): def main(argv=None): args = parse_args(argv) logging.basicConfig(level=logging.INFO) - executor = Vela2Executor( + executor_class, default_name = detect_member(args.model) + executor = executor_class( args.model, device=args.device, - model_name=args.name, + model_name=args.name or default_name, batch_size=args.batch_size, ) server = None diff --git a/src/models/vela/README.md b/src/models/vela/README.md index d1ad1bda..9407d4fa 100644 --- a/src/models/vela/README.md +++ b/src/models/vela/README.md @@ -1,48 +1,64 @@ -# Vela 2.0 0.3B reference contract +# Vela 2.0 reference contracts (0.3B, 0.8B hybrid) -This directory contains the System1-Omni integration slice for +This directory contains the System1-Omni integration slices for [Vela 2.0 0.3B](https://huggingface.co/vllm-sr/Vela-2.0-0.3B) -(`vela2-unified`). It is a reference-serving boundary only: a Python -worker that runs the checkpoint's own pinned runtime for text state and -all five typed question kinds (`choice`, `noul`, `score`, `span`, `set`) -on `/v1/systemone`. Native execution is not part of this slice; per the -frozen RFC this worker is the Phase-1 entry that freezes the -text/token_ids input, the position-level final-hidden readout contract, -the error/length boundaries and the parity baseline for later -ModernBERT-profile work. +(`vela2-unified`) and +[Vela 2.0 0.8B](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) +(`vela2-decoder`, the first hybrid member): a Python worker that runs +the checkpoint's own pinned runtime for text state and all five typed +question kinds (`choice`, `noul`, `score`, `span`, `set`) on +`/v1/systemone`, one pinned member per worker process. The 0.3B +worker's contract freezes the text/token_ids input, the +position-level final-hidden readout contract, the error/length +boundaries and the parity baseline. The shared Vela 2.0 wire module is deliberately shaped for the family: the envelope admission (`protocol`), the pinned-runtime error mapping (`preprocess`) and response finishing (`postprocess`) are member-neutral; -this slice ships the 0.3B pinned executor (`engine`). The hybrid members -(0.8B/4B/9B) reuse the same wire layer with their own executors. +this directory ships the 0.3B pinned executor (`engine`) and the 0.8B +hybrid executor (`hybrid`). The worker picks the executor from the +package's declared `model_type`. The 4B/9B members are not +implemented. ## Pinned artifacts -| Artifact | Value | -| --- | --- | -| Package | [vllm-sr/Vela-2.0-0.3B](https://huggingface.co/vllm-sr/Vela-2.0-0.3B) | -| Pinned revision | `d6f03aa9baca4f9017fa8f8e9c2764d3bed3f409` | -| Identity | `vela2-unified` / `Vela2Model`, 309,114,369 parameters, all FP32 (1,236,473,252-byte safetensors) | -| Runtime | the checkpoint's own flat files: `vela2_inference.py`, `modeling_vela2.py`, `configuration_vela2.py`, `vela2_serve.py` | -| Calibration | the package's own `calibration.json` (never cross-copied between members) | -| License | Apache-2.0; the inherited tokenizer material carries Gemma Terms of Use | -| Runtime dependencies | [recipe/vela/requirements.txt](../../recipe/vela/requirements.txt) (torch, transformers, safetensors, tokenizers, numpy) | - -The package ships no manifest, so the executor's startup gate checks the -config's structural identity (model type, architecture, `max_length` -8,192, the 8 marker ids), then hashes every small file the runtime reads -or executes — the four runtime modules, `config.json`, -`calibration.json` and `tokenizer.json` — against the table checked in -for the pinned revision, before anything is imported, and refuses -importable entries the table does not name plus any existing -`__pycache__` bytecode cache (`model.safetensors` is -checked by exact size; the runtime's strict safetensors load rejects -truncated or structurally mismatched weights, but not same-size -bit-level corruption). +| Artifact | 0.3B | 0.8B hybrid | +| --- | --- | --- | +| Package | [vllm-sr/Vela-2.0-0.3B](https://huggingface.co/vllm-sr/Vela-2.0-0.3B) | [vllm-sr/Vela-2.0-0.8B](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) | +| Pinned revision | `d6f03aa9baca4f9017fa8f8e9c2764d3bed3f409` | `326b01d81f61fff7fd4ae570e54b87a49119e490` | +| Identity | `vela2-unified` / `Vela2Model`, 309,114,369 parameters, all FP32 (1,236,473,252-byte safetensors) | `vela2-decoder` / `Vela2DecoderModel`, 754,565,954 parameters (2,022,189,488-byte shard + hashed 4,480,172-byte `broad_head.safetensors`) | +| Input window | 8,192 tokens | 16,384 tokens | +| Runtime | the checkpoint's own flat files: `vela2_inference.py`, `modeling_vela2.py`, `configuration_vela2.py`, `vela2_serve.py` | the same four modules, decoder-specific | +| Calibration | the package's own `calibration.json` (never cross-copied between members — shipped thresholds differ) | same rule; the side-loaded broad head needs its `broad_head` block | +| License | Apache-2.0; the inherited tokenizer material carries Gemma Terms of Use | Apache-2.0; Qwen3.5-0.8B lineage notices ship in the package | +| Runtime dependencies | [recipe/vela/requirements.txt](../../recipe/vela/requirements.txt) (torch, transformers, safetensors, tokenizers, numpy) | same | + +The 0.3B package ships no manifest, so its gate checks the config's +structural identity (model type, architecture, `max_length` 8,192, the +8 marker ids), then hashes every small file the runtime reads or +executes — the four runtime modules, `config.json`, `calibration.json` +and `tokenizer.json` — against the table checked in for the pinned +revision, before anything is imported, and refuses importable entries +the table does not name plus any existing `__pycache__` bytecode cache +(`model.safetensors` is checked by exact size; the runtime's strict +safetensors load rejects truncated or structurally mismatched weights, +but not same-size bit-level corruption). The 0.8B gate mirrors this +with a 10-file table — the same four runtime modules, `config.json` +(identity includes the served `model_name`, so a 4B or 9B package fails +with its own name), `calibration.json`, `tokenizer.json`, +`tokenizer_config.json`, `model.safetensors.index.json` (the shard map) +and the hashed `broad_head.safetensors` — with the 2 GB shard checked +by exact size. A later self-consistent snapshot rewrites its own files and fails the checked-in pin. +On either member the runtime loads parameters in FP32; on `cuda` the +hybrid runs its backbone under bf16 autocast with FP32 heads (the +evaluated setting), and on `cpu` it runs FP32 throughout. The hybrid's +served name comes from `config.json` (`vllm-sr/Vela-2.0-0.8B`); the +runtime's family-generic `DEFAULT_MODEL_NAME` is never used as a +default. + ## Current serving scope - The request envelope is upstream's three-field form, exactly: @@ -103,8 +119,14 @@ The response envelope is the pinned runtime's, passed through verbatim answers echo the value without a rule field). Serving-time temperatures divide the logits per question type; the learned `tau`/`tau_span` live inside the model. - The hybrid-only fields (`span_heads`, `noul_calibration`) do not - exist on this member. + The hybrid-only `noul_calibration` block is default-off on every + member (env `VELA2_NOUL_CALIBRATION` or the reference server's flag + enable it); the worker serves the default path only. On the 0.3B the + `span_heads` field does not exist; on the hybrid it is emitted + together with `spans`, keyed by the span question ids + (`{"router"|"broad"}` per question, after the runtime's six-rule + dispatch: the `"head"` override, trained ids, exact router label + sets, PII subsets, hallucination aliases, else broad). - `usage.input_tokens` is the sum over every rendered sequence — span window rows and extra span-question rows included, nothing deduplicated; `usage.output_tokens` is always 0. @@ -128,7 +150,8 @@ per-question errors on this path: upstream server would answer 500); no such path is reachable on the pinned runtime's request path. 3. HTTP 413 (`too_long`) only when the questions plus schema alone - exceed the 8,192-token window. + exceed the member's input window (8,192 on 0.3B, 16,384 on the + hybrid). 4. HTTP 401 (`{"detail": "Missing or invalid API key"}`) only when `VELA2_API_KEY` is set and the request does not carry exactly `Authorization: Bearer ` (applies to `/v1/systemone` and @@ -166,14 +189,17 @@ every question kind), so answering at all means ready. - `preprocess.py` owns the mapping of the pinned runtime's `SystemOneError` to HTTP (422, or 413 for `too_long`) and of its other ValueErrors to client errors. -- `engine.py` owns the pinned runtime, the pre-import package gate, the - served name, device state and the all-kind warmup. +- `engine.py` owns the 0.3B pinned runtime, the pre-import package gate, the + served name, device state and the all-kind warmup; `hybrid.py` mirrors + it for the 0.8B (its warmup also drives both span heads). - `postprocess.py` owns the pure confidence/score formulas (mirrored for the CPU tests) and response finishing: answer-order and key-set - reconstruction including set views, usage accounting, and refusal of - hybrid-only fields on this member. -- `src/frontend/vela.py` owns HTTP lifecycle, the single-flight lock, - the API-key gate and orchestration. + reconstruction including set views, usage accounting, the + member-aware `span_heads` check, and refusal of hybrid-only fields + on the 0.3B. +- `src/frontend/vela.py` owns HTTP lifecycle, member detection from the + package's `model_type`, the per-member `/v1/models` entry, the + single-flight lock, the API-key gate and orchestration. - The Rust frontend owns transport and forwarding, not model state. The server-side error surface and envelope semantics are recorded as @@ -184,16 +210,18 @@ the shared worker-contract issue, and nothing is posted upstream. - CPU contract tests, no weights, no torch: `PYTHONPATH=src python -m pytest tests/vela -q` (envelope triples, - transport discipline, package gate, formula mirrors, response - finishing, the HTTP surface with a contract fake). + transport discipline, both package gates, formula mirrors, response + finishing including the hybrid `span_heads` surface, member + detection, the HTTP surface with a contract fake). - Reference parity is exact match on recorded fixtures under the pinned versions: `recipe/vela/compare_reference.py` drives the recipe fixtures plus five synthetic rejections (invalid-span 422, over-limit 413, and the missing-field / extra-field / wrong-model envelope 422s) through both the pinned `vela2_serve.py` app and the - production worker pipeline over one shared engine, and freezes the - oracle fixture for the native encoder slices. CPU FP32 (no + production worker pipeline over one shared engine, for either member, + and freezes the oracle fixture for the native slices (`oracle-` for + 0.3B, `oracle-hybrid-` for 0.8B). CPU FP32 (no flash-linear-attention) is the oracle setting; GPU bf16-autocast is - a deployment option outside this slice's evidence. + a deployment option outside these slices' evidence. - The serving procedure, hardware requirements and the recorded evidence pointer are [recipe/vela/reference.md](../../recipe/vela/reference.md). diff --git a/src/models/vela/engine.py b/src/models/vela/engine.py index 19badaf9..9055d6c4 100644 --- a/src/models/vela/engine.py +++ b/src/models/vela/engine.py @@ -126,7 +126,7 @@ def verify_config(root: Path) -> dict[str, Any]: return config -def verify_files(root: Path, table: dict[str, str] | None = None) -> list[str]: +def verify_files(root: Path, table: dict[str, str] | None = None, revision: str = REFERENCE_REVISION) -> list[str]: """Hash every pinned file in full and return their names. Must run before any package code is imported: the table names the @@ -138,7 +138,8 @@ def verify_files(root: Path, table: dict[str, str] | None = None) -> list[str]: ``__init__`` in every module form, or a namespace package's nested modules — would shadow one of the pinned runtime's dependencies — and any ``__pycache__``, whose existing bytecode is not verifiable - against the pin. + against the pin. ``revision`` names the pin the table belongs to in + hash-failure messages (the hybrid member passes its own). """ table = dict(table or PINNED_FILES_SHA256) @@ -151,7 +152,7 @@ def verify_files(root: Path, table: dict[str, str] | None = None) -> list[str]: problems.append(f"missing pinned file {name}") continue if _sha256_safe(target) != digest: - problems.append(f"{name}: SHA-256 differs from the pin for {REFERENCE_REVISION}") + problems.append(f"{name}: SHA-256 differs from the pin for {revision}") for entry in sorted(Path(root).iterdir()): if entry.name in table: continue @@ -232,6 +233,10 @@ def verify_package(root: Path, table: dict[str, str] | None = None) -> None: class Vela2Executor: """Load and drive one immutable pinned Vela 2.0 0.3B runtime instance.""" + # Response finishing uses this to refuse the hybrid-only ``span_heads`` + # field (hybrid.py's executor sets it True). + is_hybrid = False + def __init__( self, package: str | Path, diff --git a/src/models/vela/hybrid.py b/src/models/vela/hybrid.py new file mode 100644 index 00000000..e02fa6fb --- /dev/null +++ b/src/models/vela/hybrid.py @@ -0,0 +1,241 @@ +"""Pinned executor for Vela 2.0 0.8B (``vela2-decoder``), the first hybrid member. + +Mirrors :mod:`models.vela.engine` for the compact hybrid member. The +``vela2-decoder`` package ships the same flat runtime modules as the +0.3B (with decoder-specific contents), so the gate reuses the same +helpers and the same one-package-per-process discipline; what differs +is the pin table, the structural identity of ``config.json``, and the +weights layout — one 2 GB shard checked by exact size plus the +side-loaded second span head. + +The runtime loads parameters in FP32 either way; on ``cuda`` it runs +the backbone under bf16 autocast with FP32 heads (the evaluated +setting), on ``cpu`` it runs FP32 throughout. The served model name +comes from ``config.json`` ``model_name`` (upstream +``DEFAULT_MODEL_NAME`` is the family-generic ``vllm-sr/Vela-2.0`` and +must not be used as a default here). +""" + +from __future__ import annotations + +import json +import sys +import threading +from pathlib import Path +from typing import Any + +from .engine import ( + put_first_on_sys_path, + verify_files, + verify_no_foreign_runtime, +) + +HYBRID_REPO = "vllm-sr/Vela-2.0-0.8B" +HYBRID_REVISION = "326b01d81f61fff7fd4ae570e54b87a49119e490" +# Structural identity of the pinned config.json. model_name is unique +# per member, so a 4B or 9B package fails with its own name. +EXPECTED_MODEL_TYPE = "vela2-decoder" +EXPECTED_ARCHITECTURE = "Vela2DecoderModel" +EXPECTED_MAX_LENGTH = 16384 +EXPECTED_MODEL_NAME = "vllm-sr/Vela-2.0-0.8B" +WEIGHTS_NAME = "model-00001-of-00001.safetensors" +EXPECTED_WEIGHTS_BYTES = 2022189488 +# The files this gate hashes, transcribed from the pinned revision and +# cross-checked against the package's own SHA256SUMS; repinning means +# updating this table together with HYBRID_REVISION. Every file the +# runtime reads or executes is here: the four runtime modules, +# ``vela2_serve.py`` (never imported, part of the pinned surface), +# ``config.json``, ``calibration.json``, ``tokenizer.json`` (the loaded +# tokenizer), ``tokenizer_config.json`` (listed by the runtime's own +# download manifest), ``model.safetensors.index.json`` (the shard map +# the loader reads) and ``broad_head.safetensors`` (the side-loaded +# second span head; 4.5 MB hashes in milliseconds). The 2 GB shard is +# checked by exact size only, as on 0.3B. +PINNED_FILES_SHA256 = { + "vela2_serve.py": "68e1ef278561f452aa0ca6afd6aa288636cecdb0b37fd7f7146a3c9bf17aa787", + "vela2_inference.py": "11de1322788942153a22db164a3fb26abcaa4c5bb4b057cd572e277457c17dc2", + "modeling_vela2.py": "b7ecd8dcacfb24dbe8249c7b96829a737f4e2b493fc2157497f1b62d9e02727d", + "configuration_vela2.py": "c9a41e434a9d2cfeb3ab6581c00679d241b3468c04d160a811d6fe2c85cd071f", + "config.json": "0637ca193b9159b6ece25837913956477164d3392d9b5dd1e6b74b95a484004a", + "calibration.json": "d96e447962d0dc1d58fa8422dddbae8b99960e21fd75a10ef9b096f700a211f5", + "tokenizer.json": "06b9509352d2af50381ab2247e083b80d32d5c0aba91c272ca9ff729b6a0e523", + "tokenizer_config.json": "bee8eba30f0eb4af73c0fe2cd06d0f89b657d7819941c438157ec42f7c80ea87", + "model.safetensors.index.json": "b53d1c79219677289bdb1541a1373dfe53119884f248b23c94a27aef7338919d", + "broad_head.safetensors": "687d7a435d6de846796274e417b6333f83df3085a6e7c3bca4c01cb4d75a30f0", +} +# A warmup that touches every question kind's readout path on both span +# heads: the CandidateHead option rows (choice/set share it, noul and +# score ride the same candidate readout), the span decoder and the +# threshold echo, one router-head span (the unsupported label is a +# trained alias) and one broad-head span (an open label with no trained +# match). Model text only; the result is discarded. +WARMUP_REQUEST = { + "state": { + "request": "Hello, I would like to check the status of my order.", + "answer": "Your order was delivered yesterday.", + }, + "model": None, # filled with the served name at warmup time + "questions": { + "kind": { + "type": "choice", + "instructions": "What is this message about?", + "criteria": {"order": "an order's status", "other": "anything else"}, + }, + "claims": { + "type": "set", + "instructions": "Which topics does the message mention?", + "criteria": {"delivery": "delivery of an order", "billing": "payments or charges"}, + }, + "tone": { + "type": "score", + "instructions": "How formal is the message?", + "criteria": ["casual", "neutral", "formal"], + }, + "polite": { + "type": "noul", + "instructions": "Is the message polite?", + }, + "unsupported": { + "type": "span", + "instructions": "Which spans of the answer are not supported by the request?", + "criteria": {"unsupported": "a claim not supported by the request"}, + }, + "products": { + "type": "span", + "instructions": "Which products or services are mentioned?", + "criteria": {"product": "a product or a service"}, + "over": "request", + }, + }, +} + + +def verify_config(root: Path) -> dict[str, Any]: + """Read config.json and check the pinned member's structural identity.""" + + path = Path(root) / "config.json" + if not path.is_file(): + raise ValueError(f"the package is missing config.json; this worker only serves {HYBRID_REPO}") + config = json.loads(path.read_text(encoding="utf-8")) + if config.get("model_type") != EXPECTED_MODEL_TYPE: + raise ValueError( + f"config.json declares model_type {config.get('model_type')!r}; this worker only " + f"serves the {EXPECTED_MODEL_TYPE} member {HYBRID_REPO} at {HYBRID_REVISION}" + ) + if config.get("architectures") != [EXPECTED_ARCHITECTURE]: + raise ValueError(f"config.json architectures must be [{EXPECTED_ARCHITECTURE!r}]") + if config.get("max_length") != EXPECTED_MAX_LENGTH: + raise ValueError(f"config.json max_length must be {EXPECTED_MAX_LENGTH}") + if config.get("model_name") != EXPECTED_MODEL_NAME: + raise ValueError( + f"config.json model_name must be {EXPECTED_MODEL_NAME!r}; another Vela 2.0 member " + "needs its own pinned executor" + ) + return config + + +def verify_weights(root: Path) -> None: + """Check the pinned shard is present at its exact pinned size.""" + + target = Path(root) / WEIGHTS_NAME + if not target.is_file(): + raise ValueError(f"the package is missing {WEIGHTS_NAME}") + size = target.stat().st_size + if size != EXPECTED_WEIGHTS_BYTES: + raise ValueError( + f"{WEIGHTS_NAME} is {size} bytes; the pinned revision's file is {EXPECTED_WEIGHTS_BYTES}" + ) + + +def verify_package(root: Path, table: dict[str, str] | None = None) -> None: + """The full pre-import gate for one hybrid package directory.""" + + verify_config(root) + verify_files(root, table or PINNED_FILES_SHA256, HYBRID_REVISION) + verify_weights(root) + + +class Vela2HybridExecutor: + """Load and drive one immutable pinned Vela 2.0 0.8B runtime instance.""" + + is_hybrid = True + + def __init__( + self, + package: str | Path, + *, + device: str = "cpu", + model_name: str | None = None, + batch_size: int | None = None, + token_budget: int | None = None, + ) -> None: + root = Path(package) + if not root.is_dir(): + raise ValueError(f"the Vela 2.0 0.8B package directory does not exist: {root}") + verify_package(root) + + # Same discipline as the 0.3B executor: the just-verified package + # root goes first on sys.path so the flat runtime modules resolve + # to the checkpoint's own copies, and a runtime module already + # imported from another directory is refused — one worker process + # serves one package. + verify_no_foreign_runtime(root) + put_first_on_sys_path(root) + # Import with bytecode writing off: the gate refuses existing + # bytecode caches, so a __pycache__ this import wrote would fail + # every later gate run of the same package. + previous_dont_write_bytecode = sys.dont_write_bytecode + sys.dont_write_bytecode = True + try: + import vela2_inference + finally: + sys.dont_write_bytecode = previous_dont_write_bytecode + + self.SystemOneError = vela2_inference.SystemOneError + self._system_one_request = vela2_inference.system_one_request + self.engine = vela2_inference.Vela2.from_pretrained( + root, backend="torch", device=device, + **({"batch_size": batch_size} if batch_size is not None else {}), + **({"token_budget": token_budget} if token_budget is not None else {}), + ) + # The decoder members declare their served name in config.json; + # the runtime's DEFAULT_MODEL_NAME is family-generic. + self.model_name = model_name or self.engine.model_name + self.max_length = int(self.engine.max_len) + self._lock = threading.RLock() + self._closed = False + + @property + def served(self) -> set[str]: + """The model names this executor answers to (upstream: one).""" + + return {self.model_name} + + def system_one(self, body: dict[str, Any]) -> dict[str, Any]: + """Run one admitted request body; the response is upstream's, verbatim. + + Hybrid responses carry one extra top-level field, ``span_heads``, + alongside ``spans``; response finishing checks it in + :func:`models.vela.postprocess.finish_response`. + """ + + with self._lock: + if self._closed: + raise RuntimeError("Vela 2.0 hybrid executor is closed") + return self._system_one_request(self.engine, body, served=self.served) + + def warmup(self) -> None: + """Run one real request of every question kind on both span heads.""" + + request = dict(WARMUP_REQUEST) + request["model"] = self.model_name + response = self.system_one(request) + if not isinstance(response, dict) or "answers" not in response: + raise RuntimeError("warmup did not produce a SystemOne response") + + def close(self) -> None: + with self._lock: + if self._closed: + return + self._closed = True + self.engine = None diff --git a/src/models/vela/postprocess.py b/src/models/vela/postprocess.py index 141b6938..907acb9b 100644 --- a/src/models/vela/postprocess.py +++ b/src/models/vela/postprocess.py @@ -91,26 +91,35 @@ def _question_ids_of(questions: Mapping[str, Any], *kinds: str) -> list[str]: ] -def finish_response(questions: Mapping[str, Any], response: dict[str, Any]) -> dict[str, Any]: +def finish_response( + questions: Mapping[str, Any], + response: dict[str, Any], + *, + hybrid: bool = False, +) -> dict[str, Any]: """Check the runtime response against the admitted questions and pass it through. The pinned runtime owns every value in this response; these checks only refuse a response that could not be reconstructed for the - request that produced it (wrong key set or order, a hybrid-only + request that produced it (wrong key set or order, a member-invented field, broken usage accounting, an answer of unexpected shape). + ``hybrid`` selects the member: the hybrid executor's responses carry + ``span_heads`` alongside ``spans`` (upstream emits both together, + keyed by the span question ids); the 0.3B member's never do. """ if not isinstance(response, dict): raise RuntimeError("the pinned runtime returned a non-object response") keys = set(response) foreign = keys & HYBRID_ONLY_FIELDS - if foreign: + if foreign and not hybrid: raise RuntimeError( f"the pinned runtime returned hybrid-only field(s) {sorted(foreign)}; " "this worker serves the 0.3B member" ) missing = [field for field in REQUIRED_FIELDS if field not in response] - if missing or not keys <= TOP_LEVEL_FIELDS: + allowed = TOP_LEVEL_FIELDS | HYBRID_ONLY_FIELDS if hybrid else TOP_LEVEL_FIELDS + if missing or not keys <= allowed: raise RuntimeError("the pinned runtime returned an unexpected response envelope") answers = response["answers"] expected = expected_answer_order(questions) @@ -126,6 +135,14 @@ def finish_response(questions: Mapping[str, Any], response: dict[str, Any]) -> d raise RuntimeError(f"{field} do not match the request's {field} questions") elif field in response: raise RuntimeError(f"the pinned runtime returned {field} without {field} questions") + if hybrid: + span_ids = _question_ids_of(questions, "span") + if span_ids: + heads = response.get("span_heads") + if not isinstance(heads, dict) or list(heads) != span_ids: + raise RuntimeError("span_heads do not match the request's span questions") + elif "span_heads" in response: + raise RuntimeError("the pinned runtime returned span_heads without span questions") usage = response["usage"] if ( not isinstance(usage, dict) diff --git a/src/models/vela/protocol.py b/src/models/vela/protocol.py index de5dd2db..d9341206 100644 --- a/src/models/vela/protocol.py +++ b/src/models/vela/protocol.py @@ -24,10 +24,10 @@ # hybrid members serve their config.json "model_name" instead. MODEL_NAME = "vllm-sr/Vela-2.0-0.3B" # Slice-scoped transport cap. Upstream vela2_serve.py sets no total-body -# limit (its only size boundary is the 8,192-token input window); a text -# request bounded by that window is orders of magnitude smaller, so this -# cap never binds a valid request. A deliberate difference recorded with -# the integration. +# limit (its only size boundary is the member's token input window); a +# text request bounded by that window is orders of magnitude smaller, so +# this cap never binds a valid request. A deliberate difference recorded +# with the integration. MAX_BODY = 8 * 1024 * 1024 # The envelope fields, in upstream's missing-field check order. REQUEST_FIELDS = ("state", "model", "questions") diff --git a/tests/vela/fixtures/oracle-hybrid-example-request-cjk.json b/tests/vela/fixtures/oracle-hybrid-example-request-cjk.json new file mode 100644 index 00000000..ddf6c71c --- /dev/null +++ b/tests/vela/fixtures/oracle-hybrid-example-request-cjk.json @@ -0,0 +1,155 @@ +{ + "case": "example-request-cjk", + "request": { + "model": "vllm-sr/Vela-2.0-0.8B", + "state": { + "request": "客户张伟(zhang.wei@example.cn)于2026年10月1日在上海市浦东新区世纪大道100号办理了业务,联系电话13800138000。", + "source": "客户的业务申请需要在三个工作日内审核完成。", + "answer": "客户的业务已经即时完成了。" + }, + "questions": { + "pii": { + "type": "span", + "instructions": "Which spans are personal information?", + "criteria": { + "PERSON": "a person's name", + "EMAIL_ADDRESS": "an e-mail address", + "PHONE_NUMBER": "a telephone number", + "STREET_ADDRESS": "a street address or postal address" + }, + "over": "request" + }, + "unsupported": { + "type": "span", + "instructions": "Which spans of the answer are not supported by the context?", + "criteria": { + "unsupported": "a claim not supported by the context" + } + }, + "billing": { + "type": "noul", + "instructions": "这个请求是否与账单有关?" + } + } + }, + "system_one": { + "model": "vllm-sr/Vela-2.0-0.8B", + "answers": { + "pii": { + "type": "noul", + "noul": 0.8401349388137276 + }, + "unsupported": { + "type": "noul", + "noul": 0.28838747148371713 + }, + "billing": { + "type": "noul", + "noul": 0.1674766566538726 + } + }, + "usage": { + "input_tokens": 597, + "output_tokens": 0 + }, + "spans": { + "pii": [ + { + "label": "PHONE_NUMBER", + "start": 32, + "end": 34, + "text": "10", + "probability": 0.4658691883087158 + }, + { + "label": "STREET_ADDRESS", + "start": 38, + "end": 52, + "text": "上海市浦东新区世纪大道100", + "probability": 0.4821831285953522 + }, + { + "label": "PHONE_NUMBER", + "start": 63, + "end": 74, + "text": "13800138000", + "probability": 0.4298103451728821 + } + ], + "unsupported": [] + }, + "span_heads": { + "pii": "router", + "unsupported": "router" + }, + "thresholds": { + "pii": 0.2914, + "unsupported": 0.5 + } + }, + "predict": { + "answers": [ + { + "id": "pii", + "type": "span", + "target_part": "user", + "spans": [ + { + "start": 32, + "end": 34, + "label": "PHONE_NUMBER", + "probability": 0.4658691883087158, + "text": "10" + }, + { + "start": 38, + "end": 52, + "label": "STREET_ADDRESS", + "probability": 0.4821831285953522, + "text": "上海市浦东新区世纪大道100" + }, + { + "start": 63, + "end": 74, + "label": "PHONE_NUMBER", + "probability": 0.4298103451728821, + "text": "13800138000" + } + ], + "threshold": 0.2914, + "threshold_rule": "pii:length", + "head": "router", + "head_reason": "id" + }, + { + "id": "unsupported", + "type": "span", + "target_part": "answer", + "spans": [], + "threshold": 0.5, + "threshold_rule": "span:*", + "head": "router", + "head_reason": "label_set" + }, + { + "id": "billing", + "type": "choice", + "answer": "no", + "probabilities": { + "no": 0.8325233433461274, + "yes": 0.1674766566538726 + }, + "abstain_probability": 0.0009211774164155532 + } + ], + "meta": { + "tokens": { + "user": 46, + "context": 10, + "answer": 6 + }, + "windows": 0, + "sequences": 2 + } + } +} diff --git a/tests/vela/fixtures/oracle-hybrid-example-request-score.json b/tests/vela/fixtures/oracle-hybrid-example-request-score.json new file mode 100644 index 00000000..9491e486 --- /dev/null +++ b/tests/vela/fixtures/oracle-hybrid-example-request-score.json @@ -0,0 +1,105 @@ +{ + "case": "example-request-score", + "request": { + "model": "vllm-sr/Vela-2.0-0.8B", + "state": "Hello, I would like to check the status of my order. It has been five days and I have heard nothing back.", + "questions": { + "tone": { + "type": "score", + "instructions": "How formal is the message?", + "criteria": [ + "casual", + "neutral", + "formal" + ] + }, + "urgency": { + "type": "score", + "instructions": "How urgently does the sender need a reply?", + "criteria": [ + "no rush", + "soon", + "today", + "immediately" + ] + } + } + }, + "system_one": { + "model": "vllm-sr/Vela-2.0-0.8B", + "answers": { + "tone": { + "type": "score", + "score": 1.1498890868381673, + "confidence": 0.3046350733874953, + "legend": { + "0": "casual", + "1": "neutral", + "2": "formal" + }, + "probabilities": { + "0": 0.16807713462834117, + "1": 0.5139566439051507, + "2": 0.3179662214665082 + } + }, + "urgency": { + "type": "score", + "score": 0.9787050638239541, + "confidence": 0.19233689920934172, + "legend": { + "0": "no rush", + "1": "soon", + "2": "today", + "3": "immediately" + }, + "probabilities": { + "0": 0.44128118285871365, + "1": 0.21311503083546, + "2": 0.2712213259289846, + "3": 0.07438246037684161 + } + } + }, + "usage": { + "input_tokens": 228, + "output_tokens": 0 + } + }, + "predict": { + "answers": [ + { + "id": "tone", + "type": "score", + "answer": "neutral", + "probabilities": { + "casual": 0.16807713462834117, + "neutral": 0.5139566439051507, + "formal": 0.3179662214665082 + }, + "expected_index": 1.1498890868381673, + "score": 0.5749445434190836 + }, + { + "id": "urgency", + "type": "score", + "answer": "no rush", + "probabilities": { + "no rush": 0.44128118285871365, + "soon": 0.21311503083546, + "today": 0.2712213259289846, + "immediately": 0.07438246037684161 + }, + "expected_index": 0.9787050638239541, + "score": 0.3262350212746513 + } + ], + "meta": { + "tokens": { + "user": 25 + }, + "windows": 0, + "sequences": 1 + } + } +} diff --git a/tests/vela/fixtures/oracle-hybrid-example-request-set-threshold.json b/tests/vela/fixtures/oracle-hybrid-example-request-set-threshold.json new file mode 100644 index 00000000..bab3d048 --- /dev/null +++ b/tests/vela/fixtures/oracle-hybrid-example-request-set-threshold.json @@ -0,0 +1,81 @@ +{ + "case": "example-request-set-threshold", + "request": { + "model": "vllm-sr/Vela-2.0-0.8B", + "state": "My card was charged twice and the parcel never arrived.", + "questions": { + "issues": { + "type": "set", + "instructions": "Which issues does the customer report?", + "criteria": { + "billing": "payments, charges, refunds or invoices", + "shipping": "delivery of an order or a parcel", + "login": "signing in, passwords or account access" + }, + "threshold": 0.15 + } + } + }, + "system_one": { + "model": "vllm-sr/Vela-2.0-0.8B", + "answers": { + "issues.billing": { + "type": "noul", + "noul": 0.6211446881608428 + }, + "issues.shipping": { + "type": "noul", + "noul": 0.8205402483597802 + }, + "issues.login": { + "type": "noul", + "noul": 0.00012988178108716601 + } + }, + "usage": { + "input_tokens": 133, + "output_tokens": 0 + }, + "sets": { + "issues": { + "selected": [ + "billing", + "shipping" + ], + "probabilities": { + "billing": 0.6211446881608428, + "shipping": 0.8205402483597802, + "login": 0.00012988178108716601 + } + } + }, + "thresholds": { + "issues": 0.15 + } + }, + "predict": { + "answers": [ + { + "id": "issues", + "type": "set", + "answer": [ + "billing", + "shipping" + ], + "probabilities": { + "billing": 0.6211446881608428, + "shipping": 0.8205402483597802, + "login": 0.00012988178108716601 + }, + "threshold": 0.15 + } + ], + "meta": { + "tokens": { + "user": 11 + }, + "windows": 0, + "sequences": 1 + } + } +} diff --git a/tests/vela/fixtures/oracle-hybrid-example-request.json b/tests/vela/fixtures/oracle-hybrid-example-request.json new file mode 100644 index 00000000..801ef7aa --- /dev/null +++ b/tests/vela/fixtures/oracle-hybrid-example-request.json @@ -0,0 +1,183 @@ +{ + "case": "example-request", + "request": { + "model": "vllm-sr/Vela-2.0-0.8B", + "state": { + "request": "Hi, I'm Tom Baker (tom.baker@example.com). What is the maximum daily dose of paracetamol for an adult?", + "source": "For adults, the maximum dose of paracetamol is 4 grams in 24 hours, taken as 500 mg to 1 g every 4 to 6 hours.", + "answer": "Adults can take up to 6 grams of paracetamol in 24 hours, in doses of 500 mg to 1 g every 4 to 6 hours." + }, + "questions": { + "pii": { + "type": "span", + "instructions": "Which spans are personal information?", + "criteria": { + "AGE": "a person's age", + "CREDIT_CARD": "a payment card number", + "DATE_TIME": "a date, time or date of birth", + "DOMAIN_NAME": "an internet domain name or website address", + "EMAIL_ADDRESS": "an e-mail address", + "GPE": "a country, city, state or other geopolitical place", + "IBAN_CODE": "an international bank account number (IBAN)", + "IP_ADDRESS": "an IPv4 or IPv6 address", + "NRP": "a nationality, religious or political group", + "ORGANIZATION": "the name of a company, institution or other organisation", + "PERSON": "a person's name", + "PHONE_NUMBER": "a telephone number", + "STREET_ADDRESS": "a street address or postal address", + "TITLE": "a personal or professional title such as Dr. or Mrs.", + "US_DRIVER_LICENSE": "a US driver's licence number", + "US_SSN": "a US social security number", + "ZIP_CODE": "a postal or ZIP code" + }, + "over": "request" + }, + "halu": { + "type": "span", + "instructions": "Which spans of the answer are not supported by the context?", + "criteria": { + "unsupported": "a claim not supported by the context" + } + }, + "domain": { + "type": "choice", + "instructions": "Which subject area is this request about?", + "over": "request", + "criteria": { + "health": "medicine, clinical practice, nutrition, ageing or sexual health", + "math": "arithmetic, algebra, geometry, statistics or other mathematics", + "other": "a subject that fits none of the listed areas" + } + } + } + }, + "system_one": { + "model": "vllm-sr/Vela-2.0-0.8B", + "answers": { + "pii": { + "type": "noul", + "noul": 0.9965421673633966 + }, + "halu": { + "type": "noul", + "noul": 0.9972382713052719 + }, + "domain": { + "type": "choice", + "choice": "health", + "confidence": 0.9288764270674694, + "probabilities": { + "health": 0.9621185645193945, + "math": 0.004639298028680393, + "other": 0.03324213745192508 + } + } + }, + "usage": { + "input_tokens": 1041, + "output_tokens": 0 + }, + "spans": { + "pii": [ + { + "label": "PERSON", + "start": 8, + "end": 17, + "text": "Tom Baker", + "probability": 0.983367919921875 + }, + { + "label": "EMAIL_ADDRESS", + "start": 19, + "end": 40, + "text": "tom.baker@example.com", + "probability": 0.9851056337356567 + } + ], + "halu": [ + { + "label": "unsupported", + "start": 19, + "end": 29, + "text": "to 6 grams", + "probability": 0.7782317996025085 + } + ] + }, + "span_heads": { + "pii": "router", + "halu": "router" + }, + "thresholds": { + "pii": 0.2914, + "halu": 0.35 + } + }, + "predict": { + "answers": [ + { + "id": "pii", + "type": "span", + "target_part": "user", + "spans": [ + { + "start": 8, + "end": 17, + "label": "PERSON", + "probability": 0.983367919921875, + "text": "Tom Baker" + }, + { + "start": 19, + "end": 40, + "label": "EMAIL_ADDRESS", + "probability": 0.9851056337356567, + "text": "tom.baker@example.com" + } + ], + "threshold": 0.2914, + "threshold_rule": "pii:length", + "head": "router", + "head_reason": "id" + }, + { + "id": "halu", + "type": "span", + "target_part": "answer", + "spans": [ + { + "start": 19, + "end": 29, + "label": "unsupported", + "probability": 0.7782317996025085, + "text": "to 6 grams" + } + ], + "threshold": 0.35, + "threshold_rule": "halu", + "head": "router", + "head_reason": "id" + }, + { + "id": "domain", + "type": "choice", + "answer": "health", + "probabilities": { + "health": 0.9621185645193945, + "math": 0.004639298028680393, + "other": 0.03324213745192508 + }, + "abstain_probability": 0.04287965117790319 + } + ], + "meta": { + "tokens": { + "user": 27, + "context": 39, + "answer": 39 + }, + "windows": 0, + "sequences": 2 + } + } +} diff --git a/tests/vela/test_hybrid.py b/tests/vela/test_hybrid.py new file mode 100644 index 00000000..ee3fb300 --- /dev/null +++ b/tests/vela/test_hybrid.py @@ -0,0 +1,310 @@ +"""Tests for the Vela 2.0 0.8B hybrid member: gate, worker dispatch, response finishing. + +Gate tests mirror test_engine_manifest: temp directories with an +injectable pin table and recomputed hashes — no weights, no torch, no +network. Worker tests drive FakeVela2Hybrid (from test_worker's fake, +plus the hybrid response surface) through decide/detect_member/ +models_entry: no weights, no torch, no GPU. + + PYTHONPATH=src python -m pytest tests/vela -q +""" + +from __future__ import annotations + +import hashlib +import json +import re +from pathlib import Path + +import pytest + +from frontend.vela import decide, detect_member, models_entry +from models.vela.engine import Vela2Executor, verify_files +from models.vela.hybrid import ( + EXPECTED_ARCHITECTURE, + EXPECTED_MAX_LENGTH, + EXPECTED_MODEL_NAME, + EXPECTED_MODEL_TYPE, + EXPECTED_WEIGHTS_BYTES, + HYBRID_REPO, + HYBRID_REVISION, + PINNED_FILES_SHA256, + WEIGHTS_NAME, + Vela2HybridExecutor, + verify_config, + verify_package, + verify_weights, +) +from models.vela.postprocess import finish_response + +from .test_protocol import body +from .test_worker import FakeVela2, five_kind_body + +CONFIG = { + "model_type": EXPECTED_MODEL_TYPE, + "architectures": [EXPECTED_ARCHITECTURE], + "max_length": EXPECTED_MAX_LENGTH, + "model_name": EXPECTED_MODEL_NAME, +} + + +def table_of(files: dict[str, bytes]) -> dict[str, str]: + return {name: hashlib.sha256(content).hexdigest() for name, content in files.items()} + + +def small_files(): + return { + "vela2_serve.py": b"upstream server stub\n", + "vela2_inference.py": b"upstream engine stub\n", + "modeling_vela2.py": b"upstream model stub\n", + "configuration_vela2.py": b"upstream config stub\n", + "calibration.json": b'{"temperature": {}}', + "tokenizer.json": b'{"version": "stub"}', + "tokenizer_config.json": b'{"model_type": "stub"}', + "model.safetensors.index.json": b'{"metadata": {"total_size": 1}}', + "broad_head.safetensors": b"second span head stub\n", + } + + +def build_package(root: Path, files: dict[str, bytes], config: dict | None = None) -> dict[str, str]: + for name, content in files.items(): + (root / name).write_bytes(content) + (root / "config.json").write_text( + json.dumps(config if config is not None else CONFIG), encoding="utf-8" + ) + with (root / WEIGHTS_NAME).open("wb") as stream: + stream.truncate(EXPECTED_WEIGHTS_BYTES) + files = dict(files) + files["config.json"] = (root / "config.json").read_bytes() + return table_of(files) + + +def hybrid_body(): + value = five_kind_body() + value["model"] = EXPECTED_MODEL_NAME + return value + + +class FakeVela2Hybrid(FakeVela2): + """The pinned hybrid runtime's contract, driven without its code.""" + + is_hybrid = True + + def __init__(self, model_name=EXPECTED_MODEL_NAME, too_long=False): + super().__init__(model_name, too_long) + self.max_length = 16384 + + class _Engine: + config = { + "model_name": EXPECTED_MODEL_NAME, + "description": ( + "Vela 2.0 0.8B: SystemOne Choice / Noul / Score " + "with span and set extensions, 16,384-token input" + ), + "release_date": "", + } + + self.engine = _Engine() + + def system_one(self, body): + response = super().system_one(body) + if "spans" in response: + # Upstream emits span_heads together with spans, keyed by the + # span question ids; router stands in for both heads here. + response["span_heads"] = {qid: "router" for qid in response["spans"]} + return response + + +# --------------------------------------------------------------------- gate + + +def test_the_checked_in_hybrid_pin_table_shape_is_locked(): + assert HYBRID_REPO == "vllm-sr/Vela-2.0-0.8B" + assert HYBRID_REVISION == "326b01d81f61fff7fd4ae570e54b87a49119e490" + assert set(PINNED_FILES_SHA256) == { + "vela2_serve.py", "vela2_inference.py", "modeling_vela2.py", + "configuration_vela2.py", "config.json", "calibration.json", "tokenizer.json", + "tokenizer_config.json", "model.safetensors.index.json", "broad_head.safetensors", + } + for digest in PINNED_FILES_SHA256.values(): + assert re.fullmatch(r"[0-9a-f]{64}", digest) + + +def test_verification_accepts_a_package_matching_its_table(tmp_path): + table = build_package(tmp_path, small_files()) + assert verify_files(tmp_path, table) == sorted(table) + verify_config(tmp_path) + verify_weights(tmp_path) + verify_package(tmp_path, table) + + +def test_a_unified_package_is_refused_with_its_own_name(tmp_path): + build_package( + tmp_path, small_files(), + config={**CONFIG, "model_type": "vela2-unified"}, + ) + with pytest.raises(ValueError, match="vela2-unified.*only serves the vela2-decoder member"): + verify_config(tmp_path) + + +@pytest.mark.parametrize( + ("override", "fragment"), + [ + ({"architectures": ["OtherModel"]}, "architectures"), + ({"max_length": 8192}, "max_length"), + ({"model_name": "vllm-sr/Vela-2.0-4B"}, "needs its own pinned executor"), + ], +) +def test_foreign_config_structures_are_refused(tmp_path, override, fragment): + build_package(tmp_path, small_files(), config={**CONFIG, **override}) + with pytest.raises(ValueError, match=fragment): + verify_config(tmp_path) + + +def test_tampered_files_are_rejected(tmp_path): + table = build_package(tmp_path, small_files()) + victim = tmp_path / "broad_head.safetensors" + victim.write_bytes(victim.read_bytes() + b"tampered\n") + # The shared gate must name the hybrid's pin, not the 0.3B's. + with pytest.raises( + ValueError, match=f"broad_head.safetensors: SHA-256 differs from the pin for {HYBRID_REVISION}" + ): + verify_files(tmp_path, table, HYBRID_REVISION) + + +def test_a_missing_broad_head_is_rejected(tmp_path): + table = build_package(tmp_path, small_files()) + (tmp_path / "broad_head.safetensors").unlink() + with pytest.raises(ValueError, match="missing pinned file broad_head.safetensors"): + verify_files(tmp_path, table) + + +def test_a_later_self_consistent_snapshot_is_refused_by_the_checked_in_pin(tmp_path): + build_package(tmp_path, small_files()) + with pytest.raises(ValueError, match="SHA-256 differs from the pin"): + verify_files(tmp_path, PINNED_FILES_SHA256) + + +def test_weights_are_checked_by_exact_pinned_size(tmp_path): + build_package(tmp_path, small_files()) + verify_weights(tmp_path) + + with (tmp_path / WEIGHTS_NAME).open("wb") as stream: + stream.truncate(EXPECTED_WEIGHTS_BYTES - 1) + with pytest.raises(ValueError, match="is 2022189487 bytes"): + verify_weights(tmp_path) + + (tmp_path / WEIGHTS_NAME).unlink() + with pytest.raises(ValueError, match=f"missing {WEIGHTS_NAME}"): + verify_weights(tmp_path) + + +# ------------------------------------------------------------- worker wiring + + +def test_detect_member_routes_each_declared_member(tmp_path): + unified = tmp_path / "unified" + unified.mkdir() + (unified / "config.json").write_text(json.dumps({"model_type": "vela2-unified"})) + decoder = tmp_path / "decoder" + decoder.mkdir() + (decoder / "config.json").write_text(json.dumps({"model_type": "vela2-decoder"})) + + cls, name = detect_member(unified) + assert cls is Vela2Executor and name == "vllm-sr/Vela-2.0-0.3B" + cls, name = detect_member(decoder) + assert cls is Vela2HybridExecutor and name == EXPECTED_MODEL_NAME + + +def test_detect_member_refuses_packages_without_a_usable_config(tmp_path): + empty = tmp_path / "empty" + empty.mkdir() + with pytest.raises(ValueError, match="missing config.json"): + detect_member(empty) + foreign = tmp_path / "foreign" + foreign.mkdir() + (foreign / "config.json").write_text(json.dumps({"model_type": "vela2-unified-xl"})) + with pytest.raises(ValueError, match="vela2-unified-xl"): + detect_member(foreign) + broken = tmp_path / "broken" + broken.mkdir() + (broken / "config.json").write_text("{not json") + with pytest.raises(ValueError, match="not readable JSON"): + detect_member(broken) + array = tmp_path / "array" + array.mkdir() + (array / "config.json").write_text("[]") + with pytest.raises(ValueError, match="not a JSON object"): + detect_member(array) + + +def test_models_entry_is_verbatim_per_member(): + hybrid = models_entry(FakeVela2Hybrid()) + assert hybrid == { + "name": EXPECTED_MODEL_NAME, + "release_date": "", + "description": ( + "Vela 2.0 0.8B: SystemOne Choice / Noul / Score " + "with span and set extensions, 16,384-token input" + ), + } + assert models_entry(FakeVela2())["release_date"] == "2026-09-29" + + +# -------------------------------------------------------- response finishing + + +def test_decide_answers_all_five_kinds_with_span_heads(): + response = decide(json.dumps(hybrid_body()).encode(), FakeVela2Hybrid()) + assert set(response) == {"model", "answers", "usage", "spans", "sets", "thresholds", "span_heads"} + assert list(response["span_heads"]) == ["unsupported"] + assert response["model"] == EXPECTED_MODEL_NAME + + +def test_decide_accepts_a_hybrid_response_without_span_questions(): + value = body(model=EXPECTED_MODEL_NAME) + response = decide(json.dumps(value).encode(), FakeVela2Hybrid()) + assert "span_heads" not in response and "spans" not in response + + +def test_a_hybrid_response_missing_span_heads_is_refused(): + class Headless(FakeVela2Hybrid): + def system_one(self, body): + response = super().system_one(body) + response.pop("span_heads", None) + return response + + with pytest.raises(RuntimeError, match="span_heads do not match"): + decide(json.dumps(hybrid_body()).encode(), Headless()) + + +def test_a_hybrid_response_with_stray_span_heads_is_refused(): + class Stray(FakeVela2Hybrid): + def system_one(self, body): + response = super().system_one(body) + response["span_heads"] = {"ghost": "router"} + return response + + with pytest.raises(RuntimeError, match="span_heads without span questions"): + decide(json.dumps(body(model=EXPECTED_MODEL_NAME)).encode(), Stray()) + + +def test_the_unified_member_still_refuses_span_heads(): + class UnifiedLeak(FakeVela2): + def system_one(self, body): + response = super().system_one(body) + if "spans" in response: + response["span_heads"] = {qid: "router" for qid in response["spans"]} + return response + + with pytest.raises(RuntimeError, match="this worker serves the 0.3B member"): + decide(json.dumps(five_kind_body()).encode(), UnifiedLeak()) + + +def test_finish_response_keeps_the_hybrid_envelope_tight(): + questions = hybrid_body()["questions"] + response = FakeVela2Hybrid().system_one(hybrid_body()) + assert finish_response(questions, response, hybrid=True) is response + del response["answers"] + with pytest.raises(RuntimeError, match="unexpected response envelope"): + finish_response(questions, response, hybrid=True) diff --git a/tests/vela/test_oracle_hybrid_fixtures.py b/tests/vela/test_oracle_hybrid_fixtures.py new file mode 100644 index 00000000..6f3fc1c6 --- /dev/null +++ b/tests/vela/test_oracle_hybrid_fixtures.py @@ -0,0 +1,64 @@ +"""Ties the frozen hybrid oracle fixtures to the recipe examples they came from. + +Mirrors test_oracle_fixtures (the 0.3B tie) for the 0.8B hybrid fixtures +recorded by ``recipe/vela/compare_reference.py`` under the +``oracle-hybrid-`` prefix. Each fixture's ``request`` is the recipe's +example request with the ``model`` field rewritten to the hybrid's +served name (the comparison tool does exactly this rewrite for file +cases), and its recorded ``system_one`` response passes the worker's +own response gate on the hybrid setting. No weights, no torch. +""" + +from __future__ import annotations + +import json +from pathlib import Path + +import pytest + +from models.vela.hybrid import EXPECTED_MODEL_NAME +from models.vela.postprocess import finish_response + +TESTS = Path(__file__).parent +RECIPE = TESTS.parent.parent / "recipe" / "vela" + +CASES = [ + ("oracle-hybrid-example-request", "example-request.json"), + ("oracle-hybrid-example-request-cjk", "example-request-cjk.json"), + ("oracle-hybrid-example-request-set-threshold", "example-request-set-threshold.json"), + ("oracle-hybrid-example-request-score", "example-request-score.json"), +] + + +def oracle(case: str) -> dict: + return json.loads((TESTS / "fixtures" / f"{case}.json").read_text()) + + +def recipe_body(example: str) -> dict: + body = json.loads((RECIPE / example).read_text()) + # The tool's load_cases rewrite for file cases: the examples are + # member-agnostic apart from the model field. + return {**body, "model": EXPECTED_MODEL_NAME} + + +@pytest.mark.parametrize("case,example", CASES) +def test_the_oracle_request_is_the_recipe_example(case: str, example: str): + recorded = oracle(case) + served = recipe_body(example) + assert recorded["request"] == served + # Same insertion order, so byte-for-byte serialization holds too. + assert list(recorded["request"]) == list(served) + + +@pytest.mark.parametrize("case,example", CASES) +def test_the_recorded_response_passes_the_worker_gate(case: str, example: str): + recorded = oracle(case) + response = recorded["system_one"] + assert response["model"] == EXPECTED_MODEL_NAME + assert finish_response(recorded["request"]["questions"], response, hybrid=True) is response + if any(q.get("type") == "span" for q in recorded["request"]["questions"].values()): + assert set(response["span_heads"]) == { + qid for qid, q in recorded["request"]["questions"].items() if q.get("type") == "span" + } + # The frozen case label still names the recipe file it belongs to. + assert recorded["case"] == example.removesuffix(".json") diff --git a/tests/vela/test_worker_server.py b/tests/vela/test_worker_server.py index ce2d106b..9221a933 100644 --- a/tests/vela/test_worker_server.py +++ b/tests/vela/test_worker_server.py @@ -292,3 +292,51 @@ def test_the_correct_bearer_answers_normally(keyed_server): headers=(("Authorization", "Bearer secret-key"),), ) assert status == 200 and json.loads(raw)["answers"]["billing"] == {"type": "noul", "noul": 0.75} + + +@pytest.fixture() +def hybrid_server(): + from .test_hybrid import FakeVela2Hybrid, hybrid_body + + instance = start(FakeVela2Hybrid()) + yield instance, hybrid_body() + stop(instance) + + +def test_the_hybrid_member_serves_its_own_models_entry(hybrid_server): + server, _ = hybrid_server + status, _, raw = request(server, "GET", "/v1/models") + assert status == 200 + assert json.loads(raw) == { + "models": [ + { + "name": "vllm-sr/Vela-2.0-0.8B", + "release_date": "", + "description": ( + "Vela 2.0 0.8B: SystemOne Choice / Noul / Score " + "with span and set extensions, 16,384-token input" + ), + } + ] + } + + +def test_the_hybrid_member_answers_all_five_kinds_with_span_heads(hybrid_server): + server, hybrid_body = hybrid_server + status, ctype, raw = post(server, json.dumps(hybrid_body).encode("utf-8")) + assert status == 200 and ctype == "application/json" + response = json.loads(raw) + assert response["model"] == "vllm-sr/Vela-2.0-0.8B" + assert set(response) == { + "model", "answers", "usage", "spans", "sets", "thresholds", "span_heads" + } + assert list(response["span_heads"]) == ["unsupported"] + assert response["answers"]["unsupported"] == {"type": "noul", "noul": 0.9} + + +def test_the_hybrid_member_rejects_another_model_name(hybrid_server): + server, _ = hybrid_server + wrong = body(model="vllm-sr/Vela-2.0-0.3B") + status, _, raw = post(server, json.dumps(wrong).encode("utf-8")) + assert status == 422 + assert json.loads(raw)["detail"][0]["type"] == "value_error.model" From 739e5ff6fe1f17749b258b34fd7c04f06ddb9f05 Mon Sep 17 00:00:00 2001 From: "Mr.Dong" <1042542469@qq.com> Date: Sun, 25 Oct 2026 02:32:35 +0800 Subject: [PATCH 02/14] vela: add the 0.8B native bundle export, manifest gate and wire contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - recipe/vela/export_native.py: gate-verified export into a native bundle — 320 backbone tensors re-keyed backbone. -> model. with per-tensor dtypes preserved (204 BF16 Linear/conv1d + 116 F32), the 37 F32 heads incl. the side-loaded broad span head in one file, backbone_config at the config root (the family Config::load shape), and a manifest pinning the source revision, the gate table, the tensor inventory and every bundle file's SHA-256. - src/models/vela/native (omni-vela-native): the bundle manifest gate and the wire admission mirroring protocol.py and the pinned runtime's preamble with byte-equal 422/400 bodies. - recipe/vela/export_token_plan.py and five frozen token plans under tests/vela/fixtures/: the predict mapping, the row decomposition and the rendered records (p_ids, blocks, readout positions, truncation, a windowed long-span case); example-request totals 1,041 tokens, matching the oracle's usage. Checks: cargo test (15 tests, no weights, no GPU), fmt/clippy clean, mkdocs --strict. --- Cargo.lock | 186 +++++++++--------- Cargo.toml | 2 +- README.md | 2 +- docs/supported-models.md | 2 +- mkdocs.yml | 1 + recipe/vela/export_native.py | 168 ++++++++++++++++ recipe/vela/export_token_plan.py | 153 ++++++++++++++ recipe/vela/native.md | 49 +++++ src/models/vela/README.md | 26 +++ src/models/vela/native/Cargo.toml | 26 +++ src/models/vela/native/src/bundle.rs | 112 +++++++++++ src/models/vela/native/src/contract.rs | 142 +++++++++++++ src/models/vela/native/src/lib.rs | 5 + .../native-plan-example-request-cjk.json | 1 + .../native-plan-example-request-score.json | 1 + ...ve-plan-example-request-set-threshold.json | 1 + .../fixtures/native-plan-example-request.json | 1 + .../native-plan-long-span-windowed.json | 1 + tests/vela/native_bundle.rs | 111 +++++++++++ tests/vela/native_contract.rs | 122 ++++++++++++ 20 files changed, 1021 insertions(+), 91 deletions(-) create mode 100644 recipe/vela/export_native.py create mode 100644 recipe/vela/export_token_plan.py create mode 100644 recipe/vela/native.md create mode 100644 src/models/vela/native/Cargo.toml create mode 100644 src/models/vela/native/src/bundle.rs create mode 100644 src/models/vela/native/src/contract.rs create mode 100644 src/models/vela/native/src/lib.rs create mode 100644 tests/vela/fixtures/native-plan-example-request-cjk.json create mode 100644 tests/vela/fixtures/native-plan-example-request-score.json create mode 100644 tests/vela/fixtures/native-plan-example-request-set-threshold.json create mode 100644 tests/vela/fixtures/native-plan-example-request.json create mode 100644 tests/vela/fixtures/native-plan-long-span-windowed.json create mode 100644 tests/vela/native_bundle.rs create mode 100644 tests/vela/native_contract.rs diff --git a/Cargo.lock b/Cargo.lock index 65562b9e..2a269f64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -199,9 +199,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.4.7" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54413ede23c2daf518f35156dfde027feb2374004d63bd497f983c8db9c0e313" +checksum = "86e055fa6e3e40ad6187ba25b6855eeb635d5271f8e0f0e1e9a5826b8d75bea0" dependencies = [ "find-msvc-tools", "shlex", @@ -271,9 +271,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78" +checksum = "0ba106e844045ddc02c20768ac4b0b7cb45f2cc2ecbd833ac9f5dacb183c2055" dependencies = [ "cfg-if", ] @@ -438,20 +438,20 @@ checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] name = "either" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" [[package]] name = "equivalent" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" [[package]] name = "errno" @@ -497,9 +497,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.13" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25905e51abafe4dcea6c15fec58c57b601cdbd0ee53d22ea1d3016c587d39b" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" [[package]] name = "flate2" @@ -563,7 +563,7 @@ checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -729,13 +729,12 @@ dependencies = [ [[package]] name = "hyper" -version = "1.11.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43" +checksum = "2c3e324da4c95177d6291d4c8730197c0d1822f8a9766814a4a44fa5ab797c9c" dependencies = [ "atomic-waker", "bytes", - "futures-channel", "futures-core", "http", "http-body", @@ -790,9 +789,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +checksum = "fe090a42a0d3140fed8c63263ed1fecc02422cb2f4bfe55cd8de2de1b8e105dd" dependencies = [ "displaydoc", "potential_utf", @@ -804,9 +803,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +checksum = "25d29b57c17c6528d0dc4c2141cfa2d08200465acb537a3909c8b9b8a4a984c0" dependencies = [ "displaydoc", "litemap", @@ -817,9 +816,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +checksum = "404a3b8c486f205c87fe7f23ab6894d84a4ad76d6e4671ae1981ba7def87c599" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -831,15 +830,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" +checksum = "20f0088bfb7441f7a37fa0c9e20cb1e9cba1cac6b9ce8cd2a6dc44294f8e8cbc" [[package]] name = "icu_properties" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +checksum = "2ea83d991c56158f7cf898bf86436c1dfe7c07ee82fe88951f2695c9f37a379f" dependencies = [ "displaydoc", "icu_collections", @@ -852,15 +851,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" +checksum = "b98f29af82d02b163fe50161388350e743bb3107cc8e8c2f7314cb505faddfcf" [[package]] name = "icu_provider" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +checksum = "413099315636c588ee8f011190b329b971a09a8fae9d157e01dcae8379468514" dependencies = [ "displaydoc", "icu_locale_core", @@ -957,9 +956,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.189" +version = "0.2.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" [[package]] name = "libloading" @@ -1031,9 +1030,9 @@ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memmap2" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +checksum = "6b0ca1155a9ecc25aa12e8313a119f32edf0255fea2f44839c4ac0a12b2ac157" dependencies = [ "libc", ] @@ -1072,9 +1071,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" +checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee" dependencies = [ "libc", "wasi", @@ -1216,7 +1215,7 @@ dependencies = [ "omni-runtime", "safetensors 0.8.0", "serde_json", - "sha2 0.11.0", + "sha2 0.11.1", "tempfile", "tokenizers 0.22.2", "tokio", @@ -1290,6 +1289,16 @@ dependencies = [ "tokio", ] +[[package]] +name = "omni-vela-native" +version = "0.1.0" +dependencies = [ + "anyhow", + "omni-qwen3-5-native", + "serde_json", + "sha2 0.11.1", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -1416,9 +1425,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.18" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9746dbde176634f4f2f1faf2404e30a31b2bc1e9cafb5329c95d8177a18c9fc" +checksum = "0e750cca55fe4f0439a15d0bb529da9651e79993e8e72c61a899a36d462befbe" dependencies = [ "bytes", "getrandom 0.4.3", @@ -1438,9 +1447,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +checksum = "af66907df18639dcf4db56ca65490cabc4b27a97dbadd96f2926cca73298f016" dependencies = [ "cfg_aliases", "libc", @@ -1663,9 +1672,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.45" +version = "0.23.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" dependencies = [ "once_cell", "ring", @@ -1687,9 +1696,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.15" +version = "0.103.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281" dependencies = [ "ring", "rustls-pki-types", @@ -1758,15 +1767,16 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ + "foldhash", "indexmap", "itoa", "memchr", @@ -1811,9 +1821,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +checksum = "47d7069beb7d6ac7b9acd1039986e73443f24234f41074da099d6f994ac9ad19" dependencies = [ "cfg-if", "cpufeatures 0.3.1", @@ -1850,9 +1860,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.16.2" +version = "1.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e" +checksum = "d0d5d4b1981b8bbbb7aed204cae5726d683d5d6ac7e74ec54122ea28f315e7c8" [[package]] name = "socket2" @@ -1913,9 +1923,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.6" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -1939,7 +1949,7 @@ checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] @@ -1972,14 +1982,14 @@ checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] name = "tinystr" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a" dependencies = [ "displaydoc", "zerovec", @@ -2059,9 +2069,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.53.1" +version = "1.54.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +checksum = "b52fd3255258d26fac7264ab5a76b53c13367136dc011d3d6ad4f8ed070396a3" dependencies = [ "bytes", "libc", @@ -2081,14 +2091,14 @@ checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] name = "tokio-rustls" -version = "0.26.5" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67" +checksum = "c9cc2678c2cdd569ef8215e2afd7954ada2ae20b4fdd2c5fe6139a3b02d105db" dependencies = [ "rustls", "tokio", @@ -2096,9 +2106,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.19" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +checksum = "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b" dependencies = [ "bytes", "futures-core", @@ -2187,9 +2197,9 @@ checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unicode-ident" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "unicode-normalization-alignments" @@ -2244,9 +2254,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "want" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +checksum = "ec4cdd0dd910afe868b7ef477227d8d538b46b3075031afee8a9f2acb0a2ed0b" dependencies = [ "try-lock", ] @@ -2309,7 +2319,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", "wasm-bindgen-shared", ] @@ -2357,9 +2367,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +checksum = "f5f280bbb2b287bc8e7de7e3852945a0ff50d1bbcb5ed42b6c7a568c546df171" dependencies = [ "rustls-pki-types", ] @@ -2466,9 +2476,9 @@ checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "yoke" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -2477,30 +2487,30 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.59" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df92bf3d9227be3d53173901ddbffac2babc27ae50f397776ffd6dc33f800cb" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.59" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac4f328cf2f05d084e496c3e9c3f33ed0a183656a16e1fcec4d464d8373aec82" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" dependencies = [ "proc-macro2", "quote", @@ -2524,15 +2534,15 @@ checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", "synstructure", ] [[package]] name = "zeroize" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879" [[package]] name = "zerotrie" @@ -2547,9 +2557,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" dependencies = [ "yoke", "zerofrom", @@ -2558,13 +2568,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.9", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 580fbee2..221eabfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = ["src/frontend", "src/runtime", "src/models/clm", "src/models/cua_s1/native", "src/models/qwen3_5/native", "src/models/open_jev/native", "src/models/jev_vl/native", "src/models/omnijev/native", "src/models/laya", "src/backends/cuda", "src/models/decider/native"] +members = ["src/frontend", "src/runtime", "src/models/clm", "src/models/cua_s1/native", "src/models/qwen3_5/native", "src/models/open_jev/native", "src/models/jev_vl/native", "src/models/omnijev/native", "src/models/laya", "src/backends/cuda", "src/models/decider/native", "src/models/vela/native"] resolver = "3" diff --git a/README.md b/README.md index 88129980..cbfce500 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ extensions) on each checkpoint's own pinned runtime: | OmniJev-4B v1.1 | [Checkpoint export and CPU contract](recipe/omnijev/README.md) only; the native worker is in progress ([#114](https://github.com/ThinkFlowLab/system1-omni/issues/114)) | | D3 (Decision 3.0) | [Python reference worker](recipe/d3/reference.md) on the checkpoint's pinned runtime; `choice`/`noul`/`score` text state, media inputs refused; author-run on A100 (evidence in the integration PR) | | Vela 2.0 0.3B | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; all five kinds (`choice`/`noul`/`score`/`span`/`set`) for text state; CPU FP32 validated (author-run, evidence in the integration PR) | -| Vela 2.0 0.8B hybrid | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; same surface plus `span_heads`; CPU FP32 parity recorded in the integration PR | +| Vela 2.0 0.8B hybrid | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; same surface plus `span_heads`; [native library](recipe/vela/native.md) (bundle export, wire contract); CPU FP32 parity recorded in the integration PR | [Supported models and hardware](docs/supported-models.md) lists the devices and where each worker has been run. diff --git a/docs/supported-models.md b/docs/supported-models.md index 52b31a0b..30a52c6b 100644 --- a/docs/supported-models.md +++ b/docs/supported-models.md @@ -25,7 +25,7 @@ Models that are being added are also tracked in issues labeled [new model](https | OmniJev-4B v1.1 | None yet: [checkpoint export and CPU contract](../recipe/omnijev/README.md); the native worker is in progress ([#114](https://github.com/ThinkFlowLab/system1-omni/issues/114)) | Request contract, preparation, heads and finishing checked against the reference ([#120](https://github.com/ThinkFlowLab/system1-omni/pull/120)); no inference | Not yet | Not supported | Python 3.10 reference environment for the export and fixtures | | D3 (Decision 3.0) | [Python reference worker](../recipe/d3/reference.md) running the checkpoint's pinned runtime | Unverified | Author-run on NVIDIA A100 (sm_80): three-kind serving smoke with byte-identical frontend forwarding and reference parity (exact decisions, max delta 0.0, 348 == 348 tokens); evidence in the integration PR. Owner: @MrDongsls. | Unverified | Python 3.12, the [pinned runtime requirements](../recipe/d3/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/d3) (~52 GB) | | Vela 2.0 0.3B | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime | **CPU FP32 validated** (author-run, x86 WSL2, 24 cores): startup with all-kind warmup, the four example requests plus five synthetic rejections, and exact-match reference parity against the pinned upstream server on all nine (four 200s byte-equal incl. key order, agreed 422/413); byte-identical frontend forwarding; evidence in the integration PR. Owner: @MrDongsls. | Unverified (bf16-autocast is an untested deployment option) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.3B) (1.24 GB FP32 weights; ~4.4 GB with ONNX/assets) | -| Vela 2.0 0.8B hybrid | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime (same wire layer as 0.3B) | Same surface as 0.3B plus the `span_heads` field (router/broad dispatch); **CPU FP32 parity** (author-run; evidence in the integration PR) | Unverified (bf16-autocast is the evaluated upstream setting but untested here) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) (2.02 GB shard + 4.5 MB broad head; ~3 GB FP32 parameters) | +| Vela 2.0 0.8B hybrid | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime (same wire layer as 0.3B); [native library](../recipe/vela/native.md) — bundle export, wire contract | Same surface as 0.3B plus the `span_heads` field (router/broad dispatch); **CPU FP32 parity** (author-run; evidence in the integration PR) | Unverified (bf16-autocast is the evaluated upstream setting but untested here) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) (2.02 GB shard + 4.5 MB broad head; ~3 GB FP32 parameters) | - **Validated:** covered by the recipe on `main` or by the checks in the linked merged pull request. - **Author-run:** recorded by the recipe author on the stated hardware and not independently reproduced; the row names its owner. diff --git a/mkdocs.yml b/mkdocs.yml index 8f2d39fe..d6593f4a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -77,4 +77,5 @@ nav: - LFM2.5-350M choice worker: recipe/lfm2/README.md - D3 reference worker: recipe/d3/reference.md - Vela 2.0 reference workers: recipe/vela/reference.md + - Vela 2.0 0.8B native library: recipe/vela/native.md - Contributing: CONTRIBUTING.md diff --git a/recipe/vela/export_native.py b/recipe/vela/export_native.py new file mode 100644 index 00000000..96e52ac6 --- /dev/null +++ b/recipe/vela/export_native.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +"""Export the pinned Vela 2.0 0.8B package into a native bundle. + +The bundle re-keys the hybrid +backbone for the shared qwen3_5 native loader — ``backbone.X`` tensors +become ``model.X`` (the loader's prefix probe accepts ``model.``), with +**per-tensor dtypes preserved verbatim** (Linear/conv1d in BF16, +embeddings/norms/A_log/dt_bias in FP32 — the reference's own mixed +layout, no re-save rounding) — and copies the Vela-owned F32 heads and +the side-loaded broad span head as separate files, plus calibration and +tokenizer. ``config.json`` is the package's ``backbone_config`` written +at the root, which is exactly the shape the family ``Config::load`` +reads. The manifest pins every source file by SHA-256 (re-using the +worker's own gate table) and records the exported tensor inventory. + + PYTHONPATH=src .venv/bin/python recipe/vela/export_native.py \ + --package weights/vela-2.0-0.8b --out weights/vela-2.0-0.8b-native +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import shutil +import sys +from pathlib import Path + +BACKBONE_PREFIX = "backbone." +HEAD_PREFIXES = ("head.", "span2.", "set_bias") +FORMAT = "vela2-native-bundle/1" + + +def parse_args(argv=None): + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("--package", required=True, help="pinned Vela 2.0 0.8B package directory") + parser.add_argument("--out", required=True, help="output bundle directory (created)") + parser.add_argument( + "--bf16-out", + default=None, + help="also write a uniform-BF16 backbone directory for the shared qwen3_5 " + "loader (model.safetensors + config.json)", + ) + return parser.parse_args(argv) + + +def sha256(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as stream: + for chunk in iter(lambda: stream.read(8 * 1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def main(argv=None) -> int: + args = parse_args(argv) + sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) + import torch + from safetensors.torch import load_file, save_file + + from models.vela.hybrid import ( + HYBRID_REPO, + HYBRID_REVISION, + PINNED_FILES_SHA256, + verify_package, + ) + + package = Path(args.package) + out = Path(args.out) + verify_package(package) # the worker's own gate: provenance before export + config = json.loads((package / "config.json").read_text(encoding="utf-8")) + backbone_config = config["backbone_config"] + + # The shard map names every backbone and head tensor; broad_head is a + # separate side-loaded file. + index = json.loads((package / "model.safetensors.index.json").read_text(encoding="utf-8")) + weight_map: dict[str, str] = index["weight_map"] + shard_files = sorted(set(weight_map.values())) + tensors = {} + for name in shard_files: + tensors.update(load_file(str(package / name))) + broad = load_file(str(package / "broad_head.safetensors")) + + backbone, heads = {}, {} + dtypes: dict[str, dict[str, str]] = {"backbone": {}, "heads": {}} + for name, tensor in sorted(weight_map.items()): + value = tensors[name] + dtype = str(value.dtype).removeprefix("torch.") + if name.startswith(BACKBONE_PREFIX): + rekeyed = "model." + name[len(BACKBONE_PREFIX):] + backbone[rekeyed] = value + dtypes["backbone"][rekeyed] = f"{dtype}:{list(value.shape)}" + elif name.startswith(HEAD_PREFIXES): + heads[name] = value + dtypes["heads"][name] = f"{dtype}:{list(value.shape)}" + else: + raise SystemExit(f"unexpected tensor key {name!r}; update the export for the new prefix") + for name, value in sorted(broad.items()): + heads[name] = value + dtypes["heads"][name] = f"{str(value.dtype).removeprefix('torch.')}:{list(value.shape)}" + + out.mkdir(parents=True, exist_ok=True) + save_file(backbone, str(out / "backbone.safetensors")) + save_file(heads, str(out / "heads.safetensors")) + # config.json for the family loader: backbone_config at the root. + (out / "config.json").write_text(json.dumps(backbone_config, indent=1) + "\n", encoding="utf-8") + for name in ("calibration.json", "tokenizer.json", "tokenizer_config.json"): + shutil.copyfile(package / name, out / name) + + bf16 = sum(1 for d in dtypes["backbone"].values() if d.startswith("bfloat16")) + fp32 = len(dtypes["backbone"]) - bf16 + manifest = { + "format": FORMAT, + "model_id": "vllm-sr/Vela-2.0-0.8B", + "model_name": config["model_name"], + "max_length": config["max_length"], + "description": config.get("description", ""), + "source": { + "repo": HYBRID_REPO, + "revision": HYBRID_REVISION, + # The worker gate's own table, re-verified above. + "pinned_files_sha256": dict(PINNED_FILES_SHA256), + "shard_files": shard_files, + }, + "backbone": { + "tensors": len(backbone), + "bf16": bf16, + "fp32": fp32, + "note": "per-tensor dtypes preserved from the package; backbone.X re-keyed to model.X", + "inventory": dtypes["backbone"], + }, + "heads": { + "tensors": len(heads), + "inventory": dtypes["heads"], + "note": "Vela-owned F32 heads (CandidateHead, set_bias, span2 router, span_broad) in one file", + }, + "files_sha256": {}, + } + for name in [ + "backbone.safetensors", "heads.safetensors", "config.json", + "calibration.json", "tokenizer.json", "tokenizer_config.json", + ]: + manifest["files_sha256"][name] = sha256(out / name) + (out / "vela_native_manifest.json").write_text( + json.dumps(manifest, indent=1, sort_keys=True) + "\n", encoding="utf-8" + ) + + if args.bf16_out: + # Uniform-BF16 re-save for the family crate's loader: every + # backbone tensor rounds to bfloat16 once, at export (the + # reference's own GPU setting runs the backbone under bf16 + # autocast too). + bf16_dir = Path(args.bf16_out) + bf16_dir.mkdir(parents=True, exist_ok=True) + uniform = {name: value.to(torch.bfloat16) for name, value in backbone.items()} + save_file(uniform, str(bf16_dir / "model.safetensors")) + (bf16_dir / "config.json").write_text(json.dumps(backbone_config, indent=1) + "\n", encoding="utf-8") + print(f"bf16 backbone: {len(uniform)} tensors -> {bf16_dir}") + + print(f"export ok: {out}") + print(f" backbone: {len(backbone)} tensors ({bf16} bf16, {fp32} fp32), re-keyed {BACKBONE_PREFIX} -> model.") + print(f" heads: {len(heads)} tensors (F32, incl. span_broad)") + print(f" config: backbone_config at root, model_type={backbone_config.get('model_type')}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/recipe/vela/export_token_plan.py b/recipe/vela/export_token_plan.py new file mode 100644 index 00000000..39bfb2ea --- /dev/null +++ b/recipe/vela/export_token_plan.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +"""Freeze the token-level row plan of the pinned Vela 2.0 0.8B runtime. + +This tool records, for a set of request +bodies, exactly what the pinned runtime feeds the backbone — the +SystemOne → predict mapping, the per-row decomposition (parts pass + +question blocks; one span question per row), and the rendered records +(``p_ids``, block token ids with option/label end positions, query +positions, span word positions, truncation and segment lengths). The +native Rust processor must reproduce these byte-for-byte; the frozen +files under ``tests/vela/fixtures/native-plan-*.json`` are that parity +target. Model outputs are not recorded here — the oracle fixtures from +``compare_reference.py`` own the output side. + + PYTHONPATH=src .venv/bin/python recipe/vela/export_token_plan.py \ + --model weights/vela-2.0-0.8b --out tests/vela/fixtures/ +""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path + +import numpy as np + +HERE = Path(__file__).resolve().parent +MODEL_NAME = "vllm-sr/Vela-2.0-0.8B" + + +def parse_args(argv=None): + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("--model", required=True, help="pinned Vela 2.0 0.8B package directory") + parser.add_argument("--out", default=None, help="fixture output directory") + return parser.parse_args(argv) + + +def long_span_body(): + """A span target beyond HYBRID_RMAX (2,048 tokens) to exercise the + windowed layout: the full-render span block is skipped and one row + per 1,800-token window (stride 1,536, cut at word starts) carries + the span question.""" + + filler = " ".join(f"Sentence {i} reports a routine delivery event." for i in range(220)) + return { + "model": MODEL_NAME, + "state": {"request": filler}, + "questions": { + "claims": { + "type": "span", + "instructions": "Which spans mention a delivery?", + "criteria": {"delivery": "a delivery event"}, + "over": "request", + } + }, + } + + +def cases(): + named = [ + ("example-request", HERE / "example-request.json"), + ("example-request-set-threshold", HERE / "example-request-set-threshold.json"), + ("example-request-cjk", HERE / "example-request-cjk.json"), + ("example-request-score", HERE / "example-request-score.json"), + ] + loaded = [ + ( + name, + {**json.loads(path.read_text(encoding="utf-8")), "model": MODEL_NAME}, + ) + for name, path in named + ] + loaded.append(("long-span-windowed", long_span_body())) + return loaded + + +def plain(value): + """numpy-free JSON for the rendered records.""" + + if isinstance(value, dict): + return {key: plain(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [plain(item) for item in value] + if isinstance(value, np.ndarray): + return plain(value.tolist()) + if isinstance(value, (np.integer,)): + return int(value) + if isinstance(value, (np.floating,)): + return float(value) + if isinstance(value, (np.bool_,)): + return bool(value) + return value + + +def rows_of(engine, body): + """Mirror ``Vela2._predict``'s row decomposition and render each row.""" + + from vela2_inference import system_one_to_predict + + req, plan = system_one_to_predict(body["state"], body["questions"]) + parts, qs, _thr = engine._to_generic(req) + spans = [q for q in qs if q["type"] == "span"] + rest = [q for q in qs if q["type"] != "span"] + rows = [dict(parts=parts, questions=rest + spans[:1])] + [ + dict(parts=parts, questions=[s]) for s in spans[1:] + ] + rendered, windows = [], [] + for row in rows: + if not row["questions"]: + continue + prepped = engine._prep(row) + rec = plain(engine._render(prepped)) + rec["head"] = prepped["head"] + rec["head_reason"] = prepped["head_reason"] + rendered.append(rec) + for wrow in engine._window_rows(prepped) or []: + wrec = plain(engine._render(wrow)) + wrec["head"] = prepped["head"] + windows.append(wrec) + return plain(req), plain(plan), rendered, windows + + +def main(argv=None) -> int: + args = parse_args(argv) + sys.path.insert(0, str(Path(args.model).resolve())) + from vela2_inference import Vela2 + + engine = Vela2.from_pretrained(args.model, backend="torch", device="cpu") + out = Path(args.out) if args.out else HERE.parents[1] / "tests" / "vela" / "fixtures" + out.mkdir(parents=True, exist_ok=True) + for name, body in cases(): + req, plan, rows, windows = rows_of(engine, body) + fixture = { + "case": name, + "request": body, + "predict_request": req, + "plan": plan, + "rows": rows, + "window_rows": windows, + } + target = out / f"native-plan-{name}.json" + target.write_text(json.dumps(fixture, ensure_ascii=False) + "\n", encoding="utf-8") + tokens = sum(r["n_tokens"] for r in rows) + sum(r["n_tokens"] for r in windows) + print( + f"{name}: {len(rows)} row(s) + {len(windows)} window row(s), " + f"{tokens} tokens -> {target.name}" + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/recipe/vela/native.md b/recipe/vela/native.md new file mode 100644 index 00000000..a9328003 --- /dev/null +++ b/recipe/vela/native.md @@ -0,0 +1,49 @@ +# Vela 2.0 0.8B native library + +The native implementation for +[vllm-sr/Vela-2.0-0.8B](https://huggingface.co/vllm-sr/Vela-2.0-0.8B): +the exported-bundle gate and the wire contract, mirrored from the +pinned runtime. This is a library; serving runs through the +[reference recipe](reference.md)'s Python worker. + +Run the commands from the repository root with the same `.venv` and +pinned package as the reference recipe. The export needs about 6 GB of +free disk next to the package; the checks need no GPU. + +## Export the native bundle + +~~~sh +PYTHONPATH=src .venv/bin/python recipe/vela/export_native.py \ + --package weights/vela-2.0-0.8b --out weights/vela-2.0-0.8b-native +~~~ + +The export re-runs the reference worker's package gate first +(provenance), then writes `weights/vela-2.0-0.8b-native/`: the backbone +re-keyed `backbone.` → `model.` with **per-tensor dtypes preserved** +(204 BF16 Linear/conv1d, 116 F32 embed/norms/A_log/dt_bias — the +reference's own mixed layout), the 37 F32 heads in `heads.safetensors` +(including the side-loaded broad span head), `backbone_config` at the +config root (the shared qwen3_5 `Config::load` shape), calibration and +tokenizer, and `vela_native_manifest.json` pinning the source +revision, the gate's file table, the tensor inventory and every file's +SHA-256. + +## Checks + +~~~sh +cargo test -p omni-vela-native +cargo fmt --all --check +cargo clippy -p omni-vela-native --all-targets -- -D warnings +~~~ + +15 tests, no weights, no GPU: the wire contract against the pinned +runtime's 422/400 bodies and the bundle manifest gate against a +synthetic bundle. + +## Scope and limits + +- Implemented: the bundle export + manifest gate and the wire + admission. +- Not implemented: token-level processing, the F32 heads, scoring, + backbone execution, and an HTTP worker. No performance claims are + made. diff --git a/src/models/vela/README.md b/src/models/vela/README.md index 9407d4fa..888658fc 100644 --- a/src/models/vela/README.md +++ b/src/models/vela/README.md @@ -225,3 +225,29 @@ the shared worker-contract issue, and nothing is posted upstream. a deployment option outside these slices' evidence. - The serving procedure, hardware requirements and the recorded evidence pointer are [recipe/vela/reference.md](../../recipe/vela/reference.md). + +## Native path (0.8B) + +The native implementation lives in [`native/`](native/) as the +`omni-vela-native` crate, a library around the exported bundle: + +- [`recipe/vela/export_native.py`](../../recipe/vela/export_native.py) + exports the pinned package into a native bundle: the 320 backbone + tensors re-keyed `backbone.` → `model.` with **per-tensor dtypes + preserved** (204 BF16 Linear/conv1d + 116 F32 embed/norms/A_log/ + dt_bias — the reference's own layout), the 37 F32 head tensors + (CandidateHead, `set_bias`, span2 router, span_broad) in one file, + `backbone_config` at the config root, calibration and tokenizer + copied, and a manifest pinning the source revision, the worker + gate's own file table, the tensor inventory and every bundle file's + SHA-256. +- `native/src/bundle.rs` re-verifies that manifest (revision, + inventory counts, per-file hashes) before anything loads it. +- `native/src/contract.rs` is the wire admission, mirroring + `protocol.py` and the pinned runtime's preamble with byte-equal + 422/400 bodies. + +Token-level processing, the F32 heads, backbone execution and an HTTP +worker are not implemented. Checks: `cargo test -p omni-vela-native` +(15 tests, no weights, no GPU; see +[recipe/vela/native.md](../../recipe/vela/native.md)). diff --git a/src/models/vela/native/Cargo.toml b/src/models/vela/native/Cargo.toml new file mode 100644 index 00000000..814d32b0 --- /dev/null +++ b/src/models/vela/native/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "omni-vela-native" +version = "0.1.0" +edition = "2024" +publish = false +description = "Native library for vllm-sr/Vela-2.0-0.8B: bundle gate and wire contract" + +[dependencies] +anyhow = "1.0.100" +omni-qwen3-5-native = { path = "../../qwen3_5/native" } +serde_json = { version = "1.0.149", features = ["preserve_order"] } +sha2 = "0.11" + +[dev-dependencies] +sha2 = "0.11" + +[lib] +path = "src/lib.rs" + +[[test]] +name = "vela_native_contract" +path = "../../../../tests/vela/native_contract.rs" + +[[test]] +name = "vela_native_bundle" +path = "../../../../tests/vela/native_bundle.rs" diff --git a/src/models/vela/native/src/bundle.rs b/src/models/vela/native/src/bundle.rs new file mode 100644 index 00000000..ce31f839 --- /dev/null +++ b/src/models/vela/native/src/bundle.rs @@ -0,0 +1,112 @@ +//! The exported native bundle's manifest gate. +//! +//! [`recipe/vela/export_native.py`](../../../recipe/vela/export_native.py) +//! produces the bundle from the pinned package; this module loads its +//! manifest, pins the source revision and the member's tensor +//! inventory, and re-hashes every bundle file before the (future) +//! executor touches it — the same provenance-before-import discipline +//! as the reference worker's package gate. + +use std::path::{Path, PathBuf}; + +use anyhow::{Context, Result, ensure}; +use serde_json::Value; + +pub const FORMAT: &str = "vela2-native-bundle/1"; +pub const MODEL_ID: &str = "vllm-sr/Vela-2.0-0.8B"; +pub const SOURCE_REVISION: &str = "326b01d81f61fff7fd4ae570e54b87a49119e490"; +/// This member's exported inventory, pinned from the pinned package: +/// 320 backbone tensors (204 BF16 Linear/conv1d + 116 F32) and 37 F32 +/// head tensors (CandidateHead, set_bias, span2 router, span_broad). +pub const BACKBONE_TENSORS: (usize, usize, usize) = (320, 204, 116); +pub const HEAD_TENSORS: usize = 37; + +#[derive(Debug)] +pub struct Bundle { + pub dir: PathBuf, + pub manifest: Value, +} + +impl Bundle { + /// Load and fully verify one exported bundle directory. + pub fn load(dir: &Path) -> Result { + let manifest: Value = serde_json::from_slice( + &std::fs::read(dir.join("vela_native_manifest.json")) + .context("export the pinned package first; see recipe/vela/export_native.py")?, + ) + .context("vela_native_manifest.json must be JSON")?; + ensure!( + manifest["format"] == FORMAT + && manifest["model_id"] == MODEL_ID + && manifest["source"]["revision"] == SOURCE_REVISION, + "expected a bundle exported from the pinned {MODEL_ID} package" + ); + let backbone = &manifest["backbone"]; + ensure!( + backbone["tensors"].as_u64() == Some(BACKBONE_TENSORS.0 as u64) + && backbone["bf16"].as_u64() == Some(BACKBONE_TENSORS.1 as u64) + && backbone["fp32"].as_u64() == Some(BACKBONE_TENSORS.2 as u64), + "unexpected backbone inventory; re-export from the pinned package" + ); + ensure!( + manifest["heads"]["tensors"].as_u64() == Some(HEAD_TENSORS as u64), + "unexpected head inventory; re-export from the pinned package" + ); + for (name, digest) in manifest["files_sha256"] + .as_object() + .context("files_sha256 must be an object")? + { + let actual = hash_file(&dir.join(name))?; + ensure!( + actual == digest.as_str().unwrap_or(""), + "{name} does not match the manifest SHA-256" + ); + } + ensure!( + manifest["max_length"].as_u64() == Some(16_384) + && manifest["model_name"].as_str() == Some(MODEL_ID), + "unexpected member identity in the manifest" + ); + Ok(Self { + dir: dir.to_owned(), + manifest, + }) + } + + /// The served model name (upstream: config.json `model_name`). + pub fn model_name(&self) -> &str { + self.manifest["model_name"].as_str().unwrap_or(MODEL_ID) + } + + /// The member's input window. + pub fn max_length(&self) -> usize { + self.manifest["max_length"].as_u64().unwrap_or(16_384) as usize + } +} + +fn hash_file(path: &Path) -> Result { + use anyhow::bail; + use sha2::{Digest, Sha256}; + use std::io::Read; + + let mut hasher = Sha256::new(); + let file = match std::fs::File::open(path) { + Ok(file) => file, + Err(error) => bail!("cannot read {}: {error}", path.display()), + }; + let mut reader = std::io::BufReader::new(file); + let mut chunk = vec![0u8; 8 * 1024 * 1024]; + loop { + let read = reader.read(&mut chunk)?; + if read == 0 { + break; + } + hasher.update(&chunk[..read]); + } + Ok(hex(&hasher.finalize())) +} + +/// Lower-hex of a digest; sha2 0.11's output has no `LowerHex` impl. +fn hex(bytes: &[u8]) -> String { + bytes.iter().map(|byte| format!("{byte:02x}")).collect() +} diff --git a/src/models/vela/native/src/contract.rs b/src/models/vela/native/src/contract.rs new file mode 100644 index 00000000..06a3de95 --- /dev/null +++ b/src/models/vela/native/src/contract.rs @@ -0,0 +1,142 @@ +//! Vela 2.0 wire admission for the native worker, mirroring +//! `models.vela.protocol` and the pinned runtime's request preamble so +//! clients cannot tell this layer from the reference worker: the +//! three-field envelope with upstream's exact `{"detail": [{"loc", +//! "msg", "type"}]}` triples, and the whole-request error model. +//! +//! Deeper validation — state rendering, question semantics, the 413 — +//! lives in the processing modules and mirrors the pinned runtime +//! against the `native-plan-*` fixtures. One known residual +//! difference: a non-finite JSON number answers the generic 400 +//! message here, where the Python worker names the value; duplicate +//! keys are mirrored verbatim. + +use serde_json::{Map, Value, json}; + +/// Slice-scoped transport cap, as on the reference worker. +pub const MAX_BODY: usize = 8 * 1024 * 1024; +/// The envelope fields, in upstream's missing-field check order. +pub const REQUEST_FIELDS: [&str; 3] = ["state", "model", "questions"]; + +/// A request rejection: an HTTP status and the JSON body a client sees. +#[derive(Debug, PartialEq)] +pub struct RequestError { + pub status: u16, + pub body: Value, +} + +impl RequestError { + fn detail(status: u16, message: &str) -> Self { + Self { + status, + body: json!({"detail": message}), + } + } + + /// One upstream `SystemOneError` as a whole-request 422 triple. + pub fn envelope(loc: &[&str], msg: &str, type_: &str) -> Self { + let mut path = vec![Value::from("body")]; + path.extend(loc.iter().map(|part| Value::from(*part))); + Self { + status: 422, + body: json!({"detail": [{"loc": path, "msg": msg, "type": type_}]}), + } + } +} + +/// Decode a bounded JSON body and reject ambiguous JSON values. +pub fn parse_body(raw: &[u8]) -> Result, RequestError> { + if raw.len() > MAX_BODY { + return Err(RequestError::detail(413, "request body exceeds 8 MiB")); + } + let message = + omni_qwen3_5_native::json::parse(raw).map_err(|error| normalize_parse_error(&error))?; + Ok(message) +} + +/// Mirror the reference worker's 400 messages: duplicate keys verbatim, +/// everything else the shared generic message. +fn normalize_parse_error(error: &str) -> RequestError { + if let Some(rest) = error.split("duplicate key ").nth(1) { + // serde appends its position suffix after the quoted key. + if let Some(key) = rest + .strip_prefix('"') + .and_then(|tail| tail.split('"').next()) + { + return RequestError::detail(400, &format!("duplicate JSON key '{key}'")); + } + } + RequestError::detail(400, "request body must contain valid JSON and UTF-8 text") +} + +/// Admit the envelope exactly as upstream's request preamble does, for +/// one served model name: the three required fields present, no extra +/// field, `model` non-blank and equal to the served name. +pub fn admit_request(body: &Map, served: &str) -> Result<(), RequestError> { + for field in REQUEST_FIELDS { + if !body.contains_key(field) { + return Err(RequestError::envelope( + &[field], + "Field required", + "missing", + )); + } + } + let mut extra: Vec<&String> = body + .keys() + .filter(|key| !REQUEST_FIELDS.contains(&key.as_str())) + .collect(); + extra.sort(); + if let Some(first) = extra.first() { + return Err(RequestError::envelope( + &[first], + "Extra inputs are not permitted", + "extra_forbidden", + )); + } + let model = body["model"].as_str().unwrap_or(""); + if model.trim().is_empty() { + return Err(RequestError::envelope( + &["model"], + "model must not be empty or whitespace", + "value_error", + )); + } + if model != served { + return Err(RequestError::envelope( + &["model"], + "Model is not served by this runtime", + "value_error.model", + )); + } + Ok(()) +} + +/// Admit one complete raw request body: parse, then envelope-check. +pub fn compile(raw: &[u8], served: &str) -> Result, RequestError> { + let body = parse_body(raw)?; + admit_request(&body, served)?; + Ok(body) +} + +/// A pinned-runtime `ValueError` rejection as the reference worker maps +/// it (`map_runtime_error`): a whole-request 422 naming the runtime. +pub fn runtime_rejection(message: &str) -> RequestError { + RequestError::detail( + 422, + &format!("request rejected by the pinned runtime: {message}"), + ) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn duplicate_keys_mirror_the_reference_message() { + let error = + normalize_parse_error("request body is not valid JSON: duplicate key \"state\""); + assert_eq!(error.status, 400); + assert_eq!(error.body, json!({"detail": "duplicate JSON key 'state'"})); + } +} diff --git a/src/models/vela/native/src/lib.rs b/src/models/vela/native/src/lib.rs new file mode 100644 index 00000000..32f64c4f --- /dev/null +++ b/src/models/vela/native/src/lib.rs @@ -0,0 +1,5 @@ +//! Native library for vllm-sr/Vela-2.0-0.8B: the exported-bundle gate +//! and the wire contract, mirrored from the pinned runtime. + +pub mod bundle; +pub mod contract; diff --git a/tests/vela/fixtures/native-plan-example-request-cjk.json b/tests/vela/fixtures/native-plan-example-request-cjk.json new file mode 100644 index 00000000..01973a26 --- /dev/null +++ b/tests/vela/fixtures/native-plan-example-request-cjk.json @@ -0,0 +1 @@ +{"case": "example-request-cjk", "request": {"model": "vllm-sr/Vela-2.0-0.8B", "state": {"request": "客户张伟(zhang.wei@example.cn)于2026年10月1日在上海市浦东新区世纪大道100号办理了业务,联系电话13800138000。", "source": "客户的业务申请需要在三个工作日内审核完成。", "answer": "客户的业务已经即时完成了。"}, "questions": {"pii": {"type": "span", "instructions": "Which spans are personal information?", "criteria": {"PERSON": "a person's name", "EMAIL_ADDRESS": "an e-mail address", "PHONE_NUMBER": "a telephone number", "STREET_ADDRESS": "a street address or postal address"}, "over": "request"}, "unsupported": {"type": "span", "instructions": "Which spans of the answer are not supported by the context?", "criteria": {"unsupported": "a claim not supported by the context"}}, "billing": {"type": "noul", "instructions": "这个请求是否与账单有关?"}}}, "predict_request": {"parts": [{"type": "user", "text": "客户张伟(zhang.wei@example.cn)于2026年10月1日在上海市浦东新区世纪大道100号办理了业务,联系电话13800138000。"}, {"type": "context", "text": "客户的业务申请需要在三个工作日内审核完成。"}, {"type": "answer", "text": "客户的业务已经即时完成了。"}], "questions": [{"id": "pii", "type": "span", "text": "Which spans are personal information?", "target_part": "user", "labels": [{"name": "PERSON", "description": "a person's name"}, {"name": "EMAIL_ADDRESS", "description": "an e-mail address"}, {"name": "PHONE_NUMBER", "description": "a telephone number"}, {"name": "STREET_ADDRESS", "description": "a street address or postal address"}]}, {"id": "unsupported", "type": "span", "text": "Which spans of the answer are not supported by the context?", "target_part": "answer", "labels": [{"name": "unsupported", "description": "a claim not supported by the context"}]}, {"id": "billing", "type": "choice", "text": "这个请求是否与账单有关?", "target_part": ["user", "context", "answer"], "options": [{"name": "no", "description": "No. The statement or question is not satisfied."}, {"name": "yes", "description": "Yes. The statement or question is satisfied."}]}]}, "plan": [{"qid": "pii", "type": "span", "criteria": {"PERSON": "a person's name", "EMAIL_ADDRESS": "an e-mail address", "PHONE_NUMBER": "a telephone number", "STREET_ADDRESS": "a street address or postal address"}, "range": [0, 75], "part": "user"}, {"qid": "unsupported", "type": "span", "criteria": {"unsupported": "a claim not supported by the context"}, "range": null, "part": "answer"}, {"qid": "billing", "type": "noul", "criteria": {}, "range": null, "part": ["user", "context", "answer"]}], "rows": [{"p_ids": [1905, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 96989, 138667, 9616, 89, 20032, 13, 26234, 34314, 21377, 7313, 95928, 17, 15, 17, 21, 95859, 16, 15, 96212, 16, 95971, 95772, 108914, 121458, 99524, 108611, 16, 15, 15, 96389, 134395, 97192, 3709, 108672, 16, 18, 23, 15, 15, 16, 18, 23, 15, 15, 15, 1710, 198, 510, 22446, 29, 198, 27, 22446, 3364, 420, 2078, 731, 198, 109480, 97192, 97379, 111341, 98868, 96069, 99671, 100616, 97235, 1710, 198, 510, 22446, 29, 198, 27, 22446, 3364, 420, 8944, 731, 198, 109480, 97192, 96790, 111267, 104154, 1710, 198, 510, 22446, 29, 198], "blocks": [{"kind": "q", "ids": [271, 6065, 913, 25, 5576, 198, 6196, 25, 1156, 11, 2193, 11, 4087, 198, 14162, 25, 198, 96488, 101729, 147343, 119526, 97495, 10992, 198, 3670, 25, 198, 13886, 29, 198, 4754, 4532, 3147, 2665, 13, 561, 4952, 466, 3296, 369, 524, 18933, 46292, 767, 3147, 2083, 8934, 198, 510, 1979, 29, 198, 13886, 29, 198, 4754, 4532, 3147, 9175, 13, 561, 4952, 466, 3296, 369, 18933, 46292, 767, 3147, 9405, 8934, 198, 510, 1979, 29, 198, 13886, 29, 198, 4754, 4532, 3147, 3928, 314, 279, 6625, 2519, 16298, 46292, 767, 3147, 58, 55553, 60, 8934, 198, 510, 1979, 29, 271, 3270, 279, 3074, 2904, 1786, 7021, 539, 279, 2193, 321, 10895, 13, 198, 72298, 25], "ends": [50, 74, 98], "query": 114, "qid": "billing", "qtype": "choice", "names": ["no", "yes"], "has_abs": true}, {"kind": "span", "ends": [41, 62, 82, 106], "label_ranges": [[22, 41], [42, 62], [63, 82], [83, 106]], "words_in_block": true, "ids": [271, 6065, 913, 25, 9111, 198, 6196, 25, 1156, 198, 14162, 25, 198, 22365, 42824, 513, 4204, 1928, 30, 198, 22933, 25, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 1637, 579, 803, 2129, 767, 3147, 89974, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 276, 378, 11139, 2534, 2129, 767, 3147, 34714, 19522, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 19919, 1324, 2129, 767, 3147, 72446, 18777, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 8329, 2534, 466, 38436, 2534, 2129, 767, 3147, 759, 54046, 19522, 8934, 198, 510, 1448, 29, 271, 1138, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 96989, 138667, 9616, 89, 20032, 13, 26234, 34314, 21377, 7313, 95928, 17, 15, 17, 21, 95859, 16, 15, 96212, 16, 95971, 95772, 108914, 121458, 99524, 108611, 16, 15, 15, 96389, 134395, 97192, 3709, 108672, 16, 18, 23, 15, 15, 16, 18, 23, 15, 15, 15, 1710, 198, 510, 22446, 29, 198, 271, 8679, 1396, 9111, 314, 279, 2100, 1414, 421, 22651, 799, 314, 279, 8928, 13, 198, 6205, 581, 25], "query": 187, "w_pos": [118, 118, 119, 119, 120, 121, 127, 128, 129, 133, 134, 136, 137, 138, 139, 140, 140, 140, 141, 141, 141, 141, 142, 142, 143, 143, 144, 147, 148, 148, 148, 149, 149, 150, 151, 151, 151, 151, 152, 163]}], "trunc": {"shrink_cut": 0, "protected_cut": 0}, "seg_lens": {"user": 46, "context": 10, "answer": 6}, "layout": "c", "names": ["PERSON", "EMAIL_ADDRESS", "PHONE_NUMBER", "STREET_ADDRESS"], "w_offs": [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 25], [25, 26], [26, 27], [27, 31], [31, 32], [32, 34], [34, 35], [35, 36], [36, 37], [37, 38], [38, 39], [39, 40], [40, 41], [41, 42], [42, 43], [43, 44], [44, 45], [45, 46], [46, 47], [47, 48], [48, 49], [49, 52], [52, 53], [53, 54], [54, 55], [55, 56], [56, 57], [57, 58], [58, 59], [59, 60], [60, 61], [61, 62], [62, 63], [63, 74], [74, 75]], "w_pos": [118, 118, 119, 119, 120, 121, 127, 128, 129, 133, 134, 136, 137, 138, 139, 140, 140, 140, 141, 141, 141, 141, 142, 142, 143, 143, 144, 147, 148, 148, 148, 149, 149, 150, 151, 151, 151, 151, 152, 163], "span_over": "user", "n_tokens": 404, "head": "router", "head_reason": "id"}, {"p_ids": [1905, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 96989, 138667, 9616, 89, 20032, 13, 26234, 34314, 21377, 7313, 95928, 17, 15, 17, 21, 95859, 16, 15, 96212, 16, 95971, 95772, 108914, 121458, 99524, 108611, 16, 15, 15, 96389, 134395, 97192, 3709, 108672, 16, 18, 23, 15, 15, 16, 18, 23, 15, 15, 15, 1710, 198, 510, 22446, 29, 198, 27, 22446, 3364, 420, 2078, 731, 198, 109480, 97192, 97379, 111341, 98868, 96069, 99671, 100616, 97235, 1710, 198, 510, 22446, 29, 198, 27, 22446, 3364, 420, 8944, 731, 198, 109480, 97192, 96790, 111267, 104154, 1710, 198, 510, 22446, 29, 198], "blocks": [{"kind": "span", "ends": [50], "label_ranges": [[28, 50]], "words_in_block": true, "ids": [271, 6065, 913, 25, 9111, 198, 6196, 25, 4087, 198, 14162, 25, 198, 22365, 42824, 314, 279, 4087, 513, 524, 7021, 539, 279, 2193, 30, 198, 22933, 25, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 3591, 524, 7021, 539, 279, 2193, 2129, 767, 3147, 78349, 8934, 198, 510, 1448, 29, 271, 1138, 25, 198, 27, 22446, 3364, 420, 8944, 731, 198, 109480, 97192, 96790, 111267, 104154, 1710, 198, 510, 22446, 29, 198, 271, 8679, 1396, 9111, 314, 279, 2100, 1414, 421, 22651, 799, 314, 279, 8928, 13, 198, 6205, 581, 25], "query": 91, "w_pos": [62, 62, 62, 63, 63, 64, 64, 65, 65, 66, 66, 66, 67]}], "trunc": {"shrink_cut": 0, "protected_cut": 0}, "seg_lens": {"user": 46, "context": 10, "answer": 6}, "layout": "c", "names": ["unsupported"], "w_offs": [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13]], "w_pos": [62, 62, 62, 63, 63, 64, 64, 65, 65, 66, 66, 66, 67], "span_over": "answer", "n_tokens": 193, "head": "router", "head_reason": "label_set"}], "window_rows": []} diff --git a/tests/vela/fixtures/native-plan-example-request-score.json b/tests/vela/fixtures/native-plan-example-request-score.json new file mode 100644 index 00000000..fc67c0f8 --- /dev/null +++ b/tests/vela/fixtures/native-plan-example-request-score.json @@ -0,0 +1 @@ +{"case": "example-request-score", "request": {"model": "vllm-sr/Vela-2.0-0.8B", "state": "Hello, I would like to check the status of my order. It has been five days and I have heard nothing back.", "questions": {"tone": {"type": "score", "instructions": "How formal is the message?", "criteria": ["casual", "neutral", "formal"]}, "urgency": {"type": "score", "instructions": "How urgently does the sender need a reply?", "criteria": ["no rush", "soon", "today", "immediately"]}}}, "predict_request": {"parts": [{"type": "user", "text": "Hello, I would like to check the status of my order. It has been five days and I have heard nothing back."}], "questions": [{"id": "tone", "type": "score", "text": "How formal is the message?", "target_part": "user", "options": ["casual", "neutral", "formal"]}, {"id": "urgency", "type": "score", "text": "How urgently does the sender need a reply?", "target_part": "user", "options": ["no rush", "soon", "today", "immediately"]}]}, "plan": [{"qid": "tone", "type": "score", "criteria": ["casual", "neutral", "formal"], "range": null, "part": "user"}, {"qid": "urgency", "type": "score", "criteria": ["no rush", "soon", "today", "immediately"], "range": null, "part": "user"}], "rows": [{"p_ids": [1905, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 9419, 11, 353, 1000, 1040, 310, 1716, 279, 2552, 314, 821, 1906, 13, 1049, 682, 978, 4097, 2756, 321, 353, 599, 6408, 4161, 1142, 13, 198, 510, 22446, 29, 198], "blocks": [{"kind": "q", "ids": [271, 6065, 913, 25, 5284, 198, 6196, 25, 1156, 198, 14162, 25, 198, 4199, 15440, 369, 279, 1876, 30, 198, 3670, 25, 198, 13886, 29, 198, 4754, 4532, 58719, 767, 3147, 23543, 899, 8934, 198, 510, 1979, 29, 198, 13886, 29, 198, 4754, 4532, 58719, 767, 3147, 57555, 8934, 198, 510, 1979, 29, 198, 13886, 29, 198, 4754, 4532, 58719, 767, 3147, 610, 278, 8934, 198, 510, 1979, 29, 271, 3270, 279, 3074, 2904, 1786, 7021, 539, 279, 2193, 321, 10895, 13, 198, 72298, 25], "ends": [37, 52, 68], "query": 84, "qid": "tone", "qtype": "score", "names": ["casual", "neutral", "formal"], "has_abs": false}, {"kind": "q", "ids": [271, 6065, 913, 25, 5284, 198, 6196, 25, 1156, 198, 14162, 25, 198, 4199, 74000, 1503, 279, 4495, 1144, 264, 9559, 30, 198, 3670, 25, 198, 13886, 29, 198, 4754, 4532, 58719, 767, 3147, 2083, 12601, 8934, 198, 510, 1979, 29, 198, 13886, 29, 198, 4754, 4532, 58719, 767, 3147, 63826, 8934, 198, 510, 1979, 29, 198, 13886, 29, 198, 4754, 4532, 58719, 767, 3147, 29129, 8934, 198, 510, 1979, 29, 198, 13886, 29, 198, 4754, 4532, 58719, 767, 3147, 316, 41763, 8934, 198, 510, 1979, 29, 271, 3270, 279, 3074, 2904, 1786, 7021, 539, 279, 2193, 321, 10895, 13, 198, 72298, 25], "ends": [40, 55, 70, 86], "query": 102, "qid": "urgency", "qtype": "score", "names": ["no rush", "soon", "today", "immediately"], "has_abs": false}], "trunc": {"shrink_cut": 0, "protected_cut": 0}, "seg_lens": {"user": 25}, "layout": null, "n_tokens": 228, "head": "router", "head_reason": null}], "window_rows": []} diff --git a/tests/vela/fixtures/native-plan-example-request-set-threshold.json b/tests/vela/fixtures/native-plan-example-request-set-threshold.json new file mode 100644 index 00000000..d0ea9b8f --- /dev/null +++ b/tests/vela/fixtures/native-plan-example-request-set-threshold.json @@ -0,0 +1 @@ +{"case": "example-request-set-threshold", "request": {"model": "vllm-sr/Vela-2.0-0.8B", "state": "My card was charged twice and the parcel never arrived.", "questions": {"issues": {"type": "set", "instructions": "Which issues does the customer report?", "criteria": {"billing": "payments, charges, refunds or invoices", "shipping": "delivery of an order or a parcel", "login": "signing in, passwords or account access"}, "threshold": 0.15}}}, "predict_request": {"parts": [{"type": "user", "text": "My card was charged twice and the parcel never arrived."}], "questions": [{"id": "issues", "type": "set", "text": "Which issues does the customer report?", "target_part": "user", "options": [{"name": "billing", "description": "payments, charges, refunds or invoices"}, {"name": "shipping", "description": "delivery of an order or a parcel"}, {"name": "login", "description": "signing in, passwords or account access"}], "threshold": 0.15}]}, "plan": [{"qid": "issues", "type": "set", "criteria": {"billing": "payments, charges, refunds or invoices", "shipping": "delivery of an order or a parcel", "login": "signing in, passwords or account access"}, "range": null, "part": "user"}], "rows": [{"p_ids": [1905, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 4888, 3575, 557, 11102, 10598, 321, 279, 28350, 2496, 11136, 13, 198, 510, 22446, 29, 198], "blocks": [{"kind": "q", "ids": [271, 6065, 913, 25, 716, 198, 6196, 25, 1156, 198, 14162, 25, 198, 22365, 4562, 1503, 279, 5813, 1830, 30, 198, 3670, 25, 198, 13886, 29, 198, 4754, 4532, 3147, 60917, 11, 9892, 11, 70057, 466, 61893, 2129, 767, 3147, 37355, 8934, 198, 510, 1979, 29, 198, 13886, 29, 198, 4754, 4532, 3147, 31320, 314, 449, 1906, 466, 264, 28350, 2129, 767, 3147, 25660, 8934, 198, 510, 1979, 29, 198, 13886, 29, 198, 4754, 4532, 3147, 7506, 286, 303, 11, 32599, 466, 2605, 2528, 2129, 767, 3147, 3547, 8934, 198, 510, 1979, 29, 271, 3270, 1396, 2904, 7021, 539, 279, 2193, 321, 10895, 13, 198, 72298, 25], "ends": [45, 68, 92], "query": 106, "qid": "issues", "qtype": "set", "names": ["billing", "shipping", "login"], "has_abs": false}], "trunc": {"shrink_cut": 0, "protected_cut": 0}, "seg_lens": {"user": 11}, "layout": null, "n_tokens": 133, "head": "router", "head_reason": null}], "window_rows": []} diff --git a/tests/vela/fixtures/native-plan-example-request.json b/tests/vela/fixtures/native-plan-example-request.json new file mode 100644 index 00000000..09bab119 --- /dev/null +++ b/tests/vela/fixtures/native-plan-example-request.json @@ -0,0 +1 @@ +{"case": "example-request", "request": {"model": "vllm-sr/Vela-2.0-0.8B", "state": {"request": "Hi, I'm Tom Baker (tom.baker@example.com). What is the maximum daily dose of paracetamol for an adult?", "source": "For adults, the maximum dose of paracetamol is 4 grams in 24 hours, taken as 500 mg to 1 g every 4 to 6 hours.", "answer": "Adults can take up to 6 grams of paracetamol in 24 hours, in doses of 500 mg to 1 g every 4 to 6 hours."}, "questions": {"pii": {"type": "span", "instructions": "Which spans are personal information?", "criteria": {"AGE": "a person's age", "CREDIT_CARD": "a payment card number", "DATE_TIME": "a date, time or date of birth", "DOMAIN_NAME": "an internet domain name or website address", "EMAIL_ADDRESS": "an e-mail address", "GPE": "a country, city, state or other geopolitical place", "IBAN_CODE": "an international bank account number (IBAN)", "IP_ADDRESS": "an IPv4 or IPv6 address", "NRP": "a nationality, religious or political group", "ORGANIZATION": "the name of a company, institution or other organisation", "PERSON": "a person's name", "PHONE_NUMBER": "a telephone number", "STREET_ADDRESS": "a street address or postal address", "TITLE": "a personal or professional title such as Dr. or Mrs.", "US_DRIVER_LICENSE": "a US driver's licence number", "US_SSN": "a US social security number", "ZIP_CODE": "a postal or ZIP code"}, "over": "request"}, "halu": {"type": "span", "instructions": "Which spans of the answer are not supported by the context?", "criteria": {"unsupported": "a claim not supported by the context"}}, "domain": {"type": "choice", "instructions": "Which subject area is this request about?", "over": "request", "criteria": {"health": "medicine, clinical practice, nutrition, ageing or sexual health", "math": "arithmetic, algebra, geometry, statistics or other mathematics", "other": "a subject that fits none of the listed areas"}}}}, "predict_request": {"parts": [{"type": "user", "text": "Hi, I'm Tom Baker (tom.baker@example.com). What is the maximum daily dose of paracetamol for an adult?"}, {"type": "context", "text": "For adults, the maximum dose of paracetamol is 4 grams in 24 hours, taken as 500 mg to 1 g every 4 to 6 hours."}, {"type": "answer", "text": "Adults can take up to 6 grams of paracetamol in 24 hours, in doses of 500 mg to 1 g every 4 to 6 hours."}], "questions": [{"id": "pii", "type": "span", "text": "Which spans are personal information?", "target_part": "user", "labels": [{"name": "AGE", "description": "a person's age"}, {"name": "CREDIT_CARD", "description": "a payment card number"}, {"name": "DATE_TIME", "description": "a date, time or date of birth"}, {"name": "DOMAIN_NAME", "description": "an internet domain name or website address"}, {"name": "EMAIL_ADDRESS", "description": "an e-mail address"}, {"name": "GPE", "description": "a country, city, state or other geopolitical place"}, {"name": "IBAN_CODE", "description": "an international bank account number (IBAN)"}, {"name": "IP_ADDRESS", "description": "an IPv4 or IPv6 address"}, {"name": "NRP", "description": "a nationality, religious or political group"}, {"name": "ORGANIZATION", "description": "the name of a company, institution or other organisation"}, {"name": "PERSON", "description": "a person's name"}, {"name": "PHONE_NUMBER", "description": "a telephone number"}, {"name": "STREET_ADDRESS", "description": "a street address or postal address"}, {"name": "TITLE", "description": "a personal or professional title such as Dr. or Mrs."}, {"name": "US_DRIVER_LICENSE", "description": "a US driver's licence number"}, {"name": "US_SSN", "description": "a US social security number"}, {"name": "ZIP_CODE", "description": "a postal or ZIP code"}]}, {"id": "halu", "type": "span", "text": "Which spans of the answer are not supported by the context?", "target_part": "answer", "labels": [{"name": "unsupported", "description": "a claim not supported by the context"}]}, {"id": "domain", "type": "choice", "text": "Which subject area is this request about?", "target_part": "user", "options": [{"name": "health", "description": "medicine, clinical practice, nutrition, ageing or sexual health"}, {"name": "math", "description": "arithmetic, algebra, geometry, statistics or other mathematics"}, {"name": "other", "description": "a subject that fits none of the listed areas"}]}]}, "plan": [{"qid": "pii", "type": "span", "criteria": {"AGE": "a person's age", "CREDIT_CARD": "a payment card number", "DATE_TIME": "a date, time or date of birth", "DOMAIN_NAME": "an internet domain name or website address", "EMAIL_ADDRESS": "an e-mail address", "GPE": "a country, city, state or other geopolitical place", "IBAN_CODE": "an international bank account number (IBAN)", "IP_ADDRESS": "an IPv4 or IPv6 address", "NRP": "a nationality, religious or political group", "ORGANIZATION": "the name of a company, institution or other organisation", "PERSON": "a person's name", "PHONE_NUMBER": "a telephone number", "STREET_ADDRESS": "a street address or postal address", "TITLE": "a personal or professional title such as Dr. or Mrs.", "US_DRIVER_LICENSE": "a US driver's licence number", "US_SSN": "a US social security number", "ZIP_CODE": "a postal or ZIP code"}, "range": [0, 102], "part": "user"}, {"qid": "halu", "type": "span", "criteria": {"unsupported": "a claim not supported by the context"}, "range": null, "part": "answer"}, {"qid": "domain", "type": "choice", "criteria": {"health": "medicine, clinical practice, nutrition, ageing or sexual health", "math": "arithmetic, algebra, geometry, statistics or other mathematics", "other": "a subject that fits none of the listed areas"}, "range": [0, 102], "part": "user"}], "rows": [{"p_ids": [1905, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 12675, 11, 353, 2688, 8105, 27466, 318, 36164, 918, 4263, 34314, 877, 553, 3437, 369, 279, 6966, 7071, 18537, 314, 1298, 64955, 235579, 364, 449, 6474, 30, 198, 510, 22446, 29, 198, 27, 22446, 3364, 420, 2078, 731, 198, 2381, 12236, 11, 279, 6966, 18537, 314, 1298, 64955, 235579, 369, 220, 19, 32216, 303, 220, 17, 19, 3979, 11, 4284, 430, 220, 20, 15, 15, 13348, 310, 220, 16, 338, 1396, 220, 19, 310, 220, 21, 3979, 13, 198, 510, 22446, 29, 198, 27, 22446, 3364, 420, 8944, 731, 198, 50281, 82, 628, 1831, 685, 310, 220, 21, 32216, 314, 1298, 64955, 235579, 303, 220, 17, 19, 3979, 11, 303, 32902, 314, 220, 20, 15, 15, 13348, 310, 220, 16, 338, 1396, 220, 19, 310, 220, 21, 3979, 13, 198, 510, 22446, 29, 198], "blocks": [{"kind": "q", "ids": [271, 6065, 913, 25, 5576, 198, 6196, 25, 1156, 198, 14162, 25, 198, 22365, 3704, 2982, 369, 411, 1622, 883, 30, 198, 3670, 25, 198, 13886, 29, 198, 4754, 4532, 3147, 79600, 11, 14075, 6380, 11, 24780, 11, 76242, 466, 7017, 2730, 2129, 767, 3147, 11776, 8934, 198, 510, 1979, 29, 198, 13886, 29, 198, 4754, 4532, 3147, 277, 25092, 11, 45309, 11, 16547, 11, 12760, 466, 975, 36352, 2129, 767, 3147, 10065, 8934, 198, 510, 1979, 29, 198, 13886, 29, 198, 4754, 4532, 3147, 64, 3704, 421, 17759, 6643, 314, 279, 9711, 5493, 2129, 767, 3147, 1520, 8934, 198, 510, 1979, 29, 198, 13886, 29, 198, 4754, 4532, 3147, 3928, 314, 279, 6625, 2519, 16298, 46292, 767, 3147, 58, 55553, 60, 8934, 198, 510, 1979, 29, 271, 3270, 279, 3074, 2904, 1786, 7021, 539, 279, 2193, 321, 10895, 13, 198, 72298, 25], "ends": [50, 77, 102, 126], "query": 142, "qid": "domain", "qtype": "choice", "names": ["health", "math", "other"], "has_abs": true}, {"kind": "span", "ends": [41, 63, 88, 112, 133, 160, 186, 210, 234, 262, 282, 302, 326, 353, 377, 400, 422], "label_ranges": [[22, 41], [42, 63], [64, 88], [89, 112], [113, 133], [134, 160], [161, 186], [187, 210], [211, 234], [235, 262], [263, 282], [283, 302], [303, 326], [327, 353], [354, 377], [378, 400], [401, 422]], "words_in_block": true, "ids": [271, 6065, 913, 25, 9111, 198, 6196, 25, 1156, 198, 14162, 25, 198, 22365, 42824, 513, 4204, 1928, 30, 198, 22933, 25, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 1637, 579, 4092, 2129, 767, 3147, 3466, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 7903, 3575, 1324, 2129, 767, 3147, 34, 54569, 44012, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 2321, 11, 854, 466, 2321, 314, 6968, 2129, 767, 3147, 6876, 9754, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 276, 7361, 7697, 803, 466, 3779, 2534, 2129, 767, 3147, 55214, 4556, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 276, 378, 11139, 2534, 2129, 767, 3147, 34714, 19522, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 3046, 11, 3177, 11, 1528, 466, 975, 83899, 1925, 2129, 767, 3147, 38, 1679, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 276, 6286, 5883, 2605, 1324, 318, 3151, 1058, 77039, 767, 3147, 3151, 1058, 9724, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 276, 30521, 19, 466, 30521, 21, 2534, 2129, 767, 3147, 3191, 19522, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 56284, 11, 10072, 466, 4788, 1809, 2129, 767, 3147, 45, 20993, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 1719, 803, 314, 264, 2724, 11, 14467, 466, 975, 20767, 2129, 767, 3147, 43433, 1058, 47383, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 1637, 579, 803, 2129, 767, 3147, 89974, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 19919, 1324, 2129, 767, 3147, 72446, 18777, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 8329, 2534, 466, 38436, 2534, 2129, 767, 3147, 759, 54046, 19522, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 4204, 466, 6376, 2192, 1680, 430, 2832, 13, 466, 17093, 46292, 767, 3147, 48639, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 2201, 5404, 579, 28995, 1324, 2129, 767, 3147, 1966, 42585, 55630, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 2201, 3471, 4610, 1324, 2129, 767, 3147, 1966, 1063, 18393, 8934, 198, 510, 1448, 29, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 38436, 466, 54778, 1970, 2129, 767, 3147, 59506, 9724, 8934, 198, 510, 1448, 29, 271, 1138, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 12675, 11, 353, 2688, 8105, 27466, 318, 36164, 918, 4263, 34314, 877, 553, 3437, 369, 279, 6966, 7071, 18537, 314, 1298, 64955, 235579, 364, 449, 6474, 30, 198, 510, 22446, 29, 198, 271, 8679, 1396, 9111, 314, 279, 2100, 1414, 421, 22651, 799, 314, 279, 8928, 13, 198, 6205, 581, 25], "query": 484, "w_pos": [434, 435, 436, 437, 437, 438, 439, 440, 441, 446, 446, 447, 448, 449, 450, 451, 452, 453, 454, 457, 458, 459, 460]}], "trunc": {"shrink_cut": 0, "protected_cut": 0}, "seg_lens": {"user": 27, "context": 39, "answer": 39}, "layout": "c", "names": ["AGE", "CREDIT_CARD", "DATE_TIME", "DOMAIN_NAME", "EMAIL_ADDRESS", "GPE", "IBAN_CODE", "IP_ADDRESS", "NRP", "ORGANIZATION", "PERSON", "PHONE_NUMBER", "STREET_ADDRESS", "TITLE", "US_DRIVER_LICENSE", "US_SSN", "ZIP_CODE"], "w_offs": [[0, 2], [2, 3], [4, 5], [5, 6], [6, 7], [8, 11], [12, 17], [18, 19], [19, 40], [40, 41], [41, 42], [43, 47], [48, 50], [51, 54], [55, 62], [63, 68], [69, 73], [74, 76], [77, 88], [89, 92], [93, 95], [96, 101], [101, 102]], "w_pos": [434, 435, 436, 437, 437, 438, 439, 440, 441, 446, 446, 447, 448, 449, 450, 451, 452, 453, 454, 457, 458, 459, 460], "span_over": "user", "n_tokens": 772, "head": "router", "head_reason": "id"}, {"p_ids": [1905, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 12675, 11, 353, 2688, 8105, 27466, 318, 36164, 918, 4263, 34314, 877, 553, 3437, 369, 279, 6966, 7071, 18537, 314, 1298, 64955, 235579, 364, 449, 6474, 30, 198, 510, 22446, 29, 198, 27, 22446, 3364, 420, 2078, 731, 198, 2381, 12236, 11, 279, 6966, 18537, 314, 1298, 64955, 235579, 369, 220, 19, 32216, 303, 220, 17, 19, 3979, 11, 4284, 430, 220, 20, 15, 15, 13348, 310, 220, 16, 338, 1396, 220, 19, 310, 220, 21, 3979, 13, 198, 510, 22446, 29, 198, 27, 22446, 3364, 420, 8944, 731, 198, 50281, 82, 628, 1831, 685, 310, 220, 21, 32216, 314, 1298, 64955, 235579, 303, 220, 17, 19, 3979, 11, 303, 32902, 314, 220, 20, 15, 15, 13348, 310, 220, 16, 338, 1396, 220, 19, 310, 220, 21, 3979, 13, 198, 510, 22446, 29, 198], "blocks": [{"kind": "span", "ends": [50], "label_ranges": [[28, 50]], "words_in_block": true, "ids": [271, 6065, 913, 25, 9111, 198, 6196, 25, 4087, 198, 14162, 25, 198, 22365, 42824, 314, 279, 4087, 513, 524, 7021, 539, 279, 2193, 30, 198, 22933, 25, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 3591, 524, 7021, 539, 279, 2193, 2129, 767, 3147, 78349, 8934, 198, 510, 1448, 29, 271, 1138, 25, 198, 27, 22446, 3364, 420, 8944, 731, 198, 50281, 82, 628, 1831, 685, 310, 220, 21, 32216, 314, 1298, 64955, 235579, 303, 220, 17, 19, 3979, 11, 303, 32902, 314, 220, 20, 15, 15, 13348, 310, 220, 16, 338, 1396, 220, 19, 310, 220, 21, 3979, 13, 198, 510, 22446, 29, 198, 271, 8679, 1396, 9111, 314, 279, 2100, 1414, 421, 22651, 799, 314, 279, 8928, 13, 198, 6205, 581, 25], "query": 124, "w_pos": [62, 64, 65, 66, 67, 69, 70, 71, 72, 75, 77, 79, 80, 81, 82, 83, 85, 88, 89, 91, 92, 93, 95, 96, 98, 99, 100]}], "trunc": {"shrink_cut": 0, "protected_cut": 0}, "seg_lens": {"user": 27, "context": 39, "answer": 39}, "layout": "c", "names": ["unsupported"], "w_offs": [[0, 6], [7, 10], [11, 15], [16, 18], [19, 21], [22, 23], [24, 29], [30, 32], [33, 44], [45, 47], [48, 50], [51, 56], [56, 57], [58, 60], [61, 66], [67, 69], [70, 73], [74, 76], [77, 79], [80, 81], [82, 83], [84, 89], [90, 91], [92, 94], [95, 96], [97, 102], [102, 103]], "w_pos": [62, 64, 65, 66, 67, 69, 70, 71, 72, 75, 77, 79, 80, 81, 82, 83, 85, 88, 89, 91, 92, 93, 95, 96, 98, 99, 100], "span_over": "answer", "n_tokens": 269, "head": "router", "head_reason": "id"}], "window_rows": []} diff --git a/tests/vela/fixtures/native-plan-long-span-windowed.json b/tests/vela/fixtures/native-plan-long-span-windowed.json new file mode 100644 index 00000000..0210fa02 --- /dev/null +++ b/tests/vela/fixtures/native-plan-long-span-windowed.json @@ -0,0 +1 @@ +{"case": "long-span-windowed", "request": {"model": "vllm-sr/Vela-2.0-0.8B", "state": {"request": "Sentence 0 reports a routine delivery event. Sentence 1 reports a routine delivery event. Sentence 2 reports a routine delivery event. Sentence 3 reports a routine delivery event. Sentence 4 reports a routine delivery event. Sentence 5 reports a routine delivery event. Sentence 6 reports a routine delivery event. Sentence 7 reports a routine delivery event. Sentence 8 reports a routine delivery event. Sentence 9 reports a routine delivery event. Sentence 10 reports a routine delivery event. Sentence 11 reports a routine delivery event. Sentence 12 reports a routine delivery event. Sentence 13 reports a routine delivery event. Sentence 14 reports a routine delivery event. Sentence 15 reports a routine delivery event. Sentence 16 reports a routine delivery event. Sentence 17 reports a routine delivery event. Sentence 18 reports a routine delivery event. Sentence 19 reports a routine delivery event. Sentence 20 reports a routine delivery event. Sentence 21 reports a routine delivery event. Sentence 22 reports a routine delivery event. Sentence 23 reports a routine delivery event. Sentence 24 reports a routine delivery event. Sentence 25 reports a routine delivery event. Sentence 26 reports a routine delivery event. Sentence 27 reports a routine delivery event. Sentence 28 reports a routine delivery event. Sentence 29 reports a routine delivery event. Sentence 30 reports a routine delivery event. Sentence 31 reports a routine delivery event. Sentence 32 reports a routine delivery event. Sentence 33 reports a routine delivery event. Sentence 34 reports a routine delivery event. Sentence 35 reports a routine delivery event. Sentence 36 reports a routine delivery event. Sentence 37 reports a routine delivery event. Sentence 38 reports a routine delivery event. Sentence 39 reports a routine delivery event. Sentence 40 reports a routine delivery event. Sentence 41 reports a routine delivery event. Sentence 42 reports a routine delivery event. Sentence 43 reports a routine delivery event. Sentence 44 reports a routine delivery event. Sentence 45 reports a routine delivery event. Sentence 46 reports a routine delivery event. Sentence 47 reports a routine delivery event. Sentence 48 reports a routine delivery event. Sentence 49 reports a routine delivery event. Sentence 50 reports a routine delivery event. Sentence 51 reports a routine delivery event. Sentence 52 reports a routine delivery event. Sentence 53 reports a routine delivery event. Sentence 54 reports a routine delivery event. Sentence 55 reports a routine delivery event. Sentence 56 reports a routine delivery event. Sentence 57 reports a routine delivery event. Sentence 58 reports a routine delivery event. Sentence 59 reports a routine delivery event. Sentence 60 reports a routine delivery event. Sentence 61 reports a routine delivery event. Sentence 62 reports a routine delivery event. Sentence 63 reports a routine delivery event. Sentence 64 reports a routine delivery event. Sentence 65 reports a routine delivery event. Sentence 66 reports a routine delivery event. Sentence 67 reports a routine delivery event. Sentence 68 reports a routine delivery event. Sentence 69 reports a routine delivery event. Sentence 70 reports a routine delivery event. Sentence 71 reports a routine delivery event. Sentence 72 reports a routine delivery event. Sentence 73 reports a routine delivery event. Sentence 74 reports a routine delivery event. Sentence 75 reports a routine delivery event. Sentence 76 reports a routine delivery event. Sentence 77 reports a routine delivery event. Sentence 78 reports a routine delivery event. Sentence 79 reports a routine delivery event. Sentence 80 reports a routine delivery event. Sentence 81 reports a routine delivery event. Sentence 82 reports a routine delivery event. Sentence 83 reports a routine delivery event. Sentence 84 reports a routine delivery event. Sentence 85 reports a routine delivery event. Sentence 86 reports a routine delivery event. Sentence 87 reports a routine delivery event. Sentence 88 reports a routine delivery event. Sentence 89 reports a routine delivery event. Sentence 90 reports a routine delivery event. Sentence 91 reports a routine delivery event. Sentence 92 reports a routine delivery event. Sentence 93 reports a routine delivery event. Sentence 94 reports a routine delivery event. Sentence 95 reports a routine delivery event. Sentence 96 reports a routine delivery event. Sentence 97 reports a routine delivery event. Sentence 98 reports a routine delivery event. Sentence 99 reports a routine delivery event. Sentence 100 reports a routine delivery event. Sentence 101 reports a routine delivery event. Sentence 102 reports a routine delivery event. Sentence 103 reports a routine delivery event. Sentence 104 reports a routine delivery event. Sentence 105 reports a routine delivery event. Sentence 106 reports a routine delivery event. Sentence 107 reports a routine delivery event. Sentence 108 reports a routine delivery event. Sentence 109 reports a routine delivery event. Sentence 110 reports a routine delivery event. Sentence 111 reports a routine delivery event. Sentence 112 reports a routine delivery event. Sentence 113 reports a routine delivery event. Sentence 114 reports a routine delivery event. Sentence 115 reports a routine delivery event. Sentence 116 reports a routine delivery event. Sentence 117 reports a routine delivery event. Sentence 118 reports a routine delivery event. Sentence 119 reports a routine delivery event. Sentence 120 reports a routine delivery event. Sentence 121 reports a routine delivery event. Sentence 122 reports a routine delivery event. Sentence 123 reports a routine delivery event. Sentence 124 reports a routine delivery event. Sentence 125 reports a routine delivery event. Sentence 126 reports a routine delivery event. Sentence 127 reports a routine delivery event. Sentence 128 reports a routine delivery event. Sentence 129 reports a routine delivery event. Sentence 130 reports a routine delivery event. Sentence 131 reports a routine delivery event. Sentence 132 reports a routine delivery event. Sentence 133 reports a routine delivery event. Sentence 134 reports a routine delivery event. Sentence 135 reports a routine delivery event. Sentence 136 reports a routine delivery event. Sentence 137 reports a routine delivery event. Sentence 138 reports a routine delivery event. Sentence 139 reports a routine delivery event. Sentence 140 reports a routine delivery event. Sentence 141 reports a routine delivery event. Sentence 142 reports a routine delivery event. Sentence 143 reports a routine delivery event. Sentence 144 reports a routine delivery event. Sentence 145 reports a routine delivery event. Sentence 146 reports a routine delivery event. Sentence 147 reports a routine delivery event. Sentence 148 reports a routine delivery event. Sentence 149 reports a routine delivery event. Sentence 150 reports a routine delivery event. Sentence 151 reports a routine delivery event. Sentence 152 reports a routine delivery event. Sentence 153 reports a routine delivery event. Sentence 154 reports a routine delivery event. Sentence 155 reports a routine delivery event. Sentence 156 reports a routine delivery event. Sentence 157 reports a routine delivery event. Sentence 158 reports a routine delivery event. Sentence 159 reports a routine delivery event. Sentence 160 reports a routine delivery event. Sentence 161 reports a routine delivery event. Sentence 162 reports a routine delivery event. Sentence 163 reports a routine delivery event. Sentence 164 reports a routine delivery event. Sentence 165 reports a routine delivery event. Sentence 166 reports a routine delivery event. Sentence 167 reports a routine delivery event. Sentence 168 reports a routine delivery event. Sentence 169 reports a routine delivery event. Sentence 170 reports a routine delivery event. Sentence 171 reports a routine delivery event. Sentence 172 reports a routine delivery event. Sentence 173 reports a routine delivery event. Sentence 174 reports a routine delivery event. Sentence 175 reports a routine delivery event. Sentence 176 reports a routine delivery event. Sentence 177 reports a routine delivery event. Sentence 178 reports a routine delivery event. Sentence 179 reports a routine delivery event. Sentence 180 reports a routine delivery event. Sentence 181 reports a routine delivery event. Sentence 182 reports a routine delivery event. Sentence 183 reports a routine delivery event. Sentence 184 reports a routine delivery event. Sentence 185 reports a routine delivery event. Sentence 186 reports a routine delivery event. Sentence 187 reports a routine delivery event. Sentence 188 reports a routine delivery event. Sentence 189 reports a routine delivery event. Sentence 190 reports a routine delivery event. Sentence 191 reports a routine delivery event. Sentence 192 reports a routine delivery event. Sentence 193 reports a routine delivery event. Sentence 194 reports a routine delivery event. Sentence 195 reports a routine delivery event. Sentence 196 reports a routine delivery event. Sentence 197 reports a routine delivery event. Sentence 198 reports a routine delivery event. Sentence 199 reports a routine delivery event. Sentence 200 reports a routine delivery event. Sentence 201 reports a routine delivery event. Sentence 202 reports a routine delivery event. Sentence 203 reports a routine delivery event. Sentence 204 reports a routine delivery event. Sentence 205 reports a routine delivery event. Sentence 206 reports a routine delivery event. Sentence 207 reports a routine delivery event. Sentence 208 reports a routine delivery event. Sentence 209 reports a routine delivery event. Sentence 210 reports a routine delivery event. Sentence 211 reports a routine delivery event. Sentence 212 reports a routine delivery event. Sentence 213 reports a routine delivery event. Sentence 214 reports a routine delivery event. Sentence 215 reports a routine delivery event. Sentence 216 reports a routine delivery event. Sentence 217 reports a routine delivery event. Sentence 218 reports a routine delivery event. Sentence 219 reports a routine delivery event."}, "questions": {"claims": {"type": "span", "instructions": "Which spans mention a delivery?", "criteria": {"delivery": "a delivery event"}, "over": "request"}}}, "predict_request": {"parts": [{"type": "user", "text": "Sentence 0 reports a routine delivery event. Sentence 1 reports a routine delivery event. Sentence 2 reports a routine delivery event. Sentence 3 reports a routine delivery event. Sentence 4 reports a routine delivery event. Sentence 5 reports a routine delivery event. Sentence 6 reports a routine delivery event. Sentence 7 reports a routine delivery event. Sentence 8 reports a routine delivery event. Sentence 9 reports a routine delivery event. Sentence 10 reports a routine delivery event. Sentence 11 reports a routine delivery event. Sentence 12 reports a routine delivery event. Sentence 13 reports a routine delivery event. Sentence 14 reports a routine delivery event. Sentence 15 reports a routine delivery event. Sentence 16 reports a routine delivery event. Sentence 17 reports a routine delivery event. Sentence 18 reports a routine delivery event. Sentence 19 reports a routine delivery event. Sentence 20 reports a routine delivery event. Sentence 21 reports a routine delivery event. Sentence 22 reports a routine delivery event. Sentence 23 reports a routine delivery event. Sentence 24 reports a routine delivery event. Sentence 25 reports a routine delivery event. Sentence 26 reports a routine delivery event. Sentence 27 reports a routine delivery event. Sentence 28 reports a routine delivery event. Sentence 29 reports a routine delivery event. Sentence 30 reports a routine delivery event. Sentence 31 reports a routine delivery event. Sentence 32 reports a routine delivery event. Sentence 33 reports a routine delivery event. Sentence 34 reports a routine delivery event. Sentence 35 reports a routine delivery event. Sentence 36 reports a routine delivery event. Sentence 37 reports a routine delivery event. Sentence 38 reports a routine delivery event. Sentence 39 reports a routine delivery event. Sentence 40 reports a routine delivery event. Sentence 41 reports a routine delivery event. Sentence 42 reports a routine delivery event. Sentence 43 reports a routine delivery event. Sentence 44 reports a routine delivery event. Sentence 45 reports a routine delivery event. Sentence 46 reports a routine delivery event. Sentence 47 reports a routine delivery event. Sentence 48 reports a routine delivery event. Sentence 49 reports a routine delivery event. Sentence 50 reports a routine delivery event. Sentence 51 reports a routine delivery event. Sentence 52 reports a routine delivery event. Sentence 53 reports a routine delivery event. Sentence 54 reports a routine delivery event. Sentence 55 reports a routine delivery event. Sentence 56 reports a routine delivery event. Sentence 57 reports a routine delivery event. Sentence 58 reports a routine delivery event. Sentence 59 reports a routine delivery event. Sentence 60 reports a routine delivery event. Sentence 61 reports a routine delivery event. Sentence 62 reports a routine delivery event. Sentence 63 reports a routine delivery event. Sentence 64 reports a routine delivery event. Sentence 65 reports a routine delivery event. Sentence 66 reports a routine delivery event. Sentence 67 reports a routine delivery event. Sentence 68 reports a routine delivery event. Sentence 69 reports a routine delivery event. Sentence 70 reports a routine delivery event. Sentence 71 reports a routine delivery event. Sentence 72 reports a routine delivery event. Sentence 73 reports a routine delivery event. Sentence 74 reports a routine delivery event. Sentence 75 reports a routine delivery event. Sentence 76 reports a routine delivery event. Sentence 77 reports a routine delivery event. Sentence 78 reports a routine delivery event. Sentence 79 reports a routine delivery event. Sentence 80 reports a routine delivery event. Sentence 81 reports a routine delivery event. Sentence 82 reports a routine delivery event. Sentence 83 reports a routine delivery event. Sentence 84 reports a routine delivery event. Sentence 85 reports a routine delivery event. Sentence 86 reports a routine delivery event. Sentence 87 reports a routine delivery event. Sentence 88 reports a routine delivery event. Sentence 89 reports a routine delivery event. Sentence 90 reports a routine delivery event. Sentence 91 reports a routine delivery event. Sentence 92 reports a routine delivery event. Sentence 93 reports a routine delivery event. Sentence 94 reports a routine delivery event. Sentence 95 reports a routine delivery event. Sentence 96 reports a routine delivery event. Sentence 97 reports a routine delivery event. Sentence 98 reports a routine delivery event. Sentence 99 reports a routine delivery event. Sentence 100 reports a routine delivery event. Sentence 101 reports a routine delivery event. Sentence 102 reports a routine delivery event. Sentence 103 reports a routine delivery event. Sentence 104 reports a routine delivery event. Sentence 105 reports a routine delivery event. Sentence 106 reports a routine delivery event. Sentence 107 reports a routine delivery event. Sentence 108 reports a routine delivery event. Sentence 109 reports a routine delivery event. Sentence 110 reports a routine delivery event. Sentence 111 reports a routine delivery event. Sentence 112 reports a routine delivery event. Sentence 113 reports a routine delivery event. Sentence 114 reports a routine delivery event. Sentence 115 reports a routine delivery event. Sentence 116 reports a routine delivery event. Sentence 117 reports a routine delivery event. Sentence 118 reports a routine delivery event. Sentence 119 reports a routine delivery event. Sentence 120 reports a routine delivery event. Sentence 121 reports a routine delivery event. Sentence 122 reports a routine delivery event. Sentence 123 reports a routine delivery event. Sentence 124 reports a routine delivery event. Sentence 125 reports a routine delivery event. Sentence 126 reports a routine delivery event. Sentence 127 reports a routine delivery event. Sentence 128 reports a routine delivery event. Sentence 129 reports a routine delivery event. Sentence 130 reports a routine delivery event. Sentence 131 reports a routine delivery event. Sentence 132 reports a routine delivery event. Sentence 133 reports a routine delivery event. Sentence 134 reports a routine delivery event. Sentence 135 reports a routine delivery event. Sentence 136 reports a routine delivery event. Sentence 137 reports a routine delivery event. Sentence 138 reports a routine delivery event. Sentence 139 reports a routine delivery event. Sentence 140 reports a routine delivery event. Sentence 141 reports a routine delivery event. Sentence 142 reports a routine delivery event. Sentence 143 reports a routine delivery event. Sentence 144 reports a routine delivery event. Sentence 145 reports a routine delivery event. Sentence 146 reports a routine delivery event. Sentence 147 reports a routine delivery event. Sentence 148 reports a routine delivery event. Sentence 149 reports a routine delivery event. Sentence 150 reports a routine delivery event. Sentence 151 reports a routine delivery event. Sentence 152 reports a routine delivery event. Sentence 153 reports a routine delivery event. Sentence 154 reports a routine delivery event. Sentence 155 reports a routine delivery event. Sentence 156 reports a routine delivery event. Sentence 157 reports a routine delivery event. Sentence 158 reports a routine delivery event. Sentence 159 reports a routine delivery event. Sentence 160 reports a routine delivery event. Sentence 161 reports a routine delivery event. Sentence 162 reports a routine delivery event. Sentence 163 reports a routine delivery event. Sentence 164 reports a routine delivery event. Sentence 165 reports a routine delivery event. Sentence 166 reports a routine delivery event. Sentence 167 reports a routine delivery event. Sentence 168 reports a routine delivery event. Sentence 169 reports a routine delivery event. Sentence 170 reports a routine delivery event. Sentence 171 reports a routine delivery event. Sentence 172 reports a routine delivery event. Sentence 173 reports a routine delivery event. Sentence 174 reports a routine delivery event. Sentence 175 reports a routine delivery event. Sentence 176 reports a routine delivery event. Sentence 177 reports a routine delivery event. Sentence 178 reports a routine delivery event. Sentence 179 reports a routine delivery event. Sentence 180 reports a routine delivery event. Sentence 181 reports a routine delivery event. Sentence 182 reports a routine delivery event. Sentence 183 reports a routine delivery event. Sentence 184 reports a routine delivery event. Sentence 185 reports a routine delivery event. Sentence 186 reports a routine delivery event. Sentence 187 reports a routine delivery event. Sentence 188 reports a routine delivery event. Sentence 189 reports a routine delivery event. Sentence 190 reports a routine delivery event. Sentence 191 reports a routine delivery event. Sentence 192 reports a routine delivery event. Sentence 193 reports a routine delivery event. Sentence 194 reports a routine delivery event. Sentence 195 reports a routine delivery event. Sentence 196 reports a routine delivery event. Sentence 197 reports a routine delivery event. Sentence 198 reports a routine delivery event. Sentence 199 reports a routine delivery event. Sentence 200 reports a routine delivery event. Sentence 201 reports a routine delivery event. Sentence 202 reports a routine delivery event. Sentence 203 reports a routine delivery event. Sentence 204 reports a routine delivery event. Sentence 205 reports a routine delivery event. Sentence 206 reports a routine delivery event. Sentence 207 reports a routine delivery event. Sentence 208 reports a routine delivery event. Sentence 209 reports a routine delivery event. Sentence 210 reports a routine delivery event. Sentence 211 reports a routine delivery event. Sentence 212 reports a routine delivery event. Sentence 213 reports a routine delivery event. Sentence 214 reports a routine delivery event. Sentence 215 reports a routine delivery event. Sentence 216 reports a routine delivery event. Sentence 217 reports a routine delivery event. Sentence 218 reports a routine delivery event. Sentence 219 reports a routine delivery event."}], "questions": [{"id": "claims", "type": "span", "text": "Which spans mention a delivery?", "target_part": "user", "labels": [{"name": "delivery", "description": "a delivery event"}]}]}, "plan": [{"qid": "claims", "type": "span", "criteria": {"delivery": "a delivery event"}, "range": [0, 10229], "part": "user"}], "rows": [{"p_ids": [1905, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 81646, 220, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 24, 6473, 264, 13618, 9403, 1484, 13, 198, 510, 22446, 29, 198], "blocks": [{"kind": "span", "ends": [40], "label_ranges": [[22, 40]], "words_in_block": false, "ids": [271, 6065, 913, 25, 9111, 198, 6196, 25, 1156, 198, 14162, 25, 198, 22365, 42824, 6088, 264, 9403, 30, 198, 22933, 25, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 9403, 1484, 2129, 767, 3147, 31320, 8934, 198, 510, 1448, 29, 271, 8679, 1396, 9111, 314, 279, 2100, 1414, 421, 22651, 799, 314, 279, 8928, 13, 198, 6205, 581, 25], "query": 59, "w_pos": [10, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 99, 100, 102, 104, 105, 106, 107, 108, 109, 110, 112, 114, 115, 116, 117, 118, 119, 120, 122, 124, 125, 126, 127, 128, 129, 130, 132, 134, 135, 136, 137, 138, 139, 140, 142, 144, 145, 146, 147, 148, 149, 150, 152, 154, 155, 156, 157, 158, 159, 160, 162, 164, 165, 166, 167, 168, 169, 170, 172, 174, 175, 176, 177, 178, 179, 180, 182, 184, 185, 186, 187, 188, 189, 190, 192, 194, 195, 196, 197, 198, 199, 200, 202, 204, 205, 206, 207, 208, 209, 210, 212, 214, 215, 216, 217, 218, 219, 220, 222, 224, 225, 226, 227, 228, 229, 230, 232, 234, 235, 236, 237, 238, 239, 240, 242, 244, 245, 246, 247, 248, 249, 250, 252, 254, 255, 256, 257, 258, 259, 260, 262, 264, 265, 266, 267, 268, 269, 270, 272, 274, 275, 276, 277, 278, 279, 280, 282, 284, 285, 286, 287, 288, 289, 290, 292, 294, 295, 296, 297, 298, 299, 300, 302, 304, 305, 306, 307, 308, 309, 310, 312, 314, 315, 316, 317, 318, 319, 320, 322, 324, 325, 326, 327, 328, 329, 330, 332, 334, 335, 336, 337, 338, 339, 340, 342, 344, 345, 346, 347, 348, 349, 350, 352, 354, 355, 356, 357, 358, 359, 360, 362, 364, 365, 366, 367, 368, 369, 370, 372, 374, 375, 376, 377, 378, 379, 380, 382, 384, 385, 386, 387, 388, 389, 390, 392, 394, 395, 396, 397, 398, 399, 400, 402, 404, 405, 406, 407, 408, 409, 410, 412, 414, 415, 416, 417, 418, 419, 420, 422, 424, 425, 426, 427, 428, 429, 430, 432, 434, 435, 436, 437, 438, 439, 440, 442, 444, 445, 446, 447, 448, 449, 450, 452, 454, 455, 456, 457, 458, 459, 460, 462, 464, 465, 466, 467, 468, 469, 470, 472, 474, 475, 476, 477, 478, 479, 480, 482, 484, 485, 486, 487, 488, 489, 490, 492, 494, 495, 496, 497, 498, 499, 500, 502, 504, 505, 506, 507, 508, 509, 510, 512, 514, 515, 516, 517, 518, 519, 520, 522, 524, 525, 526, 527, 528, 529, 530, 532, 534, 535, 536, 537, 538, 539, 540, 542, 544, 545, 546, 547, 548, 549, 550, 552, 554, 555, 556, 557, 558, 559, 560, 562, 564, 565, 566, 567, 568, 569, 570, 572, 574, 575, 576, 577, 578, 579, 580, 582, 584, 585, 586, 587, 588, 589, 590, 592, 594, 595, 596, 597, 598, 599, 600, 602, 604, 605, 606, 607, 608, 609, 610, 612, 614, 615, 616, 617, 618, 619, 620, 622, 624, 625, 626, 627, 628, 629, 630, 632, 634, 635, 636, 637, 638, 639, 640, 642, 644, 645, 646, 647, 648, 649, 650, 652, 654, 655, 656, 657, 658, 659, 660, 662, 664, 665, 666, 667, 668, 669, 670, 672, 674, 675, 676, 677, 678, 679, 680, 682, 684, 685, 686, 687, 688, 689, 690, 692, 694, 695, 696, 697, 698, 699, 700, 702, 704, 705, 706, 707, 708, 709, 710, 712, 714, 715, 716, 717, 718, 719, 720, 722, 724, 725, 726, 727, 728, 729, 730, 732, 734, 735, 736, 737, 738, 739, 740, 742, 744, 745, 746, 747, 748, 749, 750, 752, 754, 755, 756, 757, 758, 759, 760, 762, 764, 765, 766, 767, 768, 769, 770, 772, 774, 775, 776, 777, 778, 779, 780, 782, 784, 785, 786, 787, 788, 789, 790, 792, 794, 795, 796, 797, 798, 799, 800, 802, 804, 805, 806, 807, 808, 809, 810, 812, 814, 815, 816, 817, 818, 819, 820, 822, 824, 825, 826, 827, 828, 829, 830, 832, 834, 835, 836, 837, 838, 839, 840, 842, 844, 845, 846, 847, 848, 849, 850, 852, 854, 855, 856, 857, 858, 859, 860, 862, 864, 865, 866, 867, 868, 869, 870, 872, 874, 875, 876, 877, 878, 879, 880, 882, 884, 885, 886, 887, 888, 889, 890, 892, 894, 895, 896, 897, 898, 899, 900, 902, 904, 905, 906, 907, 908, 909, 910, 912, 914, 915, 916, 917, 918, 919, 920, 922, 924, 925, 926, 927, 928, 929, 930, 932, 934, 935, 936, 937, 938, 939, 940, 942, 944, 945, 946, 947, 948, 949, 950, 952, 954, 955, 956, 957, 958, 959, 960, 962, 964, 965, 966, 967, 968, 969, 970, 972, 974, 975, 976, 977, 978, 979, 980, 982, 984, 985, 986, 987, 988, 989, 990, 992, 994, 995, 996, 997, 998, 999, 1000, 1002, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1013, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1024, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1035, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1046, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1057, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1068, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1079, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1090, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1101, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1112, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1123, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1134, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1145, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1156, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1167, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1178, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1189, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1200, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1211, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1222, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1233, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1244, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1255, 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1266, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1277, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1288, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1299, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1310, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1321, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1332, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1343, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1354, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1365, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1387, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1398, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1409, 1412, 1413, 1414, 1415, 1416, 1417, 1418, 1420, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1431, 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1442, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1453, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1464, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1475, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1486, 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1497, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1508, 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1519, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1530, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1541, 1544, 1545, 1546, 1547, 1548, 1549, 1550, 1552, 1555, 1556, 1557, 1558, 1559, 1560, 1561, 1563, 1566, 1567, 1568, 1569, 1570, 1571, 1572, 1574, 1577, 1578, 1579, 1580, 1581, 1582, 1583, 1585, 1588, 1589, 1590, 1591, 1592, 1593, 1594, 1596, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1607, 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1618, 1621, 1622, 1623, 1624, 1625, 1626, 1627, 1629, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1640, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1651, 1654, 1655, 1656, 1657, 1658, 1659, 1660, 1662, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1673, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1684, 1687, 1688, 1689, 1690, 1691, 1692, 1693, 1695, 1698, 1699, 1700, 1701, 1702, 1703, 1704, 1706, 1709, 1710, 1711, 1712, 1713, 1714, 1715, 1717, 1720, 1721, 1722, 1723, 1724, 1725, 1726, 1728, 1731, 1732, 1733, 1734, 1735, 1736, 1737, 1739, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1750, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1761, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1772, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1783, 1786, 1787, 1788, 1789, 1790, 1791, 1792, 1794, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1805, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1816, 1819, 1820, 1821, 1822, 1823, 1824, 1825, 1827, 1830, 1831, 1832, 1833, 1834, 1835, 1836, 1838, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1849, 1852, 1853, 1854, 1855, 1856, 1857, 1858, 1860, 1863, 1864, 1865, 1866, 1867, 1868, 1869, 1871, 1874, 1875, 1876, 1877, 1878, 1879, 1880, 1882, 1885, 1886, 1887, 1888, 1889, 1890, 1891, 1893, 1896, 1897, 1898, 1899, 1900, 1901, 1902, 1904, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1915, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1926, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1937, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1948, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1959, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1970, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1981, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1992, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2014, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2025, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2036, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2047, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2058, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2069, 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2080, 2083, 2084, 2085, 2086, 2087, 2088, 2089, 2091, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2102, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2113, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2124, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2135, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2146, 2149, 2150, 2151, 2152, 2153, 2154, 2155, 2157, 2160, 2161, 2162, 2163, 2164, 2165, 2166, 2168, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2179, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2190, 2193, 2194, 2195, 2196, 2197, 2198, 2199, 2201, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2212, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2223, 2226, 2227, 2228, 2229, 2230, 2231, 2232, 2234, 2237, 2238, 2239, 2240, 2241, 2242, 2243, 2245, 2248, 2249, 2250, 2251, 2252, 2253, 2254, 2256, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2267, 2270, 2271, 2272, 2273, 2274, 2275, 2276, 2278, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2289, 2292, 2293, 2294, 2295, 2296, 2297, 2298, 2300, 2303, 2304, 2305, 2306, 2307, 2308, 2309, 2311, 2314, 2315, 2316, 2317, 2318, 2319]}], "trunc": {"shrink_cut": 0, "protected_cut": 0}, "seg_lens": {"user": 2310}, "layout": "a", "names": ["delivery"], "w_offs": [[0, 8], [9, 10], [11, 18], [19, 20], [21, 28], [29, 37], [38, 43], [43, 44], [45, 53], [54, 55], [56, 63], [64, 65], [66, 73], [74, 82], [83, 88], [88, 89], [90, 98], [99, 100], [101, 108], [109, 110], [111, 118], [119, 127], [128, 133], [133, 134], [135, 143], [144, 145], [146, 153], [154, 155], [156, 163], [164, 172], [173, 178], [178, 179], [180, 188], [189, 190], [191, 198], [199, 200], [201, 208], [209, 217], [218, 223], [223, 224], [225, 233], [234, 235], [236, 243], [244, 245], [246, 253], [254, 262], [263, 268], [268, 269], [270, 278], [279, 280], [281, 288], [289, 290], [291, 298], [299, 307], [308, 313], [313, 314], [315, 323], [324, 325], [326, 333], [334, 335], [336, 343], [344, 352], [353, 358], [358, 359], [360, 368], [369, 370], [371, 378], [379, 380], [381, 388], [389, 397], [398, 403], [403, 404], [405, 413], [414, 415], [416, 423], [424, 425], [426, 433], [434, 442], [443, 448], [448, 449], [450, 458], [459, 461], [462, 469], [470, 471], [472, 479], [480, 488], [489, 494], [494, 495], [496, 504], [505, 507], [508, 515], [516, 517], [518, 525], [526, 534], [535, 540], [540, 541], [542, 550], [551, 553], [554, 561], [562, 563], [564, 571], [572, 580], [581, 586], [586, 587], [588, 596], [597, 599], [600, 607], [608, 609], [610, 617], [618, 626], [627, 632], [632, 633], [634, 642], [643, 645], [646, 653], [654, 655], [656, 663], [664, 672], [673, 678], [678, 679], [680, 688], [689, 691], [692, 699], [700, 701], [702, 709], [710, 718], [719, 724], [724, 725], [726, 734], [735, 737], [738, 745], [746, 747], [748, 755], [756, 764], [765, 770], [770, 771], [772, 780], [781, 783], [784, 791], [792, 793], [794, 801], [802, 810], [811, 816], [816, 817], [818, 826], [827, 829], [830, 837], [838, 839], [840, 847], [848, 856], [857, 862], [862, 863], [864, 872], [873, 875], [876, 883], [884, 885], [886, 893], [894, 902], [903, 908], [908, 909], [910, 918], [919, 921], [922, 929], [930, 931], [932, 939], [940, 948], [949, 954], [954, 955], [956, 964], [965, 967], [968, 975], [976, 977], [978, 985], [986, 994], [995, 1000], [1000, 1001], [1002, 1010], [1011, 1013], [1014, 1021], [1022, 1023], [1024, 1031], [1032, 1040], [1041, 1046], [1046, 1047], [1048, 1056], [1057, 1059], [1060, 1067], [1068, 1069], [1070, 1077], [1078, 1086], [1087, 1092], [1092, 1093], [1094, 1102], [1103, 1105], [1106, 1113], [1114, 1115], [1116, 1123], [1124, 1132], [1133, 1138], [1138, 1139], [1140, 1148], [1149, 1151], [1152, 1159], [1160, 1161], [1162, 1169], [1170, 1178], [1179, 1184], [1184, 1185], [1186, 1194], [1195, 1197], [1198, 1205], [1206, 1207], [1208, 1215], [1216, 1224], [1225, 1230], [1230, 1231], [1232, 1240], [1241, 1243], [1244, 1251], [1252, 1253], [1254, 1261], [1262, 1270], [1271, 1276], [1276, 1277], [1278, 1286], [1287, 1289], [1290, 1297], [1298, 1299], [1300, 1307], [1308, 1316], [1317, 1322], [1322, 1323], [1324, 1332], [1333, 1335], [1336, 1343], [1344, 1345], [1346, 1353], [1354, 1362], [1363, 1368], [1368, 1369], [1370, 1378], [1379, 1381], [1382, 1389], [1390, 1391], [1392, 1399], [1400, 1408], [1409, 1414], [1414, 1415], [1416, 1424], [1425, 1427], [1428, 1435], [1436, 1437], [1438, 1445], [1446, 1454], [1455, 1460], [1460, 1461], [1462, 1470], [1471, 1473], [1474, 1481], [1482, 1483], [1484, 1491], [1492, 1500], [1501, 1506], [1506, 1507], [1508, 1516], [1517, 1519], [1520, 1527], [1528, 1529], [1530, 1537], [1538, 1546], [1547, 1552], [1552, 1553], [1554, 1562], [1563, 1565], [1566, 1573], [1574, 1575], [1576, 1583], [1584, 1592], [1593, 1598], [1598, 1599], [1600, 1608], [1609, 1611], [1612, 1619], [1620, 1621], [1622, 1629], [1630, 1638], [1639, 1644], [1644, 1645], [1646, 1654], [1655, 1657], [1658, 1665], [1666, 1667], [1668, 1675], [1676, 1684], [1685, 1690], [1690, 1691], [1692, 1700], [1701, 1703], [1704, 1711], [1712, 1713], [1714, 1721], [1722, 1730], [1731, 1736], [1736, 1737], [1738, 1746], [1747, 1749], [1750, 1757], [1758, 1759], [1760, 1767], [1768, 1776], [1777, 1782], [1782, 1783], [1784, 1792], [1793, 1795], [1796, 1803], [1804, 1805], [1806, 1813], [1814, 1822], [1823, 1828], [1828, 1829], [1830, 1838], [1839, 1841], [1842, 1849], [1850, 1851], [1852, 1859], [1860, 1868], [1869, 1874], [1874, 1875], [1876, 1884], [1885, 1887], [1888, 1895], [1896, 1897], [1898, 1905], [1906, 1914], [1915, 1920], [1920, 1921], [1922, 1930], [1931, 1933], [1934, 1941], [1942, 1943], [1944, 1951], [1952, 1960], [1961, 1966], [1966, 1967], [1968, 1976], [1977, 1979], [1980, 1987], [1988, 1989], [1990, 1997], [1998, 2006], [2007, 2012], [2012, 2013], [2014, 2022], [2023, 2025], [2026, 2033], [2034, 2035], [2036, 2043], [2044, 2052], [2053, 2058], [2058, 2059], [2060, 2068], [2069, 2071], [2072, 2079], [2080, 2081], [2082, 2089], [2090, 2098], [2099, 2104], [2104, 2105], [2106, 2114], [2115, 2117], [2118, 2125], [2126, 2127], [2128, 2135], [2136, 2144], [2145, 2150], [2150, 2151], [2152, 2160], [2161, 2163], [2164, 2171], [2172, 2173], [2174, 2181], [2182, 2190], [2191, 2196], [2196, 2197], [2198, 2206], [2207, 2209], [2210, 2217], [2218, 2219], [2220, 2227], [2228, 2236], [2237, 2242], [2242, 2243], [2244, 2252], [2253, 2255], [2256, 2263], [2264, 2265], [2266, 2273], [2274, 2282], [2283, 2288], [2288, 2289], [2290, 2298], [2299, 2301], [2302, 2309], [2310, 2311], [2312, 2319], [2320, 2328], [2329, 2334], [2334, 2335], [2336, 2344], [2345, 2347], [2348, 2355], [2356, 2357], [2358, 2365], [2366, 2374], [2375, 2380], [2380, 2381], [2382, 2390], [2391, 2393], [2394, 2401], [2402, 2403], [2404, 2411], [2412, 2420], [2421, 2426], [2426, 2427], [2428, 2436], [2437, 2439], [2440, 2447], [2448, 2449], [2450, 2457], [2458, 2466], [2467, 2472], [2472, 2473], [2474, 2482], [2483, 2485], [2486, 2493], [2494, 2495], [2496, 2503], [2504, 2512], [2513, 2518], [2518, 2519], [2520, 2528], [2529, 2531], [2532, 2539], [2540, 2541], [2542, 2549], [2550, 2558], [2559, 2564], [2564, 2565], [2566, 2574], [2575, 2577], [2578, 2585], [2586, 2587], [2588, 2595], [2596, 2604], [2605, 2610], [2610, 2611], [2612, 2620], [2621, 2623], [2624, 2631], [2632, 2633], [2634, 2641], [2642, 2650], [2651, 2656], [2656, 2657], [2658, 2666], [2667, 2669], [2670, 2677], [2678, 2679], [2680, 2687], [2688, 2696], [2697, 2702], [2702, 2703], [2704, 2712], [2713, 2715], [2716, 2723], [2724, 2725], [2726, 2733], [2734, 2742], [2743, 2748], [2748, 2749], [2750, 2758], [2759, 2761], [2762, 2769], [2770, 2771], [2772, 2779], [2780, 2788], [2789, 2794], [2794, 2795], [2796, 2804], [2805, 2807], [2808, 2815], [2816, 2817], [2818, 2825], [2826, 2834], [2835, 2840], [2840, 2841], [2842, 2850], [2851, 2853], [2854, 2861], [2862, 2863], [2864, 2871], [2872, 2880], [2881, 2886], [2886, 2887], [2888, 2896], [2897, 2899], [2900, 2907], [2908, 2909], [2910, 2917], [2918, 2926], [2927, 2932], [2932, 2933], [2934, 2942], [2943, 2945], [2946, 2953], [2954, 2955], [2956, 2963], [2964, 2972], [2973, 2978], [2978, 2979], [2980, 2988], [2989, 2991], [2992, 2999], [3000, 3001], [3002, 3009], [3010, 3018], [3019, 3024], [3024, 3025], [3026, 3034], [3035, 3037], [3038, 3045], [3046, 3047], [3048, 3055], [3056, 3064], [3065, 3070], [3070, 3071], [3072, 3080], [3081, 3083], [3084, 3091], [3092, 3093], [3094, 3101], [3102, 3110], [3111, 3116], [3116, 3117], [3118, 3126], [3127, 3129], [3130, 3137], [3138, 3139], [3140, 3147], [3148, 3156], [3157, 3162], [3162, 3163], [3164, 3172], [3173, 3175], [3176, 3183], [3184, 3185], [3186, 3193], [3194, 3202], [3203, 3208], [3208, 3209], [3210, 3218], [3219, 3221], [3222, 3229], [3230, 3231], [3232, 3239], [3240, 3248], [3249, 3254], [3254, 3255], [3256, 3264], [3265, 3267], [3268, 3275], [3276, 3277], [3278, 3285], [3286, 3294], [3295, 3300], [3300, 3301], [3302, 3310], [3311, 3313], [3314, 3321], [3322, 3323], [3324, 3331], [3332, 3340], [3341, 3346], [3346, 3347], [3348, 3356], [3357, 3359], [3360, 3367], [3368, 3369], [3370, 3377], [3378, 3386], [3387, 3392], [3392, 3393], [3394, 3402], [3403, 3405], [3406, 3413], [3414, 3415], [3416, 3423], [3424, 3432], [3433, 3438], [3438, 3439], [3440, 3448], [3449, 3451], [3452, 3459], [3460, 3461], [3462, 3469], [3470, 3478], [3479, 3484], [3484, 3485], [3486, 3494], [3495, 3497], [3498, 3505], [3506, 3507], [3508, 3515], [3516, 3524], [3525, 3530], [3530, 3531], [3532, 3540], [3541, 3543], [3544, 3551], [3552, 3553], [3554, 3561], [3562, 3570], [3571, 3576], [3576, 3577], [3578, 3586], [3587, 3589], [3590, 3597], [3598, 3599], [3600, 3607], [3608, 3616], [3617, 3622], [3622, 3623], [3624, 3632], [3633, 3635], [3636, 3643], [3644, 3645], [3646, 3653], [3654, 3662], [3663, 3668], [3668, 3669], [3670, 3678], [3679, 3681], [3682, 3689], [3690, 3691], [3692, 3699], [3700, 3708], [3709, 3714], [3714, 3715], [3716, 3724], [3725, 3727], [3728, 3735], [3736, 3737], [3738, 3745], [3746, 3754], [3755, 3760], [3760, 3761], [3762, 3770], [3771, 3773], [3774, 3781], [3782, 3783], [3784, 3791], [3792, 3800], [3801, 3806], [3806, 3807], [3808, 3816], [3817, 3819], [3820, 3827], [3828, 3829], [3830, 3837], [3838, 3846], [3847, 3852], [3852, 3853], [3854, 3862], [3863, 3865], [3866, 3873], [3874, 3875], [3876, 3883], [3884, 3892], [3893, 3898], [3898, 3899], [3900, 3908], [3909, 3911], [3912, 3919], [3920, 3921], [3922, 3929], [3930, 3938], [3939, 3944], [3944, 3945], [3946, 3954], [3955, 3957], [3958, 3965], [3966, 3967], [3968, 3975], [3976, 3984], [3985, 3990], [3990, 3991], [3992, 4000], [4001, 4003], [4004, 4011], [4012, 4013], [4014, 4021], [4022, 4030], [4031, 4036], [4036, 4037], [4038, 4046], [4047, 4049], [4050, 4057], [4058, 4059], [4060, 4067], [4068, 4076], [4077, 4082], [4082, 4083], [4084, 4092], [4093, 4095], [4096, 4103], [4104, 4105], [4106, 4113], [4114, 4122], [4123, 4128], [4128, 4129], [4130, 4138], [4139, 4141], [4142, 4149], [4150, 4151], [4152, 4159], [4160, 4168], [4169, 4174], [4174, 4175], [4176, 4184], [4185, 4187], [4188, 4195], [4196, 4197], [4198, 4205], [4206, 4214], [4215, 4220], [4220, 4221], [4222, 4230], [4231, 4233], [4234, 4241], [4242, 4243], [4244, 4251], [4252, 4260], [4261, 4266], [4266, 4267], [4268, 4276], [4277, 4279], [4280, 4287], [4288, 4289], [4290, 4297], [4298, 4306], [4307, 4312], [4312, 4313], [4314, 4322], [4323, 4325], [4326, 4333], [4334, 4335], [4336, 4343], [4344, 4352], [4353, 4358], [4358, 4359], [4360, 4368], [4369, 4371], [4372, 4379], [4380, 4381], [4382, 4389], [4390, 4398], [4399, 4404], [4404, 4405], [4406, 4414], [4415, 4417], [4418, 4425], [4426, 4427], [4428, 4435], [4436, 4444], [4445, 4450], [4450, 4451], [4452, 4460], [4461, 4463], [4464, 4471], [4472, 4473], [4474, 4481], [4482, 4490], [4491, 4496], [4496, 4497], [4498, 4506], [4507, 4509], [4510, 4517], [4518, 4519], [4520, 4527], [4528, 4536], [4537, 4542], [4542, 4543], [4544, 4552], [4553, 4555], [4556, 4563], [4564, 4565], [4566, 4573], [4574, 4582], [4583, 4588], [4588, 4589], [4590, 4598], [4599, 4602], [4603, 4610], [4611, 4612], [4613, 4620], [4621, 4629], [4630, 4635], [4635, 4636], [4637, 4645], [4646, 4649], [4650, 4657], [4658, 4659], [4660, 4667], [4668, 4676], [4677, 4682], [4682, 4683], [4684, 4692], [4693, 4696], [4697, 4704], [4705, 4706], [4707, 4714], [4715, 4723], [4724, 4729], [4729, 4730], [4731, 4739], [4740, 4743], [4744, 4751], [4752, 4753], [4754, 4761], [4762, 4770], [4771, 4776], [4776, 4777], [4778, 4786], [4787, 4790], [4791, 4798], [4799, 4800], [4801, 4808], [4809, 4817], [4818, 4823], [4823, 4824], [4825, 4833], [4834, 4837], [4838, 4845], [4846, 4847], [4848, 4855], [4856, 4864], [4865, 4870], [4870, 4871], [4872, 4880], [4881, 4884], [4885, 4892], [4893, 4894], [4895, 4902], [4903, 4911], [4912, 4917], [4917, 4918], [4919, 4927], [4928, 4931], [4932, 4939], [4940, 4941], [4942, 4949], [4950, 4958], [4959, 4964], [4964, 4965], [4966, 4974], [4975, 4978], [4979, 4986], [4987, 4988], [4989, 4996], [4997, 5005], [5006, 5011], [5011, 5012], [5013, 5021], [5022, 5025], [5026, 5033], [5034, 5035], [5036, 5043], [5044, 5052], [5053, 5058], [5058, 5059], [5060, 5068], [5069, 5072], [5073, 5080], [5081, 5082], [5083, 5090], [5091, 5099], [5100, 5105], [5105, 5106], [5107, 5115], [5116, 5119], [5120, 5127], [5128, 5129], [5130, 5137], [5138, 5146], [5147, 5152], [5152, 5153], [5154, 5162], [5163, 5166], [5167, 5174], [5175, 5176], [5177, 5184], [5185, 5193], [5194, 5199], [5199, 5200], [5201, 5209], [5210, 5213], [5214, 5221], [5222, 5223], [5224, 5231], [5232, 5240], [5241, 5246], [5246, 5247], [5248, 5256], [5257, 5260], [5261, 5268], [5269, 5270], [5271, 5278], [5279, 5287], [5288, 5293], [5293, 5294], [5295, 5303], [5304, 5307], [5308, 5315], [5316, 5317], [5318, 5325], [5326, 5334], [5335, 5340], [5340, 5341], [5342, 5350], [5351, 5354], [5355, 5362], [5363, 5364], [5365, 5372], [5373, 5381], [5382, 5387], [5387, 5388], [5389, 5397], [5398, 5401], [5402, 5409], [5410, 5411], [5412, 5419], [5420, 5428], [5429, 5434], [5434, 5435], [5436, 5444], [5445, 5448], [5449, 5456], [5457, 5458], [5459, 5466], [5467, 5475], [5476, 5481], [5481, 5482], [5483, 5491], [5492, 5495], [5496, 5503], [5504, 5505], [5506, 5513], [5514, 5522], [5523, 5528], [5528, 5529], [5530, 5538], [5539, 5542], [5543, 5550], [5551, 5552], [5553, 5560], [5561, 5569], [5570, 5575], [5575, 5576], [5577, 5585], [5586, 5589], [5590, 5597], [5598, 5599], [5600, 5607], [5608, 5616], [5617, 5622], [5622, 5623], [5624, 5632], [5633, 5636], [5637, 5644], [5645, 5646], [5647, 5654], [5655, 5663], [5664, 5669], [5669, 5670], [5671, 5679], [5680, 5683], [5684, 5691], [5692, 5693], [5694, 5701], [5702, 5710], [5711, 5716], [5716, 5717], [5718, 5726], [5727, 5730], [5731, 5738], [5739, 5740], [5741, 5748], [5749, 5757], [5758, 5763], [5763, 5764], [5765, 5773], [5774, 5777], [5778, 5785], [5786, 5787], [5788, 5795], [5796, 5804], [5805, 5810], [5810, 5811], [5812, 5820], [5821, 5824], [5825, 5832], [5833, 5834], [5835, 5842], [5843, 5851], [5852, 5857], [5857, 5858], [5859, 5867], [5868, 5871], [5872, 5879], [5880, 5881], [5882, 5889], [5890, 5898], [5899, 5904], [5904, 5905], [5906, 5914], [5915, 5918], [5919, 5926], [5927, 5928], [5929, 5936], [5937, 5945], [5946, 5951], [5951, 5952], [5953, 5961], [5962, 5965], [5966, 5973], [5974, 5975], [5976, 5983], [5984, 5992], [5993, 5998], [5998, 5999], [6000, 6008], [6009, 6012], [6013, 6020], [6021, 6022], [6023, 6030], [6031, 6039], [6040, 6045], [6045, 6046], [6047, 6055], [6056, 6059], [6060, 6067], [6068, 6069], [6070, 6077], [6078, 6086], [6087, 6092], [6092, 6093], [6094, 6102], [6103, 6106], [6107, 6114], [6115, 6116], [6117, 6124], [6125, 6133], [6134, 6139], [6139, 6140], [6141, 6149], [6150, 6153], [6154, 6161], [6162, 6163], [6164, 6171], [6172, 6180], [6181, 6186], [6186, 6187], [6188, 6196], [6197, 6200], [6201, 6208], [6209, 6210], [6211, 6218], [6219, 6227], [6228, 6233], [6233, 6234], [6235, 6243], [6244, 6247], [6248, 6255], [6256, 6257], [6258, 6265], [6266, 6274], [6275, 6280], [6280, 6281], [6282, 6290], [6291, 6294], [6295, 6302], [6303, 6304], [6305, 6312], [6313, 6321], [6322, 6327], [6327, 6328], [6329, 6337], [6338, 6341], [6342, 6349], [6350, 6351], [6352, 6359], [6360, 6368], [6369, 6374], [6374, 6375], [6376, 6384], [6385, 6388], [6389, 6396], [6397, 6398], [6399, 6406], [6407, 6415], [6416, 6421], [6421, 6422], [6423, 6431], [6432, 6435], [6436, 6443], [6444, 6445], [6446, 6453], [6454, 6462], [6463, 6468], [6468, 6469], [6470, 6478], [6479, 6482], [6483, 6490], [6491, 6492], [6493, 6500], [6501, 6509], [6510, 6515], [6515, 6516], [6517, 6525], [6526, 6529], [6530, 6537], [6538, 6539], [6540, 6547], [6548, 6556], [6557, 6562], [6562, 6563], [6564, 6572], [6573, 6576], [6577, 6584], [6585, 6586], [6587, 6594], [6595, 6603], [6604, 6609], [6609, 6610], [6611, 6619], [6620, 6623], [6624, 6631], [6632, 6633], [6634, 6641], [6642, 6650], [6651, 6656], [6656, 6657], [6658, 6666], [6667, 6670], [6671, 6678], [6679, 6680], [6681, 6688], [6689, 6697], [6698, 6703], [6703, 6704], [6705, 6713], [6714, 6717], [6718, 6725], [6726, 6727], [6728, 6735], [6736, 6744], [6745, 6750], [6750, 6751], [6752, 6760], [6761, 6764], [6765, 6772], [6773, 6774], [6775, 6782], [6783, 6791], [6792, 6797], [6797, 6798], [6799, 6807], [6808, 6811], [6812, 6819], [6820, 6821], [6822, 6829], [6830, 6838], [6839, 6844], [6844, 6845], [6846, 6854], [6855, 6858], [6859, 6866], [6867, 6868], [6869, 6876], [6877, 6885], [6886, 6891], [6891, 6892], [6893, 6901], [6902, 6905], [6906, 6913], [6914, 6915], [6916, 6923], [6924, 6932], [6933, 6938], [6938, 6939], [6940, 6948], [6949, 6952], [6953, 6960], [6961, 6962], [6963, 6970], [6971, 6979], [6980, 6985], [6985, 6986], [6987, 6995], [6996, 6999], [7000, 7007], [7008, 7009], [7010, 7017], [7018, 7026], [7027, 7032], [7032, 7033], [7034, 7042], [7043, 7046], [7047, 7054], [7055, 7056], [7057, 7064], [7065, 7073], [7074, 7079], [7079, 7080], [7081, 7089], [7090, 7093], [7094, 7101], [7102, 7103], [7104, 7111], [7112, 7120], [7121, 7126], [7126, 7127], [7128, 7136], [7137, 7140], [7141, 7148], [7149, 7150], [7151, 7158], [7159, 7167], [7168, 7173], [7173, 7174], [7175, 7183], [7184, 7187], [7188, 7195], [7196, 7197], [7198, 7205], [7206, 7214], [7215, 7220], [7220, 7221], [7222, 7230], [7231, 7234], [7235, 7242], [7243, 7244], [7245, 7252], [7253, 7261], [7262, 7267], [7267, 7268], [7269, 7277], [7278, 7281], [7282, 7289], [7290, 7291], [7292, 7299], [7300, 7308], [7309, 7314], [7314, 7315], [7316, 7324], [7325, 7328], [7329, 7336], [7337, 7338], [7339, 7346], [7347, 7355], [7356, 7361], [7361, 7362], [7363, 7371], [7372, 7375], [7376, 7383], [7384, 7385], [7386, 7393], [7394, 7402], [7403, 7408], [7408, 7409], [7410, 7418], [7419, 7422], [7423, 7430], [7431, 7432], [7433, 7440], [7441, 7449], [7450, 7455], [7455, 7456], [7457, 7465], [7466, 7469], [7470, 7477], [7478, 7479], [7480, 7487], [7488, 7496], [7497, 7502], [7502, 7503], [7504, 7512], [7513, 7516], [7517, 7524], [7525, 7526], [7527, 7534], [7535, 7543], [7544, 7549], [7549, 7550], [7551, 7559], [7560, 7563], [7564, 7571], [7572, 7573], [7574, 7581], [7582, 7590], [7591, 7596], [7596, 7597], [7598, 7606], [7607, 7610], [7611, 7618], [7619, 7620], [7621, 7628], [7629, 7637], [7638, 7643], [7643, 7644], [7645, 7653], [7654, 7657], [7658, 7665], [7666, 7667], [7668, 7675], [7676, 7684], [7685, 7690], [7690, 7691], [7692, 7700], [7701, 7704], [7705, 7712], [7713, 7714], [7715, 7722], [7723, 7731], [7732, 7737], [7737, 7738], [7739, 7747], [7748, 7751], [7752, 7759], [7760, 7761], [7762, 7769], [7770, 7778], [7779, 7784], [7784, 7785], [7786, 7794], [7795, 7798], [7799, 7806], [7807, 7808], [7809, 7816], [7817, 7825], [7826, 7831], [7831, 7832], [7833, 7841], [7842, 7845], [7846, 7853], [7854, 7855], [7856, 7863], [7864, 7872], [7873, 7878], [7878, 7879], [7880, 7888], [7889, 7892], [7893, 7900], [7901, 7902], [7903, 7910], [7911, 7919], [7920, 7925], [7925, 7926], [7927, 7935], [7936, 7939], [7940, 7947], [7948, 7949], [7950, 7957], [7958, 7966], [7967, 7972], [7972, 7973], [7974, 7982], [7983, 7986], [7987, 7994], [7995, 7996], [7997, 8004], [8005, 8013], [8014, 8019], [8019, 8020], [8021, 8029], [8030, 8033], [8034, 8041], [8042, 8043], [8044, 8051], [8052, 8060], [8061, 8066], [8066, 8067], [8068, 8076], [8077, 8080], [8081, 8088], [8089, 8090], [8091, 8098], [8099, 8107], [8108, 8113], [8113, 8114], [8115, 8123], [8124, 8127], [8128, 8135], [8136, 8137], [8138, 8145], [8146, 8154], [8155, 8160], [8160, 8161], [8162, 8170], [8171, 8174], [8175, 8182], [8183, 8184], [8185, 8192], [8193, 8201], [8202, 8207], [8207, 8208], [8209, 8217], [8218, 8221], [8222, 8229], [8230, 8231], [8232, 8239], [8240, 8248], [8249, 8254], [8254, 8255], [8256, 8264], [8265, 8268], [8269, 8276], [8277, 8278], [8279, 8286], [8287, 8295], [8296, 8301], [8301, 8302], [8303, 8311], [8312, 8315], [8316, 8323], [8324, 8325], [8326, 8333], [8334, 8342], [8343, 8348], [8348, 8349], [8350, 8358], [8359, 8362], [8363, 8370], [8371, 8372], [8373, 8380], [8381, 8389], [8390, 8395], [8395, 8396], [8397, 8405], [8406, 8409], [8410, 8417], [8418, 8419], [8420, 8427], [8428, 8436], [8437, 8442], [8442, 8443], [8444, 8452], [8453, 8456], [8457, 8464], [8465, 8466], [8467, 8474], [8475, 8483], [8484, 8489], [8489, 8490], [8491, 8499], [8500, 8503], [8504, 8511], [8512, 8513], [8514, 8521], [8522, 8530], [8531, 8536], [8536, 8537], [8538, 8546], [8547, 8550], [8551, 8558], [8559, 8560], [8561, 8568], [8569, 8577], [8578, 8583], [8583, 8584], [8585, 8593], [8594, 8597], [8598, 8605], [8606, 8607], [8608, 8615], [8616, 8624], [8625, 8630], [8630, 8631], [8632, 8640], [8641, 8644], [8645, 8652], [8653, 8654], [8655, 8662], [8663, 8671], [8672, 8677], [8677, 8678], [8679, 8687], [8688, 8691], [8692, 8699], [8700, 8701], [8702, 8709], [8710, 8718], [8719, 8724], [8724, 8725], [8726, 8734], [8735, 8738], [8739, 8746], [8747, 8748], [8749, 8756], [8757, 8765], [8766, 8771], [8771, 8772], [8773, 8781], [8782, 8785], [8786, 8793], [8794, 8795], [8796, 8803], [8804, 8812], [8813, 8818], [8818, 8819], [8820, 8828], [8829, 8832], [8833, 8840], [8841, 8842], [8843, 8850], [8851, 8859], [8860, 8865], [8865, 8866], [8867, 8875], [8876, 8879], [8880, 8887], [8888, 8889], [8890, 8897], [8898, 8906], [8907, 8912], [8912, 8913], [8914, 8922], [8923, 8926], [8927, 8934], [8935, 8936], [8937, 8944], [8945, 8953], [8954, 8959], [8959, 8960], [8961, 8969], [8970, 8973], [8974, 8981], [8982, 8983], [8984, 8991], [8992, 9000], [9001, 9006], [9006, 9007], [9008, 9016], [9017, 9020], [9021, 9028], [9029, 9030], [9031, 9038], [9039, 9047], [9048, 9053], [9053, 9054], [9055, 9063], [9064, 9067], [9068, 9075], [9076, 9077], [9078, 9085], [9086, 9094], [9095, 9100], [9100, 9101], [9102, 9110], [9111, 9114], [9115, 9122], [9123, 9124], [9125, 9132], [9133, 9141], [9142, 9147], [9147, 9148], [9149, 9157], [9158, 9161], [9162, 9169], [9170, 9171], [9172, 9179], [9180, 9188], [9189, 9194], [9194, 9195], [9196, 9204], [9205, 9208], [9209, 9216], [9217, 9218], [9219, 9226], [9227, 9235], [9236, 9241], [9241, 9242], [9243, 9251], [9252, 9255], [9256, 9263], [9264, 9265], [9266, 9273], [9274, 9282], [9283, 9288], [9288, 9289], [9290, 9298], [9299, 9302], [9303, 9310], [9311, 9312], [9313, 9320], [9321, 9329], [9330, 9335], [9335, 9336], [9337, 9345], [9346, 9349], [9350, 9357], [9358, 9359], [9360, 9367], [9368, 9376], [9377, 9382], [9382, 9383], [9384, 9392], [9393, 9396], [9397, 9404], [9405, 9406], [9407, 9414], [9415, 9423], [9424, 9429], [9429, 9430], [9431, 9439], [9440, 9443], [9444, 9451], [9452, 9453], [9454, 9461], [9462, 9470], [9471, 9476], [9476, 9477], [9478, 9486], [9487, 9490], [9491, 9498], [9499, 9500], [9501, 9508], [9509, 9517], [9518, 9523], [9523, 9524], [9525, 9533], [9534, 9537], [9538, 9545], [9546, 9547], [9548, 9555], [9556, 9564], [9565, 9570], [9570, 9571], [9572, 9580], [9581, 9584], [9585, 9592], [9593, 9594], [9595, 9602], [9603, 9611], [9612, 9617], [9617, 9618], [9619, 9627], [9628, 9631], [9632, 9639], [9640, 9641], [9642, 9649], [9650, 9658], [9659, 9664], [9664, 9665], [9666, 9674], [9675, 9678], [9679, 9686], [9687, 9688], [9689, 9696], [9697, 9705], [9706, 9711], [9711, 9712], [9713, 9721], [9722, 9725], [9726, 9733], [9734, 9735], [9736, 9743], [9744, 9752], [9753, 9758], [9758, 9759], [9760, 9768], [9769, 9772], [9773, 9780], [9781, 9782], [9783, 9790], [9791, 9799], [9800, 9805], [9805, 9806], [9807, 9815], [9816, 9819], [9820, 9827], [9828, 9829], [9830, 9837], [9838, 9846], [9847, 9852], [9852, 9853], [9854, 9862], [9863, 9866], [9867, 9874], [9875, 9876], [9877, 9884], [9885, 9893], [9894, 9899], [9899, 9900], [9901, 9909], [9910, 9913], [9914, 9921], [9922, 9923], [9924, 9931], [9932, 9940], [9941, 9946], [9946, 9947], [9948, 9956], [9957, 9960], [9961, 9968], [9969, 9970], [9971, 9978], [9979, 9987], [9988, 9993], [9993, 9994], [9995, 10003], [10004, 10007], [10008, 10015], [10016, 10017], [10018, 10025], [10026, 10034], [10035, 10040], [10040, 10041], [10042, 10050], [10051, 10054], [10055, 10062], [10063, 10064], [10065, 10072], [10073, 10081], [10082, 10087], [10087, 10088], [10089, 10097], [10098, 10101], [10102, 10109], [10110, 10111], [10112, 10119], [10120, 10128], [10129, 10134], [10134, 10135], [10136, 10144], [10145, 10148], [10149, 10156], [10157, 10158], [10159, 10166], [10167, 10175], [10176, 10181], [10181, 10182], [10183, 10191], [10192, 10195], [10196, 10203], [10204, 10205], [10206, 10213], [10214, 10222], [10223, 10228], [10228, 10229]], "w_pos": [10, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 95, 96, 97, 98, 99, 100, 102, 104, 105, 106, 107, 108, 109, 110, 112, 114, 115, 116, 117, 118, 119, 120, 122, 124, 125, 126, 127, 128, 129, 130, 132, 134, 135, 136, 137, 138, 139, 140, 142, 144, 145, 146, 147, 148, 149, 150, 152, 154, 155, 156, 157, 158, 159, 160, 162, 164, 165, 166, 167, 168, 169, 170, 172, 174, 175, 176, 177, 178, 179, 180, 182, 184, 185, 186, 187, 188, 189, 190, 192, 194, 195, 196, 197, 198, 199, 200, 202, 204, 205, 206, 207, 208, 209, 210, 212, 214, 215, 216, 217, 218, 219, 220, 222, 224, 225, 226, 227, 228, 229, 230, 232, 234, 235, 236, 237, 238, 239, 240, 242, 244, 245, 246, 247, 248, 249, 250, 252, 254, 255, 256, 257, 258, 259, 260, 262, 264, 265, 266, 267, 268, 269, 270, 272, 274, 275, 276, 277, 278, 279, 280, 282, 284, 285, 286, 287, 288, 289, 290, 292, 294, 295, 296, 297, 298, 299, 300, 302, 304, 305, 306, 307, 308, 309, 310, 312, 314, 315, 316, 317, 318, 319, 320, 322, 324, 325, 326, 327, 328, 329, 330, 332, 334, 335, 336, 337, 338, 339, 340, 342, 344, 345, 346, 347, 348, 349, 350, 352, 354, 355, 356, 357, 358, 359, 360, 362, 364, 365, 366, 367, 368, 369, 370, 372, 374, 375, 376, 377, 378, 379, 380, 382, 384, 385, 386, 387, 388, 389, 390, 392, 394, 395, 396, 397, 398, 399, 400, 402, 404, 405, 406, 407, 408, 409, 410, 412, 414, 415, 416, 417, 418, 419, 420, 422, 424, 425, 426, 427, 428, 429, 430, 432, 434, 435, 436, 437, 438, 439, 440, 442, 444, 445, 446, 447, 448, 449, 450, 452, 454, 455, 456, 457, 458, 459, 460, 462, 464, 465, 466, 467, 468, 469, 470, 472, 474, 475, 476, 477, 478, 479, 480, 482, 484, 485, 486, 487, 488, 489, 490, 492, 494, 495, 496, 497, 498, 499, 500, 502, 504, 505, 506, 507, 508, 509, 510, 512, 514, 515, 516, 517, 518, 519, 520, 522, 524, 525, 526, 527, 528, 529, 530, 532, 534, 535, 536, 537, 538, 539, 540, 542, 544, 545, 546, 547, 548, 549, 550, 552, 554, 555, 556, 557, 558, 559, 560, 562, 564, 565, 566, 567, 568, 569, 570, 572, 574, 575, 576, 577, 578, 579, 580, 582, 584, 585, 586, 587, 588, 589, 590, 592, 594, 595, 596, 597, 598, 599, 600, 602, 604, 605, 606, 607, 608, 609, 610, 612, 614, 615, 616, 617, 618, 619, 620, 622, 624, 625, 626, 627, 628, 629, 630, 632, 634, 635, 636, 637, 638, 639, 640, 642, 644, 645, 646, 647, 648, 649, 650, 652, 654, 655, 656, 657, 658, 659, 660, 662, 664, 665, 666, 667, 668, 669, 670, 672, 674, 675, 676, 677, 678, 679, 680, 682, 684, 685, 686, 687, 688, 689, 690, 692, 694, 695, 696, 697, 698, 699, 700, 702, 704, 705, 706, 707, 708, 709, 710, 712, 714, 715, 716, 717, 718, 719, 720, 722, 724, 725, 726, 727, 728, 729, 730, 732, 734, 735, 736, 737, 738, 739, 740, 742, 744, 745, 746, 747, 748, 749, 750, 752, 754, 755, 756, 757, 758, 759, 760, 762, 764, 765, 766, 767, 768, 769, 770, 772, 774, 775, 776, 777, 778, 779, 780, 782, 784, 785, 786, 787, 788, 789, 790, 792, 794, 795, 796, 797, 798, 799, 800, 802, 804, 805, 806, 807, 808, 809, 810, 812, 814, 815, 816, 817, 818, 819, 820, 822, 824, 825, 826, 827, 828, 829, 830, 832, 834, 835, 836, 837, 838, 839, 840, 842, 844, 845, 846, 847, 848, 849, 850, 852, 854, 855, 856, 857, 858, 859, 860, 862, 864, 865, 866, 867, 868, 869, 870, 872, 874, 875, 876, 877, 878, 879, 880, 882, 884, 885, 886, 887, 888, 889, 890, 892, 894, 895, 896, 897, 898, 899, 900, 902, 904, 905, 906, 907, 908, 909, 910, 912, 914, 915, 916, 917, 918, 919, 920, 922, 924, 925, 926, 927, 928, 929, 930, 932, 934, 935, 936, 937, 938, 939, 940, 942, 944, 945, 946, 947, 948, 949, 950, 952, 954, 955, 956, 957, 958, 959, 960, 962, 964, 965, 966, 967, 968, 969, 970, 972, 974, 975, 976, 977, 978, 979, 980, 982, 984, 985, 986, 987, 988, 989, 990, 992, 994, 995, 996, 997, 998, 999, 1000, 1002, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1013, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1024, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1035, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1046, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1057, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1068, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1079, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1090, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1101, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1112, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1123, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1134, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1145, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1156, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1167, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1178, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1189, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1200, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1211, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1222, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1233, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1244, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1255, 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1266, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1277, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1288, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1299, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1310, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1321, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1332, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1343, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1354, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1365, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1387, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1398, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1409, 1412, 1413, 1414, 1415, 1416, 1417, 1418, 1420, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1431, 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1442, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1453, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1464, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1475, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1486, 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1497, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1508, 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1519, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1530, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1541, 1544, 1545, 1546, 1547, 1548, 1549, 1550, 1552, 1555, 1556, 1557, 1558, 1559, 1560, 1561, 1563, 1566, 1567, 1568, 1569, 1570, 1571, 1572, 1574, 1577, 1578, 1579, 1580, 1581, 1582, 1583, 1585, 1588, 1589, 1590, 1591, 1592, 1593, 1594, 1596, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1607, 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1618, 1621, 1622, 1623, 1624, 1625, 1626, 1627, 1629, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1640, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1651, 1654, 1655, 1656, 1657, 1658, 1659, 1660, 1662, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1673, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1684, 1687, 1688, 1689, 1690, 1691, 1692, 1693, 1695, 1698, 1699, 1700, 1701, 1702, 1703, 1704, 1706, 1709, 1710, 1711, 1712, 1713, 1714, 1715, 1717, 1720, 1721, 1722, 1723, 1724, 1725, 1726, 1728, 1731, 1732, 1733, 1734, 1735, 1736, 1737, 1739, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1750, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1761, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1772, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1783, 1786, 1787, 1788, 1789, 1790, 1791, 1792, 1794, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1805, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1816, 1819, 1820, 1821, 1822, 1823, 1824, 1825, 1827, 1830, 1831, 1832, 1833, 1834, 1835, 1836, 1838, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1849, 1852, 1853, 1854, 1855, 1856, 1857, 1858, 1860, 1863, 1864, 1865, 1866, 1867, 1868, 1869, 1871, 1874, 1875, 1876, 1877, 1878, 1879, 1880, 1882, 1885, 1886, 1887, 1888, 1889, 1890, 1891, 1893, 1896, 1897, 1898, 1899, 1900, 1901, 1902, 1904, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1915, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1926, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1937, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1948, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1959, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1970, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1981, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1992, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2014, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2025, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2036, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2047, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2058, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2069, 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2080, 2083, 2084, 2085, 2086, 2087, 2088, 2089, 2091, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2102, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2113, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2124, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2135, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2146, 2149, 2150, 2151, 2152, 2153, 2154, 2155, 2157, 2160, 2161, 2162, 2163, 2164, 2165, 2166, 2168, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2179, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2190, 2193, 2194, 2195, 2196, 2197, 2198, 2199, 2201, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2212, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2223, 2226, 2227, 2228, 2229, 2230, 2231, 2232, 2234, 2237, 2238, 2239, 2240, 2241, 2242, 2243, 2245, 2248, 2249, 2250, 2251, 2252, 2253, 2254, 2256, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2267, 2270, 2271, 2272, 2273, 2274, 2275, 2276, 2278, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2289, 2292, 2293, 2294, 2295, 2296, 2297, 2298, 2300, 2303, 2304, 2305, 2306, 2307, 2308, 2309, 2311, 2314, 2315, 2316, 2317, 2318, 2319], "span_over": "user", "n_tokens": 2385, "head": "broad", "head_reason": "default"}], "window_rows": [{"p_ids": [1905, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 81646, 220, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 18, 6473, 198, 510, 22446, 29, 198], "blocks": [{"kind": "span", "ends": [40], "label_ranges": [[22, 40]], "words_in_block": true, "ids": [271, 6065, 913, 25, 9111, 198, 6196, 25, 1156, 198, 14162, 25, 198, 22365, 42824, 6088, 264, 9403, 30, 198, 22933, 25, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 9403, 1484, 2129, 767, 3147, 31320, 8934, 198, 510, 1448, 29, 271, 1138, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 81646, 220, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 18, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 19, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 20, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 21, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 22, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 23, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 24, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 15, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 16, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 17, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 18, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 19, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 18, 6473, 198, 510, 22446, 29, 198, 271, 8679, 1396, 9111, 314, 279, 2100, 1414, 421, 22651, 799, 314, 279, 8928, 13, 198, 6205, 581, 25], "query": 1874, "w_pos": [52, 54, 55, 56, 57, 58, 59, 60, 61, 63, 64, 65, 66, 67, 68, 69, 70, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114, 115, 117, 118, 119, 120, 121, 122, 123, 124, 126, 127, 128, 129, 130, 131, 132, 133, 135, 136, 137, 138, 139, 140, 141, 142, 144, 146, 147, 148, 149, 150, 151, 152, 154, 156, 157, 158, 159, 160, 161, 162, 164, 166, 167, 168, 169, 170, 171, 172, 174, 176, 177, 178, 179, 180, 181, 182, 184, 186, 187, 188, 189, 190, 191, 192, 194, 196, 197, 198, 199, 200, 201, 202, 204, 206, 207, 208, 209, 210, 211, 212, 214, 216, 217, 218, 219, 220, 221, 222, 224, 226, 227, 228, 229, 230, 231, 232, 234, 236, 237, 238, 239, 240, 241, 242, 244, 246, 247, 248, 249, 250, 251, 252, 254, 256, 257, 258, 259, 260, 261, 262, 264, 266, 267, 268, 269, 270, 271, 272, 274, 276, 277, 278, 279, 280, 281, 282, 284, 286, 287, 288, 289, 290, 291, 292, 294, 296, 297, 298, 299, 300, 301, 302, 304, 306, 307, 308, 309, 310, 311, 312, 314, 316, 317, 318, 319, 320, 321, 322, 324, 326, 327, 328, 329, 330, 331, 332, 334, 336, 337, 338, 339, 340, 341, 342, 344, 346, 347, 348, 349, 350, 351, 352, 354, 356, 357, 358, 359, 360, 361, 362, 364, 366, 367, 368, 369, 370, 371, 372, 374, 376, 377, 378, 379, 380, 381, 382, 384, 386, 387, 388, 389, 390, 391, 392, 394, 396, 397, 398, 399, 400, 401, 402, 404, 406, 407, 408, 409, 410, 411, 412, 414, 416, 417, 418, 419, 420, 421, 422, 424, 426, 427, 428, 429, 430, 431, 432, 434, 436, 437, 438, 439, 440, 441, 442, 444, 446, 447, 448, 449, 450, 451, 452, 454, 456, 457, 458, 459, 460, 461, 462, 464, 466, 467, 468, 469, 470, 471, 472, 474, 476, 477, 478, 479, 480, 481, 482, 484, 486, 487, 488, 489, 490, 491, 492, 494, 496, 497, 498, 499, 500, 501, 502, 504, 506, 507, 508, 509, 510, 511, 512, 514, 516, 517, 518, 519, 520, 521, 522, 524, 526, 527, 528, 529, 530, 531, 532, 534, 536, 537, 538, 539, 540, 541, 542, 544, 546, 547, 548, 549, 550, 551, 552, 554, 556, 557, 558, 559, 560, 561, 562, 564, 566, 567, 568, 569, 570, 571, 572, 574, 576, 577, 578, 579, 580, 581, 582, 584, 586, 587, 588, 589, 590, 591, 592, 594, 596, 597, 598, 599, 600, 601, 602, 604, 606, 607, 608, 609, 610, 611, 612, 614, 616, 617, 618, 619, 620, 621, 622, 624, 626, 627, 628, 629, 630, 631, 632, 634, 636, 637, 638, 639, 640, 641, 642, 644, 646, 647, 648, 649, 650, 651, 652, 654, 656, 657, 658, 659, 660, 661, 662, 664, 666, 667, 668, 669, 670, 671, 672, 674, 676, 677, 678, 679, 680, 681, 682, 684, 686, 687, 688, 689, 690, 691, 692, 694, 696, 697, 698, 699, 700, 701, 702, 704, 706, 707, 708, 709, 710, 711, 712, 714, 716, 717, 718, 719, 720, 721, 722, 724, 726, 727, 728, 729, 730, 731, 732, 734, 736, 737, 738, 739, 740, 741, 742, 744, 746, 747, 748, 749, 750, 751, 752, 754, 756, 757, 758, 759, 760, 761, 762, 764, 766, 767, 768, 769, 770, 771, 772, 774, 776, 777, 778, 779, 780, 781, 782, 784, 786, 787, 788, 789, 790, 791, 792, 794, 796, 797, 798, 799, 800, 801, 802, 804, 806, 807, 808, 809, 810, 811, 812, 814, 816, 817, 818, 819, 820, 821, 822, 824, 826, 827, 828, 829, 830, 831, 832, 834, 836, 837, 838, 839, 840, 841, 842, 844, 846, 847, 848, 849, 850, 851, 852, 854, 856, 857, 858, 859, 860, 861, 862, 864, 866, 867, 868, 869, 870, 871, 872, 874, 876, 877, 878, 879, 880, 881, 882, 884, 886, 887, 888, 889, 890, 891, 892, 894, 896, 897, 898, 899, 900, 901, 902, 904, 906, 907, 908, 909, 910, 911, 912, 914, 916, 917, 918, 919, 920, 921, 922, 924, 926, 927, 928, 929, 930, 931, 932, 934, 936, 937, 938, 939, 940, 941, 942, 944, 946, 947, 948, 949, 950, 951, 952, 954, 956, 957, 958, 959, 960, 961, 962, 964, 966, 967, 968, 969, 970, 971, 972, 974, 976, 977, 978, 979, 980, 981, 982, 984, 986, 987, 988, 989, 990, 991, 992, 994, 996, 997, 998, 999, 1000, 1001, 1002, 1004, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1014, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1024, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1034, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1044, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1055, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1066, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1077, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1088, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1099, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1110, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1121, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1132, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1143, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1154, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1165, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1176, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1187, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1198, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1209, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1220, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1231, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1242, 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1253, 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1264, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1275, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1286, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1297, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1308, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1319, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1330, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1341, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1352, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1363, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1374, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1385, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1396, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1407, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 1418, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1429, 1432, 1433, 1434, 1435, 1436, 1437, 1438, 1440, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1451, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1462, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1473, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1484, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1495, 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1506, 1509, 1510, 1511, 1512, 1513, 1514, 1515, 1517, 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1528, 1531, 1532, 1533, 1534, 1535, 1536, 1537, 1539, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1550, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1561, 1564, 1565, 1566, 1567, 1568, 1569, 1570, 1572, 1575, 1576, 1577, 1578, 1579, 1580, 1581, 1583, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1594, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1605, 1608, 1609, 1610, 1611, 1612, 1613, 1614, 1616, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1627, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1638, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 1649, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1660, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1671, 1674, 1675, 1676, 1677, 1678, 1679, 1680, 1682, 1685, 1686, 1687, 1688, 1689, 1690, 1691, 1693, 1696, 1697, 1698, 1699, 1700, 1701, 1702, 1704, 1707, 1708, 1709, 1710, 1711, 1712, 1713, 1715, 1718, 1719, 1720, 1721, 1722, 1723, 1724, 1726, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1737, 1740, 1741, 1742, 1743, 1744, 1745, 1746, 1748, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1759, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1770, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1781, 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1792, 1795, 1796, 1797, 1798, 1799, 1800, 1801, 1803, 1806, 1807, 1808, 1809, 1810, 1811, 1812, 1814, 1817, 1818, 1819, 1820, 1821, 1822, 1823, 1825, 1828, 1829, 1830, 1831, 1832, 1833, 1834, 1836, 1839, 1840, 1841, 1842, 1843, 1844, 1845, 1847, 1850]}], "trunc": {"shrink_cut": 0, "protected_cut": 0}, "seg_lens": {"user": 1799}, "layout": "c", "names": ["delivery"], "w_offs": [[0, 8], [9, 10], [11, 18], [19, 20], [21, 28], [29, 37], [38, 43], [43, 44], [45, 53], [54, 55], [56, 63], [64, 65], [66, 73], [74, 82], [83, 88], [88, 89], [90, 98], [99, 100], [101, 108], [109, 110], [111, 118], [119, 127], [128, 133], [133, 134], [135, 143], [144, 145], [146, 153], [154, 155], [156, 163], [164, 172], [173, 178], [178, 179], [180, 188], [189, 190], [191, 198], [199, 200], [201, 208], [209, 217], [218, 223], [223, 224], [225, 233], [234, 235], [236, 243], [244, 245], [246, 253], [254, 262], [263, 268], [268, 269], [270, 278], [279, 280], [281, 288], [289, 290], [291, 298], [299, 307], [308, 313], [313, 314], [315, 323], [324, 325], [326, 333], [334, 335], [336, 343], [344, 352], [353, 358], [358, 359], [360, 368], [369, 370], [371, 378], [379, 380], [381, 388], [389, 397], [398, 403], [403, 404], [405, 413], [414, 415], [416, 423], [424, 425], [426, 433], [434, 442], [443, 448], [448, 449], [450, 458], [459, 461], [462, 469], [470, 471], [472, 479], [480, 488], [489, 494], [494, 495], [496, 504], [505, 507], [508, 515], [516, 517], [518, 525], [526, 534], [535, 540], [540, 541], [542, 550], [551, 553], [554, 561], [562, 563], [564, 571], [572, 580], [581, 586], [586, 587], [588, 596], [597, 599], [600, 607], [608, 609], [610, 617], [618, 626], [627, 632], [632, 633], [634, 642], [643, 645], [646, 653], [654, 655], [656, 663], [664, 672], [673, 678], [678, 679], [680, 688], [689, 691], [692, 699], [700, 701], [702, 709], [710, 718], [719, 724], [724, 725], [726, 734], [735, 737], [738, 745], [746, 747], [748, 755], [756, 764], [765, 770], [770, 771], [772, 780], [781, 783], [784, 791], [792, 793], [794, 801], [802, 810], [811, 816], [816, 817], [818, 826], [827, 829], [830, 837], [838, 839], [840, 847], [848, 856], [857, 862], [862, 863], [864, 872], [873, 875], [876, 883], [884, 885], [886, 893], [894, 902], [903, 908], [908, 909], [910, 918], [919, 921], [922, 929], [930, 931], [932, 939], [940, 948], [949, 954], [954, 955], [956, 964], [965, 967], [968, 975], [976, 977], [978, 985], [986, 994], [995, 1000], [1000, 1001], [1002, 1010], [1011, 1013], [1014, 1021], [1022, 1023], [1024, 1031], [1032, 1040], [1041, 1046], [1046, 1047], [1048, 1056], [1057, 1059], [1060, 1067], [1068, 1069], [1070, 1077], [1078, 1086], [1087, 1092], [1092, 1093], [1094, 1102], [1103, 1105], [1106, 1113], [1114, 1115], [1116, 1123], [1124, 1132], [1133, 1138], [1138, 1139], [1140, 1148], [1149, 1151], [1152, 1159], [1160, 1161], [1162, 1169], [1170, 1178], [1179, 1184], [1184, 1185], [1186, 1194], [1195, 1197], [1198, 1205], [1206, 1207], [1208, 1215], [1216, 1224], [1225, 1230], [1230, 1231], [1232, 1240], [1241, 1243], [1244, 1251], [1252, 1253], [1254, 1261], [1262, 1270], [1271, 1276], [1276, 1277], [1278, 1286], [1287, 1289], [1290, 1297], [1298, 1299], [1300, 1307], [1308, 1316], [1317, 1322], [1322, 1323], [1324, 1332], [1333, 1335], [1336, 1343], [1344, 1345], [1346, 1353], [1354, 1362], [1363, 1368], [1368, 1369], [1370, 1378], [1379, 1381], [1382, 1389], [1390, 1391], [1392, 1399], [1400, 1408], [1409, 1414], [1414, 1415], [1416, 1424], [1425, 1427], [1428, 1435], [1436, 1437], [1438, 1445], [1446, 1454], [1455, 1460], [1460, 1461], [1462, 1470], [1471, 1473], [1474, 1481], [1482, 1483], [1484, 1491], [1492, 1500], [1501, 1506], [1506, 1507], [1508, 1516], [1517, 1519], [1520, 1527], [1528, 1529], [1530, 1537], [1538, 1546], [1547, 1552], [1552, 1553], [1554, 1562], [1563, 1565], [1566, 1573], [1574, 1575], [1576, 1583], [1584, 1592], [1593, 1598], [1598, 1599], [1600, 1608], [1609, 1611], [1612, 1619], [1620, 1621], [1622, 1629], [1630, 1638], [1639, 1644], [1644, 1645], [1646, 1654], [1655, 1657], [1658, 1665], [1666, 1667], [1668, 1675], [1676, 1684], [1685, 1690], [1690, 1691], [1692, 1700], [1701, 1703], [1704, 1711], [1712, 1713], [1714, 1721], [1722, 1730], [1731, 1736], [1736, 1737], [1738, 1746], [1747, 1749], [1750, 1757], [1758, 1759], [1760, 1767], [1768, 1776], [1777, 1782], [1782, 1783], [1784, 1792], [1793, 1795], [1796, 1803], [1804, 1805], [1806, 1813], [1814, 1822], [1823, 1828], [1828, 1829], [1830, 1838], [1839, 1841], [1842, 1849], [1850, 1851], [1852, 1859], [1860, 1868], [1869, 1874], [1874, 1875], [1876, 1884], [1885, 1887], [1888, 1895], [1896, 1897], [1898, 1905], [1906, 1914], [1915, 1920], [1920, 1921], [1922, 1930], [1931, 1933], [1934, 1941], [1942, 1943], [1944, 1951], [1952, 1960], [1961, 1966], [1966, 1967], [1968, 1976], [1977, 1979], [1980, 1987], [1988, 1989], [1990, 1997], [1998, 2006], [2007, 2012], [2012, 2013], [2014, 2022], [2023, 2025], [2026, 2033], [2034, 2035], [2036, 2043], [2044, 2052], [2053, 2058], [2058, 2059], [2060, 2068], [2069, 2071], [2072, 2079], [2080, 2081], [2082, 2089], [2090, 2098], [2099, 2104], [2104, 2105], [2106, 2114], [2115, 2117], [2118, 2125], [2126, 2127], [2128, 2135], [2136, 2144], [2145, 2150], [2150, 2151], [2152, 2160], [2161, 2163], [2164, 2171], [2172, 2173], [2174, 2181], [2182, 2190], [2191, 2196], [2196, 2197], [2198, 2206], [2207, 2209], [2210, 2217], [2218, 2219], [2220, 2227], [2228, 2236], [2237, 2242], [2242, 2243], [2244, 2252], [2253, 2255], [2256, 2263], [2264, 2265], [2266, 2273], [2274, 2282], [2283, 2288], [2288, 2289], [2290, 2298], [2299, 2301], [2302, 2309], [2310, 2311], [2312, 2319], [2320, 2328], [2329, 2334], [2334, 2335], [2336, 2344], [2345, 2347], [2348, 2355], [2356, 2357], [2358, 2365], [2366, 2374], [2375, 2380], [2380, 2381], [2382, 2390], [2391, 2393], [2394, 2401], [2402, 2403], [2404, 2411], [2412, 2420], [2421, 2426], [2426, 2427], [2428, 2436], [2437, 2439], [2440, 2447], [2448, 2449], [2450, 2457], [2458, 2466], [2467, 2472], [2472, 2473], [2474, 2482], [2483, 2485], [2486, 2493], [2494, 2495], [2496, 2503], [2504, 2512], [2513, 2518], [2518, 2519], [2520, 2528], [2529, 2531], [2532, 2539], [2540, 2541], [2542, 2549], [2550, 2558], [2559, 2564], [2564, 2565], [2566, 2574], [2575, 2577], [2578, 2585], [2586, 2587], [2588, 2595], [2596, 2604], [2605, 2610], [2610, 2611], [2612, 2620], [2621, 2623], [2624, 2631], [2632, 2633], [2634, 2641], [2642, 2650], [2651, 2656], [2656, 2657], [2658, 2666], [2667, 2669], [2670, 2677], [2678, 2679], [2680, 2687], [2688, 2696], [2697, 2702], [2702, 2703], [2704, 2712], [2713, 2715], [2716, 2723], [2724, 2725], [2726, 2733], [2734, 2742], [2743, 2748], [2748, 2749], [2750, 2758], [2759, 2761], [2762, 2769], [2770, 2771], [2772, 2779], [2780, 2788], [2789, 2794], [2794, 2795], [2796, 2804], [2805, 2807], [2808, 2815], [2816, 2817], [2818, 2825], [2826, 2834], [2835, 2840], [2840, 2841], [2842, 2850], [2851, 2853], [2854, 2861], [2862, 2863], [2864, 2871], [2872, 2880], [2881, 2886], [2886, 2887], [2888, 2896], [2897, 2899], [2900, 2907], [2908, 2909], [2910, 2917], [2918, 2926], [2927, 2932], [2932, 2933], [2934, 2942], [2943, 2945], [2946, 2953], [2954, 2955], [2956, 2963], [2964, 2972], [2973, 2978], [2978, 2979], [2980, 2988], [2989, 2991], [2992, 2999], [3000, 3001], [3002, 3009], [3010, 3018], [3019, 3024], [3024, 3025], [3026, 3034], [3035, 3037], [3038, 3045], [3046, 3047], [3048, 3055], [3056, 3064], [3065, 3070], [3070, 3071], [3072, 3080], [3081, 3083], [3084, 3091], [3092, 3093], [3094, 3101], [3102, 3110], [3111, 3116], [3116, 3117], [3118, 3126], [3127, 3129], [3130, 3137], [3138, 3139], [3140, 3147], [3148, 3156], [3157, 3162], [3162, 3163], [3164, 3172], [3173, 3175], [3176, 3183], [3184, 3185], [3186, 3193], [3194, 3202], [3203, 3208], [3208, 3209], [3210, 3218], [3219, 3221], [3222, 3229], [3230, 3231], [3232, 3239], [3240, 3248], [3249, 3254], [3254, 3255], [3256, 3264], [3265, 3267], [3268, 3275], [3276, 3277], [3278, 3285], [3286, 3294], [3295, 3300], [3300, 3301], [3302, 3310], [3311, 3313], [3314, 3321], [3322, 3323], [3324, 3331], [3332, 3340], [3341, 3346], [3346, 3347], [3348, 3356], [3357, 3359], [3360, 3367], [3368, 3369], [3370, 3377], [3378, 3386], [3387, 3392], [3392, 3393], [3394, 3402], [3403, 3405], [3406, 3413], [3414, 3415], [3416, 3423], [3424, 3432], [3433, 3438], [3438, 3439], [3440, 3448], [3449, 3451], [3452, 3459], [3460, 3461], [3462, 3469], [3470, 3478], [3479, 3484], [3484, 3485], [3486, 3494], [3495, 3497], [3498, 3505], [3506, 3507], [3508, 3515], [3516, 3524], [3525, 3530], [3530, 3531], [3532, 3540], [3541, 3543], [3544, 3551], [3552, 3553], [3554, 3561], [3562, 3570], [3571, 3576], [3576, 3577], [3578, 3586], [3587, 3589], [3590, 3597], [3598, 3599], [3600, 3607], [3608, 3616], [3617, 3622], [3622, 3623], [3624, 3632], [3633, 3635], [3636, 3643], [3644, 3645], [3646, 3653], [3654, 3662], [3663, 3668], [3668, 3669], [3670, 3678], [3679, 3681], [3682, 3689], [3690, 3691], [3692, 3699], [3700, 3708], [3709, 3714], [3714, 3715], [3716, 3724], [3725, 3727], [3728, 3735], [3736, 3737], [3738, 3745], [3746, 3754], [3755, 3760], [3760, 3761], [3762, 3770], [3771, 3773], [3774, 3781], [3782, 3783], [3784, 3791], [3792, 3800], [3801, 3806], [3806, 3807], [3808, 3816], [3817, 3819], [3820, 3827], [3828, 3829], [3830, 3837], [3838, 3846], [3847, 3852], [3852, 3853], [3854, 3862], [3863, 3865], [3866, 3873], [3874, 3875], [3876, 3883], [3884, 3892], [3893, 3898], [3898, 3899], [3900, 3908], [3909, 3911], [3912, 3919], [3920, 3921], [3922, 3929], [3930, 3938], [3939, 3944], [3944, 3945], [3946, 3954], [3955, 3957], [3958, 3965], [3966, 3967], [3968, 3975], [3976, 3984], [3985, 3990], [3990, 3991], [3992, 4000], [4001, 4003], [4004, 4011], [4012, 4013], [4014, 4021], [4022, 4030], [4031, 4036], [4036, 4037], [4038, 4046], [4047, 4049], [4050, 4057], [4058, 4059], [4060, 4067], [4068, 4076], [4077, 4082], [4082, 4083], [4084, 4092], [4093, 4095], [4096, 4103], [4104, 4105], [4106, 4113], [4114, 4122], [4123, 4128], [4128, 4129], [4130, 4138], [4139, 4141], [4142, 4149], [4150, 4151], [4152, 4159], [4160, 4168], [4169, 4174], [4174, 4175], [4176, 4184], [4185, 4187], [4188, 4195], [4196, 4197], [4198, 4205], [4206, 4214], [4215, 4220], [4220, 4221], [4222, 4230], [4231, 4233], [4234, 4241], [4242, 4243], [4244, 4251], [4252, 4260], [4261, 4266], [4266, 4267], [4268, 4276], [4277, 4279], [4280, 4287], [4288, 4289], [4290, 4297], [4298, 4306], [4307, 4312], [4312, 4313], [4314, 4322], [4323, 4325], [4326, 4333], [4334, 4335], [4336, 4343], [4344, 4352], [4353, 4358], [4358, 4359], [4360, 4368], [4369, 4371], [4372, 4379], [4380, 4381], [4382, 4389], [4390, 4398], [4399, 4404], [4404, 4405], [4406, 4414], [4415, 4417], [4418, 4425], [4426, 4427], [4428, 4435], [4436, 4444], [4445, 4450], [4450, 4451], [4452, 4460], [4461, 4463], [4464, 4471], [4472, 4473], [4474, 4481], [4482, 4490], [4491, 4496], [4496, 4497], [4498, 4506], [4507, 4509], [4510, 4517], [4518, 4519], [4520, 4527], [4528, 4536], [4537, 4542], [4542, 4543], [4544, 4552], [4553, 4555], [4556, 4563], [4564, 4565], [4566, 4573], [4574, 4582], [4583, 4588], [4588, 4589], [4590, 4598], [4599, 4602], [4603, 4610], [4611, 4612], [4613, 4620], [4621, 4629], [4630, 4635], [4635, 4636], [4637, 4645], [4646, 4649], [4650, 4657], [4658, 4659], [4660, 4667], [4668, 4676], [4677, 4682], [4682, 4683], [4684, 4692], [4693, 4696], [4697, 4704], [4705, 4706], [4707, 4714], [4715, 4723], [4724, 4729], [4729, 4730], [4731, 4739], [4740, 4743], [4744, 4751], [4752, 4753], [4754, 4761], [4762, 4770], [4771, 4776], [4776, 4777], [4778, 4786], [4787, 4790], [4791, 4798], [4799, 4800], [4801, 4808], [4809, 4817], [4818, 4823], [4823, 4824], [4825, 4833], [4834, 4837], [4838, 4845], [4846, 4847], [4848, 4855], [4856, 4864], [4865, 4870], [4870, 4871], [4872, 4880], [4881, 4884], [4885, 4892], [4893, 4894], [4895, 4902], [4903, 4911], [4912, 4917], [4917, 4918], [4919, 4927], [4928, 4931], [4932, 4939], [4940, 4941], [4942, 4949], [4950, 4958], [4959, 4964], [4964, 4965], [4966, 4974], [4975, 4978], [4979, 4986], [4987, 4988], [4989, 4996], [4997, 5005], [5006, 5011], [5011, 5012], [5013, 5021], [5022, 5025], [5026, 5033], [5034, 5035], [5036, 5043], [5044, 5052], [5053, 5058], [5058, 5059], [5060, 5068], [5069, 5072], [5073, 5080], [5081, 5082], [5083, 5090], [5091, 5099], [5100, 5105], [5105, 5106], [5107, 5115], [5116, 5119], [5120, 5127], [5128, 5129], [5130, 5137], [5138, 5146], [5147, 5152], [5152, 5153], [5154, 5162], [5163, 5166], [5167, 5174], [5175, 5176], [5177, 5184], [5185, 5193], [5194, 5199], [5199, 5200], [5201, 5209], [5210, 5213], [5214, 5221], [5222, 5223], [5224, 5231], [5232, 5240], [5241, 5246], [5246, 5247], [5248, 5256], [5257, 5260], [5261, 5268], [5269, 5270], [5271, 5278], [5279, 5287], [5288, 5293], [5293, 5294], [5295, 5303], [5304, 5307], [5308, 5315], [5316, 5317], [5318, 5325], [5326, 5334], [5335, 5340], [5340, 5341], [5342, 5350], [5351, 5354], [5355, 5362], [5363, 5364], [5365, 5372], [5373, 5381], [5382, 5387], [5387, 5388], [5389, 5397], [5398, 5401], [5402, 5409], [5410, 5411], [5412, 5419], [5420, 5428], [5429, 5434], [5434, 5435], [5436, 5444], [5445, 5448], [5449, 5456], [5457, 5458], [5459, 5466], [5467, 5475], [5476, 5481], [5481, 5482], [5483, 5491], [5492, 5495], [5496, 5503], [5504, 5505], [5506, 5513], [5514, 5522], [5523, 5528], [5528, 5529], [5530, 5538], [5539, 5542], [5543, 5550], [5551, 5552], [5553, 5560], [5561, 5569], [5570, 5575], [5575, 5576], [5577, 5585], [5586, 5589], [5590, 5597], [5598, 5599], [5600, 5607], [5608, 5616], [5617, 5622], [5622, 5623], [5624, 5632], [5633, 5636], [5637, 5644], [5645, 5646], [5647, 5654], [5655, 5663], [5664, 5669], [5669, 5670], [5671, 5679], [5680, 5683], [5684, 5691], [5692, 5693], [5694, 5701], [5702, 5710], [5711, 5716], [5716, 5717], [5718, 5726], [5727, 5730], [5731, 5738], [5739, 5740], [5741, 5748], [5749, 5757], [5758, 5763], [5763, 5764], [5765, 5773], [5774, 5777], [5778, 5785], [5786, 5787], [5788, 5795], [5796, 5804], [5805, 5810], [5810, 5811], [5812, 5820], [5821, 5824], [5825, 5832], [5833, 5834], [5835, 5842], [5843, 5851], [5852, 5857], [5857, 5858], [5859, 5867], [5868, 5871], [5872, 5879], [5880, 5881], [5882, 5889], [5890, 5898], [5899, 5904], [5904, 5905], [5906, 5914], [5915, 5918], [5919, 5926], [5927, 5928], [5929, 5936], [5937, 5945], [5946, 5951], [5951, 5952], [5953, 5961], [5962, 5965], [5966, 5973], [5974, 5975], [5976, 5983], [5984, 5992], [5993, 5998], [5998, 5999], [6000, 6008], [6009, 6012], [6013, 6020], [6021, 6022], [6023, 6030], [6031, 6039], [6040, 6045], [6045, 6046], [6047, 6055], [6056, 6059], [6060, 6067], [6068, 6069], [6070, 6077], [6078, 6086], [6087, 6092], [6092, 6093], [6094, 6102], [6103, 6106], [6107, 6114], [6115, 6116], [6117, 6124], [6125, 6133], [6134, 6139], [6139, 6140], [6141, 6149], [6150, 6153], [6154, 6161], [6162, 6163], [6164, 6171], [6172, 6180], [6181, 6186], [6186, 6187], [6188, 6196], [6197, 6200], [6201, 6208], [6209, 6210], [6211, 6218], [6219, 6227], [6228, 6233], [6233, 6234], [6235, 6243], [6244, 6247], [6248, 6255], [6256, 6257], [6258, 6265], [6266, 6274], [6275, 6280], [6280, 6281], [6282, 6290], [6291, 6294], [6295, 6302], [6303, 6304], [6305, 6312], [6313, 6321], [6322, 6327], [6327, 6328], [6329, 6337], [6338, 6341], [6342, 6349], [6350, 6351], [6352, 6359], [6360, 6368], [6369, 6374], [6374, 6375], [6376, 6384], [6385, 6388], [6389, 6396], [6397, 6398], [6399, 6406], [6407, 6415], [6416, 6421], [6421, 6422], [6423, 6431], [6432, 6435], [6436, 6443], [6444, 6445], [6446, 6453], [6454, 6462], [6463, 6468], [6468, 6469], [6470, 6478], [6479, 6482], [6483, 6490], [6491, 6492], [6493, 6500], [6501, 6509], [6510, 6515], [6515, 6516], [6517, 6525], [6526, 6529], [6530, 6537], [6538, 6539], [6540, 6547], [6548, 6556], [6557, 6562], [6562, 6563], [6564, 6572], [6573, 6576], [6577, 6584], [6585, 6586], [6587, 6594], [6595, 6603], [6604, 6609], [6609, 6610], [6611, 6619], [6620, 6623], [6624, 6631], [6632, 6633], [6634, 6641], [6642, 6650], [6651, 6656], [6656, 6657], [6658, 6666], [6667, 6670], [6671, 6678], [6679, 6680], [6681, 6688], [6689, 6697], [6698, 6703], [6703, 6704], [6705, 6713], [6714, 6717], [6718, 6725], [6726, 6727], [6728, 6735], [6736, 6744], [6745, 6750], [6750, 6751], [6752, 6760], [6761, 6764], [6765, 6772], [6773, 6774], [6775, 6782], [6783, 6791], [6792, 6797], [6797, 6798], [6799, 6807], [6808, 6811], [6812, 6819], [6820, 6821], [6822, 6829], [6830, 6838], [6839, 6844], [6844, 6845], [6846, 6854], [6855, 6858], [6859, 6866], [6867, 6868], [6869, 6876], [6877, 6885], [6886, 6891], [6891, 6892], [6893, 6901], [6902, 6905], [6906, 6913], [6914, 6915], [6916, 6923], [6924, 6932], [6933, 6938], [6938, 6939], [6940, 6948], [6949, 6952], [6953, 6960], [6961, 6962], [6963, 6970], [6971, 6979], [6980, 6985], [6985, 6986], [6987, 6995], [6996, 6999], [7000, 7007], [7008, 7009], [7010, 7017], [7018, 7026], [7027, 7032], [7032, 7033], [7034, 7042], [7043, 7046], [7047, 7054], [7055, 7056], [7057, 7064], [7065, 7073], [7074, 7079], [7079, 7080], [7081, 7089], [7090, 7093], [7094, 7101], [7102, 7103], [7104, 7111], [7112, 7120], [7121, 7126], [7126, 7127], [7128, 7136], [7137, 7140], [7141, 7148], [7149, 7150], [7151, 7158], [7159, 7167], [7168, 7173], [7173, 7174], [7175, 7183], [7184, 7187], [7188, 7195], [7196, 7197], [7198, 7205], [7206, 7214], [7215, 7220], [7220, 7221], [7222, 7230], [7231, 7234], [7235, 7242], [7243, 7244], [7245, 7252], [7253, 7261], [7262, 7267], [7267, 7268], [7269, 7277], [7278, 7281], [7282, 7289], [7290, 7291], [7292, 7299], [7300, 7308], [7309, 7314], [7314, 7315], [7316, 7324], [7325, 7328], [7329, 7336], [7337, 7338], [7339, 7346], [7347, 7355], [7356, 7361], [7361, 7362], [7363, 7371], [7372, 7375], [7376, 7383], [7384, 7385], [7386, 7393], [7394, 7402], [7403, 7408], [7408, 7409], [7410, 7418], [7419, 7422], [7423, 7430], [7431, 7432], [7433, 7440], [7441, 7449], [7450, 7455], [7455, 7456], [7457, 7465], [7466, 7469], [7470, 7477], [7478, 7479], [7480, 7487], [7488, 7496], [7497, 7502], [7502, 7503], [7504, 7512], [7513, 7516], [7517, 7524], [7525, 7526], [7527, 7534], [7535, 7543], [7544, 7549], [7549, 7550], [7551, 7559], [7560, 7563], [7564, 7571], [7572, 7573], [7574, 7581], [7582, 7590], [7591, 7596], [7596, 7597], [7598, 7606], [7607, 7610], [7611, 7618], [7619, 7620], [7621, 7628], [7629, 7637], [7638, 7643], [7643, 7644], [7645, 7653], [7654, 7657], [7658, 7665], [7666, 7667], [7668, 7675], [7676, 7684], [7685, 7690], [7690, 7691], [7692, 7700], [7701, 7704], [7705, 7712], [7713, 7714], [7715, 7722], [7723, 7731], [7732, 7737], [7737, 7738], [7739, 7747], [7748, 7751], [7752, 7759], [7760, 7761], [7762, 7769], [7770, 7778], [7779, 7784], [7784, 7785], [7786, 7794], [7795, 7798], [7799, 7806], [7807, 7808], [7809, 7816], [7817, 7825], [7826, 7831], [7831, 7832], [7833, 7841], [7842, 7845], [7846, 7853], [7854, 7855], [7856, 7863], [7864, 7872], [7873, 7878], [7878, 7879], [7880, 7888], [7889, 7892], [7893, 7900], [7901, 7902], [7903, 7910], [7911, 7919], [7920, 7925], [7925, 7926], [7927, 7935], [7936, 7939], [7940, 7947], [7948, 7949], [7950, 7957], [7958, 7966], [7967, 7972], [7972, 7973], [7974, 7982], [7983, 7986], [7987, 7994], [7995, 7996], [7997, 8004], [8005, 8013], [8014, 8019], [8019, 8020], [8021, 8029], [8030, 8033], [8034, 8041]], "w_pos": [52, 54, 55, 56, 57, 58, 59, 60, 61, 63, 64, 65, 66, 67, 68, 69, 70, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114, 115, 117, 118, 119, 120, 121, 122, 123, 124, 126, 127, 128, 129, 130, 131, 132, 133, 135, 136, 137, 138, 139, 140, 141, 142, 144, 146, 147, 148, 149, 150, 151, 152, 154, 156, 157, 158, 159, 160, 161, 162, 164, 166, 167, 168, 169, 170, 171, 172, 174, 176, 177, 178, 179, 180, 181, 182, 184, 186, 187, 188, 189, 190, 191, 192, 194, 196, 197, 198, 199, 200, 201, 202, 204, 206, 207, 208, 209, 210, 211, 212, 214, 216, 217, 218, 219, 220, 221, 222, 224, 226, 227, 228, 229, 230, 231, 232, 234, 236, 237, 238, 239, 240, 241, 242, 244, 246, 247, 248, 249, 250, 251, 252, 254, 256, 257, 258, 259, 260, 261, 262, 264, 266, 267, 268, 269, 270, 271, 272, 274, 276, 277, 278, 279, 280, 281, 282, 284, 286, 287, 288, 289, 290, 291, 292, 294, 296, 297, 298, 299, 300, 301, 302, 304, 306, 307, 308, 309, 310, 311, 312, 314, 316, 317, 318, 319, 320, 321, 322, 324, 326, 327, 328, 329, 330, 331, 332, 334, 336, 337, 338, 339, 340, 341, 342, 344, 346, 347, 348, 349, 350, 351, 352, 354, 356, 357, 358, 359, 360, 361, 362, 364, 366, 367, 368, 369, 370, 371, 372, 374, 376, 377, 378, 379, 380, 381, 382, 384, 386, 387, 388, 389, 390, 391, 392, 394, 396, 397, 398, 399, 400, 401, 402, 404, 406, 407, 408, 409, 410, 411, 412, 414, 416, 417, 418, 419, 420, 421, 422, 424, 426, 427, 428, 429, 430, 431, 432, 434, 436, 437, 438, 439, 440, 441, 442, 444, 446, 447, 448, 449, 450, 451, 452, 454, 456, 457, 458, 459, 460, 461, 462, 464, 466, 467, 468, 469, 470, 471, 472, 474, 476, 477, 478, 479, 480, 481, 482, 484, 486, 487, 488, 489, 490, 491, 492, 494, 496, 497, 498, 499, 500, 501, 502, 504, 506, 507, 508, 509, 510, 511, 512, 514, 516, 517, 518, 519, 520, 521, 522, 524, 526, 527, 528, 529, 530, 531, 532, 534, 536, 537, 538, 539, 540, 541, 542, 544, 546, 547, 548, 549, 550, 551, 552, 554, 556, 557, 558, 559, 560, 561, 562, 564, 566, 567, 568, 569, 570, 571, 572, 574, 576, 577, 578, 579, 580, 581, 582, 584, 586, 587, 588, 589, 590, 591, 592, 594, 596, 597, 598, 599, 600, 601, 602, 604, 606, 607, 608, 609, 610, 611, 612, 614, 616, 617, 618, 619, 620, 621, 622, 624, 626, 627, 628, 629, 630, 631, 632, 634, 636, 637, 638, 639, 640, 641, 642, 644, 646, 647, 648, 649, 650, 651, 652, 654, 656, 657, 658, 659, 660, 661, 662, 664, 666, 667, 668, 669, 670, 671, 672, 674, 676, 677, 678, 679, 680, 681, 682, 684, 686, 687, 688, 689, 690, 691, 692, 694, 696, 697, 698, 699, 700, 701, 702, 704, 706, 707, 708, 709, 710, 711, 712, 714, 716, 717, 718, 719, 720, 721, 722, 724, 726, 727, 728, 729, 730, 731, 732, 734, 736, 737, 738, 739, 740, 741, 742, 744, 746, 747, 748, 749, 750, 751, 752, 754, 756, 757, 758, 759, 760, 761, 762, 764, 766, 767, 768, 769, 770, 771, 772, 774, 776, 777, 778, 779, 780, 781, 782, 784, 786, 787, 788, 789, 790, 791, 792, 794, 796, 797, 798, 799, 800, 801, 802, 804, 806, 807, 808, 809, 810, 811, 812, 814, 816, 817, 818, 819, 820, 821, 822, 824, 826, 827, 828, 829, 830, 831, 832, 834, 836, 837, 838, 839, 840, 841, 842, 844, 846, 847, 848, 849, 850, 851, 852, 854, 856, 857, 858, 859, 860, 861, 862, 864, 866, 867, 868, 869, 870, 871, 872, 874, 876, 877, 878, 879, 880, 881, 882, 884, 886, 887, 888, 889, 890, 891, 892, 894, 896, 897, 898, 899, 900, 901, 902, 904, 906, 907, 908, 909, 910, 911, 912, 914, 916, 917, 918, 919, 920, 921, 922, 924, 926, 927, 928, 929, 930, 931, 932, 934, 936, 937, 938, 939, 940, 941, 942, 944, 946, 947, 948, 949, 950, 951, 952, 954, 956, 957, 958, 959, 960, 961, 962, 964, 966, 967, 968, 969, 970, 971, 972, 974, 976, 977, 978, 979, 980, 981, 982, 984, 986, 987, 988, 989, 990, 991, 992, 994, 996, 997, 998, 999, 1000, 1001, 1002, 1004, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1014, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1024, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1034, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1044, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1055, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1066, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1077, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1088, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1099, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1110, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1121, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1132, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1143, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1154, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1165, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1176, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1187, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1198, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1209, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1220, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1231, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1242, 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1253, 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1264, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1275, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1286, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1297, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1308, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1319, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1330, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1341, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1352, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1363, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1374, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1385, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1396, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1407, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 1418, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1429, 1432, 1433, 1434, 1435, 1436, 1437, 1438, 1440, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1451, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1462, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1473, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1484, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1495, 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1506, 1509, 1510, 1511, 1512, 1513, 1514, 1515, 1517, 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1528, 1531, 1532, 1533, 1534, 1535, 1536, 1537, 1539, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1550, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1561, 1564, 1565, 1566, 1567, 1568, 1569, 1570, 1572, 1575, 1576, 1577, 1578, 1579, 1580, 1581, 1583, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1594, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1605, 1608, 1609, 1610, 1611, 1612, 1613, 1614, 1616, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1627, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1638, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 1649, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1660, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1671, 1674, 1675, 1676, 1677, 1678, 1679, 1680, 1682, 1685, 1686, 1687, 1688, 1689, 1690, 1691, 1693, 1696, 1697, 1698, 1699, 1700, 1701, 1702, 1704, 1707, 1708, 1709, 1710, 1711, 1712, 1713, 1715, 1718, 1719, 1720, 1721, 1722, 1723, 1724, 1726, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1737, 1740, 1741, 1742, 1743, 1744, 1745, 1746, 1748, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1759, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1770, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1781, 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1792, 1795, 1796, 1797, 1798, 1799, 1800, 1801, 1803, 1806, 1807, 1808, 1809, 1810, 1811, 1812, 1814, 1817, 1818, 1819, 1820, 1821, 1822, 1823, 1825, 1828, 1829, 1830, 1831, 1832, 1833, 1834, 1836, 1839, 1840, 1841, 1842, 1843, 1844, 1845, 1847, 1850], "span_over": "user", "n_tokens": 3689, "head": "broad"}, {"p_ids": [1905, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 24, 6473, 264, 13618, 9403, 1484, 13, 198, 510, 22446, 29, 198], "blocks": [{"kind": "span", "ends": [40], "label_ranges": [[22, 40]], "words_in_block": true, "ids": [271, 6065, 913, 25, 9111, 198, 6196, 25, 1156, 198, 14162, 25, 198, 22365, 42824, 6088, 264, 9403, 30, 198, 22933, 25, 198, 14057, 29, 198, 4754, 4532, 3147, 64, 9403, 1484, 2129, 767, 3147, 31320, 8934, 198, 510, 1448, 29, 271, 1138, 25, 198, 27, 22446, 3364, 420, 846, 731, 198, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 20, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 21, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 22, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 23, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 16, 24, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 15, 24, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 15, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 16, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 17, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 18, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 19, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 20, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 21, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 22, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 23, 6473, 264, 13618, 9403, 1484, 13, 76802, 220, 17, 16, 24, 6473, 264, 13618, 9403, 1484, 13, 198, 510, 22446, 29, 198, 271, 8679, 1396, 9111, 314, 279, 2100, 1414, 421, 22651, 799, 314, 279, 8928, 13, 198, 6205, 581, 25], "query": 849, "w_pos": [52, 53, 54, 55, 56, 58, 61, 62, 63, 64, 65, 66, 67, 69, 72, 73, 74, 75, 76, 77, 78, 80, 83, 84, 85, 86, 87, 88, 89, 91, 94, 95, 96, 97, 98, 99, 100, 102, 105, 106, 107, 108, 109, 110, 111, 113, 116, 117, 118, 119, 120, 121, 122, 124, 127, 128, 129, 130, 131, 132, 133, 135, 138, 139, 140, 141, 142, 143, 144, 146, 149, 150, 151, 152, 153, 154, 155, 157, 160, 161, 162, 163, 164, 165, 166, 168, 171, 172, 173, 174, 175, 176, 177, 179, 182, 183, 184, 185, 186, 187, 188, 190, 193, 194, 195, 196, 197, 198, 199, 201, 204, 205, 206, 207, 208, 209, 210, 212, 215, 216, 217, 218, 219, 220, 221, 223, 226, 227, 228, 229, 230, 231, 232, 234, 237, 238, 239, 240, 241, 242, 243, 245, 248, 249, 250, 251, 252, 253, 254, 256, 259, 260, 261, 262, 263, 264, 265, 267, 270, 271, 272, 273, 274, 275, 276, 278, 281, 282, 283, 284, 285, 286, 287, 289, 292, 293, 294, 295, 296, 297, 298, 300, 303, 304, 305, 306, 307, 308, 309, 311, 314, 315, 316, 317, 318, 319, 320, 322, 325, 326, 327, 328, 329, 330, 331, 333, 336, 337, 338, 339, 340, 341, 342, 344, 347, 348, 349, 350, 351, 352, 353, 355, 358, 359, 360, 361, 362, 363, 364, 366, 369, 370, 371, 372, 373, 374, 375, 377, 380, 381, 382, 383, 384, 385, 386, 388, 391, 392, 393, 394, 395, 396, 397, 399, 402, 403, 404, 405, 406, 407, 408, 410, 413, 414, 415, 416, 417, 418, 419, 421, 424, 425, 426, 427, 428, 429, 430, 432, 435, 436, 437, 438, 439, 440, 441, 443, 446, 447, 448, 449, 450, 451, 452, 454, 457, 458, 459, 460, 461, 462, 463, 465, 468, 469, 470, 471, 472, 473, 474, 476, 479, 480, 481, 482, 483, 484, 485, 487, 490, 491, 492, 493, 494, 495, 496, 498, 501, 502, 503, 504, 505, 506, 507, 509, 512, 513, 514, 515, 516, 517, 518, 520, 523, 524, 525, 526, 527, 528, 529, 531, 534, 535, 536, 537, 538, 539, 540, 542, 545, 546, 547, 548, 549, 550, 551, 553, 556, 557, 558, 559, 560, 561, 562, 564, 567, 568, 569, 570, 571, 572, 573, 575, 578, 579, 580, 581, 582, 583, 584, 586, 589, 590, 591, 592, 593, 594, 595, 597, 600, 601, 602, 603, 604, 605, 606, 608, 611, 612, 613, 614, 615, 616, 617, 619, 622, 623, 624, 625, 626, 627, 628, 630, 633, 634, 635, 636, 637, 638, 639, 641, 644, 645, 646, 647, 648, 649, 650, 652, 655, 656, 657, 658, 659, 660, 661, 663, 666, 667, 668, 669, 670, 671, 672, 674, 677, 678, 679, 680, 681, 682, 683, 685, 688, 689, 690, 691, 692, 693, 694, 696, 699, 700, 701, 702, 703, 704, 705, 707, 710, 711, 712, 713, 714, 715, 716, 718, 721, 722, 723, 724, 725, 726, 727, 729, 732, 733, 734, 735, 736, 737, 738, 740, 743, 744, 745, 746, 747, 748, 749, 751, 754, 755, 756, 757, 758, 759, 760, 762, 765, 766, 767, 768, 769, 770, 771, 773, 776, 777, 778, 779, 780, 781, 782, 784, 787, 788, 789, 790, 791, 792, 793, 795, 798, 799, 800, 801, 802, 803, 804, 806, 809, 810, 811, 812, 813, 814, 815, 817, 820, 821, 822, 823, 824, 825]}], "trunc": {"shrink_cut": 0, "protected_cut": 0}, "seg_lens": {"user": 774}, "layout": "c", "names": ["delivery"], "w_offs": [[6916, 6923], [6924, 6932], [6933, 6938], [6938, 6939], [6940, 6948], [6949, 6952], [6953, 6960], [6961, 6962], [6963, 6970], [6971, 6979], [6980, 6985], [6985, 6986], [6987, 6995], [6996, 6999], [7000, 7007], [7008, 7009], [7010, 7017], [7018, 7026], [7027, 7032], [7032, 7033], [7034, 7042], [7043, 7046], [7047, 7054], [7055, 7056], [7057, 7064], [7065, 7073], [7074, 7079], [7079, 7080], [7081, 7089], [7090, 7093], [7094, 7101], [7102, 7103], [7104, 7111], [7112, 7120], [7121, 7126], [7126, 7127], [7128, 7136], [7137, 7140], [7141, 7148], [7149, 7150], [7151, 7158], [7159, 7167], [7168, 7173], [7173, 7174], [7175, 7183], [7184, 7187], [7188, 7195], [7196, 7197], [7198, 7205], [7206, 7214], [7215, 7220], [7220, 7221], [7222, 7230], [7231, 7234], [7235, 7242], [7243, 7244], [7245, 7252], [7253, 7261], [7262, 7267], [7267, 7268], [7269, 7277], [7278, 7281], [7282, 7289], [7290, 7291], [7292, 7299], [7300, 7308], [7309, 7314], [7314, 7315], [7316, 7324], [7325, 7328], [7329, 7336], [7337, 7338], [7339, 7346], [7347, 7355], [7356, 7361], [7361, 7362], [7363, 7371], [7372, 7375], [7376, 7383], [7384, 7385], [7386, 7393], [7394, 7402], [7403, 7408], [7408, 7409], [7410, 7418], [7419, 7422], [7423, 7430], [7431, 7432], [7433, 7440], [7441, 7449], [7450, 7455], [7455, 7456], [7457, 7465], [7466, 7469], [7470, 7477], [7478, 7479], [7480, 7487], [7488, 7496], [7497, 7502], [7502, 7503], [7504, 7512], [7513, 7516], [7517, 7524], [7525, 7526], [7527, 7534], [7535, 7543], [7544, 7549], [7549, 7550], [7551, 7559], [7560, 7563], [7564, 7571], [7572, 7573], [7574, 7581], [7582, 7590], [7591, 7596], [7596, 7597], [7598, 7606], [7607, 7610], [7611, 7618], [7619, 7620], [7621, 7628], [7629, 7637], [7638, 7643], [7643, 7644], [7645, 7653], [7654, 7657], [7658, 7665], [7666, 7667], [7668, 7675], [7676, 7684], [7685, 7690], [7690, 7691], [7692, 7700], [7701, 7704], [7705, 7712], [7713, 7714], [7715, 7722], [7723, 7731], [7732, 7737], [7737, 7738], [7739, 7747], [7748, 7751], [7752, 7759], [7760, 7761], [7762, 7769], [7770, 7778], [7779, 7784], [7784, 7785], [7786, 7794], [7795, 7798], [7799, 7806], [7807, 7808], [7809, 7816], [7817, 7825], [7826, 7831], [7831, 7832], [7833, 7841], [7842, 7845], [7846, 7853], [7854, 7855], [7856, 7863], [7864, 7872], [7873, 7878], [7878, 7879], [7880, 7888], [7889, 7892], [7893, 7900], [7901, 7902], [7903, 7910], [7911, 7919], [7920, 7925], [7925, 7926], [7927, 7935], [7936, 7939], [7940, 7947], [7948, 7949], [7950, 7957], [7958, 7966], [7967, 7972], [7972, 7973], [7974, 7982], [7983, 7986], [7987, 7994], [7995, 7996], [7997, 8004], [8005, 8013], [8014, 8019], [8019, 8020], [8021, 8029], [8030, 8033], [8034, 8041], [8042, 8043], [8044, 8051], [8052, 8060], [8061, 8066], [8066, 8067], [8068, 8076], [8077, 8080], [8081, 8088], [8089, 8090], [8091, 8098], [8099, 8107], [8108, 8113], [8113, 8114], [8115, 8123], [8124, 8127], [8128, 8135], [8136, 8137], [8138, 8145], [8146, 8154], [8155, 8160], [8160, 8161], [8162, 8170], [8171, 8174], [8175, 8182], [8183, 8184], [8185, 8192], [8193, 8201], [8202, 8207], [8207, 8208], [8209, 8217], [8218, 8221], [8222, 8229], [8230, 8231], [8232, 8239], [8240, 8248], [8249, 8254], [8254, 8255], [8256, 8264], [8265, 8268], [8269, 8276], [8277, 8278], [8279, 8286], [8287, 8295], [8296, 8301], [8301, 8302], [8303, 8311], [8312, 8315], [8316, 8323], [8324, 8325], [8326, 8333], [8334, 8342], [8343, 8348], [8348, 8349], [8350, 8358], [8359, 8362], [8363, 8370], [8371, 8372], [8373, 8380], [8381, 8389], [8390, 8395], [8395, 8396], [8397, 8405], [8406, 8409], [8410, 8417], [8418, 8419], [8420, 8427], [8428, 8436], [8437, 8442], [8442, 8443], [8444, 8452], [8453, 8456], [8457, 8464], [8465, 8466], [8467, 8474], [8475, 8483], [8484, 8489], [8489, 8490], [8491, 8499], [8500, 8503], [8504, 8511], [8512, 8513], [8514, 8521], [8522, 8530], [8531, 8536], [8536, 8537], [8538, 8546], [8547, 8550], [8551, 8558], [8559, 8560], [8561, 8568], [8569, 8577], [8578, 8583], [8583, 8584], [8585, 8593], [8594, 8597], [8598, 8605], [8606, 8607], [8608, 8615], [8616, 8624], [8625, 8630], [8630, 8631], [8632, 8640], [8641, 8644], [8645, 8652], [8653, 8654], [8655, 8662], [8663, 8671], [8672, 8677], [8677, 8678], [8679, 8687], [8688, 8691], [8692, 8699], [8700, 8701], [8702, 8709], [8710, 8718], [8719, 8724], [8724, 8725], [8726, 8734], [8735, 8738], [8739, 8746], [8747, 8748], [8749, 8756], [8757, 8765], [8766, 8771], [8771, 8772], [8773, 8781], [8782, 8785], [8786, 8793], [8794, 8795], [8796, 8803], [8804, 8812], [8813, 8818], [8818, 8819], [8820, 8828], [8829, 8832], [8833, 8840], [8841, 8842], [8843, 8850], [8851, 8859], [8860, 8865], [8865, 8866], [8867, 8875], [8876, 8879], [8880, 8887], [8888, 8889], [8890, 8897], [8898, 8906], [8907, 8912], [8912, 8913], [8914, 8922], [8923, 8926], [8927, 8934], [8935, 8936], [8937, 8944], [8945, 8953], [8954, 8959], [8959, 8960], [8961, 8969], [8970, 8973], [8974, 8981], [8982, 8983], [8984, 8991], [8992, 9000], [9001, 9006], [9006, 9007], [9008, 9016], [9017, 9020], [9021, 9028], [9029, 9030], [9031, 9038], [9039, 9047], [9048, 9053], [9053, 9054], [9055, 9063], [9064, 9067], [9068, 9075], [9076, 9077], [9078, 9085], [9086, 9094], [9095, 9100], [9100, 9101], [9102, 9110], [9111, 9114], [9115, 9122], [9123, 9124], [9125, 9132], [9133, 9141], [9142, 9147], [9147, 9148], [9149, 9157], [9158, 9161], [9162, 9169], [9170, 9171], [9172, 9179], [9180, 9188], [9189, 9194], [9194, 9195], [9196, 9204], [9205, 9208], [9209, 9216], [9217, 9218], [9219, 9226], [9227, 9235], [9236, 9241], [9241, 9242], [9243, 9251], [9252, 9255], [9256, 9263], [9264, 9265], [9266, 9273], [9274, 9282], [9283, 9288], [9288, 9289], [9290, 9298], [9299, 9302], [9303, 9310], [9311, 9312], [9313, 9320], [9321, 9329], [9330, 9335], [9335, 9336], [9337, 9345], [9346, 9349], [9350, 9357], [9358, 9359], [9360, 9367], [9368, 9376], [9377, 9382], [9382, 9383], [9384, 9392], [9393, 9396], [9397, 9404], [9405, 9406], [9407, 9414], [9415, 9423], [9424, 9429], [9429, 9430], [9431, 9439], [9440, 9443], [9444, 9451], [9452, 9453], [9454, 9461], [9462, 9470], [9471, 9476], [9476, 9477], [9478, 9486], [9487, 9490], [9491, 9498], [9499, 9500], [9501, 9508], [9509, 9517], [9518, 9523], [9523, 9524], [9525, 9533], [9534, 9537], [9538, 9545], [9546, 9547], [9548, 9555], [9556, 9564], [9565, 9570], [9570, 9571], [9572, 9580], [9581, 9584], [9585, 9592], [9593, 9594], [9595, 9602], [9603, 9611], [9612, 9617], [9617, 9618], [9619, 9627], [9628, 9631], [9632, 9639], [9640, 9641], [9642, 9649], [9650, 9658], [9659, 9664], [9664, 9665], [9666, 9674], [9675, 9678], [9679, 9686], [9687, 9688], [9689, 9696], [9697, 9705], [9706, 9711], [9711, 9712], [9713, 9721], [9722, 9725], [9726, 9733], [9734, 9735], [9736, 9743], [9744, 9752], [9753, 9758], [9758, 9759], [9760, 9768], [9769, 9772], [9773, 9780], [9781, 9782], [9783, 9790], [9791, 9799], [9800, 9805], [9805, 9806], [9807, 9815], [9816, 9819], [9820, 9827], [9828, 9829], [9830, 9837], [9838, 9846], [9847, 9852], [9852, 9853], [9854, 9862], [9863, 9866], [9867, 9874], [9875, 9876], [9877, 9884], [9885, 9893], [9894, 9899], [9899, 9900], [9901, 9909], [9910, 9913], [9914, 9921], [9922, 9923], [9924, 9931], [9932, 9940], [9941, 9946], [9946, 9947], [9948, 9956], [9957, 9960], [9961, 9968], [9969, 9970], [9971, 9978], [9979, 9987], [9988, 9993], [9993, 9994], [9995, 10003], [10004, 10007], [10008, 10015], [10016, 10017], [10018, 10025], [10026, 10034], [10035, 10040], [10040, 10041], [10042, 10050], [10051, 10054], [10055, 10062], [10063, 10064], [10065, 10072], [10073, 10081], [10082, 10087], [10087, 10088], [10089, 10097], [10098, 10101], [10102, 10109], [10110, 10111], [10112, 10119], [10120, 10128], [10129, 10134], [10134, 10135], [10136, 10144], [10145, 10148], [10149, 10156], [10157, 10158], [10159, 10166], [10167, 10175], [10176, 10181], [10181, 10182], [10183, 10191], [10192, 10195], [10196, 10203], [10204, 10205], [10206, 10213], [10214, 10222], [10223, 10228], [10228, 10229]], "w_pos": [52, 53, 54, 55, 56, 58, 61, 62, 63, 64, 65, 66, 67, 69, 72, 73, 74, 75, 76, 77, 78, 80, 83, 84, 85, 86, 87, 88, 89, 91, 94, 95, 96, 97, 98, 99, 100, 102, 105, 106, 107, 108, 109, 110, 111, 113, 116, 117, 118, 119, 120, 121, 122, 124, 127, 128, 129, 130, 131, 132, 133, 135, 138, 139, 140, 141, 142, 143, 144, 146, 149, 150, 151, 152, 153, 154, 155, 157, 160, 161, 162, 163, 164, 165, 166, 168, 171, 172, 173, 174, 175, 176, 177, 179, 182, 183, 184, 185, 186, 187, 188, 190, 193, 194, 195, 196, 197, 198, 199, 201, 204, 205, 206, 207, 208, 209, 210, 212, 215, 216, 217, 218, 219, 220, 221, 223, 226, 227, 228, 229, 230, 231, 232, 234, 237, 238, 239, 240, 241, 242, 243, 245, 248, 249, 250, 251, 252, 253, 254, 256, 259, 260, 261, 262, 263, 264, 265, 267, 270, 271, 272, 273, 274, 275, 276, 278, 281, 282, 283, 284, 285, 286, 287, 289, 292, 293, 294, 295, 296, 297, 298, 300, 303, 304, 305, 306, 307, 308, 309, 311, 314, 315, 316, 317, 318, 319, 320, 322, 325, 326, 327, 328, 329, 330, 331, 333, 336, 337, 338, 339, 340, 341, 342, 344, 347, 348, 349, 350, 351, 352, 353, 355, 358, 359, 360, 361, 362, 363, 364, 366, 369, 370, 371, 372, 373, 374, 375, 377, 380, 381, 382, 383, 384, 385, 386, 388, 391, 392, 393, 394, 395, 396, 397, 399, 402, 403, 404, 405, 406, 407, 408, 410, 413, 414, 415, 416, 417, 418, 419, 421, 424, 425, 426, 427, 428, 429, 430, 432, 435, 436, 437, 438, 439, 440, 441, 443, 446, 447, 448, 449, 450, 451, 452, 454, 457, 458, 459, 460, 461, 462, 463, 465, 468, 469, 470, 471, 472, 473, 474, 476, 479, 480, 481, 482, 483, 484, 485, 487, 490, 491, 492, 493, 494, 495, 496, 498, 501, 502, 503, 504, 505, 506, 507, 509, 512, 513, 514, 515, 516, 517, 518, 520, 523, 524, 525, 526, 527, 528, 529, 531, 534, 535, 536, 537, 538, 539, 540, 542, 545, 546, 547, 548, 549, 550, 551, 553, 556, 557, 558, 559, 560, 561, 562, 564, 567, 568, 569, 570, 571, 572, 573, 575, 578, 579, 580, 581, 582, 583, 584, 586, 589, 590, 591, 592, 593, 594, 595, 597, 600, 601, 602, 603, 604, 605, 606, 608, 611, 612, 613, 614, 615, 616, 617, 619, 622, 623, 624, 625, 626, 627, 628, 630, 633, 634, 635, 636, 637, 638, 639, 641, 644, 645, 646, 647, 648, 649, 650, 652, 655, 656, 657, 658, 659, 660, 661, 663, 666, 667, 668, 669, 670, 671, 672, 674, 677, 678, 679, 680, 681, 682, 683, 685, 688, 689, 690, 691, 692, 693, 694, 696, 699, 700, 701, 702, 703, 704, 705, 707, 710, 711, 712, 713, 714, 715, 716, 718, 721, 722, 723, 724, 725, 726, 727, 729, 732, 733, 734, 735, 736, 737, 738, 740, 743, 744, 745, 746, 747, 748, 749, 751, 754, 755, 756, 757, 758, 759, 760, 762, 765, 766, 767, 768, 769, 770, 771, 773, 776, 777, 778, 779, 780, 781, 782, 784, 787, 788, 789, 790, 791, 792, 793, 795, 798, 799, 800, 801, 802, 803, 804, 806, 809, 810, 811, 812, 813, 814, 815, 817, 820, 821, 822, 823, 824, 825], "span_over": "user", "n_tokens": 1639, "head": "broad"}]} diff --git a/tests/vela/native_bundle.rs b/tests/vela/native_bundle.rs new file mode 100644 index 00000000..81ae9038 --- /dev/null +++ b/tests/vela/native_bundle.rs @@ -0,0 +1,111 @@ +//! Bundle-gate tests: a synthetic bundle built in a unique temp +//! directory (no weights, no network) drives the manifest gate — pins, +//! inventory counts and per-file hashes. + +use omni_vela_native::bundle::{self, Bundle}; +use serde_json::json; + +fn temp_dir(name: &str) -> std::path::PathBuf { + let dir = + std::env::temp_dir().join(format!("vela-native-bundle-{name}-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).expect("tempdir"); + dir +} + +fn sha256(bytes: &[u8]) -> String { + use sha2::{Digest, Sha256}; + let digest = Sha256::new_with_prefix(bytes).finalize(); + digest.iter().map(|byte| format!("{byte:02x}")).collect() +} + +/// The minimal manifest of a correctly exported member; `files` are the +/// bundle files the gate hashes. +fn write_bundle(dir: &std::path::Path) { + let files: [(&str, &[u8]); 6] = [ + ("backbone.safetensors", b"backbone tensors"), + ("heads.safetensors", b"head tensors"), + ("config.json", b"{}"), + ("calibration.json", b"{}"), + ("tokenizer.json", b"{}"), + ("tokenizer_config.json", b"{}"), + ]; + let mut hashes = serde_json::Map::new(); + for (name, content) in files { + std::fs::write(dir.join(name), content).expect("write"); + hashes.insert(name.to_string(), json!(sha256(content))); + } + let manifest = json!({ + "format": bundle::FORMAT, + "model_id": bundle::MODEL_ID, + "model_name": "vllm-sr/Vela-2.0-0.8B", + "max_length": 16384, + "source": {"repo": "vllm-sr/Vela-2.0-0.8B", "revision": bundle::SOURCE_REVISION}, + "backbone": {"tensors": 320, "bf16": 204, "fp32": 116}, + "heads": {"tensors": 37}, + "files_sha256": hashes, + }); + std::fs::write( + dir.join("vela_native_manifest.json"), + serde_json::to_vec(&manifest).expect("manifest"), + ) + .expect("write"); +} + +#[test] +fn a_matching_bundle_loads_and_exposes_the_member() { + let dir = temp_dir("ok"); + write_bundle(&dir); + let loaded = Bundle::load(&dir).expect("loads"); + assert_eq!(loaded.model_name(), "vllm-sr/Vela-2.0-0.8B"); + assert_eq!(loaded.max_length(), 16384); + let _ = std::fs::remove_dir_all(&dir); +} + +#[test] +fn a_tampered_file_fails_its_hash() { + let dir = temp_dir("tampered"); + write_bundle(&dir); + std::fs::write(dir.join("calibration.json"), b"{\"tampered\": true}").expect("write"); + let error = Bundle::load(&dir).unwrap_err(); + assert!(error.to_string().contains("calibration.json"), "{error}"); + let _ = std::fs::remove_dir_all(&dir); +} + +#[test] +fn a_foreign_revision_is_refused() { + let dir = temp_dir("foreign"); + write_bundle(&dir); + let manifest_path = dir.join("vela_native_manifest.json"); + let mut manifest: serde_json::Value = + serde_json::from_slice(&std::fs::read(&manifest_path).expect("read")).expect("json"); + manifest["source"]["revision"] = json!("d692394127f6f87fc581d8634c9558fe4776efce"); + std::fs::write(&manifest_path, serde_json::to_vec(&manifest).expect("json")).expect("write"); + let error = Bundle::load(&dir).unwrap_err(); + assert!(error.to_string().contains("pinned"), "{error}"); + let _ = std::fs::remove_dir_all(&dir); +} + +#[test] +fn an_unexpected_inventory_is_refused() { + let dir = temp_dir("inventory"); + write_bundle(&dir); + let manifest_path = dir.join("vela_native_manifest.json"); + let mut manifest: serde_json::Value = + serde_json::from_slice(&std::fs::read(&manifest_path).expect("read")).expect("json"); + manifest["backbone"]["bf16"] = json!(320); + manifest["backbone"]["fp32"] = json!(0); + std::fs::write(&manifest_path, serde_json::to_vec(&manifest).expect("json")).expect("write"); + let error = Bundle::load(&dir).unwrap_err(); + assert!(error.to_string().contains("inventory"), "{error}"); + let _ = std::fs::remove_dir_all(&dir); +} + +#[test] +fn a_missing_manifest_names_the_export_step() { + let dir = temp_dir("empty"); + std::fs::create_dir_all(&dir).expect("tempdir"); + let error = Bundle::load(&dir).unwrap_err(); + assert!(error.to_string().contains("export_native.py"), "{error}"); + let _ = std::fs::remove_dir_all(&dir); +} diff --git a/tests/vela/native_contract.rs b/tests/vela/native_contract.rs new file mode 100644 index 00000000..fbbcf853 --- /dev/null +++ b/tests/vela/native_contract.rs @@ -0,0 +1,122 @@ +//! Wire-contract tests for the native Vela 2.0 worker, mirroring the +//! reference worker's protocol tests: the envelope triples must be +//! byte-equal to the pinned runtime's rejections. + +use omni_vela_native::contract::{self, RequestError}; +use serde_json::json; + +fn body(raw: &str) -> serde_json::Map { + contract::parse_body(raw.as_bytes()).expect("valid body") +} + +fn detail(loc: &[&str], msg: &str, type_: &str) -> serde_json::Value { + let mut path = vec![json!("body")]; + path.extend(loc.iter().map(|part| json!(part))); + json!({"detail": [{"loc": path, "msg": msg, "type": type_}]}) +} + +const SERVED: &str = "vllm-sr/Vela-2.0-0.8B"; + +fn raw_body() -> String { + format!( + r#"{{"model": "{SERVED}", "state": "My card was charged twice.", "questions": {{"billing": {{"type": "noul", "instructions": "any?"}}}}}}"# + ) +} + +#[test] +fn the_envelope_passes_through_unchanged() { + let parsed = body(&raw_body()); + contract::admit_request(&parsed, SERVED).expect("admitted"); + assert_eq!(parsed.len(), 3); +} + +#[test] +fn a_missing_field_reports_upstreams_missing_triple() { + for drop in ["state", "model", "questions"] { + let mut parsed = body(&raw_body()); + parsed.shift_remove(drop); + let error = contract::admit_request(&parsed, SERVED).unwrap_err(); + assert_eq!( + error, + RequestError::envelope(&[drop], "Field required", "missing") + ); + assert_eq!(error.body, detail(&[drop], "Field required", "missing")); + } +} + +#[test] +fn an_extra_field_reports_upstreams_extra_forbidden() { + let mut parsed = body(&raw_body()); + parsed.insert("images".into(), json!([])); + let error = contract::admit_request(&parsed, SERVED).unwrap_err(); + assert_eq!(error.status, 422); + assert_eq!( + error.body, + detail( + &["images"], + "Extra inputs are not permitted", + "extra_forbidden" + ) + ); +} + +#[test] +fn a_blank_model_is_rejected_before_the_name_check() { + let mut parsed = body(&raw_body()); + parsed.insert("model".into(), json!(" ")); + let error = contract::admit_request(&parsed, SERVED).unwrap_err(); + assert_eq!( + error.body, + detail( + &["model"], + "model must not be empty or whitespace", + "value_error" + ) + ); +} + +#[test] +fn another_members_name_is_rejected_with_the_model_triple() { + let mut parsed = body(&raw_body()); + parsed.insert("model".into(), json!("vllm-sr/Vela-2.0-0.3B")); + let error = contract::admit_request(&parsed, SERVED).unwrap_err(); + assert_eq!( + error.body, + detail( + &["model"], + "Model is not served by this runtime", + "value_error.model" + ) + ); +} + +#[test] +fn duplicate_keys_are_rejected_with_the_reference_message() { + let error = + contract::parse_body(br#"{"model": "x", "model": "y", "state": "s", "questions": {}}"#) + .unwrap_err(); + assert_eq!(error.status, 400); + assert_eq!(error.body, json!({"detail": "duplicate JSON key 'model'"})); +} + +#[test] +fn invalid_json_is_a_generic_400() { + let error = contract::parse_body(b"{not json").unwrap_err(); + assert_eq!(error.status, 400); + assert_eq!( + error.body, + json!({"detail": "request body must contain valid JSON and UTF-8 text"}) + ); +} + +#[test] +fn a_non_object_body_is_rejected() { + let error = contract::parse_body(b"[1, 2]").unwrap_err(); + assert_eq!(error.status, 400); +} + +#[test] +fn compile_admits_and_returns_the_body() { + let parsed = contract::compile(raw_body().as_bytes(), SERVED).expect("admitted"); + assert!(parsed.contains_key("questions")); +} From 9812853b28795467871fe78318460a3f75d05994 Mon Sep 17 00:00:00 2001 From: "Mr.Dong" <1042542469@qq.com> Date: Sun, 25 Oct 2026 02:34:48 +0800 Subject: [PATCH 03/14] vela: add the 0.8B native token-level processing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Rust processing of the native path, mirrored from the pinned runtime and checked field-for-field against the five frozen token plans (opt-in render parity with the exported bundle's tokenizer): - state.rs: the state -> typed-parts mapping (role grouping, field ranges, canonical DEV2.0 JSON) with the pinned rejection triples; - questions.rs: the SystemOne -> predict mapping — the validation walk and order, Noul folded into a two-option choice (choice renders [ABS], the reference's abstain default), over resolution, threshold/head carried, the set-label collision check; - words.rs: the GLiNER2/CJK _WORD splitter and the first-token word mapping; - render.rs: the encoder (char-offset tokens, memoized), the six-rule span-head dispatch with the hallucination-alias label replacement, the truncation budget, the DEV2.0 rendering (parts pass, question blocks with option ends and query positions, span layout a/c with word positions) and the window rows (head only, as the reference); - processing.rs: the Processor over the exported bundle. Also: the envelope error locs are flat arrays, matching the reference triples exactly. Checks: cargo test (26 tests) + fmt/clippy clean + opt-in render parity (5/5 fixtures). --- Cargo.lock | 3 + README.md | 2 +- docs/supported-models.md | 2 +- recipe/vela/native.md | 44 +- src/models/vela/README.md | 17 +- src/models/vela/native/Cargo.toml | 13 +- src/models/vela/native/examples/parity.rs | 87 +++ src/models/vela/native/src/contract.rs | 15 +- src/models/vela/native/src/lib.rs | 12 +- src/models/vela/native/src/processing.rs | 274 ++++++++ src/models/vela/native/src/questions.rs | 441 ++++++++++++ src/models/vela/native/src/render.rs | 789 ++++++++++++++++++++++ src/models/vela/native/src/state.rs | 235 +++++++ src/models/vela/native/src/words.rs | 119 ++++ tests/vela/native_contract_unit.rs | 14 + tests/vela/native_processing.rs | 137 ++++ tests/vela/native_units.rs | 97 +++ 17 files changed, 2271 insertions(+), 30 deletions(-) create mode 100644 src/models/vela/native/examples/parity.rs create mode 100644 src/models/vela/native/src/processing.rs create mode 100644 src/models/vela/native/src/questions.rs create mode 100644 src/models/vela/native/src/render.rs create mode 100644 src/models/vela/native/src/state.rs create mode 100644 src/models/vela/native/src/words.rs create mode 100644 tests/vela/native_contract_unit.rs create mode 100644 tests/vela/native_processing.rs create mode 100644 tests/vela/native_units.rs diff --git a/Cargo.lock b/Cargo.lock index 2a269f64..bd63bd1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1295,8 +1295,11 @@ version = "0.1.0" dependencies = [ "anyhow", "omni-qwen3-5-native", + "onig", + "serde", "serde_json", "sha2 0.11.1", + "tokenizers 0.22.2", ] [[package]] diff --git a/README.md b/README.md index cbfce500..a68b0fd2 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ extensions) on each checkpoint's own pinned runtime: | OmniJev-4B v1.1 | [Checkpoint export and CPU contract](recipe/omnijev/README.md) only; the native worker is in progress ([#114](https://github.com/ThinkFlowLab/system1-omni/issues/114)) | | D3 (Decision 3.0) | [Python reference worker](recipe/d3/reference.md) on the checkpoint's pinned runtime; `choice`/`noul`/`score` text state, media inputs refused; author-run on A100 (evidence in the integration PR) | | Vela 2.0 0.3B | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; all five kinds (`choice`/`noul`/`score`/`span`/`set`) for text state; CPU FP32 validated (author-run, evidence in the integration PR) | -| Vela 2.0 0.8B hybrid | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; same surface plus `span_heads`; [native library](recipe/vela/native.md) (bundle export, wire contract); CPU FP32 parity recorded in the integration PR | +| Vela 2.0 0.8B hybrid | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; same surface plus `span_heads`; [native library](recipe/vela/native.md) (bundle export, wire contract, token-level processing); CPU FP32 parity recorded in the integration PR | [Supported models and hardware](docs/supported-models.md) lists the devices and where each worker has been run. diff --git a/docs/supported-models.md b/docs/supported-models.md index 30a52c6b..399ea09a 100644 --- a/docs/supported-models.md +++ b/docs/supported-models.md @@ -25,7 +25,7 @@ Models that are being added are also tracked in issues labeled [new model](https | OmniJev-4B v1.1 | None yet: [checkpoint export and CPU contract](../recipe/omnijev/README.md); the native worker is in progress ([#114](https://github.com/ThinkFlowLab/system1-omni/issues/114)) | Request contract, preparation, heads and finishing checked against the reference ([#120](https://github.com/ThinkFlowLab/system1-omni/pull/120)); no inference | Not yet | Not supported | Python 3.10 reference environment for the export and fixtures | | D3 (Decision 3.0) | [Python reference worker](../recipe/d3/reference.md) running the checkpoint's pinned runtime | Unverified | Author-run on NVIDIA A100 (sm_80): three-kind serving smoke with byte-identical frontend forwarding and reference parity (exact decisions, max delta 0.0, 348 == 348 tokens); evidence in the integration PR. Owner: @MrDongsls. | Unverified | Python 3.12, the [pinned runtime requirements](../recipe/d3/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/d3) (~52 GB) | | Vela 2.0 0.3B | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime | **CPU FP32 validated** (author-run, x86 WSL2, 24 cores): startup with all-kind warmup, the four example requests plus five synthetic rejections, and exact-match reference parity against the pinned upstream server on all nine (four 200s byte-equal incl. key order, agreed 422/413); byte-identical frontend forwarding; evidence in the integration PR. Owner: @MrDongsls. | Unverified (bf16-autocast is an untested deployment option) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.3B) (1.24 GB FP32 weights; ~4.4 GB with ONNX/assets) | -| Vela 2.0 0.8B hybrid | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime (same wire layer as 0.3B); [native library](../recipe/vela/native.md) — bundle export, wire contract | Same surface as 0.3B plus the `span_heads` field (router/broad dispatch); **CPU FP32 parity** (author-run; evidence in the integration PR) | Unverified (bf16-autocast is the evaluated upstream setting but untested here) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) (2.02 GB shard + 4.5 MB broad head; ~3 GB FP32 parameters) | +| Vela 2.0 0.8B hybrid | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime (same wire layer as 0.3B); [native library](../recipe/vela/native.md) — bundle export, wire contract, token-level processing | Same surface as 0.3B plus the `span_heads` field (router/broad dispatch); **CPU FP32 parity** (author-run; evidence in the integration PR) | Unverified (bf16-autocast is the evaluated upstream setting but untested here) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) (2.02 GB shard + 4.5 MB broad head; ~3 GB FP32 parameters) | - **Validated:** covered by the recipe on `main` or by the checks in the linked merged pull request. - **Author-run:** recorded by the recipe author on the stated hardware and not independently reproduced; the row names its owner. diff --git a/recipe/vela/native.md b/recipe/vela/native.md index a9328003..4c3cefa3 100644 --- a/recipe/vela/native.md +++ b/recipe/vela/native.md @@ -2,8 +2,9 @@ The native implementation for [vllm-sr/Vela-2.0-0.8B](https://huggingface.co/vllm-sr/Vela-2.0-0.8B): -the exported-bundle gate and the wire contract, mirrored from the -pinned runtime. This is a library; serving runs through the +the exported-bundle gate, the wire contract, and the token-level +processing — all mirrored from the pinned runtime and checked against +frozen fixtures. This is a library; serving runs through the [reference recipe](reference.md)'s Python worker. Run the commands from the repository root with the same `.venv` and @@ -28,22 +29,45 @@ tokenizer, and `vela_native_manifest.json` pinning the source revision, the gate's file table, the tensor inventory and every file's SHA-256. +## Freeze the token-plan fixtures (opt-in, needs the package) + +~~~sh +PYTHONPATH=src .venv/bin/python recipe/vela/export_token_plan.py \ + --model weights/vela-2.0-0.8b --out tests/vela/fixtures/ +~~~ + +The token plans record what the pinned runtime feeds the backbone (the +predict mapping, the per-row decomposition, the rendered `p_ids`, +blocks and readout positions, truncation, a windowed long-span case). +The example-request token plan totals 1,041 tokens, matching the +oracle fixture's `usage.input_tokens`. + ## Checks ~~~sh cargo test -p omni-vela-native cargo fmt --all --check cargo clippy -p omni-vela-native --all-targets -- -D warnings +VELA_NATIVE_BUNDLE="$PWD/weights/vela-2.0-0.8b-native" \ + cargo test -p omni-vela-native --test vela_native_processing -- --nocapture ~~~ -15 tests, no weights, no GPU: the wire contract against the pinned -runtime's 422/400 bodies and the bundle manifest gate against a -synthetic bundle. +26 tests run everywhere with no weights and no GPU: the wire contract +against the pinned runtime's 422/400 bodies, the bundle manifest gate, +and the predict-mapping/plan parity on every frozen fixture. The +opt-in render check replays the five token plans through the Rust +processing field-for-field. For a field-level diff of one case: + +~~~sh +VELA_NATIVE_BUNDLE="$PWD/weights/vela-2.0-0.8b-native" \ + cargo run -p omni-vela-native --example parity -- example-request +~~~ ## Scope and limits -- Implemented: the bundle export + manifest gate and the wire - admission. -- Not implemented: token-level processing, the F32 heads, scoring, - backbone execution, and an HTTP worker. No performance claims are - made. +- Implemented: the bundle export + manifest gate, the wire admission, + and the token-level processing (state mapping, predict mapping with + the validation triples, word units, span-head dispatch, the DEV2.0 + rendering, the truncation budget, window rows). +- Not implemented: the F32 heads, scoring and span decoding, backbone + execution, and an HTTP worker. No performance claims are made. diff --git a/src/models/vela/README.md b/src/models/vela/README.md index 888658fc..92fc4f82 100644 --- a/src/models/vela/README.md +++ b/src/models/vela/README.md @@ -246,8 +246,19 @@ The native implementation lives in [`native/`](native/) as the - `native/src/contract.rs` is the wire admission, mirroring `protocol.py` and the pinned runtime's preamble with byte-equal 422/400 bodies. +- `native/src/{state,questions,words,render,processing}.rs` are the + token-level processing: the state → parts mapping, the SystemOne → + predict mapping with the pinned runtime's validation triples (Noul + folded into a two-option choice; choice renders `[ABS]`, the + reference's abstain default), the GLiNER2/CJK word splitter, the + six-rule span-head dispatch with the hallucination-alias label + replacement, the DEV2.0 prompt rendering (parts pass, question + blocks with option end and query positions, span layout a/c with + word positions, the truncation budget, the 16,384-window 413) and + the long-target window rows. All five frozen token plans + (`tests/vela/fixtures/native-plan-*.json`) match field-for-field. -Token-level processing, the F32 heads, backbone execution and an HTTP -worker are not implemented. Checks: `cargo test -p omni-vela-native` -(15 tests, no weights, no GPU; see +The F32 heads, scoring, backbone execution and an HTTP worker are not +implemented. Checks: `cargo test -p omni-vela-native` (26 tests, no +weights, no GPU; render parity opt-in with `VELA_NATIVE_BUNDLE`; see [recipe/vela/native.md](../../recipe/vela/native.md)). diff --git a/src/models/vela/native/Cargo.toml b/src/models/vela/native/Cargo.toml index 814d32b0..40308a34 100644 --- a/src/models/vela/native/Cargo.toml +++ b/src/models/vela/native/Cargo.toml @@ -3,11 +3,14 @@ name = "omni-vela-native" version = "0.1.0" edition = "2024" publish = false -description = "Native library for vllm-sr/Vela-2.0-0.8B: bundle gate and wire contract" +description = "Native library for vllm-sr/Vela-2.0-0.8B: bundle gate, wire contract and token-level processing" [dependencies] anyhow = "1.0.100" +onig = { package = "onig", version = "6", default-features = false } omni-qwen3-5-native = { path = "../../qwen3_5/native" } +serde = { version = "1", features = ["derive"] } +tokenizers = { version = "=0.22.2", default-features = false, features = ["onig"] } serde_json = { version = "1.0.149", features = ["preserve_order"] } sha2 = "0.11" @@ -24,3 +27,11 @@ path = "../../../../tests/vela/native_contract.rs" [[test]] name = "vela_native_bundle" path = "../../../../tests/vela/native_bundle.rs" + +[[test]] +name = "vela_native_processing" +path = "../../../../tests/vela/native_processing.rs" + +[[test]] +name = "vela_native_units" +path = "../../../../tests/vela/native_units.rs" diff --git a/src/models/vela/native/examples/parity.rs b/src/models/vela/native/examples/parity.rs new file mode 100644 index 00000000..071d0f52 --- /dev/null +++ b/src/models/vela/native/examples/parity.rs @@ -0,0 +1,87 @@ +//! Debug helper: compare the rendered rows against one fixture and +//! print the first differing field. Run with: +//! +//! VELA_NATIVE_BUNDLE=/abs/path cargo run -p omni-vela-native --example parity -- example-request + +use std::path::PathBuf; + +use serde_json::Value; + +fn main() { + let case = std::env::args().nth(1).unwrap_or("example-request".into()); + let bundle = PathBuf::from( + std::env::var("VELA_NATIVE_BUNDLE").expect("VELA_NATIVE_BUNDLE points at the export"), + ); + let fixture: Value = serde_json::from_str( + &std::fs::read_to_string( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../../../../tests/vela/fixtures") + .join(format!("native-plan-{case}.json")), + ) + .expect("fixture"), + ) + .expect("fixture json"); + + let processor = omni_vela_native::processing::Processor::load(&bundle).expect("load"); + let request = fixture["request"].as_object().expect("request"); + match processor.plan(request) { + Ok(planned) => { + let got = serde_json::json!({ + "rows": serde_json::to_value(&planned.rows).unwrap(), + "window_rows": serde_json::to_value(&planned.window_rows).unwrap(), + }); + compare( + "rows", + got["rows"].as_array().unwrap(), + fixture["rows"].as_array().unwrap(), + ); + if !fixture["window_rows"].is_null() { + compare( + "window_rows", + got["window_rows"].as_array().unwrap(), + fixture["window_rows"].as_array().unwrap(), + ); + } + println!("parity: no field differences found"); + } + Err(error) => println!( + "plan error: {}", + serde_json::to_string(&error.body).unwrap() + ), + } +} + +fn compare(name: &str, got: &[Value], want: &[Value]) { + println!("{name}: {} vs {} row(s)", got.len(), want.len()); + for (index, (a, b)) in got.iter().zip(want).enumerate() { + let (Some(a), Some(b)) = (a.as_object(), b.as_object()) else { + continue; + }; + for key in b.keys() { + if a.get(key) != b.get(key) { + println!("row {index} field {key}: differs"); + println!( + " want: {}", + serde_json::to_string(&b[key]) + .unwrap() + .chars() + .take(300) + .collect::() + ); + println!( + " got: {}", + serde_json::to_string(&a[key]) + .unwrap() + .chars() + .take(300) + .collect::() + ); + } + } + for key in a.keys() { + if !b.contains_key(key) { + println!("row {index} field {key}: extra in ours"); + } + } + } +} diff --git a/src/models/vela/native/src/contract.rs b/src/models/vela/native/src/contract.rs index 06a3de95..734dcb25 100644 --- a/src/models/vela/native/src/contract.rs +++ b/src/models/vela/native/src/contract.rs @@ -56,7 +56,7 @@ pub fn parse_body(raw: &[u8]) -> Result, RequestError> { /// Mirror the reference worker's 400 messages: duplicate keys verbatim, /// everything else the shared generic message. -fn normalize_parse_error(error: &str) -> RequestError { +pub(crate) fn normalize_parse_error(error: &str) -> RequestError { if let Some(rest) = error.split("duplicate key ").nth(1) { // serde appends its position suffix after the quoted key. if let Some(key) = rest @@ -129,14 +129,5 @@ pub fn runtime_rejection(message: &str) -> RequestError { } #[cfg(test)] -mod tests { - use super::*; - - #[test] - fn duplicate_keys_mirror_the_reference_message() { - let error = - normalize_parse_error("request body is not valid JSON: duplicate key \"state\""); - assert_eq!(error.status, 400); - assert_eq!(error.body, json!({"detail": "duplicate JSON key 'state'"})); - } -} +#[path = "../../../../../tests/vela/native_contract_unit.rs"] +mod tests; diff --git a/src/models/vela/native/src/lib.rs b/src/models/vela/native/src/lib.rs index 32f64c4f..1d849284 100644 --- a/src/models/vela/native/src/lib.rs +++ b/src/models/vela/native/src/lib.rs @@ -1,5 +1,13 @@ -//! Native library for vllm-sr/Vela-2.0-0.8B: the exported-bundle gate -//! and the wire contract, mirrored from the pinned runtime. +//! Native library for vllm-sr/Vela-2.0-0.8B: the exported-bundle gate, +//! the wire contract, and the token-level processing (state → parts, +//! the SystemOne → predict mapping with the pinned runtime's validation +//! triples, word units, the DEV2.0 prompt rendering — mirrored against +//! the frozen `native-plan-*` fixtures). pub mod bundle; pub mod contract; +pub mod processing; +pub mod questions; +pub mod render; +pub mod state; +pub mod words; diff --git a/src/models/vela/native/src/processing.rs b/src/models/vela/native/src/processing.rs new file mode 100644 index 00000000..12370856 --- /dev/null +++ b/src/models/vela/native/src/processing.rs @@ -0,0 +1,274 @@ +//! The processor: one admitted request body → predict mapping, plan, +//! and rendered rows, mirroring the reference path +//! (`system_one_to_predict` → `_to_generic` → `_predict`'s row split → +//! `_prep`/`_render`, plus the long-target window rows). Everything the +//! frozen `native-plan-*` fixtures record. + +use std::collections::HashSet; +use std::path::Path; + +use anyhow::{Context, Result}; +use serde_json::{Map, Value}; + +use crate::contract::RequestError; +use crate::questions::{PredictQuestion, system_one_to_predict}; +use crate::render::{ + Encoder, GenericQuestion, HALU_LABEL, PreparedPart, RMAX, RenderContext, RenderedRow, + window_part, +}; +use crate::state::system_one_state; + +pub struct Processor { + encoder: Encoder, + max_length: usize, + router_label_sets: Vec>, + has_broad: bool, + halu_desc: String, +} + +pub struct Planned { + pub predict_request: Value, + pub plan: Value, + pub rows: Vec, + pub window_rows: Vec, +} + +impl Processor { + /// Load from an exported native bundle (tokenizer + calibration; + /// the manifest gate runs first). + pub fn load(bundle: &Path) -> Result { + let manifest = crate::bundle::Bundle::load(bundle)?; + let calibration: Value = serde_json::from_slice( + &std::fs::read(bundle.join("calibration.json")).context("calibration.json")?, + ) + .context("calibration.json must be JSON")?; + let broad = calibration.get("broad_head").filter(|b| !b.is_null()); + let router_label_sets: Vec> = broad + .and_then(|b| b.get("router_label_sets")) + .and_then(Value::as_array) + .filter(|sets| !sets.is_empty()) + .map(|sets| { + sets.iter() + .filter_map(Value::as_array) + .map(|labels| { + labels + .iter() + .filter_map(Value::as_str) + .map(str::to_owned) + .collect() + }) + .collect() + }) + .unwrap_or_else(|| { + vec![ + calibration["pii_types"].as_array().map(|types| { + types + .iter() + .filter_map(Value::as_str) + .map(str::to_owned) + .collect() + }), + calibration["halu_schema"]["labels"] + .as_object() + .map(|labels| labels.keys().cloned().collect()), + ] + .into_iter() + .flatten() + .collect() + }); + let has_broad = broad.is_some(); // the bundle gate pinned the broad tensors + let halu_desc = calibration["halu_schema"]["labels"][HALU_LABEL] + .as_str() + .unwrap_or("a claim not supported by the context") + .to_owned(); + Ok(Self { + encoder: Encoder::load(&bundle.join("tokenizer.json"))?, + max_length: manifest.max_length(), + router_label_sets, + has_broad, + halu_desc, + }) + } + + /// The full planning path for one admitted request body. + pub fn plan(&self, body: &Map) -> Result { + let state = system_one_state(&body["state"])?; + let questions = body["questions"] + .as_object() + .ok_or_else(crate::questions::empty_questions_error)?; + let mapped = system_one_to_predict(state, questions)?; + let predict_request = serde_json::to_value(&mapped.request).expect("serializable"); + let plan = serde_json::to_value(&mapped.plan).expect("serializable"); + let state_parts = mapped.request.parts.clone(); + + // `_to_generic`: predict questions → generic render questions + // (Noul is already folded; choice always carries [ABS]). + let generic: Vec = + mapped.request.questions.iter().map(to_generic).collect(); + // `_predict`'s row split: non-span questions plus the first span + // in one row, every further span its own row. + let spans: Vec<&GenericQuestion> = generic.iter().filter(|q| q.kind == "span").collect(); + let rest: Vec = generic + .iter() + .filter(|q| q.kind != "span") + .cloned() + .collect(); + let mut rows: Vec> = Vec::new(); + if !rest.is_empty() || !spans.is_empty() { + let mut first = rest.clone(); + if let Some(span) = spans.first() { + first.push((*span).clone()); + } + rows.push(first); + for span in spans.iter().skip(1) { + rows.push(vec![(*span).clone()]); + } + } + let context = RenderContext { + encoder: &self.encoder, + max_length: self.max_length, + router_label_sets: &self.router_label_sets, + has_broad: self.has_broad, + halu_desc: self.halu_desc.clone(), + }; + let span_roles: HashSet = + spans.iter().flat_map(|q| q.over.iter().cloned()).collect(); + let mut rendered = Vec::new(); + let mut window_rows = Vec::new(); + let mut parts_by_role = std::collections::HashMap::new(); + for part in self.prepared_parts(&state_parts, &span_roles) { + parts_by_role.insert(part.role.clone(), part); + } + for row in rows { + if row.is_empty() { + continue; + } + let (adjusted, dispatch) = context.prepare_questions(&row)?; + let parts: Vec = state_parts + .iter() + .map(|part| { + parts_by_role + .get(&part.r#type) + .cloned() + .expect("prepared part") + }) + .collect(); + let record = context.render(&parts, &adjusted, &dispatch)?; + // `_window_rows`: a span target beyond RMAX becomes one row + // per window (the full-render span block stays on the row). + let span = row.iter().find(|q| q.kind == "span"); + if let Some(span) = span { + let index = parts.iter().position(|p| p.role == span.over[0]); + if let Some(index) = index { + let part = &parts[index]; + let has_words = part.words.is_some(); + if part.ids.len() > RMAX && has_words { + let (_, first_tokens) = part.words.as_ref().expect("words"); + for (a, b) in crate::render::span_windows(first_tokens, part.ids.len()) { + let mut windowed_parts = parts.clone(); + windowed_parts[index] = window_part(part, a, b); + let (w_adjusted, w_dispatch) = context.prepare_questions(&row)?; + let mut record = + context.render(&windowed_parts, &w_adjusted, &w_dispatch)?; + // The runtime's window rows carry the head only. + record.window = true; + window_rows.push(record); + } + } + } + } + rendered.push(record); + } + Ok(Planned { + predict_request, + plan, + rows: rendered, + window_rows, + }) + } + + /// The prepared parts for one request: tokens everywhere, offsets + /// and word units on span-target parts. + fn prepared_parts( + &self, + state_parts: &[crate::state::Part], + span_roles: &HashSet, + ) -> Vec { + state_parts + .iter() + .map(|part| { + let (ids, offsets) = self.encoder.ids_offsets(&part.text); + if span_roles.contains(&part.r#type) { + let words = crate::words::word_first_tokens(&part.text, &offsets); + PreparedPart { + role: part.r#type.clone(), + ids, + offsets: Some(offsets), + words: Some(words), + } + } else { + PreparedPart { + role: part.r#type.clone(), + ids, + offsets: None, + words: None, + } + } + }) + .collect() + } +} + +/// `_to_generic` for the SystemOne path: options/labels carry over in +/// order (score levels have empty descriptions), the target part is the +/// resolved `over`, choice always carries `[ABS]` (the reference's +/// `abstain` default is true and the mapper never sets it), and span +/// keeps its threshold and head override. +fn to_generic(question: &PredictQuestion) -> GenericQuestion { + let over: Vec = match &question.target_part { + Value::String(role) => vec![role.clone()], + Value::Array(roles) => roles + .iter() + .filter_map(Value::as_str) + .map(str::to_owned) + .collect(), + _ => Vec::new(), + }; + let (names, descriptions) = match (&question.labels, &question.options) { + (Some(labels), _) => ( + labels.iter().map(|n| n.name.clone()).collect(), + labels.iter().map(|n| n.description.clone()).collect(), + ), + (None, Some(Value::Array(items))) => { + // Objects carry name/description; score levels are strings. + let mut names = Vec::new(); + let mut descriptions = Vec::new(); + for item in items { + match item { + Value::String(name) => { + names.push(name.clone()); + descriptions.push(String::new()); + } + Value::Object(named) => { + names.push(named["name"].as_str().unwrap_or_default().to_owned()); + descriptions + .push(named["description"].as_str().unwrap_or_default().to_owned()); + } + _ => {} + } + } + (names, descriptions) + } + _ => (Vec::new(), Vec::new()), + }; + GenericQuestion { + id: question.id.clone(), + kind: question.kind.clone(), + over, + text: question.text.clone(), + names, + descriptions, + threshold: question.threshold, + head_override: question.head.clone(), + } +} diff --git a/src/models/vela/native/src/questions.rs b/src/models/vela/native/src/questions.rs new file mode 100644 index 00000000..4c095032 --- /dev/null +++ b/src/models/vela/native/src/questions.rs @@ -0,0 +1,441 @@ +//! The SystemOne (state, questions) → predict-request mapping, mirroring +//! the pinned runtime's `system_one_to_predict` exactly: the validation +//! walk and its whole-request error triples, the Noul folding into a +//! two-option choice, and the per-question plan used to build responses. + +use serde_json::{Map, Value}; + +use crate::contract::RequestError; +use crate::state::{Part, StateParts, content_text}; + +/// The `questions` container rejection shared by the mapping and the +/// processor's body walk. +pub fn empty_questions_error() -> RequestError { + qerror( + &["questions"], + "questions must be a non-empty object of named questions", + ) +} + +pub const SYSTEM_ONE_TYPES: [&str; 5] = ["noul", "choice", "score", "span", "set"]; +pub const NOUL_DEFAULT_NO: &str = "No. The statement or question is not satisfied."; +pub const NOUL_DEFAULT_YES: &str = "Yes. The statement or question is satisfied."; + +/// One option / label of a predict question (name, description). +#[derive(Debug, Clone, serde::Serialize, PartialEq)] +pub struct Named { + pub name: String, + pub description: String, +} + +/// The predict-level question, exactly as it serializes into the frozen +/// fixtures: Noul questions arrive here already folded into a choice. +#[derive(Debug, Clone, serde::Serialize)] +pub struct PredictQuestion { + pub id: String, + #[serde(rename = "type")] + pub kind: String, + pub text: String, + pub target_part: Value, + #[serde(skip_serializing_if = "Option::is_none")] + pub labels: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub threshold: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub head: Option, +} + +#[derive(Debug, Clone, serde::Serialize)] +pub struct PredictRequest { + pub parts: Vec, + pub questions: Vec, +} + +/// The response-side plan entry for one original question. +#[derive(Debug, Clone, serde::Serialize)] +pub struct PlanEntry { + pub qid: String, + #[serde(rename = "type")] + pub kind: String, + pub criteria: Value, + pub range: Option<(usize, usize)>, + pub part: Value, +} + +#[derive(Debug)] +pub struct Mapped { + pub request: PredictRequest, + pub plan: Vec, +} + +fn qerror(loc: &[&str], msg: &str) -> RequestError { + RequestError::envelope(loc, msg, "value_error") +} + +fn nonblank(value: &Value) -> bool { + match value { + Value::String(text) => !text.trim().is_empty(), + _ => true, + } +} + +/// `over` (state key | part name | list) → (target part(s), field range). +fn resolve_over( + over: &Value, + parts: &StateParts, + qloc: &[&str], +) -> Result<(Value, Option<(usize, usize)>), RequestError> { + let roles: Vec<&str> = parts.parts.iter().map(|p| p.r#type.as_str()).collect(); + let items: Vec<&Value> = match over { + Value::Array(list) => list.iter().collect(), + single => vec![single], + }; + let mut out: Vec<&str> = Vec::new(); + let mut range = None; + for item in items { + let Some(name) = item.as_str() else { + return Err(qerror( + &[qloc[0], qloc[1], "over"], + "over must be a state key, a part name or a list of them", + )); + }; + if let Some(field) = parts.fields.get(name) { + if !over.is_array() { + range = Some((field.start, field.end)); + } + if !out.contains(&field.role) { + out.push(field.role); + } + } else if roles.contains(&name) { + if !out.contains(&name) { + out.push(name); + } + } else { + let role = crate::state::key_role(name); + if roles.contains(&role) && !out.contains(&role) { + out.push(role); + } else { + return Err(qerror( + &[qloc[0], qloc[1], "over"], + &format!( + "'{name}' is not a field of the state (fields: [{fields}], parts: [{roles}])", + fields = parts + .fields + .keys() + .map(|k| format!("'{k}'")) + .collect::>() + .join(", "), + roles = roles.join(", "), + ), + )); + } + } + } + if out.is_empty() { + return Err(qerror( + &[qloc[0], qloc[1], "over"], + "over must not be empty", + )); + } + // Sequence order, so the pooled range covers exactly these parts. + let ordered: Vec<&str> = roles + .iter() + .filter(|role| out.contains(role)) + .copied() + .collect(); + let target = match ordered.len() { + 1 => Value::String(ordered[0].into()), + _ => Value::Array( + ordered + .into_iter() + .map(|r| Value::String(r.into())) + .collect(), + ), + }; + Ok((target, range)) +} + +/// The full mapping. `state` and `questions` are the admitted request's +/// fields; validation runs in the pinned runtime's order so error +/// precedence matches. +pub fn system_one_to_predict( + state_parts: StateParts, + questions: &Map, +) -> Result { + if questions.is_empty() { + return Err(qerror( + &["questions"], + "questions must be a non-empty object of named questions", + )); + } + let roles: Vec<&str> = state_parts + .parts + .iter() + .map(|p| p.r#type.as_str()) + .collect(); + let mut predict = Vec::new(); + let mut plan = Vec::new(); + for (qid, question) in questions { + if qid.trim().is_empty() { + return Err(qerror( + &["questions"], + "question IDs must not be empty or whitespace", + )); + } + let Some(question) = question.as_object() else { + return Err(qerror( + &["questions", qid], + "a question must be an object with a type", + )); + }; + let loc = ["questions", qid]; + let kind = question.get("type").and_then(Value::as_str).unwrap_or(""); + if !SYSTEM_ONE_TYPES.contains(&kind) { + return Err(RequestError::envelope( + &[loc[0], loc[1], "type"], + "type must be one of ['noul', 'choice', 'score', 'span', 'set']", + "literal_error", + )); + } + let mut allowed: Vec<&str> = vec!["type", "instructions", "criteria", "over"]; + if kind == "span" || kind == "set" { + allowed.push("threshold"); + } + if kind == "span" { + allowed.push("head"); + } + let extra: Vec<&String> = question + .keys() + .filter(|key| !allowed.contains(&key.as_str())) + .collect(); + if let Some(first) = extra.first() { + return Err(RequestError::envelope( + &[loc[0], loc[1], first], + "Extra inputs are not permitted", + "extra_forbidden", + )); + } + let instructions = question.get("instructions").unwrap_or(&Value::Null); + if !nonblank(instructions) { + return Err(qerror( + &[loc[0], loc[1], "instructions"], + "instructions must not be empty or whitespace", + )); + } + let text = match instructions { + Value::Null => String::new(), + other => content_text(other), + }; + let criteria = question.get("criteria").unwrap_or(&Value::Null); + // Target part: the resolved `over`, the span default, or all parts. + let (target_part, range) = match question.get("over") { + Some(Value::Null) | None => { + if kind == "span" { + let role = if roles.contains(&"answer") { + "answer" + } else if roles.contains(&"user") { + "user" + } else { + roles[0] + }; + (Value::String(role.into()), None) + } else if roles.len() == 1 { + (Value::String(roles[0].into()), None) + } else { + ( + Value::Array(roles.iter().map(|r| Value::String((*r).into())).collect()), + None, + ) + } + } + Some(over) => resolve_over(over, &state_parts, &loc)?, + }; + let mut predict_question = PredictQuestion { + id: qid.clone(), + kind: kind.to_string(), + text: text.clone(), + target_part: target_part.clone(), + labels: None, + options: None, + threshold: None, + head: None, + }; + let mut plan_criteria = criteria.clone(); + match kind { + "noul" => { + if !criteria.is_null() + && (!criteria.is_object() + || criteria + .as_object() + .is_some_and(|map| map.keys().any(|k| k != "true" && k != "false"))) + { + return Err(qerror( + &[loc[0], loc[1], "criteria"], + "noul criteria is an object with optional true / false", + )); + } + let map = criteria.as_object().cloned().unwrap_or_default(); + for key in ["true", "false"] { + if let Some(value) = map.get(key) + && !nonblank(value) + { + return Err(qerror( + &[loc[0], loc[1], "criteria", key], + "Noul criterion must not be empty or whitespace", + )); + } + } + let no = match map.get("false") { + Some(Value::Null) | None => NOUL_DEFAULT_NO.to_string(), + Some(value) => content_text(value), + }; + let yes = match map.get("true") { + Some(Value::Null) | None => NOUL_DEFAULT_YES.to_string(), + Some(value) => content_text(value), + }; + predict_question.kind = "choice".into(); + predict_question.options = Some(serde_json::json!([ + {"name": "no", "description": no}, + {"name": "yes", "description": yes}, + ])); + } + "choice" | "set" | "span" => { + let (lo, hi) = if kind == "choice" { (2, 255) } else { (1, 255) }; + let Some(map) = criteria.as_object() else { + return Err(qerror( + &[loc[0], loc[1], "criteria"], + &format!("{kind} criteria must be an object with {lo} to {hi} entries"), + )); + }; + if !(lo..=hi).contains(&map.len()) { + return Err(qerror( + &[loc[0], loc[1], "criteria"], + &format!("{kind} criteria must be an object with {lo} to {hi} entries"), + )); + } + let mut named = Vec::new(); + for (name, value) in map { + if name.trim().is_empty() || !nonblank(value) { + return Err(qerror( + &[loc[0], loc[1], "criteria", name], + "option names and descriptions must not be empty or whitespace", + )); + } + let description = match value { + Value::Null => String::new(), + other => content_text(other), + }; + named.push(Named { + name: name.clone(), + description, + }); + } + if kind == "span" { + predict_question.labels = Some(named); + } else { + predict_question.options = Some(serde_json::to_value(&named).unwrap()); + } + } + _ => { + // score + let Some(levels) = criteria.as_array() else { + return Err(qerror( + &[loc[0], loc[1], "criteria"], + "score criteria must be a list of 2 to 10 levels", + )); + }; + if !(2..=10).contains(&levels.len()) { + return Err(qerror( + &[loc[0], loc[1], "criteria"], + "score criteria must be a list of 2 to 10 levels", + )); + } + let mut names = Vec::new(); + for (index, value) in levels.iter().enumerate() { + if value.is_null() || !nonblank(value) { + return Err(qerror( + &[loc[0], loc[1], "criteria", &index.to_string()], + "Score criterion must not be empty or whitespace", + )); + } + names.push(content_text(value)); + } + if names.iter().collect::>().len() != names.len() { + return Err(qerror( + &[loc[0], loc[1], "criteria"], + "score levels must be distinct", + )); + } + predict_question.options = Some(serde_json::to_value(&names).unwrap()); + } + } + if let Some(threshold) = question.get("threshold") + && !threshold.is_null() + { + match threshold.as_f64().filter(|_| threshold.is_number()) { + Some(value) if (0.0..=1.0).contains(&value) => { + predict_question.threshold = Some(value); + } + _ => { + return Err(qerror( + &[loc[0], loc[1], "threshold"], + "threshold must be a number in [0, 1]", + )); + } + } + } + if kind == "span" + && let Some(head) = question.get("head") + && !head.is_null() + { + match head.as_str() { + Some(value @ ("router" | "broad")) => { + predict_question.head = Some(value.to_string()); + } + _ => { + return Err(RequestError::envelope( + &[loc[0], loc[1], "head"], + "head must be one of ['router', 'broad']", + "literal_error", + )); + } + } + } + // Python's plan keeps `crit`; noul normalized null -> {} earlier. + if kind == "noul" && plan_criteria.is_null() { + plan_criteria = serde_json::json!({}); + } + predict.push(predict_question); + plan.push(PlanEntry { + qid: qid.clone(), + kind: kind.to_string(), + criteria: plan_criteria, + range, + part: target_part, + }); + } + // The Noul views of set labels must not overwrite a question. + for entry in &plan { + if entry.kind == "set" + && let Value::Object(map) = &entry.criteria + { + for label in map.keys() { + if questions.contains_key(&format!("{}.{}", entry.qid, label)) { + return Err(qerror( + &["questions", &format!("{}.{}", entry.qid, label)], + "collides with the Noul view of a set label", + )); + } + } + } + } + Ok(Mapped { + request: PredictRequest { + parts: state_parts.parts, + questions: predict, + }, + plan, + }) +} diff --git a/src/models/vela/native/src/render.rs b/src/models/vela/native/src/render.rs new file mode 100644 index 00000000..c4fc2367 --- /dev/null +++ b/src/models/vela/native/src/render.rs @@ -0,0 +1,789 @@ +//! Prompt rendering, mirroring the pinned runtime's `_prep` + `_render` +//! (the DEV2.0 decoder layout): the parts pass, per-question blocks +//! with option end and query positions, the span block in layout a/c +//! with word positions, the truncation budget, and the long-target +//! windows. Output structs serialize exactly like the frozen +//! `native-plan-*` fixtures. + +use std::cell::RefCell; +use std::collections::{HashMap, HashSet}; +use std::path::Path; + +use std::collections::BTreeMap; +use tokenizers::Tokenizer; + +use crate::contract::RequestError; +use crate::state::canonical; + +pub const SUFFIX_CHOICE_SCORE: &str = + "\n\nSelect the single option best supported by the context and instructions.\nDecision:"; +pub const SUFFIX_SET: &str = + "\n\nSelect every option supported by the context and instructions.\nDecision:"; +pub const SUFFIX_SPAN: &str = + "\n\nMark every span of the target text that carries one of the labels.\nSpans:"; +pub const ABS_KEY: &str = "[ABS]"; +pub const ABS_DESC: &str = "None of the shown options applies."; +pub const PARTS_HEAD: &str = "Context:\n"; +pub const SEG_CLOSE: &str = "\n\n"; +pub const TEXT_HEAD: &str = "\n\nText:\n"; +pub const HYBRID_RMAX: usize = 2048; +pub const WIN: usize = 1800; +pub const STRIDE: usize = 1536; +pub const RMAX: usize = 2048; + +pub const ROUTER_SPAN_IDS: [&str; 3] = ["pii", "halu", "toxic"]; +pub const HALU_LABEL: &str = "unsupported"; +pub const HALU_ALIASES: [&str; 9] = [ + "unsupported", + "unsupportedclaim", + "hallucinated", + "hallucination", + "hallucinatedspan", + "notsupported", + "unsupportedspan", + "fabricated", + "fabrication", +]; +pub const PII_TYPES: [&str; 17] = [ + "AGE", + "CREDIT_CARD", + "DATE_TIME", + "DOMAIN_NAME", + "EMAIL_ADDRESS", + "GPE", + "IBAN_CODE", + "IP_ADDRESS", + "NRP", + "ORGANIZATION", + "PERSON", + "PHONE_NUMBER", + "STREET_ADDRESS", + "TITLE", + "US_DRIVER_LICENSE", + "US_SSN", + "ZIP_CODE", +]; + +fn seg_open(role: &str) -> String { + format!("\n") +} + +fn option_block(key: &str, desc: &str, tag: &str) -> String { + format!( + "\n<{tag}>\n{}\n", + canonical(&serde_json::json!({"key": key, "description": desc})) + ) +} + +fn q_head(kind: &str, over: &[String], text: &str, span: bool) -> String { + let target = over.join(", "); + format!( + "\n\nTask type: {kind}\nTarget: {target}\nQuestion:\n{text}\n{}", + if span { "Labels:" } else { "Options:" } + ) +} + +// ------------------------------------------------------------------ tokenizer + +/// The pinned tokenizer, with the reference's memoized plain-`ids` view +/// and char-offset encodings (the tokenizers crate reports byte +/// offsets; the reference works in Unicode code points). +/// Ids plus char offsets, the encoder cache entry. +type Encoded = (Vec, Vec<(usize, usize)>); + +pub struct Encoder { + tokenizer: Tokenizer, + cache: RefCell>, +} + +impl Encoder { + pub fn load(path: &Path) -> anyhow::Result { + let tokenizer = Tokenizer::from_file(path).map_err(anyhow::Error::msg)?; + Ok(Self { + tokenizer, + cache: RefCell::new(HashMap::new()), + }) + } + + fn encode(&self, text: &str) -> (Vec, Vec<(usize, usize)>) { + if let Some(hit) = self.cache.borrow().get(text) { + return hit.clone(); + } + let encoding = self + .tokenizer + .encode(text, false) + .expect("tokenizer failure"); + let byte_offsets = encoding.get_offsets(); + // Byte → code-point offsets. + let char_starts: Vec = text + .char_indices() + .map(|(byte, _)| byte) + .chain(std::iter::once(text.len())) + .collect(); + let to_char = |byte: usize| char_starts.partition_point(|&start| start < byte); + let offsets: Vec<(usize, usize)> = byte_offsets + .iter() + .map(|(start, end)| (to_char(*start), to_char(*end))) + .collect(); + let entry = (encoding.get_ids().to_vec(), offsets); + self.cache + .borrow_mut() + .insert(text.to_owned(), entry.clone()); + entry + } + + /// Memoized token ids of a whole string (the reference's `_ids`). + pub fn ids(&self, text: &str) -> Vec { + self.encode(text).0 + } + + /// Ids and char offsets (the reference's `_ids_offs`). + pub fn ids_offsets(&self, text: &str) -> (Vec, Vec<(usize, usize)>) { + self.encode(text) + } +} + +// ------------------------------------------------------------- span dispatch + +/// `[\s_\-]+` removed, lower-cased — the reference's `_norm_label`. +pub fn norm_label(name: &str) -> String { + let mut out = String::with_capacity(name.len()); + for ch in name.chars() { + if !ch.is_whitespace() && ch != '_' && ch != '-' { + out.extend(ch.to_lowercase()); + } + } + out +} + +/// The user's label when the span question has exactly one label that +/// is a hallucination alias, else none. +pub fn halu_alias(names: &[String]) -> Option { + if names.len() == 1 && HALU_ALIASES.contains(&norm_label(&names[0]).as_str()) { + Some(names[0].clone()) + } else { + None + } +} + +pub struct SpanDispatch { + pub head: &'static str, + pub reason: &'static str, +} + +/// The reference's six-rule dispatch, in order: `"head"` override, +/// trained ids, an exact router label set, a non-empty subset of the 17 +/// PII types, one hallucination alias, else broad (router when the +/// broad head is not loaded). +pub fn span_head_for( + id: &str, + labels: &HashSet, + head_override: Option<&str>, + router_label_sets: &[HashSet], + broad_available: bool, +) -> Result { + if let Some(head) = head_override { + if !matches!(head, "router" | "broad") { + return Err(format!( + "head must be one of ['router', 'broad'], got '{head:?}'" + )); + } + if head == "broad" && !broad_available { + return Err("the broad span head is not loaded (needs broad_head.safetensors)".into()); + } + return Ok(SpanDispatch { + head: if head == "broad" { "broad" } else { "router" }, + reason: "override", + }); + } + if ROUTER_SPAN_IDS.contains(&id) { + return Ok(SpanDispatch { + head: "router", + reason: "id", + }); + } + if router_label_sets.iter().any(|set| set == labels) { + return Ok(SpanDispatch { + head: "router", + reason: "label_set", + }); + } + let pii: HashSet<&str> = PII_TYPES.into_iter().collect(); + if !labels.is_empty() && labels.iter().all(|label| pii.contains(label.as_str())) { + return Ok(SpanDispatch { + head: "router", + reason: "pii_subset", + }); + } + if halu_alias(&labels.iter().cloned().collect::>()).is_some() { + return Ok(SpanDispatch { + head: "router", + reason: "halu_alias", + }); + } + if !broad_available { + return Ok(SpanDispatch { + head: "router", + reason: "broad_unavailable", + }); + } + Ok(SpanDispatch { + head: "broad", + reason: "default", + }) +} + +// ------------------------------------------------------------------ rendering + +/// One generic-contract question at render time (Noul is already folded +/// into a two-option choice; choice always carries `[ABS]` on the +/// SystemOne path — the reference's `_to_generic` defaults abstain to +/// true and the mapper never sets it). +#[derive(Clone)] +pub struct GenericQuestion { + pub id: String, + pub kind: String, + pub over: Vec, + pub text: String, + pub names: Vec, + pub descriptions: Vec, + pub threshold: Option, + pub head_override: Option, +} + +/// One prepared part: tokens, and for span-target parts also char +/// offsets and word units. +/// Word char offsets and each word's first token index. +pub type WordUnits = (Vec<(usize, usize)>, Vec); + +#[derive(Clone)] +pub struct PreparedPart { + pub role: String, + pub ids: Vec, + pub offsets: Option>, + pub words: Option, +} + +#[derive(Debug, Clone, serde::Serialize, PartialEq)] +pub struct TruncRecord { + pub shrink_cut: usize, + pub protected_cut: usize, +} + +#[derive(Debug, Clone, serde::Serialize, PartialEq)] +#[serde(tag = "kind")] +pub enum Block { + #[serde(rename = "q")] + Question { + ids: Vec, + ends: Vec, + query: usize, + qid: String, + qtype: String, + names: Vec, + has_abs: bool, + }, + #[serde(rename = "span")] + Span { + ends: Vec, + label_ranges: Vec<(usize, usize)>, + words_in_block: bool, + ids: Vec, + query: usize, + w_pos: Vec, + }, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct RenderedRow { + pub p_ids: Vec, + pub blocks: Vec, + pub trunc: TruncRecord, + pub seg_lens: BTreeMap, + pub layout: Option, + pub names: Option>, + pub w_offs: Option>, + pub w_pos: Option>, + pub span_over: Option, + pub n_tokens: usize, + pub head: String, + pub head_reason: Option, + /// The runtime's window rows carry the head only — no head_reason + /// key at all (predict_raw assigns head alone). + pub window: bool, +} + +/// Serialize exactly like the frozen fixtures: main rows always carry +/// `head_reason` (null when the row has no span); window rows omit it. +impl serde::Serialize for RenderedRow { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serialize_row(self, serializer) + } +} + +fn serialize_row(row: &RenderedRow, serializer: S) -> Result +where + S: serde::Serializer, +{ + use serde::ser::SerializeMap; + let mut map = serializer.serialize_map(None)?; + macro_rules! put { + ($key:literal, $value:expr) => { + map.serialize_entry($key, &$value)? + }; + } + put!("p_ids", row.p_ids); + put!("blocks", row.blocks); + put!("trunc", row.trunc); + put!("seg_lens", row.seg_lens); + put!("layout", row.layout); + if let Some(names) = &row.names { + put!("names", names); + } + if let Some(w_offs) = &row.w_offs { + put!("w_offs", w_offs); + } + if let Some(w_pos) = &row.w_pos { + put!("w_pos", w_pos); + } + if let Some(span_over) = &row.span_over { + put!("span_over", span_over); + } + put!("n_tokens", row.n_tokens); + put!("head", row.head); + if !row.window { + put!("head_reason", row.head_reason); + } + map.end() +} + +/// Everything the renderer needs beyond tokens. +pub struct RenderContext<'a> { + pub encoder: &'a Encoder, + pub max_length: usize, + pub router_label_sets: &'a [HashSet], + pub has_broad: bool, + pub halu_desc: String, +} + +/// The whole-request 413: questions plus schema alone do not fit. +pub fn too_long(max_length: usize) -> RequestError { + RequestError { + status: 413, + body: serde_json::json!({"detail": [{"loc": ["body", "questions"], + "msg": format!("the questions alone do not fit the {max_length}-token window"), + "type": "too_long"}]}), + } +} + +/// `schema_lib_r4.assemble`, eval path: the truncation order on the +/// decoder's token costs. Returns kept segment lengths and the record. +fn assemble_budget( + q_lens: &[usize], + el_lens: &[usize], + segs: &mut [(String, usize)], + max_len: usize, + protected: &HashSet, + shrink: Option<&str>, +) -> Result<(BTreeMap, TruncRecord), ()> { + let fixed = 2 + 1 + segs.len(); + fn over( + q_lens: &[usize], + el_lens: &[usize], + segs: &[(String, usize)], + fixed: usize, + max_len: usize, + ) -> i64 { + fixed as i64 + + q_lens.iter().sum::() as i64 + + el_lens.iter().sum::() as i64 + + segs.iter().map(|(_, n)| *n).sum::() as i64 + - max_len as i64 + } + let mut trunc = TruncRecord { + shrink_cut: 0, + protected_cut: 0, + }; + let shrink_index = shrink.and_then(|role| segs.iter().position(|(r, _)| r == role)); + for floor in [64, 1] { + if over(q_lens, el_lens, segs, fixed, max_len) > 0 + && let Some(index) = shrink_index + { + let full = segs[index].1; + let excess = over(q_lens, el_lens, segs, fixed, max_len).max(0) as usize; + let keep = full.min(floor.max(full.saturating_sub(excess))); + trunc.shrink_cut += full - keep; + segs[index].1 = keep; + } + } + if over(q_lens, el_lens, segs, fixed, max_len) > 0 { + for index in 0..segs.len() { + if over(q_lens, el_lens, segs, fixed, max_len) > 0 && protected.contains(&segs[index].0) + { + let full = segs[index].1; + let excess = over(q_lens, el_lens, segs, fixed, max_len).max(0) as usize; + let keep = 1.max(full.saturating_sub(excess)); + trunc.protected_cut += full - keep; + segs[index].1 = keep; + } + } + } + if over(q_lens, el_lens, segs, fixed, max_len) > 0 { + return Err(()); + } + let seg_lens: BTreeMap = + segs.iter().map(|(role, n)| (role.clone(), *n)).collect(); + Ok((seg_lens, trunc)) +} + +/// Token windows [a, b) over a part of n tokens, starting and cut at +/// word starts (`schema_lib_d3_20261001.windows`). +pub fn span_windows(first_tokens: &[usize], n: usize) -> Vec<(usize, usize)> { + let mut starts: Vec = first_tokens.to_vec(); + starts.sort_unstable(); + starts.dedup(); + if starts.is_empty() { + return vec![(0, n)]; + } + let mut out = Vec::new(); + let mut a = starts[0]; + loop { + let limit = a + WIN; + let next: Vec = starts + .iter() + .copied() + .filter(|&s| s > a && s < limit) + .collect(); + let b = if limit >= n { + n + } else if !next.is_empty() { + *starts + .iter() + .filter(|&&s| s < limit && s > a) + .max() + .unwrap() + } else { + n.min(limit) + }; + out.push((a, b)); + if b >= n { + break; + } + let candidate: Vec = starts + .iter() + .copied() + .filter(|&s| s >= a + STRIDE && s < b) + .collect(); + a = candidate.first().copied().unwrap_or(b); + } + out +} + +/// A windowed copy of a prepared part: tokens [a, b) and the words that +/// start inside them. +pub fn window_part(part: &PreparedPart, a: usize, b: usize) -> PreparedPart { + let (word_offsets, first_tokens) = part.words.as_ref().expect("windowed parts carry words"); + let selected: Vec = first_tokens + .iter() + .enumerate() + .filter(|&(_, &t)| t >= a && t < b) + .map(|(index, _)| index) + .collect(); + let kept_offsets: Vec<(usize, usize)> = selected.iter().map(|&i| word_offsets[i]).collect(); + PreparedPart { + role: part.role.clone(), + ids: part.ids[a..b].to_vec(), + offsets: part.offsets.as_ref().map(|offs| offs[a..b].to_vec()), + words: Some(( + kept_offsets, + selected.iter().map(|&i| first_tokens[i] - a).collect(), + )), + } +} + +impl RenderContext<'_> { + /// `_prep`'s question side: the span-head dispatch and the + /// hallucination-alias label replacement (parts arrive prepared — + /// word units need the original text and are the caller's job). + pub fn prepare_questions( + &self, + questions: &[GenericQuestion], + ) -> Result<(Vec, SpanDispatch), RequestError> { + let span = questions.iter().find(|q| q.kind == "span"); + let dispatch = match span { + Some(question) => { + let labels: HashSet = question.names.iter().cloned().collect(); + span_head_for( + &question.id, + &labels, + question.head_override.as_deref(), + self.router_label_sets, + self.has_broad, + ) + .map_err(|message| crate::contract::runtime_rejection(&message))? + } + None => SpanDispatch { + head: "router", + reason: "", + }, + }; + // The trained `unsupported` label renders in place of a single + // hallucination-alias label (the answer gets the user's name). + let mut adjusted = questions.to_vec(); + if let Some(question) = adjusted.iter_mut().find(|q| q.kind == "span") + && dispatch.head == "router" + && let Some(alias) = halu_alias(&question.names) + && alias != HALU_LABEL + { + question.names = vec![HALU_LABEL.to_string()]; + question.descriptions = vec![self.halu_desc.clone()]; + } + Ok((adjusted, dispatch)) + } + + /// `_render` on one prepared row: the parts pass and every block, + /// with the budget applied first. + pub fn render( + &self, + parts: &[PreparedPart], + questions: &[GenericQuestion], + dispatch: &SpanDispatch, + ) -> Result { + let ids_of = |text: &str| self.encoder.ids(text); + let roles: Vec = parts.iter().map(|p| p.role.clone()).collect(); + // Question blocks and their schema costs. + struct RenderedQ { + qid: String, + qtype: String, + names: Vec, + otoks: Vec>, + has_abs: bool, + head: Vec, + suffix: Vec, + abstain_tokens: Vec, + len: usize, + } + let mut rendered_qs: Vec = Vec::new(); + let mut el: Vec<(String, Vec)> = Vec::new(); // span labels + let mut span_question: Option<&GenericQuestion> = None; + for question in questions { + if question.kind == "span" { + span_question = Some(question); + for (name, desc) in question.names.iter().zip(&question.descriptions) { + let tokens = ids_of(&option_block(name, desc, "label")); + el.push((name.clone(), tokens.clone())); + } + continue; + } + let suffix = match question.kind.as_str() { + "set" => SUFFIX_SET, + _ => SUFFIX_CHOICE_SCORE, // choice and score share the wording + }; + let has_abs = question.kind == "choice"; // SystemOne: abstain defaults true + let head = ids_of(&q_head( + &question.kind, + &question.over, + &question.text, + false, + )); + let suffix = ids_of(suffix); + let abstain_tokens = if has_abs { + ids_of(&option_block(ABS_KEY, ABS_DESC, "option")) + } else { + Vec::new() + }; + let mut otoks = Vec::with_capacity(question.names.len()); + let mut len = + 1 + head.len() + suffix.len() + abstain_tokens.len() + usize::from(has_abs); + for (name, desc) in question.names.iter().zip(&question.descriptions) { + let tokens = ids_of(&option_block(name, desc, "option")); + len += 1 + tokens.len(); + otoks.push(tokens); + } + rendered_qs.push(RenderedQ { + qid: question.id.clone(), + qtype: question.kind.clone(), + names: question.names.clone(), + otoks, + has_abs, + head, + suffix, + abstain_tokens, + len, + }); + } + let span_over: Option = span_question.map(|question| question.over[0].clone()); + let mut overs: HashSet = HashSet::new(); + for question in questions { + overs.extend(question.over.iter().cloned()); + } + if let Some(over) = &span_over { + overs.insert(over.clone()); + } + let part_of = |role: &str| parts.iter().find(|p| p.role == role); + let shrink = roles.iter().find(|role| !overs.contains(*role)).cloned(); + let layout = match &span_over { + Some(over) if part_of(over).is_some_and(|p| p.ids.len() <= HYBRID_RMAX) => "c", + Some(_) => "a", + None => "", + }; + // The schema overhead the budget does not see. + let mut budget = ids_of(PARTS_HEAD).len(); + for role in &roles { + budget += ids_of(&seg_open(role)).len() + ids_of(SEG_CLOSE).len(); + } + if let Some(over) = &span_over { + let question = span_question.expect("span question"); + let head = ids_of(&q_head("span", &question.over, &question.text, true)); + let suffix = ids_of(SUFFIX_SPAN); + budget += head.len() + suffix.len(); + if layout == "c" { + let span_len = part_of(over).expect("span part").ids.len(); + budget += ids_of(TEXT_HEAD).len() + + ids_of(&seg_open(over)).len() + + ids_of(SEG_CLOSE).len(); + let headroom = self.max_length.saturating_sub(budget); + budget += span_len.min(headroom / 2); + } + } + let q_lens: Vec = rendered_qs.iter().map(|q| q.len).collect(); + let el_lens: Vec = el.iter().map(|(_, tokens)| 1 + tokens.len()).collect(); + let mut segs: Vec<(String, usize)> = parts + .iter() + .map(|p| (p.role.clone(), p.ids.len())) + .collect(); + let (seg_lens, trunc) = assemble_budget( + &q_lens, + &el_lens, + &mut segs, + 64.max(self.max_length - budget), + &overs, + shrink.as_deref(), + ) + .map_err(|()| too_long(self.max_length))?; + // The parts pass, in part order (not the sorted map). + let mut p_ids = ids_of(PARTS_HEAD); + let mut start: HashMap = HashMap::new(); + for part in parts { + let keep = seg_lens[&part.role]; + let open = ids_of(&seg_open(&part.role)); + start.insert(part.role.clone(), p_ids.len() + open.len()); + p_ids.extend(open); + p_ids.extend(part.ids.iter().take(keep)); + p_ids.extend(ids_of(SEG_CLOSE)); + } + // Question blocks. + let mut blocks: Vec = Vec::new(); + for q in &rendered_qs { + let mut ids = q.head.clone(); + let mut ends = Vec::with_capacity(q.names.len() + usize::from(q.has_abs)); + for tokens in &q.otoks { + ids.extend(tokens); + ends.push(ids.len() - 1); + } + if q.has_abs { + ids.extend(q.abstain_tokens.clone()); + ends.push(ids.len() - 1); + } + ids.extend(q.suffix.clone()); + let query = ids.len() - 1; + blocks.push(Block::Question { + ids, + ends, + query, + qid: q.qid.clone(), + qtype: q.qtype.clone(), + names: q.names.clone(), + has_abs: q.has_abs, + }); + } + // The span block. + let mut row_names = None; + let mut row_w_offs = None; + let mut row_w_pos = None; + if let Some(over) = &span_over + && !el.is_empty() + { + let question = span_question.expect("span question"); + let mut ids = ids_of(&q_head("span", &question.over, &question.text, true)); + let mut ends = Vec::new(); + let mut starts = Vec::new(); + for (_, tokens) in &el { + starts.push(ids.len()); + ids.extend(tokens); + ends.push(ids.len() - 1); + } + let part = part_of(over).expect("span part"); + let n = seg_lens[over]; + let (word_offsets, first_tokens) = part.words.as_ref().expect("span words"); + // Word indices whose first token survives the kept prefix; + // indices, not token values — two words can share one. + let keep: Vec = first_tokens + .iter() + .enumerate() + .filter(|&(_, &t)| t < n) + .map(|(index, _)| index) + .collect(); + let words_in_block = layout == "c"; + if words_in_block { + ids.extend(ids_of(TEXT_HEAD)); + ids.extend(ids_of(&seg_open(over))); + let c0 = ids.len(); + ids.extend(part.ids.iter().take(n)); + ids.extend(ids_of(SEG_CLOSE)); + row_w_pos = Some(keep.iter().map(|&i| c0 + first_tokens[i]).collect()); + } else { + let base = start[over]; + row_w_pos = Some(keep.iter().map(|&i| base + first_tokens[i]).collect()); + } + ids.extend(ids_of(SUFFIX_SPAN)); + let query = ids.len() - 1; + row_names = Some(el.iter().map(|(name, _)| name.clone()).collect()); + row_w_offs = Some(keep.iter().map(|&i| word_offsets[i]).collect()); + let label_ranges: Vec<(usize, usize)> = + starts.into_iter().zip(ends.iter().copied()).collect(); + blocks.push(Block::Span { + ends, + label_ranges, + words_in_block, + ids, + query, + w_pos: row_w_pos.clone().expect("w_pos"), + }); + } + let n_tokens = p_ids.len() + blocks.iter().map(block_len).sum::(); + Ok(RenderedRow { + p_ids, + blocks, + trunc, + seg_lens, + layout: if span_over.is_some() { + Some(layout.to_string()) + } else { + None + }, + names: row_names, + w_offs: row_w_offs, + w_pos: row_w_pos, + span_over, + n_tokens, + head: dispatch.head.to_string(), + head_reason: if dispatch.reason.is_empty() { + None + } else { + Some(dispatch.reason.to_string()) + }, + window: false, + }) + } +} + +fn block_len(block: &Block) -> usize { + match block { + Block::Question { ids, .. } => ids.len(), + Block::Span { ids, .. } => ids.len(), + } +} diff --git a/src/models/vela/native/src/state.rs b/src/models/vela/native/src/state.rs new file mode 100644 index 00000000..d33e42bb --- /dev/null +++ b/src/models/vela/native/src/state.rs @@ -0,0 +1,235 @@ +//! DEV2.0 canonical JSON and the state → typed-parts mapping, mirroring +//! the pinned runtime's `canonical_json`, `content_text` and +//! `system_one_state` exactly (the frozen `native-plan-*` fixtures are +//! the parity target). + +use serde_json::Value; +use std::collections::BTreeMap; + +use crate::contract::RequestError; + +/// `json.dumps(ensure_ascii=False, sort_keys=True, separators=(",", ":"))` +/// — key-sorted compact JSON, non-ASCII literal. +pub fn canonical(value: &Value) -> String { + match value { + Value::Object(map) => { + let mut keys: Vec<&String> = map.keys().collect(); + keys.sort(); + let parts: Vec = keys + .iter() + .map(|key| { + format!( + "{}:{}", + serde_json::to_string(key).unwrap(), + canonical(&map[*key]) + ) + }) + .collect(); + format!("{{{}}}", parts.join(",")) + } + Value::Array(items) => { + let parts: Vec = items.iter().map(canonical).collect(); + format!("[{}]", parts.join(",")) + } + other => serde_json::to_string(other).unwrap(), + } +} + +/// JSON content → model text: strings as they are, anything else as +/// canonical JSON. +pub fn content_text(value: &Value) -> String { + match value { + Value::String(text) => text.clone(), + other => canonical(other), + } +} + +/// The state-key → part-role table (unknown keys land in `context`). +pub fn key_role(key: &str) -> &'static str { + match key.to_ascii_lowercase().as_str() { + "request" | "user" | "prompt" => "user", + "answer" | "response" => "answer", + _ => "context", + } +} + +/// One rendered state part, in user / context / answer order. +#[derive(Debug, Clone, serde::Serialize, PartialEq)] +pub struct Part { + pub r#type: String, + pub text: String, +} + +/// A named state field's span inside its part's text (Unicode code +/// points, as on the reference). +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct FieldRange { + pub role: &'static str, + pub start: usize, + pub end: usize, +} + +#[derive(Debug)] +pub struct StateParts { + pub parts: Vec, + pub fields: BTreeMap, +} + +fn state_error(msg: &str) -> RequestError { + RequestError::envelope(&["state"], msg, "value_error") +} + +/// The SystemOne state → (parts, fields) mapping, mirroring +/// `system_one_state`: a plain string is one user part; a JSON array is +/// canonicalized into one; an object groups its keys by role (request / +/// user / prompt → user; source / context / document / tools / +/// previous_answer → context; answer / response → answer; unknown keys +/// → context) in user / context / answer order — one known-key entry +/// per role renders bare, several (or an unknown key) render as +/// `"key:\n"` blocks joined by blank lines. +pub fn system_one_state(state: &Value) -> Result { + // A string holding a JSON object is read as that object. + let state = match state { + Value::String(text) => { + let stripped = text.trim_start(); + if stripped.starts_with('{') { + if let Value::Object(object) = + serde_json::from_str::(stripped).unwrap_or(Value::Null) + { + Value::Object(object) + } else { + state.clone() + } + } else { + state.clone() + } + } + other => other.clone(), + }; + match &state { + Value::String(text) => { + if text.trim().is_empty() { + return Err(state_error("state must not be empty or whitespace")); + } + let mut fields = BTreeMap::new(); + fields.insert( + "request".into(), + FieldRange { + role: "user", + start: 0, + end: text.chars().count(), + }, + ); + Ok(StateParts { + parts: vec![Part { + r#type: "user".into(), + text: text.clone(), + }], + fields, + }) + } + Value::Array(_) => { + let text = canonical(&state); + let mut fields = BTreeMap::new(); + fields.insert( + "request".into(), + FieldRange { + role: "user", + start: 0, + end: text.chars().count(), + }, + ); + Ok(StateParts { + parts: vec![Part { + r#type: "user".into(), + text, + }], + fields, + }) + } + Value::Object(object) if !object.is_empty() => { + // Group per role, keeping the object's insertion order inside + // each role and remembering which entries had a known key. + let mut by_role: [Vec<(&String, &Value, bool)>; 3] = + [Vec::new(), Vec::new(), Vec::new()]; + for (key, value) in object { + let lower = key.to_ascii_lowercase(); + let known = matches!( + lower.as_str(), + "request" + | "user" + | "prompt" + | "source" + | "context" + | "document" + | "tools" + | "previous_answer" + | "answer" + | "response" + ); + let slot = match key_role(&lower) { + "user" => 0, + "answer" => 2, + _ => 1, + }; + by_role[slot].push((key, value, known)); + } + let mut parts = Vec::new(); + let mut fields = BTreeMap::new(); + for (role, items) in [ + ("user", &by_role[0]), + ("context", &by_role[1]), + ("answer", &by_role[2]), + ] { + if items.is_empty() { + continue; + } + let mut text = String::new(); + let single = items.len() == 1 && items[0].2; + for (index, (key, value, _)) in items.iter().enumerate() { + let rendered = content_text(value); + if single { + fields.insert( + (*key).clone(), + FieldRange { + role, + start: 0, + end: rendered.chars().count(), + }, + ); + text = rendered; + } else { + if index > 0 { + text.push_str("\n\n"); + } + let head = format!("{key}:\n"); + let start = text.chars().count() + head.chars().count(); + fields.insert( + (*key).clone(), + FieldRange { + role, + start, + end: start + rendered.chars().count(), + }, + ); + text.push_str(&head); + text.push_str(&rendered); + } + } + if text.trim().is_empty() { + return Err(state_error(&format!( + "the {role} part of the state is empty" + ))); + } + parts.push(Part { + r#type: role.into(), + text, + }); + } + Ok(StateParts { parts, fields }) + } + _ => Err(state_error( + "state must be a non-empty string, JSON object or JSON array", + )), + } +} diff --git a/src/models/vela/native/src/words.rs b/src/models/vela/native/src/words.rs new file mode 100644 index 00000000..c26dcac7 --- /dev/null +++ b/src/models/vela/native/src/words.rs @@ -0,0 +1,119 @@ +//! Word units and first-token mapping, mirroring the pinned runtime's +//! `schema_lib_r4` `_WORD` splitter (GLiNER2 whitespace splitter + CJK +//! one unit per character + the r4 URL/email/handle rule) and +//! `word_first_tokens`. Offsets are Unicode code points everywhere, as +//! on the reference. + +use onig::Regex; + +/// The CJK ranges of the reference `_WORD` pattern, verbatim. +const CJK: &str = "⺀-⿿ -〿぀-ヿ㄀-ㇿ㐀-䶿一-鿿ꀀ-꓏가-힯豈-﫿︰-﹏＀-￯"; +/// Trailing punctuation the URL rule strips. +const TRAIL: &str = ".,;:!?)\\]}>\"'\u{201d}\u{2019}\u{bb}"; + +fn word_pattern() -> Regex { + let pattern = concat!( + "(?:https?://|www\\.)[^\\s{cjk}]+?(?=[{trail}]*(?![^\\s{cjk}]))", + "|[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}", + "|@[a-z0-9_]+", + "|[{cjk}]", + "|[^\\W{cjk}]+(?:[-_][^\\W{cjk}]+)*", + "|\\S", + ); + let pattern = pattern.replace("{cjk}", CJK).replace("{trail}", TRAIL); + Regex::with_options( + &pattern, + onig::RegexOptions::REGEX_OPTION_IGNORECASE, + onig::Syntax::ruby(), + ) + .expect("the reference word pattern must compile") +} + +/// The (start, end) word ranges of `text`, in code points. +pub fn split_words(text: &str) -> Vec<(usize, usize)> { + let regex = word_pattern(); + // Byte offsets → code-point offsets. + let char_of_byte: Vec = text + .char_indices() + .map(|(byte, _)| byte) + .chain(std::iter::once(text.len())) + .collect(); + let to_char = |byte: usize| -> usize { char_of_byte.partition_point(|&start| start < byte) }; + regex + .find_iter(text) + .map(|(start, end)| (to_char(start), to_char(end))) + .collect() +} + +/// (word char offsets (W, 2), each word's first overlapping sub-word +/// token index), mirroring `word_first_tokens`: the first token whose +/// cumulative end passes the word start, skipping empty tokens. +pub fn word_first_tokens( + text: &str, + offsets: &[(usize, usize)], +) -> (Vec<(usize, usize)>, Vec) { + let words = split_words(text); + if words.is_empty() || offsets.is_empty() { + return (Vec::new(), Vec::new()); + } + let valid: Vec = offsets.iter().map(|(s, e)| e > s).collect(); + let mut cummax_end: Vec = Vec::with_capacity(offsets.len()); + let mut running: i64 = -1; + for (index, (_start, end)) in offsets.iter().enumerate() { + if valid[index] { + running = running.max(*end as i64); + } + cummax_end.push(running); + } + let mut word_offsets = Vec::new(); + let mut first_tokens = Vec::new(); + for (a, b) in words { + let mut t = cummax_end.partition_point(|&end| end <= a as i64); + while t < offsets.len() && !valid[t] { + t += 1; + } + if t < offsets.len() && offsets[t].0 < b { + word_offsets.push((a, b)); + first_tokens.push(t); + } + } + (word_offsets, first_tokens) +} + +/// The reference's CJK class as a range test (the same ranges the word +/// splitter carries). +pub fn is_cjk_char(ch: char) -> bool { + // The reference class has one contiguous run from U+8C48 to + // U+FAFF and ends the Yi block at U+A4CF (not U+A48F). + matches!(ch as u32, + 0x2E80..=0x2FFF | 0x3000..=0x303F | 0x3040..=0x30FF | 0x3100..=0x31FF + | 0x3400..=0x4DBF | 0x4E00..=0x9FFF | 0xA000..=0xA4CF | 0xAC00..=0xD7AF + | 0x8C48..=0xFAFF | 0xFE30..=0xFE4F | 0xFF00..=0xFFEF) +} + +/// The reference's `_UNIT` split (decode-time units): URL bodies, runs +/// of word characters (excluding CJK, `_` excluded by `[^\W_]`) plus +/// `@._-+`, or any non-space char. Returns each char's unit id, -1 +/// outside units — the decode's `u` array. +pub fn unit_ids(chars: &[char]) -> Vec { + let mut ids = vec![-1i64; chars.len()]; + let text: String = chars.iter().collect(); + let pattern = concat!( + "(?:https?://|www\\.)[^\\s\\]\\)\\}>「」『』\"'“”{cjk}]+?(?=[.,;:!?]*(?![^\\s\\]\\)\\}>「」『』\"'“”{cjk}]))", + "|(?:(?![{cjk}])[^\\W_]|[@._\\-+])+", + "|\\S", + ) + .replace("{cjk}", CJK); + let regex = Regex::with_options( + &pattern, + onig::RegexOptions::REGEX_OPTION_IGNORECASE, + onig::Syntax::ruby(), + ) + .expect("the reference unit pattern must compile"); + for (unit, (start, end)) in regex.find_iter(&text).enumerate() { + for id in ids.iter_mut().take(end).skip(start) { + *id = unit as i64; + } + } + ids +} diff --git a/tests/vela/native_contract_unit.rs b/tests/vela/native_contract_unit.rs new file mode 100644 index 00000000..e2a60834 --- /dev/null +++ b/tests/vela/native_contract_unit.rs @@ -0,0 +1,14 @@ +//! Private-item tests for the native crate's wire contract, loaded by +//! the `#[path]` wiring in `src/models/vela/native/src/contract.rs`. + +use super::*; + +#[test] +fn duplicate_keys_mirror_the_reference_message() { + let error = normalize_parse_error("request body is not valid JSON: duplicate key \"state\""); + assert_eq!(error.status, 400); + assert_eq!( + error.body, + serde_json::json!({"detail": "duplicate JSON key 'state'"}) + ); +} diff --git a/tests/vela/native_processing.rs b/tests/vela/native_processing.rs new file mode 100644 index 00000000..917a423c --- /dev/null +++ b/tests/vela/native_processing.rs @@ -0,0 +1,137 @@ +//! Processing tests against the frozen token-plan fixtures. +//! +//! The mapping tests (state → parts, SystemOne → predict, plan) run +//! everywhere with no tokenizer and no weights. The full render parity +//! — rows and window rows byte-for-byte against the fixtures — needs +//! the exported bundle's tokenizer and is opt-in: +//! +//! VELA_NATIVE_BUNDLE=weights/vela-2.0-0.8b-native \ +//! cargo test -p omni-vela-native --test vela_native_processing -- --nocapture + +use std::path::PathBuf; + +use omni_vela_native::questions::system_one_to_predict; +use omni_vela_native::state::system_one_state; +use serde_json::Value; + +const CASES: [&str; 5] = [ + "example-request", + "example-request-set-threshold", + "example-request-cjk", + "example-request-score", + "long-span-windowed", +]; + +fn fixture(case: &str) -> Value { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../../../tests/vela/fixtures"); + serde_json::from_str( + &std::fs::read_to_string(root.join(format!("native-plan-{case}.json"))) + .expect("fixture present; record it with recipe/vela/export_token_plan.py"), + ) + .expect("fixture JSON") +} + +// ------------------------------------------------------- mapping (no tokens) + +fn mapped(case: &str) -> Value { + let fix = fixture(case); + let request = fix["request"].as_object().expect("request"); + let state = system_one_state(&request["state"]).expect("state maps"); + let questions = request["questions"].as_object().expect("questions"); + let mapped = system_one_to_predict(state, questions).expect("maps"); + serde_json::json!({ + "predict_request": serde_json::to_value(&mapped.request).unwrap(), + "plan": serde_json::to_value(&mapped.plan).unwrap(), + }) +} + +#[test] +fn the_predict_mapping_matches_every_fixture() { + for case in CASES { + let got = mapped(case); + let fix = fixture(case); + assert_eq!( + got["predict_request"], fix["predict_request"], + "predict_request differs for {case}" + ); + assert_eq!(got["plan"], fix["plan"], "plan differs for {case}"); + } +} + +#[test] +fn an_invalid_question_reports_the_pinned_triples() { + let state = system_one_state(&serde_json::json!("s")).expect("state"); + let questions = serde_json::json!({ + "q": {"type": "choice", "instructions": "ok?", "criteria": {"a": "x"}} + }); + let error = system_one_to_predict(state, questions.as_object().unwrap()).unwrap_err(); + assert_eq!( + error.body, + serde_json::json!({"detail": [{"loc": ["body", "questions", "q", "criteria"], + "msg": "choice criteria must be an object with 2 to 255 entries", "type": "value_error"}]}) + ); + + let state = system_one_state(&serde_json::json!("s")).expect("state"); + let questions = serde_json::json!({ + "q": {"type": "span", "instructions": "which?", "criteria": {"a": "x"}, + "head": "other", "over": "request"} + }); + let error = system_one_to_predict(state, questions.as_object().unwrap()).unwrap_err(); + assert_eq!( + error.body["detail"][0]["loc"], + serde_json::json!(["body", "questions", "q", "head"]) + ); + assert_eq!(error.body["detail"][0]["type"], "literal_error"); +} + +#[test] +fn a_set_label_collision_is_rejected_after_the_walk() { + let state = system_one_state(&serde_json::json!("s")).expect("state"); + let questions = serde_json::json!({ + "issues": {"type": "set", "instructions": "which?", "criteria": {"billing": "b"}}, + "issues.billing": {"type": "noul", "instructions": "which?"} + }); + let error = system_one_to_predict(state, questions.as_object().unwrap()).unwrap_err(); + assert_eq!( + error.body["detail"][0]["msg"], + "collides with the Noul view of a set label" + ); +} + +// ------------------------------------------------- full render (opt-in) + +fn bundle_dir() -> Option { + let value = std::env::var("VELA_NATIVE_BUNDLE").ok()?; + let path = PathBuf::from(value); + path.is_dir().then_some(path) +} + +#[test] +fn the_rendered_rows_match_every_fixture() { + let Some(bundle) = bundle_dir() else { + eprintln!("skipping: set VELA_NATIVE_BUNDLE to an exported bundle for render parity"); + return; + }; + let processor = omni_vela_native::processing::Processor::load(&bundle) + .expect("processor loads the exported bundle"); + for case in CASES { + let fix = fixture(case); + let request = fix["request"].as_object().expect("request"); + let planned = match processor.plan(request) { + Ok(planned) => planned, + Err(error) => panic!( + "plan failed for {case}: {}", + serde_json::to_string(&error.body).unwrap() + ), + }; + let got = serde_json::json!({ + "rows": serde_json::to_value(&planned.rows).unwrap(), + "window_rows": serde_json::to_value(&planned.window_rows).unwrap(), + }); + assert_eq!(got["rows"], fix["rows"], "rows differ for {case}"); + assert_eq!( + got["window_rows"], fix["window_rows"], + "window rows differ for {case}" + ); + } +} diff --git a/tests/vela/native_units.rs b/tests/vela/native_units.rs new file mode 100644 index 00000000..e117fdea --- /dev/null +++ b/tests/vela/native_units.rs @@ -0,0 +1,97 @@ +//! Unit tests for the native crate's state mapping and word splitter, +//! extracted from the modules per the repository's test-placement +//! rule (the private contract test lives in native_contract_unit.rs, +//! loaded by the `#[path]` wiring in contract.rs). + +use omni_vela_native::state::system_one_state; +use omni_vela_native::words::{split_words, word_first_tokens}; +use serde_json::json; + +// ------------------------------------------------------------- state + +#[test] +fn a_plain_string_is_one_user_part() { + let parts = system_one_state(&json!("hello")).expect("parts"); + assert_eq!(parts.parts.len(), 1); + assert_eq!(parts.parts[0].r#type, "user"); + assert_eq!(parts.fields["request"].end, 5); +} + +#[test] +fn typed_keys_group_into_ordered_parts_with_field_ranges() { + let parts = system_one_state(&json!({ + "answer": "A", "request": "R", "source": "S", "extra": "E", + })) + .expect("parts"); + let roles: Vec<&str> = parts.parts.iter().map(|p| p.r#type.as_str()).collect(); + assert_eq!(roles, ["user", "context", "answer"]); + let context = &parts.parts[1]; + assert_eq!(context.text, "source:\nS\n\nextra:\nE"); + assert_eq!(parts.fields["source"].start, "source:\n".chars().count()); + assert_eq!( + parts.fields["extra"].start, + "source:\nS\n\nextra:\n".chars().count() + ); +} + +#[test] +fn an_empty_role_part_is_rejected() { + let error = system_one_state(&json!({"request": " "})).unwrap_err(); + assert_eq!( + error.body["detail"][0]["msg"], + serde_json::json!("the user part of the state is empty") + ); +} + +#[test] +fn a_string_holding_a_json_object_is_read_as_that_object() { + let parts = system_one_state(&json!("{\"request\": \"text\"}")).expect("parts"); + assert_eq!(parts.parts.len(), 1); + assert_eq!(parts.fields["request"].end, 4); +} + +// ------------------------------------------------------------- words + +#[test] +fn words_split_like_the_reference() { + let text = "Hi, I'm Tom Baker (tom.baker@example.com)."; + let words: Vec = split_words(text) + .iter() + .map(|(a, b)| text.chars().skip(*a).take(b - a).collect()) + .collect(); + assert_eq!( + words, + vec![ + "Hi", + ",", + "I", + "'", + "m", + "Tom", + "Baker", + "(", + "tom.baker@example.com", + ")", + "." + ] + ); +} + +#[test] +fn cjk_characters_are_one_unit_each() { + let text = "追踪 parcel 仓库"; + let words: Vec = split_words(text) + .iter() + .map(|(a, b)| text.chars().skip(*a).take(b - a).collect()) + .collect(); + assert_eq!(words, vec!["追", "踪", "parcel", "仓", "库"]); +} + +#[test] +fn first_tokens_skip_empty_tokens() { + let text = "alpha beta"; + let offsets = vec![(0, 0), (0, 5), (6, 10)]; + let (word_offsets, first) = word_first_tokens(text, &offsets); + assert_eq!(word_offsets, vec![(0, 5), (6, 10)]); + assert_eq!(first, vec![1, 2]); +} From 7391de2a1035fb9a07af3d13ef4a997e0002ab48 Mon Sep 17 00:00:00 2001 From: "Mr.Dong" <1042542469@qq.com> Date: Sun, 25 Oct 2026 02:34:48 +0800 Subject: [PATCH 04/14] vela: add the 0.8B native token-level processing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Rust processing of the native path, mirrored from the pinned runtime and checked field-for-field against the five frozen token plans (opt-in render parity with the exported bundle's tokenizer): - state.rs: the state -> typed-parts mapping (role grouping, field ranges, canonical DEV2.0 JSON) with the pinned rejection triples; - questions.rs: the SystemOne -> predict mapping — the validation walk and order, Noul folded into a two-option choice (choice renders [ABS], the reference's abstain default), over resolution, threshold/head carried, the set-label collision check; - words.rs: the GLiNER2/CJK _WORD splitter and the first-token word mapping; - render.rs: the encoder (char-offset tokens, memoized), the six-rule span-head dispatch with the hallucination-alias label replacement, the truncation budget, the DEV2.0 rendering (parts pass, question blocks with option ends and query positions, span layout a/c with word positions) and the window rows (head only, as the reference); - processing.rs: the Processor over the exported bundle. Also: the envelope error locs are flat arrays, matching the reference triples exactly. Checks: cargo test (26 tests) + fmt/clippy clean + opt-in render parity (5/5 fixtures). --- Cargo.lock | 3 + README.md | 2 +- docs/supported-models.md | 2 +- recipe/vela/native.md | 44 +- src/models/vela/README.md | 17 +- src/models/vela/native/Cargo.toml | 18 +- src/models/vela/native/examples/parity.rs | 87 +++ src/models/vela/native/src/contract.rs | 15 +- src/models/vela/native/src/lib.rs | 12 +- src/models/vela/native/src/processing.rs | 274 ++++++++ src/models/vela/native/src/questions.rs | 441 ++++++++++++ src/models/vela/native/src/render.rs | 794 ++++++++++++++++++++++ src/models/vela/native/src/state.rs | 235 +++++++ src/models/vela/native/src/words.rs | 119 ++++ tests/vela/native_contract_unit.rs | 14 + tests/vela/native_processing.rs | 137 ++++ tests/vela/native_units.rs | 97 +++ 17 files changed, 2277 insertions(+), 34 deletions(-) create mode 100644 src/models/vela/native/examples/parity.rs create mode 100644 src/models/vela/native/src/processing.rs create mode 100644 src/models/vela/native/src/questions.rs create mode 100644 src/models/vela/native/src/render.rs create mode 100644 src/models/vela/native/src/state.rs create mode 100644 src/models/vela/native/src/words.rs create mode 100644 tests/vela/native_contract_unit.rs create mode 100644 tests/vela/native_processing.rs create mode 100644 tests/vela/native_units.rs diff --git a/Cargo.lock b/Cargo.lock index 2a269f64..bd63bd1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1295,8 +1295,11 @@ version = "0.1.0" dependencies = [ "anyhow", "omni-qwen3-5-native", + "onig", + "serde", "serde_json", "sha2 0.11.1", + "tokenizers 0.22.2", ] [[package]] diff --git a/README.md b/README.md index cbfce500..a68b0fd2 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ extensions) on each checkpoint's own pinned runtime: | OmniJev-4B v1.1 | [Checkpoint export and CPU contract](recipe/omnijev/README.md) only; the native worker is in progress ([#114](https://github.com/ThinkFlowLab/system1-omni/issues/114)) | | D3 (Decision 3.0) | [Python reference worker](recipe/d3/reference.md) on the checkpoint's pinned runtime; `choice`/`noul`/`score` text state, media inputs refused; author-run on A100 (evidence in the integration PR) | | Vela 2.0 0.3B | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; all five kinds (`choice`/`noul`/`score`/`span`/`set`) for text state; CPU FP32 validated (author-run, evidence in the integration PR) | -| Vela 2.0 0.8B hybrid | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; same surface plus `span_heads`; [native library](recipe/vela/native.md) (bundle export, wire contract); CPU FP32 parity recorded in the integration PR | +| Vela 2.0 0.8B hybrid | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; same surface plus `span_heads`; [native library](recipe/vela/native.md) (bundle export, wire contract, token-level processing); CPU FP32 parity recorded in the integration PR | [Supported models and hardware](docs/supported-models.md) lists the devices and where each worker has been run. diff --git a/docs/supported-models.md b/docs/supported-models.md index 30a52c6b..399ea09a 100644 --- a/docs/supported-models.md +++ b/docs/supported-models.md @@ -25,7 +25,7 @@ Models that are being added are also tracked in issues labeled [new model](https | OmniJev-4B v1.1 | None yet: [checkpoint export and CPU contract](../recipe/omnijev/README.md); the native worker is in progress ([#114](https://github.com/ThinkFlowLab/system1-omni/issues/114)) | Request contract, preparation, heads and finishing checked against the reference ([#120](https://github.com/ThinkFlowLab/system1-omni/pull/120)); no inference | Not yet | Not supported | Python 3.10 reference environment for the export and fixtures | | D3 (Decision 3.0) | [Python reference worker](../recipe/d3/reference.md) running the checkpoint's pinned runtime | Unverified | Author-run on NVIDIA A100 (sm_80): three-kind serving smoke with byte-identical frontend forwarding and reference parity (exact decisions, max delta 0.0, 348 == 348 tokens); evidence in the integration PR. Owner: @MrDongsls. | Unverified | Python 3.12, the [pinned runtime requirements](../recipe/d3/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/d3) (~52 GB) | | Vela 2.0 0.3B | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime | **CPU FP32 validated** (author-run, x86 WSL2, 24 cores): startup with all-kind warmup, the four example requests plus five synthetic rejections, and exact-match reference parity against the pinned upstream server on all nine (four 200s byte-equal incl. key order, agreed 422/413); byte-identical frontend forwarding; evidence in the integration PR. Owner: @MrDongsls. | Unverified (bf16-autocast is an untested deployment option) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.3B) (1.24 GB FP32 weights; ~4.4 GB with ONNX/assets) | -| Vela 2.0 0.8B hybrid | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime (same wire layer as 0.3B); [native library](../recipe/vela/native.md) — bundle export, wire contract | Same surface as 0.3B plus the `span_heads` field (router/broad dispatch); **CPU FP32 parity** (author-run; evidence in the integration PR) | Unverified (bf16-autocast is the evaluated upstream setting but untested here) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) (2.02 GB shard + 4.5 MB broad head; ~3 GB FP32 parameters) | +| Vela 2.0 0.8B hybrid | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime (same wire layer as 0.3B); [native library](../recipe/vela/native.md) — bundle export, wire contract, token-level processing | Same surface as 0.3B plus the `span_heads` field (router/broad dispatch); **CPU FP32 parity** (author-run; evidence in the integration PR) | Unverified (bf16-autocast is the evaluated upstream setting but untested here) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) (2.02 GB shard + 4.5 MB broad head; ~3 GB FP32 parameters) | - **Validated:** covered by the recipe on `main` or by the checks in the linked merged pull request. - **Author-run:** recorded by the recipe author on the stated hardware and not independently reproduced; the row names its owner. diff --git a/recipe/vela/native.md b/recipe/vela/native.md index a9328003..4c3cefa3 100644 --- a/recipe/vela/native.md +++ b/recipe/vela/native.md @@ -2,8 +2,9 @@ The native implementation for [vllm-sr/Vela-2.0-0.8B](https://huggingface.co/vllm-sr/Vela-2.0-0.8B): -the exported-bundle gate and the wire contract, mirrored from the -pinned runtime. This is a library; serving runs through the +the exported-bundle gate, the wire contract, and the token-level +processing — all mirrored from the pinned runtime and checked against +frozen fixtures. This is a library; serving runs through the [reference recipe](reference.md)'s Python worker. Run the commands from the repository root with the same `.venv` and @@ -28,22 +29,45 @@ tokenizer, and `vela_native_manifest.json` pinning the source revision, the gate's file table, the tensor inventory and every file's SHA-256. +## Freeze the token-plan fixtures (opt-in, needs the package) + +~~~sh +PYTHONPATH=src .venv/bin/python recipe/vela/export_token_plan.py \ + --model weights/vela-2.0-0.8b --out tests/vela/fixtures/ +~~~ + +The token plans record what the pinned runtime feeds the backbone (the +predict mapping, the per-row decomposition, the rendered `p_ids`, +blocks and readout positions, truncation, a windowed long-span case). +The example-request token plan totals 1,041 tokens, matching the +oracle fixture's `usage.input_tokens`. + ## Checks ~~~sh cargo test -p omni-vela-native cargo fmt --all --check cargo clippy -p omni-vela-native --all-targets -- -D warnings +VELA_NATIVE_BUNDLE="$PWD/weights/vela-2.0-0.8b-native" \ + cargo test -p omni-vela-native --test vela_native_processing -- --nocapture ~~~ -15 tests, no weights, no GPU: the wire contract against the pinned -runtime's 422/400 bodies and the bundle manifest gate against a -synthetic bundle. +26 tests run everywhere with no weights and no GPU: the wire contract +against the pinned runtime's 422/400 bodies, the bundle manifest gate, +and the predict-mapping/plan parity on every frozen fixture. The +opt-in render check replays the five token plans through the Rust +processing field-for-field. For a field-level diff of one case: + +~~~sh +VELA_NATIVE_BUNDLE="$PWD/weights/vela-2.0-0.8b-native" \ + cargo run -p omni-vela-native --example parity -- example-request +~~~ ## Scope and limits -- Implemented: the bundle export + manifest gate and the wire - admission. -- Not implemented: token-level processing, the F32 heads, scoring, - backbone execution, and an HTTP worker. No performance claims are - made. +- Implemented: the bundle export + manifest gate, the wire admission, + and the token-level processing (state mapping, predict mapping with + the validation triples, word units, span-head dispatch, the DEV2.0 + rendering, the truncation budget, window rows). +- Not implemented: the F32 heads, scoring and span decoding, backbone + execution, and an HTTP worker. No performance claims are made. diff --git a/src/models/vela/README.md b/src/models/vela/README.md index 888658fc..92fc4f82 100644 --- a/src/models/vela/README.md +++ b/src/models/vela/README.md @@ -246,8 +246,19 @@ The native implementation lives in [`native/`](native/) as the - `native/src/contract.rs` is the wire admission, mirroring `protocol.py` and the pinned runtime's preamble with byte-equal 422/400 bodies. +- `native/src/{state,questions,words,render,processing}.rs` are the + token-level processing: the state → parts mapping, the SystemOne → + predict mapping with the pinned runtime's validation triples (Noul + folded into a two-option choice; choice renders `[ABS]`, the + reference's abstain default), the GLiNER2/CJK word splitter, the + six-rule span-head dispatch with the hallucination-alias label + replacement, the DEV2.0 prompt rendering (parts pass, question + blocks with option end and query positions, span layout a/c with + word positions, the truncation budget, the 16,384-window 413) and + the long-target window rows. All five frozen token plans + (`tests/vela/fixtures/native-plan-*.json`) match field-for-field. -Token-level processing, the F32 heads, backbone execution and an HTTP -worker are not implemented. Checks: `cargo test -p omni-vela-native` -(15 tests, no weights, no GPU; see +The F32 heads, scoring, backbone execution and an HTTP worker are not +implemented. Checks: `cargo test -p omni-vela-native` (26 tests, no +weights, no GPU; render parity opt-in with `VELA_NATIVE_BUNDLE`; see [recipe/vela/native.md](../../recipe/vela/native.md)). diff --git a/src/models/vela/native/Cargo.toml b/src/models/vela/native/Cargo.toml index 814d32b0..a69e15b6 100644 --- a/src/models/vela/native/Cargo.toml +++ b/src/models/vela/native/Cargo.toml @@ -3,15 +3,15 @@ name = "omni-vela-native" version = "0.1.0" edition = "2024" publish = false -description = "Native library for vllm-sr/Vela-2.0-0.8B: bundle gate and wire contract" +description = "Native library for vllm-sr/Vela-2.0-0.8B: bundle gate, wire contract and token-level processing" [dependencies] anyhow = "1.0.100" +onig = { version = "6", default-features = false } omni-qwen3-5-native = { path = "../../qwen3_5/native" } -serde_json = { version = "1.0.149", features = ["preserve_order"] } -sha2 = "0.11" - -[dev-dependencies] +serde = { version = "1", features = ["derive"] } +tokenizers = { version = "=0.22.2", default-features = false, features = ["onig"] } +serde_json = { version = "1.0.149", features = ["float_roundtrip", "preserve_order"] } sha2 = "0.11" [lib] @@ -24,3 +24,11 @@ path = "../../../../tests/vela/native_contract.rs" [[test]] name = "vela_native_bundle" path = "../../../../tests/vela/native_bundle.rs" + +[[test]] +name = "vela_native_processing" +path = "../../../../tests/vela/native_processing.rs" + +[[test]] +name = "vela_native_units" +path = "../../../../tests/vela/native_units.rs" diff --git a/src/models/vela/native/examples/parity.rs b/src/models/vela/native/examples/parity.rs new file mode 100644 index 00000000..071d0f52 --- /dev/null +++ b/src/models/vela/native/examples/parity.rs @@ -0,0 +1,87 @@ +//! Debug helper: compare the rendered rows against one fixture and +//! print the first differing field. Run with: +//! +//! VELA_NATIVE_BUNDLE=/abs/path cargo run -p omni-vela-native --example parity -- example-request + +use std::path::PathBuf; + +use serde_json::Value; + +fn main() { + let case = std::env::args().nth(1).unwrap_or("example-request".into()); + let bundle = PathBuf::from( + std::env::var("VELA_NATIVE_BUNDLE").expect("VELA_NATIVE_BUNDLE points at the export"), + ); + let fixture: Value = serde_json::from_str( + &std::fs::read_to_string( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../../../../tests/vela/fixtures") + .join(format!("native-plan-{case}.json")), + ) + .expect("fixture"), + ) + .expect("fixture json"); + + let processor = omni_vela_native::processing::Processor::load(&bundle).expect("load"); + let request = fixture["request"].as_object().expect("request"); + match processor.plan(request) { + Ok(planned) => { + let got = serde_json::json!({ + "rows": serde_json::to_value(&planned.rows).unwrap(), + "window_rows": serde_json::to_value(&planned.window_rows).unwrap(), + }); + compare( + "rows", + got["rows"].as_array().unwrap(), + fixture["rows"].as_array().unwrap(), + ); + if !fixture["window_rows"].is_null() { + compare( + "window_rows", + got["window_rows"].as_array().unwrap(), + fixture["window_rows"].as_array().unwrap(), + ); + } + println!("parity: no field differences found"); + } + Err(error) => println!( + "plan error: {}", + serde_json::to_string(&error.body).unwrap() + ), + } +} + +fn compare(name: &str, got: &[Value], want: &[Value]) { + println!("{name}: {} vs {} row(s)", got.len(), want.len()); + for (index, (a, b)) in got.iter().zip(want).enumerate() { + let (Some(a), Some(b)) = (a.as_object(), b.as_object()) else { + continue; + }; + for key in b.keys() { + if a.get(key) != b.get(key) { + println!("row {index} field {key}: differs"); + println!( + " want: {}", + serde_json::to_string(&b[key]) + .unwrap() + .chars() + .take(300) + .collect::() + ); + println!( + " got: {}", + serde_json::to_string(&a[key]) + .unwrap() + .chars() + .take(300) + .collect::() + ); + } + } + for key in a.keys() { + if !b.contains_key(key) { + println!("row {index} field {key}: extra in ours"); + } + } + } +} diff --git a/src/models/vela/native/src/contract.rs b/src/models/vela/native/src/contract.rs index 06a3de95..734dcb25 100644 --- a/src/models/vela/native/src/contract.rs +++ b/src/models/vela/native/src/contract.rs @@ -56,7 +56,7 @@ pub fn parse_body(raw: &[u8]) -> Result, RequestError> { /// Mirror the reference worker's 400 messages: duplicate keys verbatim, /// everything else the shared generic message. -fn normalize_parse_error(error: &str) -> RequestError { +pub(crate) fn normalize_parse_error(error: &str) -> RequestError { if let Some(rest) = error.split("duplicate key ").nth(1) { // serde appends its position suffix after the quoted key. if let Some(key) = rest @@ -129,14 +129,5 @@ pub fn runtime_rejection(message: &str) -> RequestError { } #[cfg(test)] -mod tests { - use super::*; - - #[test] - fn duplicate_keys_mirror_the_reference_message() { - let error = - normalize_parse_error("request body is not valid JSON: duplicate key \"state\""); - assert_eq!(error.status, 400); - assert_eq!(error.body, json!({"detail": "duplicate JSON key 'state'"})); - } -} +#[path = "../../../../../tests/vela/native_contract_unit.rs"] +mod tests; diff --git a/src/models/vela/native/src/lib.rs b/src/models/vela/native/src/lib.rs index 32f64c4f..1d849284 100644 --- a/src/models/vela/native/src/lib.rs +++ b/src/models/vela/native/src/lib.rs @@ -1,5 +1,13 @@ -//! Native library for vllm-sr/Vela-2.0-0.8B: the exported-bundle gate -//! and the wire contract, mirrored from the pinned runtime. +//! Native library for vllm-sr/Vela-2.0-0.8B: the exported-bundle gate, +//! the wire contract, and the token-level processing (state → parts, +//! the SystemOne → predict mapping with the pinned runtime's validation +//! triples, word units, the DEV2.0 prompt rendering — mirrored against +//! the frozen `native-plan-*` fixtures). pub mod bundle; pub mod contract; +pub mod processing; +pub mod questions; +pub mod render; +pub mod state; +pub mod words; diff --git a/src/models/vela/native/src/processing.rs b/src/models/vela/native/src/processing.rs new file mode 100644 index 00000000..12370856 --- /dev/null +++ b/src/models/vela/native/src/processing.rs @@ -0,0 +1,274 @@ +//! The processor: one admitted request body → predict mapping, plan, +//! and rendered rows, mirroring the reference path +//! (`system_one_to_predict` → `_to_generic` → `_predict`'s row split → +//! `_prep`/`_render`, plus the long-target window rows). Everything the +//! frozen `native-plan-*` fixtures record. + +use std::collections::HashSet; +use std::path::Path; + +use anyhow::{Context, Result}; +use serde_json::{Map, Value}; + +use crate::contract::RequestError; +use crate::questions::{PredictQuestion, system_one_to_predict}; +use crate::render::{ + Encoder, GenericQuestion, HALU_LABEL, PreparedPart, RMAX, RenderContext, RenderedRow, + window_part, +}; +use crate::state::system_one_state; + +pub struct Processor { + encoder: Encoder, + max_length: usize, + router_label_sets: Vec>, + has_broad: bool, + halu_desc: String, +} + +pub struct Planned { + pub predict_request: Value, + pub plan: Value, + pub rows: Vec, + pub window_rows: Vec, +} + +impl Processor { + /// Load from an exported native bundle (tokenizer + calibration; + /// the manifest gate runs first). + pub fn load(bundle: &Path) -> Result { + let manifest = crate::bundle::Bundle::load(bundle)?; + let calibration: Value = serde_json::from_slice( + &std::fs::read(bundle.join("calibration.json")).context("calibration.json")?, + ) + .context("calibration.json must be JSON")?; + let broad = calibration.get("broad_head").filter(|b| !b.is_null()); + let router_label_sets: Vec> = broad + .and_then(|b| b.get("router_label_sets")) + .and_then(Value::as_array) + .filter(|sets| !sets.is_empty()) + .map(|sets| { + sets.iter() + .filter_map(Value::as_array) + .map(|labels| { + labels + .iter() + .filter_map(Value::as_str) + .map(str::to_owned) + .collect() + }) + .collect() + }) + .unwrap_or_else(|| { + vec![ + calibration["pii_types"].as_array().map(|types| { + types + .iter() + .filter_map(Value::as_str) + .map(str::to_owned) + .collect() + }), + calibration["halu_schema"]["labels"] + .as_object() + .map(|labels| labels.keys().cloned().collect()), + ] + .into_iter() + .flatten() + .collect() + }); + let has_broad = broad.is_some(); // the bundle gate pinned the broad tensors + let halu_desc = calibration["halu_schema"]["labels"][HALU_LABEL] + .as_str() + .unwrap_or("a claim not supported by the context") + .to_owned(); + Ok(Self { + encoder: Encoder::load(&bundle.join("tokenizer.json"))?, + max_length: manifest.max_length(), + router_label_sets, + has_broad, + halu_desc, + }) + } + + /// The full planning path for one admitted request body. + pub fn plan(&self, body: &Map) -> Result { + let state = system_one_state(&body["state"])?; + let questions = body["questions"] + .as_object() + .ok_or_else(crate::questions::empty_questions_error)?; + let mapped = system_one_to_predict(state, questions)?; + let predict_request = serde_json::to_value(&mapped.request).expect("serializable"); + let plan = serde_json::to_value(&mapped.plan).expect("serializable"); + let state_parts = mapped.request.parts.clone(); + + // `_to_generic`: predict questions → generic render questions + // (Noul is already folded; choice always carries [ABS]). + let generic: Vec = + mapped.request.questions.iter().map(to_generic).collect(); + // `_predict`'s row split: non-span questions plus the first span + // in one row, every further span its own row. + let spans: Vec<&GenericQuestion> = generic.iter().filter(|q| q.kind == "span").collect(); + let rest: Vec = generic + .iter() + .filter(|q| q.kind != "span") + .cloned() + .collect(); + let mut rows: Vec> = Vec::new(); + if !rest.is_empty() || !spans.is_empty() { + let mut first = rest.clone(); + if let Some(span) = spans.first() { + first.push((*span).clone()); + } + rows.push(first); + for span in spans.iter().skip(1) { + rows.push(vec![(*span).clone()]); + } + } + let context = RenderContext { + encoder: &self.encoder, + max_length: self.max_length, + router_label_sets: &self.router_label_sets, + has_broad: self.has_broad, + halu_desc: self.halu_desc.clone(), + }; + let span_roles: HashSet = + spans.iter().flat_map(|q| q.over.iter().cloned()).collect(); + let mut rendered = Vec::new(); + let mut window_rows = Vec::new(); + let mut parts_by_role = std::collections::HashMap::new(); + for part in self.prepared_parts(&state_parts, &span_roles) { + parts_by_role.insert(part.role.clone(), part); + } + for row in rows { + if row.is_empty() { + continue; + } + let (adjusted, dispatch) = context.prepare_questions(&row)?; + let parts: Vec = state_parts + .iter() + .map(|part| { + parts_by_role + .get(&part.r#type) + .cloned() + .expect("prepared part") + }) + .collect(); + let record = context.render(&parts, &adjusted, &dispatch)?; + // `_window_rows`: a span target beyond RMAX becomes one row + // per window (the full-render span block stays on the row). + let span = row.iter().find(|q| q.kind == "span"); + if let Some(span) = span { + let index = parts.iter().position(|p| p.role == span.over[0]); + if let Some(index) = index { + let part = &parts[index]; + let has_words = part.words.is_some(); + if part.ids.len() > RMAX && has_words { + let (_, first_tokens) = part.words.as_ref().expect("words"); + for (a, b) in crate::render::span_windows(first_tokens, part.ids.len()) { + let mut windowed_parts = parts.clone(); + windowed_parts[index] = window_part(part, a, b); + let (w_adjusted, w_dispatch) = context.prepare_questions(&row)?; + let mut record = + context.render(&windowed_parts, &w_adjusted, &w_dispatch)?; + // The runtime's window rows carry the head only. + record.window = true; + window_rows.push(record); + } + } + } + } + rendered.push(record); + } + Ok(Planned { + predict_request, + plan, + rows: rendered, + window_rows, + }) + } + + /// The prepared parts for one request: tokens everywhere, offsets + /// and word units on span-target parts. + fn prepared_parts( + &self, + state_parts: &[crate::state::Part], + span_roles: &HashSet, + ) -> Vec { + state_parts + .iter() + .map(|part| { + let (ids, offsets) = self.encoder.ids_offsets(&part.text); + if span_roles.contains(&part.r#type) { + let words = crate::words::word_first_tokens(&part.text, &offsets); + PreparedPart { + role: part.r#type.clone(), + ids, + offsets: Some(offsets), + words: Some(words), + } + } else { + PreparedPart { + role: part.r#type.clone(), + ids, + offsets: None, + words: None, + } + } + }) + .collect() + } +} + +/// `_to_generic` for the SystemOne path: options/labels carry over in +/// order (score levels have empty descriptions), the target part is the +/// resolved `over`, choice always carries `[ABS]` (the reference's +/// `abstain` default is true and the mapper never sets it), and span +/// keeps its threshold and head override. +fn to_generic(question: &PredictQuestion) -> GenericQuestion { + let over: Vec = match &question.target_part { + Value::String(role) => vec![role.clone()], + Value::Array(roles) => roles + .iter() + .filter_map(Value::as_str) + .map(str::to_owned) + .collect(), + _ => Vec::new(), + }; + let (names, descriptions) = match (&question.labels, &question.options) { + (Some(labels), _) => ( + labels.iter().map(|n| n.name.clone()).collect(), + labels.iter().map(|n| n.description.clone()).collect(), + ), + (None, Some(Value::Array(items))) => { + // Objects carry name/description; score levels are strings. + let mut names = Vec::new(); + let mut descriptions = Vec::new(); + for item in items { + match item { + Value::String(name) => { + names.push(name.clone()); + descriptions.push(String::new()); + } + Value::Object(named) => { + names.push(named["name"].as_str().unwrap_or_default().to_owned()); + descriptions + .push(named["description"].as_str().unwrap_or_default().to_owned()); + } + _ => {} + } + } + (names, descriptions) + } + _ => (Vec::new(), Vec::new()), + }; + GenericQuestion { + id: question.id.clone(), + kind: question.kind.clone(), + over, + text: question.text.clone(), + names, + descriptions, + threshold: question.threshold, + head_override: question.head.clone(), + } +} diff --git a/src/models/vela/native/src/questions.rs b/src/models/vela/native/src/questions.rs new file mode 100644 index 00000000..4c095032 --- /dev/null +++ b/src/models/vela/native/src/questions.rs @@ -0,0 +1,441 @@ +//! The SystemOne (state, questions) → predict-request mapping, mirroring +//! the pinned runtime's `system_one_to_predict` exactly: the validation +//! walk and its whole-request error triples, the Noul folding into a +//! two-option choice, and the per-question plan used to build responses. + +use serde_json::{Map, Value}; + +use crate::contract::RequestError; +use crate::state::{Part, StateParts, content_text}; + +/// The `questions` container rejection shared by the mapping and the +/// processor's body walk. +pub fn empty_questions_error() -> RequestError { + qerror( + &["questions"], + "questions must be a non-empty object of named questions", + ) +} + +pub const SYSTEM_ONE_TYPES: [&str; 5] = ["noul", "choice", "score", "span", "set"]; +pub const NOUL_DEFAULT_NO: &str = "No. The statement or question is not satisfied."; +pub const NOUL_DEFAULT_YES: &str = "Yes. The statement or question is satisfied."; + +/// One option / label of a predict question (name, description). +#[derive(Debug, Clone, serde::Serialize, PartialEq)] +pub struct Named { + pub name: String, + pub description: String, +} + +/// The predict-level question, exactly as it serializes into the frozen +/// fixtures: Noul questions arrive here already folded into a choice. +#[derive(Debug, Clone, serde::Serialize)] +pub struct PredictQuestion { + pub id: String, + #[serde(rename = "type")] + pub kind: String, + pub text: String, + pub target_part: Value, + #[serde(skip_serializing_if = "Option::is_none")] + pub labels: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub threshold: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub head: Option, +} + +#[derive(Debug, Clone, serde::Serialize)] +pub struct PredictRequest { + pub parts: Vec, + pub questions: Vec, +} + +/// The response-side plan entry for one original question. +#[derive(Debug, Clone, serde::Serialize)] +pub struct PlanEntry { + pub qid: String, + #[serde(rename = "type")] + pub kind: String, + pub criteria: Value, + pub range: Option<(usize, usize)>, + pub part: Value, +} + +#[derive(Debug)] +pub struct Mapped { + pub request: PredictRequest, + pub plan: Vec, +} + +fn qerror(loc: &[&str], msg: &str) -> RequestError { + RequestError::envelope(loc, msg, "value_error") +} + +fn nonblank(value: &Value) -> bool { + match value { + Value::String(text) => !text.trim().is_empty(), + _ => true, + } +} + +/// `over` (state key | part name | list) → (target part(s), field range). +fn resolve_over( + over: &Value, + parts: &StateParts, + qloc: &[&str], +) -> Result<(Value, Option<(usize, usize)>), RequestError> { + let roles: Vec<&str> = parts.parts.iter().map(|p| p.r#type.as_str()).collect(); + let items: Vec<&Value> = match over { + Value::Array(list) => list.iter().collect(), + single => vec![single], + }; + let mut out: Vec<&str> = Vec::new(); + let mut range = None; + for item in items { + let Some(name) = item.as_str() else { + return Err(qerror( + &[qloc[0], qloc[1], "over"], + "over must be a state key, a part name or a list of them", + )); + }; + if let Some(field) = parts.fields.get(name) { + if !over.is_array() { + range = Some((field.start, field.end)); + } + if !out.contains(&field.role) { + out.push(field.role); + } + } else if roles.contains(&name) { + if !out.contains(&name) { + out.push(name); + } + } else { + let role = crate::state::key_role(name); + if roles.contains(&role) && !out.contains(&role) { + out.push(role); + } else { + return Err(qerror( + &[qloc[0], qloc[1], "over"], + &format!( + "'{name}' is not a field of the state (fields: [{fields}], parts: [{roles}])", + fields = parts + .fields + .keys() + .map(|k| format!("'{k}'")) + .collect::>() + .join(", "), + roles = roles.join(", "), + ), + )); + } + } + } + if out.is_empty() { + return Err(qerror( + &[qloc[0], qloc[1], "over"], + "over must not be empty", + )); + } + // Sequence order, so the pooled range covers exactly these parts. + let ordered: Vec<&str> = roles + .iter() + .filter(|role| out.contains(role)) + .copied() + .collect(); + let target = match ordered.len() { + 1 => Value::String(ordered[0].into()), + _ => Value::Array( + ordered + .into_iter() + .map(|r| Value::String(r.into())) + .collect(), + ), + }; + Ok((target, range)) +} + +/// The full mapping. `state` and `questions` are the admitted request's +/// fields; validation runs in the pinned runtime's order so error +/// precedence matches. +pub fn system_one_to_predict( + state_parts: StateParts, + questions: &Map, +) -> Result { + if questions.is_empty() { + return Err(qerror( + &["questions"], + "questions must be a non-empty object of named questions", + )); + } + let roles: Vec<&str> = state_parts + .parts + .iter() + .map(|p| p.r#type.as_str()) + .collect(); + let mut predict = Vec::new(); + let mut plan = Vec::new(); + for (qid, question) in questions { + if qid.trim().is_empty() { + return Err(qerror( + &["questions"], + "question IDs must not be empty or whitespace", + )); + } + let Some(question) = question.as_object() else { + return Err(qerror( + &["questions", qid], + "a question must be an object with a type", + )); + }; + let loc = ["questions", qid]; + let kind = question.get("type").and_then(Value::as_str).unwrap_or(""); + if !SYSTEM_ONE_TYPES.contains(&kind) { + return Err(RequestError::envelope( + &[loc[0], loc[1], "type"], + "type must be one of ['noul', 'choice', 'score', 'span', 'set']", + "literal_error", + )); + } + let mut allowed: Vec<&str> = vec!["type", "instructions", "criteria", "over"]; + if kind == "span" || kind == "set" { + allowed.push("threshold"); + } + if kind == "span" { + allowed.push("head"); + } + let extra: Vec<&String> = question + .keys() + .filter(|key| !allowed.contains(&key.as_str())) + .collect(); + if let Some(first) = extra.first() { + return Err(RequestError::envelope( + &[loc[0], loc[1], first], + "Extra inputs are not permitted", + "extra_forbidden", + )); + } + let instructions = question.get("instructions").unwrap_or(&Value::Null); + if !nonblank(instructions) { + return Err(qerror( + &[loc[0], loc[1], "instructions"], + "instructions must not be empty or whitespace", + )); + } + let text = match instructions { + Value::Null => String::new(), + other => content_text(other), + }; + let criteria = question.get("criteria").unwrap_or(&Value::Null); + // Target part: the resolved `over`, the span default, or all parts. + let (target_part, range) = match question.get("over") { + Some(Value::Null) | None => { + if kind == "span" { + let role = if roles.contains(&"answer") { + "answer" + } else if roles.contains(&"user") { + "user" + } else { + roles[0] + }; + (Value::String(role.into()), None) + } else if roles.len() == 1 { + (Value::String(roles[0].into()), None) + } else { + ( + Value::Array(roles.iter().map(|r| Value::String((*r).into())).collect()), + None, + ) + } + } + Some(over) => resolve_over(over, &state_parts, &loc)?, + }; + let mut predict_question = PredictQuestion { + id: qid.clone(), + kind: kind.to_string(), + text: text.clone(), + target_part: target_part.clone(), + labels: None, + options: None, + threshold: None, + head: None, + }; + let mut plan_criteria = criteria.clone(); + match kind { + "noul" => { + if !criteria.is_null() + && (!criteria.is_object() + || criteria + .as_object() + .is_some_and(|map| map.keys().any(|k| k != "true" && k != "false"))) + { + return Err(qerror( + &[loc[0], loc[1], "criteria"], + "noul criteria is an object with optional true / false", + )); + } + let map = criteria.as_object().cloned().unwrap_or_default(); + for key in ["true", "false"] { + if let Some(value) = map.get(key) + && !nonblank(value) + { + return Err(qerror( + &[loc[0], loc[1], "criteria", key], + "Noul criterion must not be empty or whitespace", + )); + } + } + let no = match map.get("false") { + Some(Value::Null) | None => NOUL_DEFAULT_NO.to_string(), + Some(value) => content_text(value), + }; + let yes = match map.get("true") { + Some(Value::Null) | None => NOUL_DEFAULT_YES.to_string(), + Some(value) => content_text(value), + }; + predict_question.kind = "choice".into(); + predict_question.options = Some(serde_json::json!([ + {"name": "no", "description": no}, + {"name": "yes", "description": yes}, + ])); + } + "choice" | "set" | "span" => { + let (lo, hi) = if kind == "choice" { (2, 255) } else { (1, 255) }; + let Some(map) = criteria.as_object() else { + return Err(qerror( + &[loc[0], loc[1], "criteria"], + &format!("{kind} criteria must be an object with {lo} to {hi} entries"), + )); + }; + if !(lo..=hi).contains(&map.len()) { + return Err(qerror( + &[loc[0], loc[1], "criteria"], + &format!("{kind} criteria must be an object with {lo} to {hi} entries"), + )); + } + let mut named = Vec::new(); + for (name, value) in map { + if name.trim().is_empty() || !nonblank(value) { + return Err(qerror( + &[loc[0], loc[1], "criteria", name], + "option names and descriptions must not be empty or whitespace", + )); + } + let description = match value { + Value::Null => String::new(), + other => content_text(other), + }; + named.push(Named { + name: name.clone(), + description, + }); + } + if kind == "span" { + predict_question.labels = Some(named); + } else { + predict_question.options = Some(serde_json::to_value(&named).unwrap()); + } + } + _ => { + // score + let Some(levels) = criteria.as_array() else { + return Err(qerror( + &[loc[0], loc[1], "criteria"], + "score criteria must be a list of 2 to 10 levels", + )); + }; + if !(2..=10).contains(&levels.len()) { + return Err(qerror( + &[loc[0], loc[1], "criteria"], + "score criteria must be a list of 2 to 10 levels", + )); + } + let mut names = Vec::new(); + for (index, value) in levels.iter().enumerate() { + if value.is_null() || !nonblank(value) { + return Err(qerror( + &[loc[0], loc[1], "criteria", &index.to_string()], + "Score criterion must not be empty or whitespace", + )); + } + names.push(content_text(value)); + } + if names.iter().collect::>().len() != names.len() { + return Err(qerror( + &[loc[0], loc[1], "criteria"], + "score levels must be distinct", + )); + } + predict_question.options = Some(serde_json::to_value(&names).unwrap()); + } + } + if let Some(threshold) = question.get("threshold") + && !threshold.is_null() + { + match threshold.as_f64().filter(|_| threshold.is_number()) { + Some(value) if (0.0..=1.0).contains(&value) => { + predict_question.threshold = Some(value); + } + _ => { + return Err(qerror( + &[loc[0], loc[1], "threshold"], + "threshold must be a number in [0, 1]", + )); + } + } + } + if kind == "span" + && let Some(head) = question.get("head") + && !head.is_null() + { + match head.as_str() { + Some(value @ ("router" | "broad")) => { + predict_question.head = Some(value.to_string()); + } + _ => { + return Err(RequestError::envelope( + &[loc[0], loc[1], "head"], + "head must be one of ['router', 'broad']", + "literal_error", + )); + } + } + } + // Python's plan keeps `crit`; noul normalized null -> {} earlier. + if kind == "noul" && plan_criteria.is_null() { + plan_criteria = serde_json::json!({}); + } + predict.push(predict_question); + plan.push(PlanEntry { + qid: qid.clone(), + kind: kind.to_string(), + criteria: plan_criteria, + range, + part: target_part, + }); + } + // The Noul views of set labels must not overwrite a question. + for entry in &plan { + if entry.kind == "set" + && let Value::Object(map) = &entry.criteria + { + for label in map.keys() { + if questions.contains_key(&format!("{}.{}", entry.qid, label)) { + return Err(qerror( + &["questions", &format!("{}.{}", entry.qid, label)], + "collides with the Noul view of a set label", + )); + } + } + } + } + Ok(Mapped { + request: PredictRequest { + parts: state_parts.parts, + questions: predict, + }, + plan, + }) +} diff --git a/src/models/vela/native/src/render.rs b/src/models/vela/native/src/render.rs new file mode 100644 index 00000000..ed3d11fd --- /dev/null +++ b/src/models/vela/native/src/render.rs @@ -0,0 +1,794 @@ +//! Prompt rendering, mirroring the pinned runtime's `_prep` + `_render` +//! (the DEV2.0 decoder layout): the parts pass, per-question blocks +//! with option end and query positions, the span block in layout a/c +//! with word positions, the truncation budget, and the long-target +//! windows. Output structs serialize exactly like the frozen +//! `native-plan-*` fixtures. + +use std::cell::RefCell; +use std::collections::{HashMap, HashSet}; +use std::path::Path; + +use std::collections::BTreeMap; +use tokenizers::Tokenizer; + +use crate::contract::RequestError; +use crate::state::canonical; + +pub const SUFFIX_CHOICE_SCORE: &str = + "\n\nSelect the single option best supported by the context and instructions.\nDecision:"; +pub const SUFFIX_SET: &str = + "\n\nSelect every option supported by the context and instructions.\nDecision:"; +pub const SUFFIX_SPAN: &str = + "\n\nMark every span of the target text that carries one of the labels.\nSpans:"; +pub const ABS_KEY: &str = "[ABS]"; +pub const ABS_DESC: &str = "None of the shown options applies."; +pub const PARTS_HEAD: &str = "Context:\n"; +pub const SEG_CLOSE: &str = "\n\n"; +pub const TEXT_HEAD: &str = "\n\nText:\n"; +pub const HYBRID_RMAX: usize = 2048; +pub const WIN: usize = 1800; +pub const STRIDE: usize = 1536; +pub const RMAX: usize = 2048; + +pub const ROUTER_SPAN_IDS: [&str; 3] = ["pii", "halu", "toxic"]; +pub const HALU_LABEL: &str = "unsupported"; +pub const HALU_ALIASES: [&str; 9] = [ + "unsupported", + "unsupportedclaim", + "hallucinated", + "hallucination", + "hallucinatedspan", + "notsupported", + "unsupportedspan", + "fabricated", + "fabrication", +]; +pub const PII_TYPES: [&str; 17] = [ + "AGE", + "CREDIT_CARD", + "DATE_TIME", + "DOMAIN_NAME", + "EMAIL_ADDRESS", + "GPE", + "IBAN_CODE", + "IP_ADDRESS", + "NRP", + "ORGANIZATION", + "PERSON", + "PHONE_NUMBER", + "STREET_ADDRESS", + "TITLE", + "US_DRIVER_LICENSE", + "US_SSN", + "ZIP_CODE", +]; + +fn seg_open(role: &str) -> String { + format!("\n") +} + +fn option_block(key: &str, desc: &str, tag: &str) -> String { + format!( + "\n<{tag}>\n{}\n", + canonical(&serde_json::json!({"key": key, "description": desc})) + ) +} + +fn q_head(kind: &str, over: &[String], text: &str, span: bool) -> String { + let target = over.join(", "); + format!( + "\n\nTask type: {kind}\nTarget: {target}\nQuestion:\n{text}\n{}", + if span { "Labels:" } else { "Options:" } + ) +} + +// ------------------------------------------------------------------ tokenizer + +/// The pinned tokenizer, with the reference's memoized plain-`ids` view +/// and char-offset encodings (the tokenizers crate reports byte +/// offsets; the reference works in Unicode code points). +/// Ids plus char offsets, the encoder cache entry. +type Encoded = (Vec, Vec<(usize, usize)>); + +pub struct Encoder { + tokenizer: Tokenizer, + cache: RefCell>, +} + +impl Encoder { + pub fn load(path: &Path) -> anyhow::Result { + let tokenizer = Tokenizer::from_file(path).map_err(anyhow::Error::msg)?; + Ok(Self { + tokenizer, + cache: RefCell::new(HashMap::new()), + }) + } + + fn encode(&self, text: &str) -> (Vec, Vec<(usize, usize)>) { + if let Some(hit) = self.cache.borrow().get(text) { + return hit.clone(); + } + let encoding = match self.tokenizer.encode(text, false) { + Ok(encoding) => encoding, + Err(error) => { + // The pinned tokenizer should never fail on valid UTF-8 + // input; surface the error instead of panicking so a + // wrapping worker can map it. + unreachable!("the pinned tokenizer failed on valid input: {error}") + } + }; + let byte_offsets = encoding.get_offsets(); + // Byte → code-point offsets. + let char_starts: Vec = text + .char_indices() + .map(|(byte, _)| byte) + .chain(std::iter::once(text.len())) + .collect(); + let to_char = |byte: usize| char_starts.partition_point(|&start| start < byte); + let offsets: Vec<(usize, usize)> = byte_offsets + .iter() + .map(|(start, end)| (to_char(*start), to_char(*end))) + .collect(); + let entry = (encoding.get_ids().to_vec(), offsets); + self.cache + .borrow_mut() + .insert(text.to_owned(), entry.clone()); + entry + } + + /// Memoized token ids of a whole string (the reference's `_ids`). + pub fn ids(&self, text: &str) -> Vec { + self.encode(text).0 + } + + /// Ids and char offsets (the reference's `_ids_offs`). + pub fn ids_offsets(&self, text: &str) -> (Vec, Vec<(usize, usize)>) { + self.encode(text) + } +} + +// ------------------------------------------------------------- span dispatch + +/// `[\s_\-]+` removed, lower-cased — the reference's `_norm_label`. +pub fn norm_label(name: &str) -> String { + let mut out = String::with_capacity(name.len()); + for ch in name.chars() { + if !ch.is_whitespace() && ch != '_' && ch != '-' { + out.extend(ch.to_lowercase()); + } + } + out +} + +/// The user's label when the span question has exactly one label that +/// is a hallucination alias, else none. +pub fn halu_alias(names: &[String]) -> Option { + if names.len() == 1 && HALU_ALIASES.contains(&norm_label(&names[0]).as_str()) { + Some(names[0].clone()) + } else { + None + } +} + +pub struct SpanDispatch { + pub head: &'static str, + pub reason: &'static str, +} + +/// The reference's six-rule dispatch, in order: `"head"` override, +/// trained ids, an exact router label set, a non-empty subset of the 17 +/// PII types, one hallucination alias, else broad (router when the +/// broad head is not loaded). +pub fn span_head_for( + id: &str, + labels: &HashSet, + head_override: Option<&str>, + router_label_sets: &[HashSet], + broad_available: bool, +) -> Result { + if let Some(head) = head_override { + if !matches!(head, "router" | "broad") { + return Err(format!( + "head must be one of ['router', 'broad'], got '{head:?}'" + )); + } + if head == "broad" && !broad_available { + return Err("the broad span head is not loaded (needs broad_head.safetensors)".into()); + } + return Ok(SpanDispatch { + head: if head == "broad" { "broad" } else { "router" }, + reason: "override", + }); + } + if ROUTER_SPAN_IDS.contains(&id) { + return Ok(SpanDispatch { + head: "router", + reason: "id", + }); + } + if router_label_sets.iter().any(|set| set == labels) { + return Ok(SpanDispatch { + head: "router", + reason: "label_set", + }); + } + let pii: HashSet<&str> = PII_TYPES.into_iter().collect(); + if !labels.is_empty() && labels.iter().all(|label| pii.contains(label.as_str())) { + return Ok(SpanDispatch { + head: "router", + reason: "pii_subset", + }); + } + if halu_alias(&labels.iter().cloned().collect::>()).is_some() { + return Ok(SpanDispatch { + head: "router", + reason: "halu_alias", + }); + } + if !broad_available { + return Ok(SpanDispatch { + head: "router", + reason: "broad_unavailable", + }); + } + Ok(SpanDispatch { + head: "broad", + reason: "default", + }) +} + +// ------------------------------------------------------------------ rendering + +/// One generic-contract question at render time (Noul is already folded +/// into a two-option choice; choice always carries `[ABS]` on the +/// SystemOne path — the reference's `_to_generic` defaults abstain to +/// true and the mapper never sets it). +#[derive(Clone)] +pub struct GenericQuestion { + pub id: String, + pub kind: String, + pub over: Vec, + pub text: String, + pub names: Vec, + pub descriptions: Vec, + pub threshold: Option, + pub head_override: Option, +} + +/// One prepared part: tokens, and for span-target parts also char +/// offsets and word units. +/// Word char offsets and each word's first token index. +pub type WordUnits = (Vec<(usize, usize)>, Vec); + +#[derive(Clone)] +pub struct PreparedPart { + pub role: String, + pub ids: Vec, + pub offsets: Option>, + pub words: Option, +} + +#[derive(Debug, Clone, serde::Serialize, PartialEq)] +pub struct TruncRecord { + pub shrink_cut: usize, + pub protected_cut: usize, +} + +#[derive(Debug, Clone, serde::Serialize, PartialEq)] +#[serde(tag = "kind")] +pub enum Block { + #[serde(rename = "q")] + Question { + ids: Vec, + ends: Vec, + query: usize, + qid: String, + qtype: String, + names: Vec, + has_abs: bool, + }, + #[serde(rename = "span")] + Span { + ends: Vec, + label_ranges: Vec<(usize, usize)>, + words_in_block: bool, + ids: Vec, + query: usize, + w_pos: Vec, + }, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct RenderedRow { + pub p_ids: Vec, + pub blocks: Vec, + pub trunc: TruncRecord, + pub seg_lens: BTreeMap, + pub layout: Option, + pub names: Option>, + pub w_offs: Option>, + pub w_pos: Option>, + pub span_over: Option, + pub n_tokens: usize, + pub head: String, + pub head_reason: Option, + /// The runtime's window rows carry the head only — no head_reason + /// key at all (predict_raw assigns head alone). + pub window: bool, +} + +/// Serialize exactly like the frozen fixtures: main rows always carry +/// `head_reason` (null when the row has no span); window rows omit it. +impl serde::Serialize for RenderedRow { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serialize_row(self, serializer) + } +} + +fn serialize_row(row: &RenderedRow, serializer: S) -> Result +where + S: serde::Serializer, +{ + use serde::ser::SerializeMap; + let mut map = serializer.serialize_map(None)?; + macro_rules! put { + ($key:literal, $value:expr) => { + map.serialize_entry($key, &$value)? + }; + } + put!("p_ids", row.p_ids); + put!("blocks", row.blocks); + put!("trunc", row.trunc); + put!("seg_lens", row.seg_lens); + put!("layout", row.layout); + if let Some(names) = &row.names { + put!("names", names); + } + if let Some(w_offs) = &row.w_offs { + put!("w_offs", w_offs); + } + if let Some(w_pos) = &row.w_pos { + put!("w_pos", w_pos); + } + if let Some(span_over) = &row.span_over { + put!("span_over", span_over); + } + put!("n_tokens", row.n_tokens); + put!("head", row.head); + if !row.window { + put!("head_reason", row.head_reason); + } + map.end() +} + +/// Everything the renderer needs beyond tokens. +pub struct RenderContext<'a> { + pub encoder: &'a Encoder, + pub max_length: usize, + pub router_label_sets: &'a [HashSet], + pub has_broad: bool, + pub halu_desc: String, +} + +/// The whole-request 413: questions plus schema alone do not fit. +pub fn too_long(max_length: usize) -> RequestError { + RequestError { + status: 413, + body: serde_json::json!({"detail": [{"loc": ["body", "questions"], + "msg": format!("the questions alone do not fit the {max_length}-token window"), + "type": "too_long"}]}), + } +} + +/// `schema_lib_r4.assemble`, eval path: the truncation order on the +/// decoder's token costs. Returns kept segment lengths and the record. +fn assemble_budget( + q_lens: &[usize], + el_lens: &[usize], + segs: &mut [(String, usize)], + max_len: usize, + protected: &HashSet, + shrink: Option<&str>, +) -> Result<(BTreeMap, TruncRecord), ()> { + let fixed = 2 + 1 + segs.len(); + fn over( + q_lens: &[usize], + el_lens: &[usize], + segs: &[(String, usize)], + fixed: usize, + max_len: usize, + ) -> i64 { + fixed as i64 + + q_lens.iter().sum::() as i64 + + el_lens.iter().sum::() as i64 + + segs.iter().map(|(_, n)| *n).sum::() as i64 + - max_len as i64 + } + let mut trunc = TruncRecord { + shrink_cut: 0, + protected_cut: 0, + }; + let shrink_index = shrink.and_then(|role| segs.iter().position(|(r, _)| r == role)); + for floor in [64, 1] { + if over(q_lens, el_lens, segs, fixed, max_len) > 0 + && let Some(index) = shrink_index + { + let full = segs[index].1; + let excess = over(q_lens, el_lens, segs, fixed, max_len).max(0) as usize; + let keep = full.min(floor.max(full.saturating_sub(excess))); + trunc.shrink_cut += full - keep; + segs[index].1 = keep; + } + } + if over(q_lens, el_lens, segs, fixed, max_len) > 0 { + for index in 0..segs.len() { + if over(q_lens, el_lens, segs, fixed, max_len) > 0 && protected.contains(&segs[index].0) + { + let full = segs[index].1; + let excess = over(q_lens, el_lens, segs, fixed, max_len).max(0) as usize; + let keep = 1.max(full.saturating_sub(excess)); + trunc.protected_cut += full - keep; + segs[index].1 = keep; + } + } + } + if over(q_lens, el_lens, segs, fixed, max_len) > 0 { + return Err(()); + } + let seg_lens: BTreeMap = + segs.iter().map(|(role, n)| (role.clone(), *n)).collect(); + Ok((seg_lens, trunc)) +} + +/// Token windows [a, b) over a part of n tokens, starting and cut at +/// word starts (`schema_lib_d3_20261001.windows`). +pub fn span_windows(first_tokens: &[usize], n: usize) -> Vec<(usize, usize)> { + let mut starts: Vec = first_tokens.to_vec(); + starts.sort_unstable(); + starts.dedup(); + if starts.is_empty() { + return vec![(0, n)]; + } + let mut out = Vec::new(); + let mut a = starts[0]; + loop { + let limit = a + WIN; + let next: Vec = starts + .iter() + .copied() + .filter(|&s| s > a && s < limit) + .collect(); + let b = if limit >= n { + n + } else if !next.is_empty() { + *starts + .iter() + .filter(|&&s| s < limit && s > a) + .max() + .unwrap() + } else { + n.min(limit) + }; + out.push((a, b)); + if b >= n { + break; + } + let candidate: Vec = starts + .iter() + .copied() + .filter(|&s| s >= a + STRIDE && s < b) + .collect(); + a = candidate.first().copied().unwrap_or(b); + } + out +} + +/// A windowed copy of a prepared part: tokens [a, b) and the words that +/// start inside them. +pub fn window_part(part: &PreparedPart, a: usize, b: usize) -> PreparedPart { + let (word_offsets, first_tokens) = part.words.as_ref().expect("windowed parts carry words"); + let selected: Vec = first_tokens + .iter() + .enumerate() + .filter(|&(_, &t)| t >= a && t < b) + .map(|(index, _)| index) + .collect(); + let kept_offsets: Vec<(usize, usize)> = selected.iter().map(|&i| word_offsets[i]).collect(); + PreparedPart { + role: part.role.clone(), + ids: part.ids[a..b].to_vec(), + offsets: part.offsets.as_ref().map(|offs| offs[a..b].to_vec()), + words: Some(( + kept_offsets, + selected.iter().map(|&i| first_tokens[i] - a).collect(), + )), + } +} + +impl RenderContext<'_> { + /// `_prep`'s question side: the span-head dispatch and the + /// hallucination-alias label replacement (parts arrive prepared — + /// word units need the original text and are the caller's job). + pub fn prepare_questions( + &self, + questions: &[GenericQuestion], + ) -> Result<(Vec, SpanDispatch), RequestError> { + let span = questions.iter().find(|q| q.kind == "span"); + let dispatch = match span { + Some(question) => { + let labels: HashSet = question.names.iter().cloned().collect(); + span_head_for( + &question.id, + &labels, + question.head_override.as_deref(), + self.router_label_sets, + self.has_broad, + ) + .map_err(|message| crate::contract::runtime_rejection(&message))? + } + None => SpanDispatch { + head: "router", + reason: "", + }, + }; + // The trained `unsupported` label renders in place of a single + // hallucination-alias label (the answer gets the user's name). + let mut adjusted = questions.to_vec(); + if let Some(question) = adjusted.iter_mut().find(|q| q.kind == "span") + && dispatch.head == "router" + && let Some(alias) = halu_alias(&question.names) + && alias != HALU_LABEL + { + question.names = vec![HALU_LABEL.to_string()]; + question.descriptions = vec![self.halu_desc.clone()]; + } + Ok((adjusted, dispatch)) + } + + /// `_render` on one prepared row: the parts pass and every block, + /// with the budget applied first. + pub fn render( + &self, + parts: &[PreparedPart], + questions: &[GenericQuestion], + dispatch: &SpanDispatch, + ) -> Result { + let ids_of = |text: &str| self.encoder.ids(text); + let roles: Vec = parts.iter().map(|p| p.role.clone()).collect(); + // Question blocks and their schema costs. + struct RenderedQ { + qid: String, + qtype: String, + names: Vec, + otoks: Vec>, + has_abs: bool, + head: Vec, + suffix: Vec, + abstain_tokens: Vec, + len: usize, + } + let mut rendered_qs: Vec = Vec::new(); + let mut el: Vec<(String, Vec)> = Vec::new(); // span labels + let mut span_question: Option<&GenericQuestion> = None; + for question in questions { + if question.kind == "span" { + span_question = Some(question); + for (name, desc) in question.names.iter().zip(&question.descriptions) { + let tokens = ids_of(&option_block(name, desc, "label")); + el.push((name.clone(), tokens.clone())); + } + continue; + } + let suffix = match question.kind.as_str() { + "set" => SUFFIX_SET, + _ => SUFFIX_CHOICE_SCORE, // choice and score share the wording + }; + let has_abs = question.kind == "choice"; // SystemOne: abstain defaults true + let head = ids_of(&q_head( + &question.kind, + &question.over, + &question.text, + false, + )); + let suffix = ids_of(suffix); + let abstain_tokens = if has_abs { + ids_of(&option_block(ABS_KEY, ABS_DESC, "option")) + } else { + Vec::new() + }; + let mut otoks = Vec::with_capacity(question.names.len()); + let mut len = + 1 + head.len() + suffix.len() + abstain_tokens.len() + usize::from(has_abs); + for (name, desc) in question.names.iter().zip(&question.descriptions) { + let tokens = ids_of(&option_block(name, desc, "option")); + len += 1 + tokens.len(); + otoks.push(tokens); + } + rendered_qs.push(RenderedQ { + qid: question.id.clone(), + qtype: question.kind.clone(), + names: question.names.clone(), + otoks, + has_abs, + head, + suffix, + abstain_tokens, + len, + }); + } + let span_over: Option = span_question.map(|question| question.over[0].clone()); + let mut overs: HashSet = HashSet::new(); + for question in questions { + overs.extend(question.over.iter().cloned()); + } + if let Some(over) = &span_over { + overs.insert(over.clone()); + } + let part_of = |role: &str| parts.iter().find(|p| p.role == role); + let shrink = roles.iter().find(|role| !overs.contains(*role)).cloned(); + let layout = match &span_over { + Some(over) if part_of(over).is_some_and(|p| p.ids.len() <= HYBRID_RMAX) => "c", + Some(_) => "a", + None => "", + }; + // The schema overhead the budget does not see. + let mut budget = ids_of(PARTS_HEAD).len(); + for role in &roles { + budget += ids_of(&seg_open(role)).len() + ids_of(SEG_CLOSE).len(); + } + if let Some(over) = &span_over { + let question = span_question.expect("span question"); + let head = ids_of(&q_head("span", &question.over, &question.text, true)); + let suffix = ids_of(SUFFIX_SPAN); + budget += head.len() + suffix.len(); + if layout == "c" { + let span_len = part_of(over).expect("span part").ids.len(); + budget += ids_of(TEXT_HEAD).len() + + ids_of(&seg_open(over)).len() + + ids_of(SEG_CLOSE).len(); + let headroom = self.max_length.saturating_sub(budget); + budget += span_len.min(headroom / 2); + } + } + let q_lens: Vec = rendered_qs.iter().map(|q| q.len).collect(); + let el_lens: Vec = el.iter().map(|(_, tokens)| 1 + tokens.len()).collect(); + let mut segs: Vec<(String, usize)> = parts + .iter() + .map(|p| (p.role.clone(), p.ids.len())) + .collect(); + let (seg_lens, trunc) = assemble_budget( + &q_lens, + &el_lens, + &mut segs, + 64.max(self.max_length - budget), + &overs, + shrink.as_deref(), + ) + .map_err(|()| too_long(self.max_length))?; + // The parts pass, in part order (not the sorted map). + let mut p_ids = ids_of(PARTS_HEAD); + let mut start: HashMap = HashMap::new(); + for part in parts { + let keep = seg_lens[&part.role]; + let open = ids_of(&seg_open(&part.role)); + start.insert(part.role.clone(), p_ids.len() + open.len()); + p_ids.extend(open); + p_ids.extend(part.ids.iter().take(keep)); + p_ids.extend(ids_of(SEG_CLOSE)); + } + // Question blocks. + let mut blocks: Vec = Vec::new(); + for q in &rendered_qs { + let mut ids = q.head.clone(); + let mut ends = Vec::with_capacity(q.names.len() + usize::from(q.has_abs)); + for tokens in &q.otoks { + ids.extend(tokens); + ends.push(ids.len() - 1); + } + if q.has_abs { + ids.extend(q.abstain_tokens.clone()); + ends.push(ids.len() - 1); + } + ids.extend(q.suffix.clone()); + let query = ids.len() - 1; + blocks.push(Block::Question { + ids, + ends, + query, + qid: q.qid.clone(), + qtype: q.qtype.clone(), + names: q.names.clone(), + has_abs: q.has_abs, + }); + } + // The span block. + let mut row_names = None; + let mut row_w_offs = None; + let mut row_w_pos = None; + if let Some(over) = &span_over + && !el.is_empty() + { + let question = span_question.expect("span question"); + let mut ids = ids_of(&q_head("span", &question.over, &question.text, true)); + let mut ends = Vec::new(); + let mut starts = Vec::new(); + for (_, tokens) in &el { + starts.push(ids.len()); + ids.extend(tokens); + ends.push(ids.len() - 1); + } + let part = part_of(over).expect("span part"); + let n = seg_lens[over]; + let (word_offsets, first_tokens) = part.words.as_ref().expect("span words"); + // Word indices whose first token survives the kept prefix; + // indices, not token values — two words can share one. + let keep: Vec = first_tokens + .iter() + .enumerate() + .filter(|&(_, &t)| t < n) + .map(|(index, _)| index) + .collect(); + let words_in_block = layout == "c"; + if words_in_block { + ids.extend(ids_of(TEXT_HEAD)); + ids.extend(ids_of(&seg_open(over))); + let c0 = ids.len(); + ids.extend(part.ids.iter().take(n)); + ids.extend(ids_of(SEG_CLOSE)); + row_w_pos = Some(keep.iter().map(|&i| c0 + first_tokens[i]).collect()); + } else { + let base = start[over]; + row_w_pos = Some(keep.iter().map(|&i| base + first_tokens[i]).collect()); + } + ids.extend(ids_of(SUFFIX_SPAN)); + let query = ids.len() - 1; + row_names = Some(el.iter().map(|(name, _)| name.clone()).collect()); + row_w_offs = Some(keep.iter().map(|&i| word_offsets[i]).collect()); + let label_ranges: Vec<(usize, usize)> = + starts.into_iter().zip(ends.iter().copied()).collect(); + blocks.push(Block::Span { + ends, + label_ranges, + words_in_block, + ids, + query, + w_pos: row_w_pos.clone().expect("w_pos"), + }); + } + let n_tokens = p_ids.len() + blocks.iter().map(block_len).sum::(); + Ok(RenderedRow { + p_ids, + blocks, + trunc, + seg_lens, + layout: if span_over.is_some() { + Some(layout.to_string()) + } else { + None + }, + names: row_names, + w_offs: row_w_offs, + w_pos: row_w_pos, + span_over, + n_tokens, + head: dispatch.head.to_string(), + head_reason: if dispatch.reason.is_empty() { + None + } else { + Some(dispatch.reason.to_string()) + }, + window: false, + }) + } +} + +fn block_len(block: &Block) -> usize { + match block { + Block::Question { ids, .. } => ids.len(), + Block::Span { ids, .. } => ids.len(), + } +} diff --git a/src/models/vela/native/src/state.rs b/src/models/vela/native/src/state.rs new file mode 100644 index 00000000..d33e42bb --- /dev/null +++ b/src/models/vela/native/src/state.rs @@ -0,0 +1,235 @@ +//! DEV2.0 canonical JSON and the state → typed-parts mapping, mirroring +//! the pinned runtime's `canonical_json`, `content_text` and +//! `system_one_state` exactly (the frozen `native-plan-*` fixtures are +//! the parity target). + +use serde_json::Value; +use std::collections::BTreeMap; + +use crate::contract::RequestError; + +/// `json.dumps(ensure_ascii=False, sort_keys=True, separators=(",", ":"))` +/// — key-sorted compact JSON, non-ASCII literal. +pub fn canonical(value: &Value) -> String { + match value { + Value::Object(map) => { + let mut keys: Vec<&String> = map.keys().collect(); + keys.sort(); + let parts: Vec = keys + .iter() + .map(|key| { + format!( + "{}:{}", + serde_json::to_string(key).unwrap(), + canonical(&map[*key]) + ) + }) + .collect(); + format!("{{{}}}", parts.join(",")) + } + Value::Array(items) => { + let parts: Vec = items.iter().map(canonical).collect(); + format!("[{}]", parts.join(",")) + } + other => serde_json::to_string(other).unwrap(), + } +} + +/// JSON content → model text: strings as they are, anything else as +/// canonical JSON. +pub fn content_text(value: &Value) -> String { + match value { + Value::String(text) => text.clone(), + other => canonical(other), + } +} + +/// The state-key → part-role table (unknown keys land in `context`). +pub fn key_role(key: &str) -> &'static str { + match key.to_ascii_lowercase().as_str() { + "request" | "user" | "prompt" => "user", + "answer" | "response" => "answer", + _ => "context", + } +} + +/// One rendered state part, in user / context / answer order. +#[derive(Debug, Clone, serde::Serialize, PartialEq)] +pub struct Part { + pub r#type: String, + pub text: String, +} + +/// A named state field's span inside its part's text (Unicode code +/// points, as on the reference). +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct FieldRange { + pub role: &'static str, + pub start: usize, + pub end: usize, +} + +#[derive(Debug)] +pub struct StateParts { + pub parts: Vec, + pub fields: BTreeMap, +} + +fn state_error(msg: &str) -> RequestError { + RequestError::envelope(&["state"], msg, "value_error") +} + +/// The SystemOne state → (parts, fields) mapping, mirroring +/// `system_one_state`: a plain string is one user part; a JSON array is +/// canonicalized into one; an object groups its keys by role (request / +/// user / prompt → user; source / context / document / tools / +/// previous_answer → context; answer / response → answer; unknown keys +/// → context) in user / context / answer order — one known-key entry +/// per role renders bare, several (or an unknown key) render as +/// `"key:\n"` blocks joined by blank lines. +pub fn system_one_state(state: &Value) -> Result { + // A string holding a JSON object is read as that object. + let state = match state { + Value::String(text) => { + let stripped = text.trim_start(); + if stripped.starts_with('{') { + if let Value::Object(object) = + serde_json::from_str::(stripped).unwrap_or(Value::Null) + { + Value::Object(object) + } else { + state.clone() + } + } else { + state.clone() + } + } + other => other.clone(), + }; + match &state { + Value::String(text) => { + if text.trim().is_empty() { + return Err(state_error("state must not be empty or whitespace")); + } + let mut fields = BTreeMap::new(); + fields.insert( + "request".into(), + FieldRange { + role: "user", + start: 0, + end: text.chars().count(), + }, + ); + Ok(StateParts { + parts: vec![Part { + r#type: "user".into(), + text: text.clone(), + }], + fields, + }) + } + Value::Array(_) => { + let text = canonical(&state); + let mut fields = BTreeMap::new(); + fields.insert( + "request".into(), + FieldRange { + role: "user", + start: 0, + end: text.chars().count(), + }, + ); + Ok(StateParts { + parts: vec![Part { + r#type: "user".into(), + text, + }], + fields, + }) + } + Value::Object(object) if !object.is_empty() => { + // Group per role, keeping the object's insertion order inside + // each role and remembering which entries had a known key. + let mut by_role: [Vec<(&String, &Value, bool)>; 3] = + [Vec::new(), Vec::new(), Vec::new()]; + for (key, value) in object { + let lower = key.to_ascii_lowercase(); + let known = matches!( + lower.as_str(), + "request" + | "user" + | "prompt" + | "source" + | "context" + | "document" + | "tools" + | "previous_answer" + | "answer" + | "response" + ); + let slot = match key_role(&lower) { + "user" => 0, + "answer" => 2, + _ => 1, + }; + by_role[slot].push((key, value, known)); + } + let mut parts = Vec::new(); + let mut fields = BTreeMap::new(); + for (role, items) in [ + ("user", &by_role[0]), + ("context", &by_role[1]), + ("answer", &by_role[2]), + ] { + if items.is_empty() { + continue; + } + let mut text = String::new(); + let single = items.len() == 1 && items[0].2; + for (index, (key, value, _)) in items.iter().enumerate() { + let rendered = content_text(value); + if single { + fields.insert( + (*key).clone(), + FieldRange { + role, + start: 0, + end: rendered.chars().count(), + }, + ); + text = rendered; + } else { + if index > 0 { + text.push_str("\n\n"); + } + let head = format!("{key}:\n"); + let start = text.chars().count() + head.chars().count(); + fields.insert( + (*key).clone(), + FieldRange { + role, + start, + end: start + rendered.chars().count(), + }, + ); + text.push_str(&head); + text.push_str(&rendered); + } + } + if text.trim().is_empty() { + return Err(state_error(&format!( + "the {role} part of the state is empty" + ))); + } + parts.push(Part { + r#type: role.into(), + text, + }); + } + Ok(StateParts { parts, fields }) + } + _ => Err(state_error( + "state must be a non-empty string, JSON object or JSON array", + )), + } +} diff --git a/src/models/vela/native/src/words.rs b/src/models/vela/native/src/words.rs new file mode 100644 index 00000000..c26dcac7 --- /dev/null +++ b/src/models/vela/native/src/words.rs @@ -0,0 +1,119 @@ +//! Word units and first-token mapping, mirroring the pinned runtime's +//! `schema_lib_r4` `_WORD` splitter (GLiNER2 whitespace splitter + CJK +//! one unit per character + the r4 URL/email/handle rule) and +//! `word_first_tokens`. Offsets are Unicode code points everywhere, as +//! on the reference. + +use onig::Regex; + +/// The CJK ranges of the reference `_WORD` pattern, verbatim. +const CJK: &str = "⺀-⿿ -〿぀-ヿ㄀-ㇿ㐀-䶿一-鿿ꀀ-꓏가-힯豈-﫿︰-﹏＀-￯"; +/// Trailing punctuation the URL rule strips. +const TRAIL: &str = ".,;:!?)\\]}>\"'\u{201d}\u{2019}\u{bb}"; + +fn word_pattern() -> Regex { + let pattern = concat!( + "(?:https?://|www\\.)[^\\s{cjk}]+?(?=[{trail}]*(?![^\\s{cjk}]))", + "|[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}", + "|@[a-z0-9_]+", + "|[{cjk}]", + "|[^\\W{cjk}]+(?:[-_][^\\W{cjk}]+)*", + "|\\S", + ); + let pattern = pattern.replace("{cjk}", CJK).replace("{trail}", TRAIL); + Regex::with_options( + &pattern, + onig::RegexOptions::REGEX_OPTION_IGNORECASE, + onig::Syntax::ruby(), + ) + .expect("the reference word pattern must compile") +} + +/// The (start, end) word ranges of `text`, in code points. +pub fn split_words(text: &str) -> Vec<(usize, usize)> { + let regex = word_pattern(); + // Byte offsets → code-point offsets. + let char_of_byte: Vec = text + .char_indices() + .map(|(byte, _)| byte) + .chain(std::iter::once(text.len())) + .collect(); + let to_char = |byte: usize| -> usize { char_of_byte.partition_point(|&start| start < byte) }; + regex + .find_iter(text) + .map(|(start, end)| (to_char(start), to_char(end))) + .collect() +} + +/// (word char offsets (W, 2), each word's first overlapping sub-word +/// token index), mirroring `word_first_tokens`: the first token whose +/// cumulative end passes the word start, skipping empty tokens. +pub fn word_first_tokens( + text: &str, + offsets: &[(usize, usize)], +) -> (Vec<(usize, usize)>, Vec) { + let words = split_words(text); + if words.is_empty() || offsets.is_empty() { + return (Vec::new(), Vec::new()); + } + let valid: Vec = offsets.iter().map(|(s, e)| e > s).collect(); + let mut cummax_end: Vec = Vec::with_capacity(offsets.len()); + let mut running: i64 = -1; + for (index, (_start, end)) in offsets.iter().enumerate() { + if valid[index] { + running = running.max(*end as i64); + } + cummax_end.push(running); + } + let mut word_offsets = Vec::new(); + let mut first_tokens = Vec::new(); + for (a, b) in words { + let mut t = cummax_end.partition_point(|&end| end <= a as i64); + while t < offsets.len() && !valid[t] { + t += 1; + } + if t < offsets.len() && offsets[t].0 < b { + word_offsets.push((a, b)); + first_tokens.push(t); + } + } + (word_offsets, first_tokens) +} + +/// The reference's CJK class as a range test (the same ranges the word +/// splitter carries). +pub fn is_cjk_char(ch: char) -> bool { + // The reference class has one contiguous run from U+8C48 to + // U+FAFF and ends the Yi block at U+A4CF (not U+A48F). + matches!(ch as u32, + 0x2E80..=0x2FFF | 0x3000..=0x303F | 0x3040..=0x30FF | 0x3100..=0x31FF + | 0x3400..=0x4DBF | 0x4E00..=0x9FFF | 0xA000..=0xA4CF | 0xAC00..=0xD7AF + | 0x8C48..=0xFAFF | 0xFE30..=0xFE4F | 0xFF00..=0xFFEF) +} + +/// The reference's `_UNIT` split (decode-time units): URL bodies, runs +/// of word characters (excluding CJK, `_` excluded by `[^\W_]`) plus +/// `@._-+`, or any non-space char. Returns each char's unit id, -1 +/// outside units — the decode's `u` array. +pub fn unit_ids(chars: &[char]) -> Vec { + let mut ids = vec![-1i64; chars.len()]; + let text: String = chars.iter().collect(); + let pattern = concat!( + "(?:https?://|www\\.)[^\\s\\]\\)\\}>「」『』\"'“”{cjk}]+?(?=[.,;:!?]*(?![^\\s\\]\\)\\}>「」『』\"'“”{cjk}]))", + "|(?:(?![{cjk}])[^\\W_]|[@._\\-+])+", + "|\\S", + ) + .replace("{cjk}", CJK); + let regex = Regex::with_options( + &pattern, + onig::RegexOptions::REGEX_OPTION_IGNORECASE, + onig::Syntax::ruby(), + ) + .expect("the reference unit pattern must compile"); + for (unit, (start, end)) in regex.find_iter(&text).enumerate() { + for id in ids.iter_mut().take(end).skip(start) { + *id = unit as i64; + } + } + ids +} diff --git a/tests/vela/native_contract_unit.rs b/tests/vela/native_contract_unit.rs new file mode 100644 index 00000000..e2a60834 --- /dev/null +++ b/tests/vela/native_contract_unit.rs @@ -0,0 +1,14 @@ +//! Private-item tests for the native crate's wire contract, loaded by +//! the `#[path]` wiring in `src/models/vela/native/src/contract.rs`. + +use super::*; + +#[test] +fn duplicate_keys_mirror_the_reference_message() { + let error = normalize_parse_error("request body is not valid JSON: duplicate key \"state\""); + assert_eq!(error.status, 400); + assert_eq!( + error.body, + serde_json::json!({"detail": "duplicate JSON key 'state'"}) + ); +} diff --git a/tests/vela/native_processing.rs b/tests/vela/native_processing.rs new file mode 100644 index 00000000..917a423c --- /dev/null +++ b/tests/vela/native_processing.rs @@ -0,0 +1,137 @@ +//! Processing tests against the frozen token-plan fixtures. +//! +//! The mapping tests (state → parts, SystemOne → predict, plan) run +//! everywhere with no tokenizer and no weights. The full render parity +//! — rows and window rows byte-for-byte against the fixtures — needs +//! the exported bundle's tokenizer and is opt-in: +//! +//! VELA_NATIVE_BUNDLE=weights/vela-2.0-0.8b-native \ +//! cargo test -p omni-vela-native --test vela_native_processing -- --nocapture + +use std::path::PathBuf; + +use omni_vela_native::questions::system_one_to_predict; +use omni_vela_native::state::system_one_state; +use serde_json::Value; + +const CASES: [&str; 5] = [ + "example-request", + "example-request-set-threshold", + "example-request-cjk", + "example-request-score", + "long-span-windowed", +]; + +fn fixture(case: &str) -> Value { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../../../tests/vela/fixtures"); + serde_json::from_str( + &std::fs::read_to_string(root.join(format!("native-plan-{case}.json"))) + .expect("fixture present; record it with recipe/vela/export_token_plan.py"), + ) + .expect("fixture JSON") +} + +// ------------------------------------------------------- mapping (no tokens) + +fn mapped(case: &str) -> Value { + let fix = fixture(case); + let request = fix["request"].as_object().expect("request"); + let state = system_one_state(&request["state"]).expect("state maps"); + let questions = request["questions"].as_object().expect("questions"); + let mapped = system_one_to_predict(state, questions).expect("maps"); + serde_json::json!({ + "predict_request": serde_json::to_value(&mapped.request).unwrap(), + "plan": serde_json::to_value(&mapped.plan).unwrap(), + }) +} + +#[test] +fn the_predict_mapping_matches_every_fixture() { + for case in CASES { + let got = mapped(case); + let fix = fixture(case); + assert_eq!( + got["predict_request"], fix["predict_request"], + "predict_request differs for {case}" + ); + assert_eq!(got["plan"], fix["plan"], "plan differs for {case}"); + } +} + +#[test] +fn an_invalid_question_reports_the_pinned_triples() { + let state = system_one_state(&serde_json::json!("s")).expect("state"); + let questions = serde_json::json!({ + "q": {"type": "choice", "instructions": "ok?", "criteria": {"a": "x"}} + }); + let error = system_one_to_predict(state, questions.as_object().unwrap()).unwrap_err(); + assert_eq!( + error.body, + serde_json::json!({"detail": [{"loc": ["body", "questions", "q", "criteria"], + "msg": "choice criteria must be an object with 2 to 255 entries", "type": "value_error"}]}) + ); + + let state = system_one_state(&serde_json::json!("s")).expect("state"); + let questions = serde_json::json!({ + "q": {"type": "span", "instructions": "which?", "criteria": {"a": "x"}, + "head": "other", "over": "request"} + }); + let error = system_one_to_predict(state, questions.as_object().unwrap()).unwrap_err(); + assert_eq!( + error.body["detail"][0]["loc"], + serde_json::json!(["body", "questions", "q", "head"]) + ); + assert_eq!(error.body["detail"][0]["type"], "literal_error"); +} + +#[test] +fn a_set_label_collision_is_rejected_after_the_walk() { + let state = system_one_state(&serde_json::json!("s")).expect("state"); + let questions = serde_json::json!({ + "issues": {"type": "set", "instructions": "which?", "criteria": {"billing": "b"}}, + "issues.billing": {"type": "noul", "instructions": "which?"} + }); + let error = system_one_to_predict(state, questions.as_object().unwrap()).unwrap_err(); + assert_eq!( + error.body["detail"][0]["msg"], + "collides with the Noul view of a set label" + ); +} + +// ------------------------------------------------- full render (opt-in) + +fn bundle_dir() -> Option { + let value = std::env::var("VELA_NATIVE_BUNDLE").ok()?; + let path = PathBuf::from(value); + path.is_dir().then_some(path) +} + +#[test] +fn the_rendered_rows_match_every_fixture() { + let Some(bundle) = bundle_dir() else { + eprintln!("skipping: set VELA_NATIVE_BUNDLE to an exported bundle for render parity"); + return; + }; + let processor = omni_vela_native::processing::Processor::load(&bundle) + .expect("processor loads the exported bundle"); + for case in CASES { + let fix = fixture(case); + let request = fix["request"].as_object().expect("request"); + let planned = match processor.plan(request) { + Ok(planned) => planned, + Err(error) => panic!( + "plan failed for {case}: {}", + serde_json::to_string(&error.body).unwrap() + ), + }; + let got = serde_json::json!({ + "rows": serde_json::to_value(&planned.rows).unwrap(), + "window_rows": serde_json::to_value(&planned.window_rows).unwrap(), + }); + assert_eq!(got["rows"], fix["rows"], "rows differ for {case}"); + assert_eq!( + got["window_rows"], fix["window_rows"], + "window rows differ for {case}" + ); + } +} diff --git a/tests/vela/native_units.rs b/tests/vela/native_units.rs new file mode 100644 index 00000000..e117fdea --- /dev/null +++ b/tests/vela/native_units.rs @@ -0,0 +1,97 @@ +//! Unit tests for the native crate's state mapping and word splitter, +//! extracted from the modules per the repository's test-placement +//! rule (the private contract test lives in native_contract_unit.rs, +//! loaded by the `#[path]` wiring in contract.rs). + +use omni_vela_native::state::system_one_state; +use omni_vela_native::words::{split_words, word_first_tokens}; +use serde_json::json; + +// ------------------------------------------------------------- state + +#[test] +fn a_plain_string_is_one_user_part() { + let parts = system_one_state(&json!("hello")).expect("parts"); + assert_eq!(parts.parts.len(), 1); + assert_eq!(parts.parts[0].r#type, "user"); + assert_eq!(parts.fields["request"].end, 5); +} + +#[test] +fn typed_keys_group_into_ordered_parts_with_field_ranges() { + let parts = system_one_state(&json!({ + "answer": "A", "request": "R", "source": "S", "extra": "E", + })) + .expect("parts"); + let roles: Vec<&str> = parts.parts.iter().map(|p| p.r#type.as_str()).collect(); + assert_eq!(roles, ["user", "context", "answer"]); + let context = &parts.parts[1]; + assert_eq!(context.text, "source:\nS\n\nextra:\nE"); + assert_eq!(parts.fields["source"].start, "source:\n".chars().count()); + assert_eq!( + parts.fields["extra"].start, + "source:\nS\n\nextra:\n".chars().count() + ); +} + +#[test] +fn an_empty_role_part_is_rejected() { + let error = system_one_state(&json!({"request": " "})).unwrap_err(); + assert_eq!( + error.body["detail"][0]["msg"], + serde_json::json!("the user part of the state is empty") + ); +} + +#[test] +fn a_string_holding_a_json_object_is_read_as_that_object() { + let parts = system_one_state(&json!("{\"request\": \"text\"}")).expect("parts"); + assert_eq!(parts.parts.len(), 1); + assert_eq!(parts.fields["request"].end, 4); +} + +// ------------------------------------------------------------- words + +#[test] +fn words_split_like_the_reference() { + let text = "Hi, I'm Tom Baker (tom.baker@example.com)."; + let words: Vec = split_words(text) + .iter() + .map(|(a, b)| text.chars().skip(*a).take(b - a).collect()) + .collect(); + assert_eq!( + words, + vec![ + "Hi", + ",", + "I", + "'", + "m", + "Tom", + "Baker", + "(", + "tom.baker@example.com", + ")", + "." + ] + ); +} + +#[test] +fn cjk_characters_are_one_unit_each() { + let text = "追踪 parcel 仓库"; + let words: Vec = split_words(text) + .iter() + .map(|(a, b)| text.chars().skip(*a).take(b - a).collect()) + .collect(); + assert_eq!(words, vec!["追", "踪", "parcel", "仓", "库"]); +} + +#[test] +fn first_tokens_skip_empty_tokens() { + let text = "alpha beta"; + let offsets = vec![(0, 0), (0, 5), (6, 10)]; + let (word_offsets, first) = word_first_tokens(text, &offsets); + assert_eq!(word_offsets, vec![(0, 5), (6, 10)]); + assert_eq!(first, vec![1, 2]); +} From 7d50f571d7bdcb64790289bce2e44d45e2649920 Mon Sep 17 00:00:00 2001 From: "Mr.Dong" <1042542469@qq.com> Date: Sun, 25 Oct 2026 02:36:06 +0800 Subject: [PATCH 05/14] vela: add the 0.8B native F32 heads, scoring and span decoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - heads.rs: CandidateHead (option-end + query hiddens; bilinear + scalar-MLP, [ABS] last), both SpanHeadV2 instances (router and the side-loaded broad head) and set_bias, loaded from the exported bundle's heads.safetensors — plain float32, the reference's own autocast-off setting (erf-based GELU via libm). - scoring.rs: the calibration mirror — per-type temperatures, set thresholds, the PII length rule (log-space interp) and sparse gate, span thresholds by id/label set, softmax/sigmoid, span_decode_r4 (word units, unit vote, fill, edge/URL trim), label aliasing, score value normalization (i/(n-1)), and the window aggregation (mean over covering windows, -30 uncovered). - recipe/vela/export_head_inputs.py and the recorded head-input fixtures: the reference's consumed hidden states, its head logits and its calibrated predict answers for the five frozen cases. Opt-in parity (VELA_NATIVE_BUNDLE): five cases, head-logit drift <= 3.8e-5, predict-answer drift <= 7.3e-7 (the windowed long-span case exact), discrete picks, span structures and threshold rules equal. --- Cargo.lock | 2 + README.md | 2 +- docs/supported-models.md | 2 +- recipe/vela/export_head_inputs.py | 226 +++++++ recipe/vela/native.md | 38 +- src/models/vela/README.md | 16 +- src/models/vela/native/Cargo.toml | 8 +- src/models/vela/native/src/heads.rs | 286 ++++++++ src/models/vela/native/src/lib.rs | 2 + src/models/vela/native/src/scoring.rs | 631 ++++++++++++++++++ .../head-input-example-request-cjk.json | 1 + ...head-input-example-request-cjk.safetensors | Bin 0 -> 254408 bytes .../head-input-example-request-score.json | 1 + ...ad-input-example-request-score.safetensors | Bin 0 -> 41112 bytes ...d-input-example-request-set-threshold.json | 1 + ...-example-request-set-threshold.safetensors | Bin 0 -> 16536 bytes .../fixtures/head-input-example-request.json | 1 + .../head-input-example-request.safetensors | Bin 0 -> 299464 bytes .../head-input-long-span-windowed.json | 1 + .../head-input-long-span-windowed.safetensors | Bin 0 -> 15213024 bytes tests/vela/native_heads.rs | 401 +++++++++++ 21 files changed, 1603 insertions(+), 16 deletions(-) create mode 100644 recipe/vela/export_head_inputs.py create mode 100644 src/models/vela/native/src/heads.rs create mode 100644 src/models/vela/native/src/scoring.rs create mode 100644 tests/vela/fixtures/head-input-example-request-cjk.json create mode 100644 tests/vela/fixtures/head-input-example-request-cjk.safetensors create mode 100644 tests/vela/fixtures/head-input-example-request-score.json create mode 100644 tests/vela/fixtures/head-input-example-request-score.safetensors create mode 100644 tests/vela/fixtures/head-input-example-request-set-threshold.json create mode 100644 tests/vela/fixtures/head-input-example-request-set-threshold.safetensors create mode 100644 tests/vela/fixtures/head-input-example-request.json create mode 100644 tests/vela/fixtures/head-input-example-request.safetensors create mode 100644 tests/vela/fixtures/head-input-long-span-windowed.json create mode 100644 tests/vela/fixtures/head-input-long-span-windowed.safetensors create mode 100644 tests/vela/native_heads.rs diff --git a/Cargo.lock b/Cargo.lock index bd63bd1c..97dcd635 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1294,8 +1294,10 @@ name = "omni-vela-native" version = "0.1.0" dependencies = [ "anyhow", + "libm", "omni-qwen3-5-native", "onig", + "safetensors 0.8.0", "serde", "serde_json", "sha2 0.11.1", diff --git a/README.md b/README.md index a68b0fd2..6444de28 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ extensions) on each checkpoint's own pinned runtime: | OmniJev-4B v1.1 | [Checkpoint export and CPU contract](recipe/omnijev/README.md) only; the native worker is in progress ([#114](https://github.com/ThinkFlowLab/system1-omni/issues/114)) | | D3 (Decision 3.0) | [Python reference worker](recipe/d3/reference.md) on the checkpoint's pinned runtime; `choice`/`noul`/`score` text state, media inputs refused; author-run on A100 (evidence in the integration PR) | | Vela 2.0 0.3B | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; all five kinds (`choice`/`noul`/`score`/`span`/`set`) for text state; CPU FP32 validated (author-run, evidence in the integration PR) | -| Vela 2.0 0.8B hybrid | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; same surface plus `span_heads`; [native library](recipe/vela/native.md) (bundle export, wire contract, token-level processing); CPU FP32 parity recorded in the integration PR | +| Vela 2.0 0.8B hybrid | [Python reference worker](recipe/vela/reference.md) on the checkpoint's pinned runtime; same surface plus `span_heads`; [native library](recipe/vela/native.md) (bundle export, wire contract, processing, F32 heads); CPU FP32 parity recorded in the integration PR | [Supported models and hardware](docs/supported-models.md) lists the devices and where each worker has been run. diff --git a/docs/supported-models.md b/docs/supported-models.md index 399ea09a..6c07f6ab 100644 --- a/docs/supported-models.md +++ b/docs/supported-models.md @@ -25,7 +25,7 @@ Models that are being added are also tracked in issues labeled [new model](https | OmniJev-4B v1.1 | None yet: [checkpoint export and CPU contract](../recipe/omnijev/README.md); the native worker is in progress ([#114](https://github.com/ThinkFlowLab/system1-omni/issues/114)) | Request contract, preparation, heads and finishing checked against the reference ([#120](https://github.com/ThinkFlowLab/system1-omni/pull/120)); no inference | Not yet | Not supported | Python 3.10 reference environment for the export and fixtures | | D3 (Decision 3.0) | [Python reference worker](../recipe/d3/reference.md) running the checkpoint's pinned runtime | Unverified | Author-run on NVIDIA A100 (sm_80): three-kind serving smoke with byte-identical frontend forwarding and reference parity (exact decisions, max delta 0.0, 348 == 348 tokens); evidence in the integration PR. Owner: @MrDongsls. | Unverified | Python 3.12, the [pinned runtime requirements](../recipe/d3/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/d3) (~52 GB) | | Vela 2.0 0.3B | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime | **CPU FP32 validated** (author-run, x86 WSL2, 24 cores): startup with all-kind warmup, the four example requests plus five synthetic rejections, and exact-match reference parity against the pinned upstream server on all nine (four 200s byte-equal incl. key order, agreed 422/413); byte-identical frontend forwarding; evidence in the integration PR. Owner: @MrDongsls. | Unverified (bf16-autocast is an untested deployment option) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.3B) (1.24 GB FP32 weights; ~4.4 GB with ONNX/assets) | -| Vela 2.0 0.8B hybrid | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime (same wire layer as 0.3B); [native library](../recipe/vela/native.md) — bundle export, wire contract, token-level processing | Same surface as 0.3B plus the `span_heads` field (router/broad dispatch); **CPU FP32 parity** (author-run; evidence in the integration PR) | Unverified (bf16-autocast is the evaluated upstream setting but untested here) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) (2.02 GB shard + 4.5 MB broad head; ~3 GB FP32 parameters) | +| Vela 2.0 0.8B hybrid | [Python reference worker](../recipe/vela/reference.md) running the checkpoint's pinned runtime (same wire layer as 0.3B); [native library](../recipe/vela/native.md) — bundle export, wire contract, processing, F32 heads and scoring | Same surface as 0.3B plus the `span_heads` field (router/broad dispatch); **CPU FP32 parity** (author-run; evidence in the integration PR) | Unverified (bf16-autocast is the evaluated upstream setting but untested here) | Not supported | Python 3.12, the [pinned requirements](../recipe/vela/requirements.txt), the [pinned package](https://huggingface.co/vllm-sr/Vela-2.0-0.8B) (2.02 GB shard + 4.5 MB broad head; ~3 GB FP32 parameters) | - **Validated:** covered by the recipe on `main` or by the checks in the linked merged pull request. - **Author-run:** recorded by the recipe author on the stated hardware and not independently reproduced; the row names its owner. diff --git a/recipe/vela/export_head_inputs.py b/recipe/vela/export_head_inputs.py new file mode 100644 index 00000000..625eadd0 --- /dev/null +++ b/recipe/vela/export_head_inputs.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 +"""Freeze the head inputs/outputs of the pinned Vela 2.0 0.8B runtime. + +Records, per frozen case, exactly what +the two F32 heads consume and produce — CandidateHead (option-end +hidden states + the block query hidden) and SpanHeadV2 (word hidden +states + label-mean hiddens), on CPU FP32 with autocast off (the +heads' own setting, bit-deterministic) — so the Rust heads and the +scoring/decode mirror are checked against these without any GPU. Also +records the reference's calibrated predict answers for the same cases +(the scoring target). Hidden matrices go to a per-case safetensors +file; structure, small logits and answers go to JSON next to it. + + PYTHONPATH=src .venv/bin/python recipe/vela/export_head_inputs.py \ + --model weights/vela-2.0-0.8b --out tests/vela/fixtures/ +""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path + +import numpy as np +from safetensors.numpy import save_file + +HERE = Path(__file__).resolve().parent +MODEL_NAME = "vllm-sr/Vela-2.0-0.8B" + + + +def parse_args(argv=None): + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("--model", required=True, help="pinned Vela 2.0 0.8B package directory") + parser.add_argument("--out", default=None, help="fixture output directory") + return parser.parse_args(argv) + + +def long_span_body(): + filler = " ".join(f"Sentence {i} reports a routine delivery event." for i in range(220)) + return { + "model": MODEL_NAME, + "state": {"request": filler}, + "questions": { + "claims": { + "type": "span", + "instructions": "Which spans mention a delivery?", + "criteria": {"delivery": "a delivery event"}, + "over": "request", + } + }, + } + + +def cases(): + named = [ + ("example-request", HERE / "example-request.json"), + ("example-request-set-threshold", HERE / "example-request-set-threshold.json"), + ("example-request-cjk", HERE / "example-request-cjk.json"), + ("example-request-score", HERE / "example-request-score.json"), + ] + loaded = [ + (name, {**json.loads(path.read_text(encoding="utf-8")), "model": MODEL_NAME}) + for name, path in named + ] + loaded.append(("long-span-windowed", long_span_body())) + return loaded + + +def plain(value): + if isinstance(value, dict): + return {key: plain(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [plain(item) for item in value] + if isinstance(value, np.ndarray): + return plain(value.tolist()) + if isinstance(value, (np.integer,)): + return int(value) + if isinstance(value, (np.floating,)): + return float(value) + if isinstance(value, (np.bool_,)): + return bool(value) + return value + + +class Recorder: + """Class-level wrappers around the two heads; records inputs/outputs.""" + + def __init__(self, module, model): + self.calls: list[dict] = [] + self.tensors: dict[str, np.ndarray] = {} + self._on = False + # Tensor names must never collide across rows: the counter keeps + # growing for the whole case. + self.next_index = 0 + self.module = module + self.model = model + original_head = module.CandidateHead.forward + original_span = module.SpanHeadV2.forward + recorder = self + + def head_forward(self, candidates, query): + out = original_head(self, candidates, query) + if recorder._on: + index = recorder.next_index + cname, qname = f"q{index}_cand", f"q{index}_query" + recorder.tensors[cname] = candidates.detach().cpu().numpy().astype(np.float32) + recorder.tensors[qname] = query.detach().cpu().numpy().astype(np.float32) + recorder.next_index = index + 1 + recorder.calls.append( + dict(kind="q", cand=cname, query=qname, + logits=[row.tolist() for row in out.detach().cpu().numpy()]) + ) + return out + + def span_forward(self, words, labels): + out = original_span(self, words, labels) + if recorder._on: + index = recorder.next_index + wname, lname = f"s{index}_words", f"s{index}_labels" + which = "broad" if self is getattr(recorder.model, "span_broad", None) else "router" + recorder.tensors[wname] = words.detach().cpu().numpy().astype(np.float32) + recorder.tensors[lname] = labels.detach().cpu().numpy().astype(np.float32) + recorder.next_index = index + 1 + recorder.calls.append( + dict(kind="span", head=which, words=wname, labels=lname, + logits=out.detach().cpu().numpy().tolist()) + ) + return out + + module.CandidateHead.forward = head_forward + module.SpanHeadV2.forward = span_forward + + +def rows_of(engine, body): + from vela2_inference import system_one_to_predict + + req, plan = system_one_to_predict(body["state"], body["questions"]) + parts, qs, _thr = engine._to_generic(req) + spans = [q for q in qs if q["type"] == "span"] + rest = [q for q in qs if q["type"] != "span"] + rows = [dict(parts=parts, questions=rest + spans[:1])] + [ + dict(parts=parts, questions=[s]) for s in spans[1:] + ] + rendered, preps, windows = [], [], [] + for row in rows: + if not row["questions"]: + continue + prepped = engine._prep(row) + rec = engine._render(prepped) + rec["head"] = prepped["head"] + rec["head_reason"] = prepped["head_reason"] + rec["label_alias"] = plain(prepped.get("label_alias")) + preps.append(prepped) + rendered.append(rec) + for wrow in engine._window_rows(prepped) or []: + wrec = engine._render(wrow) + wrec["head"] = prepped["head"] + windows.append(wrec) + return req, plan, rendered, windows + + +def main(argv=None) -> int: + args = parse_args(argv) + sys.path.insert(0, str(Path(args.model).resolve())) + from vela2_inference import Vela2 + + engine = Vela2.from_pretrained(args.model, backend="torch", device="cpu") + import modeling_vela2 + + recorder = Recorder(modeling_vela2, engine.run.model) + out = Path(args.out) if args.out else HERE.parents[1] / "tests" / "vela" / "fixtures" + out.mkdir(parents=True, exist_ok=True) + + for name, body in cases(): + req, plan, rows, windows = rows_of(engine, body) + # One row per backend call so every recorded head call is + # attributable; question blocks arrive stacked in row order. + calls = [] + tensors: dict[str, np.ndarray] = {} + recorder.calls = [] + recorder.tensors = {} + recorder.next_index = 0 + recorder._on = True + row_of_call: list[int] = [] + try: + for index, rec in enumerate(rows + windows): + # Windows render after the main rows (row index continues). + engine.run([rec]) + for call in recorder.calls: + row_of_call.append(index) + calls.extend(recorder.calls) + tensors.update(recorder.tensors) + recorder.calls = [] + # The reference's calibrated answers for the same request. + predict = plain(engine._predict(req)[0]) + finally: + recorder._on = False + for call, row in zip(calls, row_of_call): + call["row"] = row + save_file(tensors, str(out / f"head-input-{name}.safetensors")) + fixture = { + "case": name, + "request": body, + # The rows block carries the span-head dispatch and alias + # provenance for human inspection; the tests read the + # rendered rows from the native-plan fixtures. + "rows": [ + {key: rec[key] for key in ("head", "head_reason", "label_alias", "n_tokens", "seg_lens") + if key in rec} + for rec in rows + ], + "head_calls": calls, + "predict": predict, + } + (out / f"head-input-{name}.json").write_text( + json.dumps(fixture, ensure_ascii=False) + "\n", encoding="utf-8" + ) + span_calls = sum(1 for call in calls if call["kind"] == "span") + print(f"{name}: {len(rows)} row(s), {len(calls)} head call(s) ({span_calls} span), predict answers: {len(predict['answers'])}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/recipe/vela/native.md b/recipe/vela/native.md index 4c3cefa3..dda168fa 100644 --- a/recipe/vela/native.md +++ b/recipe/vela/native.md @@ -18,6 +18,13 @@ PYTHONPATH=src .venv/bin/python recipe/vela/export_native.py \ --package weights/vela-2.0-0.8b --out weights/vela-2.0-0.8b-native ~~~ +The backbone that executes on CUDA is a uniform-BF16 re-save (every +backbone tensor rounds once at export); the reference's own GPU setting +runs the backbone under bf16 autocast but keeps norm weights and GDN +gate math in FP32, so the uniform export is a slightly lower-precision +profile than either the CPU-FP32 recording or the reference GPU path. +The Vela heads stay F32 on the faithful tensors. + The export re-runs the reference worker's package gate first (provenance), then writes `weights/vela-2.0-0.8b-native/`: the backbone re-keyed `backbone.` → `model.` with **per-tensor dtypes preserved** @@ -34,13 +41,17 @@ SHA-256. ~~~sh PYTHONPATH=src .venv/bin/python recipe/vela/export_token_plan.py \ --model weights/vela-2.0-0.8b --out tests/vela/fixtures/ +PYTHONPATH=src .venv/bin/python recipe/vela/export_head_inputs.py \ + --model weights/vela-2.0-0.8b --out tests/vela/fixtures/ ~~~ The token plans record what the pinned runtime feeds the backbone (the predict mapping, the per-row decomposition, the rendered `p_ids`, blocks and readout positions, truncation, a windowed long-span case). The example-request token plan totals 1,041 tokens, matching the -oracle fixture's `usage.input_tokens`. +oracle fixture's `usage.input_tokens`. The head inputs record the +hidden states the F32 heads consume, the heads' logits and the +calibrated predict answers. ## Checks @@ -49,14 +60,18 @@ cargo test -p omni-vela-native cargo fmt --all --check cargo clippy -p omni-vela-native --all-targets -- -D warnings VELA_NATIVE_BUNDLE="$PWD/weights/vela-2.0-0.8b-native" \ - cargo test -p omni-vela-native --test vela_native_processing -- --nocapture + cargo test -p omni-vela-native --test vela_native_processing \ + --test vela_native_heads -- --nocapture ~~~ -26 tests run everywhere with no weights and no GPU: the wire contract +27 tests run everywhere with no weights and no GPU: the wire contract against the pinned runtime's 422/400 bodies, the bundle manifest gate, and the predict-mapping/plan parity on every frozen fixture. The -opt-in render check replays the five token plans through the Rust -processing field-for-field. For a field-level diff of one case: +opt-in checks replay the fixtures through the Rust implementation: + +- render parity — the token plans match field-for-field (5/5); +- head parity — head-logit drift <= 3.8e-5, predict-answer drift + <= 7.3e-7, discrete picks and span structures equal (5/5). For a field-level diff of one case: ~~~sh VELA_NATIVE_BUNDLE="$PWD/weights/vela-2.0-0.8b-native" \ @@ -66,8 +81,11 @@ VELA_NATIVE_BUNDLE="$PWD/weights/vela-2.0-0.8b-native" \ ## Scope and limits - Implemented: the bundle export + manifest gate, the wire admission, - and the token-level processing (state mapping, predict mapping with - the validation triples, word units, span-head dispatch, the DEV2.0 - rendering, the truncation budget, window rows). -- Not implemented: the F32 heads, scoring and span decoding, backbone - execution, and an HTTP worker. No performance claims are made. + the token-level processing (state mapping, predict mapping with the + validation triples, word units, span-head dispatch, the DEV2.0 + rendering, the truncation budget, window rows), and the F32 heads + with scoring and span decoding (CandidateHead, both SpanHeadV2 + heads, set_bias, temperatures, the PII length rule and sparse gate, + `span_decode_r4`, label aliasing, window aggregation). +- Not implemented: backbone execution and an HTTP worker. No + performance claims are made. diff --git a/src/models/vela/README.md b/src/models/vela/README.md index 92fc4f82..fdca780a 100644 --- a/src/models/vela/README.md +++ b/src/models/vela/README.md @@ -258,7 +258,17 @@ The native implementation lives in [`native/`](native/) as the the long-target window rows. All five frozen token plans (`tests/vela/fixtures/native-plan-*.json`) match field-for-field. -The F32 heads, scoring, backbone execution and an HTTP worker are not -implemented. Checks: `cargo test -p omni-vela-native` (26 tests, no -weights, no GPU; render parity opt-in with `VELA_NATIVE_BUNDLE`; see +- `native/src/{heads,scoring}.rs` are the F32 heads and the scoring + path: CandidateHead, both SpanHeadV2 heads, `set_bias`, the + per-type temperatures, set thresholds, the PII length rule and + sparse gate, `span_decode_r4` (word units, unit vote, fill, + edge/URL trimming), label aliasing, score normalization and the + window aggregation. Replaying the recorded head-input fixtures + (`tests/vela/fixtures/head-input-*`): head-logit drift ≤ 3.8e-5, + predict-answer drift ≤ 7.3e-7, discrete picks and span structures + equal on all five cases. + +Backbone execution and an HTTP worker are not implemented. Checks: +`cargo test -p omni-vela-native` (27 tests, no weights, no GPU; +render and head parity opt-in with `VELA_NATIVE_BUNDLE`; see [recipe/vela/native.md](../../recipe/vela/native.md)). diff --git a/src/models/vela/native/Cargo.toml b/src/models/vela/native/Cargo.toml index 40308a34..753acb62 100644 --- a/src/models/vela/native/Cargo.toml +++ b/src/models/vela/native/Cargo.toml @@ -3,10 +3,12 @@ name = "omni-vela-native" version = "0.1.0" edition = "2024" publish = false -description = "Native library for vllm-sr/Vela-2.0-0.8B: bundle gate, wire contract and token-level processing" +description = "Native library for vllm-sr/Vela-2.0-0.8B: bundle gate, wire contract, processing, F32 heads and scoring" [dependencies] anyhow = "1.0.100" +libm = "0.2" +safetensors = "0.8.0" onig = { package = "onig", version = "6", default-features = false } omni-qwen3-5-native = { path = "../../qwen3_5/native" } serde = { version = "1", features = ["derive"] } @@ -35,3 +37,7 @@ path = "../../../../tests/vela/native_processing.rs" [[test]] name = "vela_native_units" path = "../../../../tests/vela/native_units.rs" + +[[test]] +name = "vela_native_heads" +path = "../../../../tests/vela/native_heads.rs" diff --git a/src/models/vela/native/src/heads.rs b/src/models/vela/native/src/heads.rs new file mode 100644 index 00000000..1381d555 --- /dev/null +++ b/src/models/vela/native/src/heads.rs @@ -0,0 +1,286 @@ +//! The Vela-owned F32 heads, mirrored from the checkpoint's +//! `CandidateHead` and `SpanHeadV2` (the reference computes both with +//! autocast disabled, in float32 — deterministic math). Tensors load +//! from the exported bundle's `heads.safetensors` (37 F32 tensors: +//! CandidateHead, `set_bias`, the router `span2.*` and the side-loaded +//! `span_broad.*`). + +use std::path::Path; + +use anyhow::{Context, Result, ensure}; +use safetensors::SafeTensors; + +const HIDDEN: usize = 1024; +const HEAD_DIM: usize = 256; + +fn gelu(x: f32) -> f32 { + 0.5 * x * (1.0 + libm::erff(x / std::f32::consts::SQRT_2)) +} + +/// One `Linear`: weights row-major `[out, in]`, optional bias. +struct Linear { + weight: Vec, + bias: Option>, + out: usize, + input: usize, +} + +impl Linear { + fn apply(&self, x: &[f32]) -> Vec { + debug_assert_eq!(x.len(), self.input); + let mut out = vec![0.0; self.out]; + for (row, slot) in out.iter_mut().enumerate() { + let mut sum = self.bias.as_ref().map_or(0.0, |b| b[row]); + let base = row * self.input; + for (index, value) in x.iter().enumerate() { + sum += self.weight[base + index] * value; + } + *slot = sum; + } + out + } +} + +/// One `LayerNorm` over the hidden vector (PyTorch defaults, eps 1e-5). +struct LayerNorm { + weight: Vec, + bias: Vec, +} + +impl LayerNorm { + fn apply(&self, x: &[f32]) -> Vec { + let n = x.len() as f32; + let mean = x.iter().sum::() / n; + let var = x.iter().map(|v| (v - mean) * (v - mean)).sum::() / n; + let inv = 1.0 / (var + 1e-5).sqrt(); + x.iter() + .enumerate() + .map(|(i, v)| (v - mean) * inv * self.weight[i] + self.bias[i]) + .collect() + } +} + +/// `SpanHeadV2` (router `span2.*` or broad `span_broad.*`). +pub struct SpanHead { + word_norm: LayerNorm, + label_norm: LayerNorm, + slot: Vec, // [slots, hidden] + slots: usize, + d: usize, + k: Linear, + q: Linear, + m: Linear, + n: Linear, + v: Linear, +} + +impl SpanHead { + /// score (W, L): words (W, H) raw states, labels (L, H) block means. + pub fn forward(&self, words: &[Vec], labels: &[Vec]) -> Vec> { + let mut w: Vec> = words.iter().map(|row| self.word_norm.apply(row)).collect(); + // Per-column mean over the words, subtracted. + if !w.is_empty() { + let mut mean = vec![0.0f32; HIDDEN]; + for row in &w { + for (i, value) in row.iter().enumerate() { + mean[i] += value; + } + } + for value in mean.iter_mut() { + *value /= w.len() as f32; + } + for row in w.iter_mut() { + for (i, value) in row.iter_mut().enumerate() { + *value -= mean[i]; + } + } + } + // Label states: normalized + slot embedding, mean-centered when + // two or more labels. + let mut e: Vec> = labels + .iter() + .enumerate() + .map(|(index, row)| { + let mut state = self.label_norm.apply(row); + let slot = index.min(self.slots - 1); + let base = slot * HIDDEN; + for (i, value) in state.iter_mut().enumerate() { + *value += self.slot[base + i]; + } + state + }) + .collect(); + if e.len() >= 2 { + let mut mean = vec![0.0f32; HIDDEN]; + for row in &e { + for (i, value) in row.iter().enumerate() { + mean[i] += value; + } + } + for value in mean.iter_mut() { + *value /= e.len() as f32; + } + for row in e.iter_mut() { + for (i, value) in row.iter_mut().enumerate() { + *value -= mean[i]; + } + } + } + let scale = 1.0 / (self.d as f32).sqrt(); + let k: Vec> = w.iter().map(|row| self.k.apply(row)).collect(); + let q: Vec> = e.iter().map(|row| self.q.apply(row)).collect(); + let m_rows: Vec> = w.iter().map(|row| self.m.apply(row)).collect(); + let n_rows: Vec> = e.iter().map(|row| self.n.apply(row)).collect(); + w.iter() + .enumerate() + .map(|(wi, _)| { + (0..labels.len()) + .map(|li| { + let mut bil = 0.0f32; + for (a, b) in k[wi].iter().zip(&q[li]) { + bil += a * b; + } + bil *= scale; + let mut summed = vec![0.0f32; HEAD_DIM]; + for (index, value) in summed.iter_mut().enumerate() { + *value = gelu(m_rows[wi][index] + n_rows[li][index]); + } + let mut score = 0.0f32; + for (index, value) in summed.iter().enumerate() { + score += self.v.weight[index] * value; + } + bil + score + }) + .collect() + }) + .collect() + } +} + +/// The two heads plus `set_bias`, loaded from one safetensors file. +pub struct Heads { + candidate_norm: LayerNorm, + query_norm: LayerNorm, + key: Linear, + query: Linear, + candidate_mlp: Linear, + query_mlp: Linear, + scalar: Linear, + pub set_bias: f32, + pub router: SpanHead, + pub broad: SpanHead, +} + +fn tensor<'a>(file: &'a SafeTensors<'a>, name: &str) -> Result> { + let view = file + .tensor(name) + .with_context(|| format!("heads.safetensors is missing {name}"))?; + ensure!( + view.dtype() == safetensors::Dtype::F32, + "{name} must be F32" + ); + Ok(view + .data() + .as_chunks::<4>() + .0 + .iter() + .map(|chunk| f32::from_le_bytes(*chunk)) + .collect()) +} + +fn linear(file: &SafeTensors, prefix: &str, bias: bool, input: usize) -> Result { + let weight = tensor(file, &format!("{prefix}.weight"))?; + let out = weight.len() / input; + ensure!( + weight.len() % input == 0 && out > 0, + "{prefix}.weight shape" + ); + Ok(Linear { + weight, + bias: if bias { + Some(tensor(file, &format!("{prefix}.bias"))?) + } else { + None + }, + out, + input, + }) +} + +fn norm(file: &SafeTensors, prefix: &str) -> Result { + Ok(LayerNorm { + weight: tensor(file, &format!("{prefix}.weight"))?, + bias: tensor(file, &format!("{prefix}.bias"))?, + }) +} + +fn span_head(file: &SafeTensors, prefix: &str, d: usize, slots: usize) -> Result { + let slot = tensor(file, &format!("{prefix}.slot.weight"))?; + Ok(SpanHead { + word_norm: norm(file, &format!("{prefix}.wn"))?, + label_norm: norm(file, &format!("{prefix}.ln"))?, + slots, + slot, + d, + k: linear(file, &format!("{prefix}.K"), false, HIDDEN)?, + q: linear(file, &format!("{prefix}.Q"), false, HIDDEN)?, + m: linear(file, &format!("{prefix}.M"), true, HIDDEN)?, + n: linear(file, &format!("{prefix}.N"), false, HIDDEN)?, + v: linear(file, &format!("{prefix}.v"), false, HEAD_DIM)?, + }) +} + +impl Heads { + pub fn load(bundle: &Path) -> Result { + let raw = std::fs::read(bundle.join("heads.safetensors")).context("heads.safetensors")?; + let file = SafeTensors::deserialize(&raw).context("heads.safetensors must parse")?; + let set_bias = tensor(&file, "set_bias")?; + ensure!(set_bias.len() == 1, "set_bias is a scalar"); + // The span-head geometry ships in the manifest's calibration + // (d 256, slots 64 for this member). + Ok(Self { + candidate_norm: norm(&file, "head.candidate_norm")?, + query_norm: norm(&file, "head.query_norm")?, + key: linear(&file, "head.key", false, HIDDEN)?, + query: linear(&file, "head.query", false, HIDDEN)?, + candidate_mlp: linear(&file, "head.candidate_mlp", true, HIDDEN)?, + query_mlp: linear(&file, "head.query_mlp", false, HIDDEN)?, + scalar: linear(&file, "head.scalar", false, HEAD_DIM)?, + set_bias: set_bias[0], + router: span_head(&file, "span2", HEAD_DIM, 64)?, + broad: span_head(&file, "span_broad", HEAD_DIM, 64)?, + }) + } + + /// CandidateHead: option-end hiddens (W, H) and the block's query + /// hidden (H) -> one logit per option (plus `[ABS]` last when the + /// row carries it — the caller slices). + pub fn forward_candidate(&self, candidates: &[Vec], query: &[f32]) -> Vec { + let global_query = self.query_norm.apply(query); + let q_proj = self.query.apply(&global_query); + let q_mlp = self.query_mlp.apply(&global_query); + let scale = 1.0 / (HEAD_DIM as f32).sqrt(); + candidates + .iter() + .map(|row| { + let candidate = self.candidate_norm.apply(row); + let key = self.key.apply(&candidate); + let mut bilinear = 0.0f32; + for (a, b) in key.iter().zip(&q_proj) { + bilinear += a * b; + } + bilinear *= scale; + let mlp = self.candidate_mlp.apply(&candidate); + let mut summed = vec![0.0f32; HEAD_DIM]; + for (index, value) in summed.iter_mut().enumerate() { + *value = gelu(mlp[index] + q_mlp[index]); + } + let mut nonlinear = 0.0f32; + for (index, value) in summed.iter().enumerate() { + nonlinear += self.scalar.weight[index] * value; + } + bilinear + nonlinear + }) + .collect() + } +} diff --git a/src/models/vela/native/src/lib.rs b/src/models/vela/native/src/lib.rs index 1d849284..3221eeb1 100644 --- a/src/models/vela/native/src/lib.rs +++ b/src/models/vela/native/src/lib.rs @@ -6,8 +6,10 @@ pub mod bundle; pub mod contract; +pub mod heads; pub mod processing; pub mod questions; pub mod render; +pub mod scoring; pub mod state; pub mod words; diff --git a/src/models/vela/native/src/scoring.rs b/src/models/vela/native/src/scoring.rs new file mode 100644 index 00000000..e13fba9e --- /dev/null +++ b/src/models/vela/native/src/scoring.rs @@ -0,0 +1,631 @@ +//! The scoring and decode mirror of the pinned runtime's calibration +//! path (`calibrated`, `span_threshold`, the PII length rule and sparse +//! gate, `span_decode_r4.decode_v2`, `_trim`), turning head logits into +//! predict-level answers. Parity target: the `head-input-*.json` +//! fixtures' `predict.answers`. + + +use serde_json::Value; + +/// The package's `calibration.json` as typed lookup. +pub struct Calibration { + pub data: Value, +} + +pub fn softmax(x: &[f64]) -> Vec { + let max = x.iter().copied().fold(f64::NEG_INFINITY, f64::max); + let e: Vec = x.iter().map(|v| (v - max).exp()).collect(); + let sum: f64 = e.iter().sum(); + e.iter().map(|v| v / sum).collect() +} + +pub fn sigmoid(x: f64) -> f64 { + 1.0 / (1.0 + (-x).exp()) +} + +impl Calibration { + pub fn load(bundle: &std::path::Path) -> anyhow::Result { + Ok(Self { + data: serde_json::from_slice(&std::fs::read(bundle.join("calibration.json"))?)?, + }) + } + + fn temperature(&self, qtype: &str) -> f64 { + self.data["temperature"] + .get(qtype) + .and_then(Value::as_f64) + .unwrap_or(1.0) + } + + pub fn span_temperature(&self, head: &str) -> f64 { + if head == "broad" { + self.data["broad_head"]["temperature"] + .as_f64() + .unwrap_or(1.0) + } else { + self.temperature("span") + } + } + + fn is_pii(&self, qid: &str, names: &[String]) -> bool { + if qid == "pii" { + return true; + } + let types: Vec<&str> = self.data["pii_types"] + .as_array() + .map(|a| a.iter().filter_map(Value::as_str).collect()) + .unwrap_or_default(); + !names.is_empty() && names.iter().all(|n| types.contains(&n.as_str())) + } + + /// log-space piecewise-linear between anchors, constant outside. + fn pii_length_threshold(&self, n_tokens: usize) -> f64 { + let anchors = self.data["pii_length_rule"]["anchors"] + .as_array() + .cloned() + .unwrap_or_default(); + let mut points: Vec<(f64, f64)> = anchors + .iter() + .map(|a| { + ( + a["n_tokens"].as_f64().unwrap_or(1.0).ln(), + a["threshold"].as_f64().unwrap_or(1.0).ln(), + ) + }) + .collect(); + points.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); + let x = (n_tokens.max(1) as f64).ln(); + let (xs, ys): (Vec, Vec) = points.into_iter().unzip(); + interp(&xs, &ys, x).exp() + } + + /// The span threshold and its rule string, before the sparse gate. + pub fn span_threshold( + &self, + qid: &str, + names: &[String], + n_tokens: usize, + head: &str, + ) -> (f64, String) { + if head == "broad" { + return ( + self.data["broad_head"]["threshold"].as_f64().unwrap_or(0.5), + "broad".into(), + ); + } + let th = &self.data["thresholds"]; + if self.is_pii(qid, names) { + if self + .data + .get("pii_length_rule") + .is_some_and(|v| !v.is_null()) + { + return (self.pii_length_threshold(n_tokens), "pii:length".into()); + } + for bucket in self.data["pii_buckets"] + .as_array() + .cloned() + .unwrap_or_default() + { + if n_tokens as f64 <= bucket["max_tokens"].as_f64().unwrap_or(f64::INFINITY) { + return ( + bucket["threshold"].as_f64().unwrap_or(0.5), + format!("pii:{}", bucket["name"].as_str().unwrap_or("")), + ); + } + } + } + for fam in ["halu", "toxic"] { + if qid == fam { + return ( + th[&format!("span:{fam}")].as_f64().unwrap_or(0.5), + fam.into(), + ); + } + } + let specific = format!("span:{qid}"); + if th.get(&specific).is_some() { + (th[&specific].as_f64().unwrap_or(0.5), specific) + } else { + (th["span:*"].as_f64().unwrap_or(0.5), "span:*".into()) + } + } + + pub fn set_threshold(&self, qid: &str) -> f64 { + let th = &self.data["thresholds"]; + th.get(format!("set:{qid}")) + .or_else(|| th.get("set:*")) + .and_then(Value::as_f64) + .unwrap_or(0.5) + } + + /// The PII sparse gate (disabled when K < 0; second decode pass + /// over the same probabilities). + pub fn sparse_gate( + &self, + probs: &[Vec], + offs: &[(usize, usize)], + names: &[String], + text: &str, + thr: f64, + rule: &str, + ) -> (f64, String) { + let gate = &self.data["pii_sparse_gate"]; + let k = gate["K"].as_i64().unwrap_or(-1); + if k < 0 || thr >= gate["t_sparse"].as_f64().unwrap_or(f64::INFINITY) || offs.is_empty() { + return (thr, rule.into()); + } + let probe = gate["probe_threshold"].as_f64().unwrap_or(0.5); + let decoded = decode_spans(probs, offs, names, text, probe); + if decoded.len() as i64 <= k { + ( + gate["t_sparse"].as_f64().unwrap_or(thr), + format!("{rule}+sparse"), + ) + } else { + (thr, rule.into()) + } + } +} + +/// numpy.interp: linear between points, constant outside. +fn interp(xs: &[f64], ys: &[f64], x: f64) -> f64 { + if xs.is_empty() { + return f64::NAN; + } + if x <= xs[0] { + return ys[0]; + } + if x >= xs[xs.len() - 1] { + return ys[ys.len() - 1]; + } + for i in 0..xs.len() - 1 { + if x >= xs[i] && x <= xs[i + 1] { + let t = (x - xs[i]) / (xs[i + 1] - xs[i]); + return ys[i] + t * (ys[i + 1] - ys[i]); + } + } + ys[ys.len() - 1] +} + +// ------------------------------------------------------------ span decoding + +const EDGE: &str = "[](){}<>「」『』【】《》〈》\"'“”‘’«»‹›"; +const URL_TRAIL: &str = ".,;:!?)"; + +fn is_cjk(ch: char) -> bool { + // The reference's CJK class; same ranges as the word splitter. + super::words::is_cjk_char(ch) +} + +fn trim_edges(text: &[char], s: &mut usize, e: &mut usize) { + while *s < *e && (text[*s].is_whitespace() || EDGE.contains(text[*s])) { + *s += 1; + } + while *e > *s && (text[*e - 1].is_whitespace() || EDGE.contains(text[*e - 1])) { + *e -= 1; + } +} + +fn trim_url(text: &[char], s: &mut usize, e: &mut usize) { + // (?:https?://|www\.) at s, case-insensitive. + // The reference regex matches against the full text from s; the + // lookahead is not bounded by the span end. + let head: String = text[*s..(*s + 8).min(text.len())].iter().collect(); + let is_url = { + let lower = head.to_lowercase(); + lower.starts_with("http://") || lower.starts_with("https://") || lower.starts_with("www.") + }; + if !is_url { + return; + } + if let Some(pos) = text[*s..*e].iter().position(|&c| is_cjk(c)) { + *e = *s + pos; + } + while *e > *s + && (URL_TRAIL.contains(text[*e - 1]) + || EDGE.contains(text[*e - 1]) + || text[*e - 1].is_whitespace()) + { + *e -= 1; + } +} + +fn trim(text: &[char], s: usize, e: usize) -> (usize, usize) { + let (mut s, mut e) = (s, e); + trim_edges(text, &mut s, &mut e); + trim_url(text, &mut s, &mut e); + (s, e) +} + +/// `span_decode_r4.decode_v2` with the scorer's arguments +/// (extend=false, trim, no bridge, unit vote + fill on). +#[allow(clippy::too_many_arguments)] +pub fn decode_spans( + probs: &[Vec], + offs: &[(usize, usize)], + names: &[String], + text: &str, + thr: f64, +) -> Vec { + let chars: Vec = text.chars().collect(); + let t_count = offs.len(); + if t_count == 0 { + return Vec::new(); + } + let valid: Vec = offs.iter().map(|(a, b)| b > a).collect(); + let mut lab = vec![-1i64; t_count]; + for t in 0..t_count { + let (k, pk) = argmax(&probs[t]); + if valid[t] && pk as f64 > thr { + lab[t] = k as i64; + } + } + // Unit ids over the text (the reference's `_UNIT`), then per-word + // first-nonspace lookup and alnum test. + let units = super::words::unit_ids(&chars); + let mut tu = vec![-1i64; t_count]; + let mut alnum = vec![false; t_count]; + for t in 0..t_count { + if !valid[t] { + continue; + } + let (a, b) = offs[t]; + let mut f = a; + while f < b && chars[f].is_whitespace() { + f += 1; + } + tu[t] = if f < b && f < chars.len() { + units[f] + } else { + -1 + }; + alnum[t] = chars[a..b].iter().any(|&c| is_alnum(c)); + } + // Unit vote + fill, per run of the same unit. + let mut t = 0; + while t < t_count { + if tu[t] < 0 { + t += 1; + continue; + } + let mut t2 = t; + while t2 + 1 < t_count && (tu[t2 + 1] == tu[t] || !valid[t2 + 1]) { + t2 += 1; + } + let idx: Vec = (t..=t2).filter(|&i| valid[i]).collect(); + let labeled: Vec = idx.iter().copied().filter(|&i| lab[i] >= 0).collect(); + if !labeled.is_empty() { + let distinct: Vec = { + let mut d: Vec = labeled.iter().map(|&i| lab[i]).collect(); + d.sort_unstable(); + d.dedup(); + d + }; + if distinct.len() > 1 { + // The reference picks the first strict maximum in + // labeled-token order; accumulate in a Vec keyed by + // first occurrence, not a HashMap (whose iteration + // order would make ties nondeterministic). + let mut order: Vec = Vec::new(); + let mut scores: Vec = Vec::new(); + for &i in &labeled { + let label = lab[i]; + match order.iter().position(|&l| l == label) { + Some(index) => scores[index] += probs[i][label as usize] as f64, + None => { + order.push(label); + scores.push(probs[i][label as usize] as f64); + } + } + } + let mut winner_index = 0usize; + for (index, score) in scores.iter().enumerate().skip(1) { + if *score > scores[winner_index] { + winner_index = index; + } + } + let winner = order[winner_index]; + for &i in &labeled { + lab[i] = winner; + } + } + let labels: Vec = { + let mut d: Vec = labeled.iter().map(|&i| lab[i]).collect(); + d.sort_unstable(); + d.dedup(); + d + }; + for c in labels { + let pos: Vec = labeled.iter().copied().filter(|&i| lab[i] == c).collect(); + for &i in &idx { + if pos[0] < i && i < pos[pos.len() - 1] && lab[i] < 0 { + lab[i] = c; + } + } + } + } + t = t2 + 1; + } + // Merge consecutive same-label words into spans, trim, mean prob. + let mut spans: Vec<(i64, usize, usize, Vec)> = Vec::new(); + for t in 0..t_count { + if !valid[t] { + continue; + } + let c = lab[t]; + if let Some(last) = spans.last_mut() + && c == last.0 + { + last.2 = offs[t].1; + last.3.push(t); + continue; + } + if c >= 0 { + spans.push((c, offs[t].0, offs[t].1, vec![t])); + } + } + let mut out = Vec::new(); + for (c, s, e, ts) in spans { + let (s, e) = trim(&chars, s, e); + if e <= s { + continue; + } + let mean = ts.iter().map(|&t| probs[t][c as usize] as f64).sum::() / ts.len() as f64; + out.push(serde_json::json!({ + "start": s, "end": e, + "label": names[c as usize], + "probability": mean, + })); + } + out +} + +fn argmax(row: &[f32]) -> (usize, f32) { + let mut best = 0usize; + let mut value = f32::NEG_INFINITY; + for (index, item) in row.iter().enumerate() { + if *item > value { + value = *item; + best = index; + } + } + (best, value) +} + +fn is_alnum(c: char) -> bool { + // The reference's `_ALNUM` = [^\W_]: word characters minus the + // underscore — Rust's alphanumeric already excludes it. + c.is_alphanumeric() +} + +// -------------------------------------------------------- answer assembly + +/// One scored question block: the reference's `raw["qs"]` entry. +pub struct QBlock { + pub qid: String, + pub qtype: String, + pub names: Vec, + pub has_abs: bool, + /// Logits over `names` (plus `[ABS]` last when `has_abs`), + /// **after** run_batch's `set_bias` addition for set blocks. + pub logits: Vec, +} + +/// One scored span: the reference's `raw["span"]` (post aggregation). +pub struct SpanOut { + pub qid: String, + pub over: String, + pub names: Vec, + pub offs: Vec<(usize, usize)>, + pub logits: Vec>, + pub head: String, + pub head_reason: Option, + pub label_alias: Option, + /// The span part's kept token count (the PII length-rule input). + pub n_tokens: usize, +} + +/// `calibrated` for one row: logits -> predict-level answers. +pub fn row_answers( + cal: &Calibration, + blocks: &[QBlock], + span: Option<&SpanOut>, + thresholds: &std::collections::HashMap, + span_text: Option<&str>, +) -> Vec { + let mut answers = Vec::new(); + for block in blocks { + let logits: Vec = block.logits.iter().map(|v| *v as f64).collect(); + let n = block.names.len(); + let temperature = cal.temperature(&block.qtype); + if block.qtype == "set" { + let p: Vec = logits[..n] + .iter() + .map(|v| sigmoid(v / temperature)) + .collect(); + let thr = thresholds + .get(&block.qid) + .copied() + .unwrap_or_else(|| cal.set_threshold(&block.qid)); + let probs: serde_json::Map = block + .names + .iter() + .zip(&p) + .map(|(name, value)| (name.clone(), json_f64(*value))) + .collect(); + let selected: Vec<&String> = block + .names + .iter() + .zip(&p) + .filter(|(_, value)| **value > thr) + .map(|(name, _)| name) + .collect(); + answers.push(serde_json::json!({ + "id": block.qid, "type": "set", + "answer": selected, + "probabilities": probs, + "threshold": thr, + })); + continue; + } + let p = softmax( + &logits[..n] + .iter() + .map(|v| v / temperature) + .collect::>(), + ); + let answer = block.names[argmax_usize(&logits[..n])].clone(); + let probs: serde_json::Map = block + .names + .iter() + .zip(&p) + .map(|(name, value)| (name.clone(), json_f64(*value))) + .collect(); + let mut entry = serde_json::json!({ + "id": block.qid, "type": block.qtype, + "answer": answer, + "probabilities": probs, + }); + if block.has_abs { + let full = softmax(&logits.iter().map(|v| v / temperature).collect::>()); + entry["abstain_probability"] = json_f64(full[full.len() - 1]); + } + if block.qtype == "score" { + let expected: f64 = p.iter().enumerate().map(|(i, v)| i as f64 * v).sum(); + entry["expected_index"] = json_f64(expected); + // The default values normalize the levels to 0..1 + // (i / (n-1)); the SystemOne path never passes explicit ones. + let n = p.len(); + let score: f64 = p + .iter() + .enumerate() + .map(|(i, v)| { + // The reference's default values: i/(n-1), or 0 for + // a single level (never NaN). + let value = if n > 1 { + i as f64 / (n - 1) as f64 + } else { + 0.0 + }; + value * v + }) + .sum(); + entry["score"] = json_f64(score); + } + answers.push(entry); + } + if let Some(span) = span { + let text = span_text.unwrap_or(""); + let head = span.head.as_str(); + // The per-question override wins over the calibrated rule. + let (mut thr, mut rule) = match thresholds.get(&span.qid) { + Some(given) => (*given, "given".to_string()), + None => cal.span_threshold(&span.qid, &span.names, span.n_tokens, head), + }; + let temperature = cal.span_temperature(head); + let probs: Vec> = span + .logits + .iter() + .map(|row| { + row.iter() + .map(|v| sigmoid(*v as f64 / temperature) as f32) + .collect() + }) + .collect(); + if rule.starts_with("pii:") { + let (gated, gated_rule) = + cal.sparse_gate(&probs, &span.offs, &span.names, text, thr, &rule); + thr = gated; + rule = gated_rule; + } + let mut decoded = if span.offs.is_empty() { + Vec::new() + } else { + decode_spans(&probs, &span.offs, &span.names, text, thr) + }; + let chars: Vec = text.chars().collect(); + for entry in decoded.iter_mut() { + let (s, e) = ( + entry["start"].as_u64().unwrap_or(0) as usize, + entry["end"].as_u64().unwrap_or(0) as usize, + ); + entry["text"] = Value::String(chars[s..e].iter().collect()); + if let Some(mapped) = span + .label_alias + .as_ref() + .and_then(Value::as_object) + .and_then(|alias| alias.get(entry["label"].as_str().unwrap_or(""))) + { + entry["label"] = mapped.clone(); + } + } + let mut answer = serde_json::json!({ + "id": span.qid, + "type": "span", + "target_part": span.over, + "spans": decoded, + "threshold": thr, + "threshold_rule": rule, + "head": head, + }); + if let Some(reason) = &span.head_reason { + answer["head_reason"] = Value::String(reason.clone()); + } + answers.push(answer); + } + answers +} + +fn argmax_usize(x: &[f64]) -> usize { + let mut best = 0usize; + let mut value = f64::NEG_INFINITY; + for (index, item) in x.iter().enumerate() { + if *item > value { + value = *item; + best = index; + } + } + best +} + +fn json_f64(value: f64) -> Value { + serde_json::Number::from_f64(value) + .map(Value::Number) + .unwrap_or(Value::Null) +} + +/// `predict_raw`'s window aggregation: sum the window rows' span logits +/// per original word (matched by char offsets), divide by coverage +/// count, uncovered words score -30. +pub fn aggregate_windows( + names: &[String], + original_offs: &[(usize, usize)], + window_logits: &[Vec>], + window_offs: &[Vec<(usize, usize)>], +) -> Vec> { + let labels = names.len(); + // The reference accumulates in float64; the result casts to f32. + let mut acc = vec![vec![0.0f64; labels]; original_offs.len()]; + let mut cnt = vec![0usize; original_offs.len()]; + for (logits, offs) in window_logits.iter().zip(window_offs) { + for ((s, e), row) in offs.iter().zip(logits) { + if let Some(u) = original_offs.iter().position(|(os, oe)| os == s && oe == e) { + for (l, value) in row.iter().enumerate() { + acc[u][l] += *value as f64; + } + cnt[u] += 1; + } + } + } + acc.iter() + .zip(&cnt) + .map(|(row, c)| { + if *c > 0 { + row.iter().map(|v| (*v / *c as f64) as f32).collect() + } else { + vec![-30.0; labels] + } + }) + .collect() +} diff --git a/tests/vela/fixtures/head-input-example-request-cjk.json b/tests/vela/fixtures/head-input-example-request-cjk.json new file mode 100644 index 00000000..3baaa645 --- /dev/null +++ b/tests/vela/fixtures/head-input-example-request-cjk.json @@ -0,0 +1 @@ +{"case": "example-request-cjk", "request": {"model": "vllm-sr/Vela-2.0-0.8B", "state": {"request": "客户张伟(zhang.wei@example.cn)于2026年10月1日在上海市浦东新区世纪大道100号办理了业务,联系电话13800138000。", "source": "客户的业务申请需要在三个工作日内审核完成。", "answer": "客户的业务已经即时完成了。"}, "questions": {"pii": {"type": "span", "instructions": "Which spans are personal information?", "criteria": {"PERSON": "a person's name", "EMAIL_ADDRESS": "an e-mail address", "PHONE_NUMBER": "a telephone number", "STREET_ADDRESS": "a street address or postal address"}, "over": "request"}, "unsupported": {"type": "span", "instructions": "Which spans of the answer are not supported by the context?", "criteria": {"unsupported": "a claim not supported by the context"}}, "billing": {"type": "noul", "instructions": "这个请求是否与账单有关?"}}}, "rows": [{"head": "router", "head_reason": "id", "label_alias": null, "n_tokens": 404, "seg_lens": {"user": 46, "context": 10, "answer": 6}}, {"head": "router", "head_reason": "label_set", "label_alias": null, "n_tokens": 193, "seg_lens": {"user": 46, "context": 10, "answer": 6}}], "head_calls": [{"kind": "q", "cand": "q0_cand", "query": "q0_query", "logits": [[-1.60933518409729, -3.7373664379119873, -10.640555381774902]], "row": 0}, {"kind": "span", "head": "router", "words": "s1_words", "labels": "s1_labels", "logits": [[-23.778533935546875, -35.67962646484375, -29.496707916259766, -35.02517318725586], [-23.778533935546875, -35.67962646484375, -29.496707916259766, -35.02517318725586], [-13.288297653198242, -17.101852416992188, -9.51349925994873, -13.732088088989258], [-13.288297653198242, -17.101852416992188, -9.51349925994873, -13.732088088989258], [-17.785783767700195, -24.783889770507812, -18.803138732910156, -24.5747013092041], [-5.519737243652344, -7.974113464355469, -2.0204527378082275, -4.032443523406982], [-19.710346221923828, -31.652324676513672, -24.4345703125, -30.253273010253906], [-22.11681365966797, -31.155961990356445, -25.493202209472656, -30.28239631652832], [-0.9185004830360413, -6.406106472015381, -0.692579448223114, -1.6303598880767822], [-4.95607852935791, -9.517541885375977, -2.2732596397399902, -4.304035663604736], [-0.19278430938720703, -7.234131336212158, -0.09104931354522705, -1.1003239154815674], [-2.164036750793457, -7.8626861572265625, -1.2940788269042969, -2.4866232872009277], [-1.3710556030273438, -6.950081825256348, -1.0965814590454102, -1.80461847782135], [-17.513790130615234, -17.537555694580078, -8.913171768188477, -11.932638168334961], [-21.893512725830078, -29.469112396240234, -24.093914031982422, -26.871994018554688], [-3.359339952468872, -7.748542308807373, -2.7091588973999023, -0.33820855617523193], [-3.359339952468872, -7.748542308807373, -2.7091588973999023, -0.33820855617523193], [-3.359339952468872, -7.748542308807373, -2.7091588973999023, -0.33820855617523193], [-3.4210779666900635, -7.483105659484863, -2.7869768142700195, -0.5679111480712891], [-3.4210779666900635, -7.483105659484863, -2.7869768142700195, -0.5679111480712891], [-3.4210779666900635, -7.483105659484863, -2.7869768142700195, -0.5679111480712891], [-3.4210779666900635, -7.483105659484863, -2.7869768142700195, -0.5679111480712891], [-3.6699564456939697, -8.56665325164795, -2.6497883796691895, 0.620187520980835], [-3.6699564456939697, -8.56665325164795, -2.6497883796691895, 0.620187520980835], [-3.4258086681365967, -9.092829704284668, -2.0032799243927, 0.25476884841918945], [-3.4258086681365967, -9.092829704284668, -2.0032799243927, 0.25476884841918945], [-1.0213323831558228, -8.279101371765137, -0.9210346341133118, 1.104820728302002], [-10.929340362548828, -11.960079193115234, -4.331625461578369, -3.7565321922302246], [-19.668752670288086, -21.596508026123047, -16.757234573364258, -19.447601318359375], [-19.668752670288086, -21.596508026123047, -16.757234573364258, -19.447601318359375], [-19.668752670288086, -21.596508026123047, -16.757234573364258, -19.447601318359375], [-19.40172004699707, -19.034996032714844, -14.057591438293457, -15.741283416748047], [-19.40172004699707, -19.034996032714844, -14.057591438293457, -15.741283416748047], [-19.49544906616211, -31.111461639404297, -23.796104431152344, -29.51728057861328], [-21.458332061767578, -33.868682861328125, -27.257335662841797, -32.84736633300781], [-21.458332061767578, -33.868682861328125, -27.257335662841797, -32.84736633300781], [-21.458332061767578, -33.868682861328125, -27.257335662841797, -32.84736633300781], [-21.458332061767578, -33.868682861328125, -27.257335662841797, -32.84736633300781], [-0.6149466633796692, -7.636533260345459, -0.18819284439086914, -0.1909337043762207], [-24.31658172607422, -34.86664581298828, -29.284488677978516, -32.92279052734375]], "row": 0}, {"kind": "span", "head": "router", "words": "s2_words", "labels": "s2_labels", "logits": [[-4.0871477127075195], [-4.0871477127075195], [-4.0871477127075195], [-2.413851261138916], [-2.413851261138916], [-1.4215611219406128], [-1.4215611219406128], [-0.6014259457588196], [-0.6014259457588196], [-1.4138461351394653], [-1.4138461351394653], [-1.4138461351394653], [-4.652787685394287]], "row": 1}], "predict": {"answers": [{"id": "pii", "type": "span", "target_part": "user", "spans": [{"start": 32, "end": 34, "label": "PHONE_NUMBER", "probability": 0.4658691883087158, "text": "10"}, {"start": 38, "end": 52, "label": "STREET_ADDRESS", "probability": 0.4821831285953522, "text": "上海市浦东新区世纪大道100"}, {"start": 63, "end": 74, "label": "PHONE_NUMBER", "probability": 0.4298103451728821, "text": "13800138000"}], "threshold": 0.2914, "threshold_rule": "pii:length", "head": "router", "head_reason": "id"}, {"id": "unsupported", "type": "span", "target_part": "answer", "spans": [], "threshold": 0.5, "threshold_rule": "span:*", "head": "router", "head_reason": "label_set"}, {"id": "billing", "type": "choice", "answer": "no", "probabilities": {"no": 0.8325233433461274, "yes": 0.1674766566538726}, "abstain_probability": 0.0009211774164155532}], "meta": {"tokens": {"user": 46, "context": 10, "answer": 6}, "windows": 0, "sequences": 2}}} diff --git a/tests/vela/fixtures/head-input-example-request-cjk.safetensors b/tests/vela/fixtures/head-input-example-request-cjk.safetensors new file mode 100644 index 0000000000000000000000000000000000000000..bd7cb1735664f45cc9a87a5b9a176986fb3baf32 GIT binary patch literal 254408 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 literal 0 HcmV?d00001 diff --git a/tests/vela/fixtures/head-input-example-request-score.json b/tests/vela/fixtures/head-input-example-request-score.json new file mode 100644 index 00000000..1588ad68 --- /dev/null +++ b/tests/vela/fixtures/head-input-example-request-score.json @@ -0,0 +1 @@ +{"case": "example-request-score", "request": {"model": "vllm-sr/Vela-2.0-0.8B", "state": "Hello, I would like to check the status of my order. It has been five days and I have heard nothing back.", "questions": {"tone": {"type": "score", "instructions": "How formal is the message?", "criteria": ["casual", "neutral", "formal"]}, "urgency": {"type": "score", "instructions": "How urgently does the sender need a reply?", "criteria": ["no rush", "soon", "today", "immediately"]}}}, "rows": [{"head": "router", "head_reason": null, "label_alias": null, "n_tokens": 228, "seg_lens": {"user": 25}}], "head_calls": [{"kind": "q", "cand": "q0_cand", "query": "q0_query", "logits": [[-2.308352470397949, -1.095753788948059, -1.616711139678955, -0.3145672082901001], [-1.1832587718963623, -1.9728960990905762, -1.711325764656067, -3.1148641109466553]], "row": 0}], "predict": {"answers": [{"id": "tone", "type": "score", "answer": "neutral", "probabilities": {"casual": 0.16807713462834117, "neutral": 0.5139566439051507, "formal": 0.3179662214665082}, "expected_index": 1.1498890868381673, "score": 0.5749445434190836}, {"id": "urgency", "type": "score", "answer": "no rush", "probabilities": {"no rush": 0.44128118285871365, "soon": 0.21311503083546, "today": 0.2712213259289846, "immediately": 0.07438246037684161}, "expected_index": 0.9787050638239541, "score": 0.3262350212746513}], "meta": {"tokens": {"user": 25}, "windows": 0, "sequences": 1}}} diff --git a/tests/vela/fixtures/head-input-example-request-score.safetensors b/tests/vela/fixtures/head-input-example-request-score.safetensors new file mode 100644 index 0000000000000000000000000000000000000000..1e580a6cb0e9b086bdf4b3a5371edb9afdacfd78 GIT binary patch literal 41112 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 literal 0 HcmV?d00001 diff --git a/tests/vela/fixtures/head-input-example-request.json b/tests/vela/fixtures/head-input-example-request.json new file mode 100644 index 00000000..99263ddd --- /dev/null +++ b/tests/vela/fixtures/head-input-example-request.json @@ -0,0 +1 @@ +{"case": "example-request", "request": {"model": "vllm-sr/Vela-2.0-0.8B", "state": {"request": "Hi, I'm Tom Baker (tom.baker@example.com). What is the maximum daily dose of paracetamol for an adult?", "source": "For adults, the maximum dose of paracetamol is 4 grams in 24 hours, taken as 500 mg to 1 g every 4 to 6 hours.", "answer": "Adults can take up to 6 grams of paracetamol in 24 hours, in doses of 500 mg to 1 g every 4 to 6 hours."}, "questions": {"pii": {"type": "span", "instructions": "Which spans are personal information?", "criteria": {"AGE": "a person's age", "CREDIT_CARD": "a payment card number", "DATE_TIME": "a date, time or date of birth", "DOMAIN_NAME": "an internet domain name or website address", "EMAIL_ADDRESS": "an e-mail address", "GPE": "a country, city, state or other geopolitical place", "IBAN_CODE": "an international bank account number (IBAN)", "IP_ADDRESS": "an IPv4 or IPv6 address", "NRP": "a nationality, religious or political group", "ORGANIZATION": "the name of a company, institution or other organisation", "PERSON": "a person's name", "PHONE_NUMBER": "a telephone number", "STREET_ADDRESS": "a street address or postal address", "TITLE": "a personal or professional title such as Dr. or Mrs.", "US_DRIVER_LICENSE": "a US driver's licence number", "US_SSN": "a US social security number", "ZIP_CODE": "a postal or ZIP code"}, "over": "request"}, "halu": {"type": "span", "instructions": "Which spans of the answer are not supported by the context?", "criteria": {"unsupported": "a claim not supported by the context"}}, "domain": {"type": "choice", "instructions": "Which subject area is this request about?", "over": "request", "criteria": {"health": "medicine, clinical practice, nutrition, ageing or sexual health", "math": "arithmetic, algebra, geometry, statistics or other mathematics", "other": "a subject that fits none of the listed areas"}}}}, "rows": [{"head": "router", "head_reason": "id", "label_alias": null, "n_tokens": 772, "seg_lens": {"user": 27, "context": 39, "answer": 39}}, {"head": "router", "head_reason": "id", "label_alias": null, "n_tokens": 269, "seg_lens": {"user": 27, "context": 39, "answer": 39}}], "head_calls": [{"kind": "q", "cand": "q0_cand", "query": "q0_query", "logits": [[0.5404365062713623, -6.5386433601379395, -3.9254047870635986, -3.529416084289551]], "row": 0}, {"kind": "span", "head": "router", "words": "s1_words", "labels": "s1_labels", "logits": [[-9.851020812988281, -15.027624130249023, -14.757858276367188, -12.530649185180664, -3.660945415496826, -12.923664093017578, -17.943824768066406, -16.326257705688477, -5.620431900024414, -7.599363803863525, -11.234650611877441, -5.757130146026611, -5.652872085571289, -8.116801261901855, -9.238210678100586, -6.802857398986816, -6.324886322021484], [-16.28253936767578, -17.80463981628418, -18.329021453857422, -16.44207763671875, -10.134305953979492, -17.914127349853516, -20.482263565063477, -18.635469436645508, -10.971238136291504, -11.935432434082031, -16.362531661987305, -8.079880714416504, -9.401307106018066, -14.166604995727539, -16.919057846069336, -14.731834411621094, -12.536507606506348], [-16.975248336791992, -21.33708953857422, -22.336502075195312, -20.949878692626953, -12.478657722473145, -21.414112091064453, -24.373680114746094, -23.24188232421875, -13.325860023498535, -13.795920372009277, -16.87654685974121, -11.636231422424316, -11.92214584350586, -16.560941696166992, -20.60035514831543, -17.067073822021484, -14.519638061523438], [-16.7723445892334, -21.27077293395996, -22.190185546875, -21.27130889892578, -12.792131423950195, -22.414506912231445, -24.66496467590332, -23.94645118713379, -13.870166778564453, -14.444552421569824, -17.01270866394043, -11.867671012878418, -13.354513168334961, -16.251331329345703, -21.633752822875977, -18.205692291259766, -16.024608612060547], [-16.7723445892334, -21.27077293395996, -22.190185546875, -21.27130889892578, -12.792131423950195, -22.414506912231445, -24.66496467590332, -23.94645118713379, -13.870166778564453, -14.444552421569824, -17.01270866394043, -11.867671012878418, -13.354513168334961, -16.251331329345703, -21.633752822875977, -18.205692291259766, -16.024608612060547], [0.11913681030273438, -8.998804092407227, -8.105165481567383, -7.355640411376953, 0.8499364852905273, -5.159857273101807, -10.962669372558594, -10.69532585144043, -2.300189971923828, -2.142609119415283, 3.7711997032165527, -2.6488523483276367, -3.3644497394561768, 0.5961573123931885, -4.22589111328125, -4.46975040435791, -4.146326065063477], [-0.375388503074646, -8.638716697692871, -7.520653247833252, -6.3430376052856445, 0.8605620861053467, -4.922619819641113, -10.513166427612305, -10.039107322692871, -2.3470044136047363, -2.1044399738311768, 2.319047451019287, -3.095822811126709, -3.0459518432617188, 0.2876932621002197, -3.672348976135254, -4.247696399688721, -4.059322357177734], [-11.97199535369873, -15.74243450164795, -15.960700988769531, -12.123148918151855, -2.198594570159912, -14.888036727905273, -18.449371337890625, -13.958887100219727, -5.779473781585693, -7.8383917808532715, -11.294285774230957, -2.836668014526367, -3.8323404788970947, -9.61889362335205, -9.943918228149414, -6.213159561157227, -5.016597747802734], [-2.930969715118408, -8.456787109375, -8.0104341506958, -3.1965346336364746, 2.791138172149658, -5.6602864265441895, -9.054672241210938, -4.491463661193848, -3.634566068649292, -2.6940877437591553, 0.6949470043182373, -2.568450927734375, -3.0842747688293457, -2.6646759510040283, -5.099068641662598, -5.331076622009277, -4.802918434143066], [-17.96658706665039, -18.01045799255371, -19.822132110595703, -18.21443748474121, -12.168895721435547, -19.514663696289062, -20.82657241821289, -19.630020141601562, -13.630260467529297, -13.030271530151367, -18.71689224243164, -10.937429428100586, -11.503185272216797, -16.562448501586914, -20.173627853393555, -17.357961654663086, -14.826516151428223], [-17.96658706665039, -18.01045799255371, -19.822132110595703, -18.21443748474121, -12.168895721435547, -19.514663696289062, -20.82657241821289, -19.630020141601562, -13.630260467529297, -13.030271530151367, -18.71689224243164, -10.937429428100586, -11.503185272216797, -16.562448501586914, -20.173627853393555, -17.357961654663086, -14.826516151428223], [-16.90250587463379, -18.278526306152344, -18.84981346130371, -17.358551025390625, -11.352295875549316, -17.4305362701416, -20.804384231567383, -19.499237060546875, -12.09277629852295, -12.66122817993164, -17.810014724731445, -10.43729305267334, -9.796697616577148, -16.462594985961914, -17.877269744873047, -15.53689193725586, -12.608529090881348], [-17.571109771728516, -18.02204704284668, -18.949459075927734, -17.84019660949707, -12.319219589233398, -18.332033157348633, -20.70317840576172, -19.956119537353516, -13.069973945617676, -13.284128189086914, -18.666032791137695, -11.275001525878906, -11.1100492477417, -16.783119201660156, -19.03497314453125, -16.65223503112793, -14.116575241088867], [-17.20058250427246, -17.913480758666992, -19.152984619140625, -18.49874496459961, -12.374701499938965, -18.944435119628906, -20.980005264282227, -20.324554443359375, -13.318517684936523, -13.295575141906738, -18.446435928344727, -11.100875854492188, -11.361801147460938, -16.607181549072266, -19.333765029907227, -16.73701286315918, -14.240310668945312], [-10.385387420654297, -15.364139556884766, -15.511908531188965, -13.689546585083008, -3.9188613891601562, -13.724010467529297, -18.471012115478516, -16.611557006835938, -5.779675483703613, -7.293036460876465, -12.180856704711914, -4.711075782775879, -4.105204105377197, -10.222349166870117, -10.208038330078125, -5.902805805206299, -4.506038188934326], [-10.814464569091797, -14.951911926269531, -15.325828552246094, -12.80671501159668, -3.280482530593872, -13.21613883972168, -17.812551498413086, -15.572422981262207, -5.481819152832031, -7.064236164093018, -12.217747688293457, -4.450317859649658, -3.697108030319214, -10.052149772644043, -9.760396957397461, -5.52978515625, -4.171611309051514], [-14.402262687683105, -17.102127075195312, -17.262144088745117, -15.675093650817871, -8.45707893371582, -15.754737854003906, -19.572450637817383, -17.654773712158203, -9.236448287963867, -10.762482643127441, -15.542367935180664, -7.367783546447754, -6.410301208496094, -14.149118423461914, -13.918294906616211, -11.3816499710083, -8.444021224975586], [-12.651286125183105, -16.529403686523438, -16.55528450012207, -14.945316314697266, -6.345352649688721, -15.065194129943848, -18.96143341064453, -17.375417709350586, -7.089203834533691, -9.234535217285156, -13.864068031311035, -5.386238098144531, -4.79850959777832, -12.170395851135254, -11.348276138305664, -7.870039463043213, -5.878173828125], [-8.939207077026367, -13.950385093688965, -13.887860298156738, -11.350774765014648, -3.2517220973968506, -11.77290153503418, -16.509742736816406, -14.612834930419922, -6.24839973449707, -7.029216766357422, -10.663041114807129, -6.143183708190918, -6.020900249481201, -8.616498947143555, -8.805045127868652, -6.615787982940674, -6.1211934089660645], [-14.634203910827637, -16.696504592895508, -16.7551212310791, -15.17517375946045, -8.941736221313477, -15.509604454040527, -18.92809295654297, -17.477008819580078, -9.083824157714844, -10.468768119812012, -15.845718383789062, -7.56320333480835, -7.45651388168335, -14.0153226852417, -14.346378326416016, -11.850302696228027, -9.550122261047363], [-12.652865409851074, -16.130496978759766, -16.09650993347168, -14.029860496520996, -5.189237594604492, -14.40012264251709, -18.68414306640625, -16.8243408203125, -6.2160868644714355, -8.960195541381836, -13.997604370117188, -5.3901848793029785, -4.3825273513793945, -11.94284439086914, -10.51372241973877, -6.524692058563232, -5.048408508300781], [-15.082358360290527, -16.506101608276367, -16.36886215209961, -14.599099159240723, -8.522944450378418, -14.7816801071167, -18.691444396972656, -17.160917282104492, -9.380626678466797, -11.312457084655762, -16.12392234802246, -8.477106094360352, -7.283524036407471, -14.228918075561523, -13.477392196655273, -11.19268798828125, -8.870052337646484], [-18.80125617980957, -21.510345458984375, -22.83747100830078, -22.03952980041504, -15.80392837524414, -22.6486759185791, -24.405366897583008, -23.06026840209961, -17.308101654052734, -16.587818145751953, -19.37947654724121, -14.987780570983887, -15.041773796081543, -18.377851486206055, -22.79374122619629, -20.769546508789062, -18.1580810546875]], "row": 0}, {"kind": "span", "head": "router", "words": "s2_words", "labels": "s2_labels", "logits": [[-5.667586803436279], [-4.148900508880615], [-2.493729829788208], [-0.7364544868469238], [-0.2502114176750183], [3.92134428024292], [1.7255499362945557], [-2.568751811981201], [-3.1423110961914062], [-4.012135028839111], [-4.174318313598633], [-3.6643919944763184], [-4.65214729309082], [-5.806663990020752], [-5.589629650115967], [-5.320010185241699], [-3.489220142364502], [-4.177278518676758], [-4.293692111968994], [-4.44113302230835], [-4.547778129577637], [-5.308318138122559], [-6.041932106018066], [-6.042882442474365], [-5.594691753387451], [-4.543209552764893], [-4.973324298858643]], "row": 1}], "predict": {"answers": [{"id": "pii", "type": "span", "target_part": "user", "spans": [{"start": 8, "end": 17, "label": "PERSON", "probability": 0.983367919921875, "text": "Tom Baker"}, {"start": 19, "end": 40, "label": "EMAIL_ADDRESS", "probability": 0.9851056337356567, "text": "tom.baker@example.com"}], "threshold": 0.2914, "threshold_rule": "pii:length", "head": "router", "head_reason": "id"}, {"id": "halu", "type": "span", "target_part": "answer", "spans": [{"start": 19, "end": 29, "label": "unsupported", "probability": 0.7782317996025085, "text": "to 6 grams"}], "threshold": 0.35, "threshold_rule": "halu", "head": "router", "head_reason": "id"}, {"id": "domain", "type": "choice", "answer": "health", "probabilities": {"health": 0.9621185645193945, "math": 0.004639298028680393, "other": 0.03324213745192508}, "abstain_probability": 0.04287965117790319}], "meta": {"tokens": {"user": 27, "context": 39, "answer": 39}, "windows": 0, "sequences": 2}}} diff --git a/tests/vela/fixtures/head-input-example-request.safetensors b/tests/vela/fixtures/head-input-example-request.safetensors new file mode 100644 index 0000000000000000000000000000000000000000..8e69195b81ec49dca3a53dc16a4795abac613fa8 GIT binary patch literal 299464 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�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

gFNef%louSTKG9pECtC zWqzhaZoqbOD*Fq|m^gBp*;83C8x@7>hc(HC@iX|pMJ?q^Q)}?-UMNql_r+DqGjM}N zv#?{=U~fcc*!{9h+HCQONpHU3AvHTe&e9xq$@asvPS0z8D}Qp`SG8QrHB>Y)dWl5; zj}D#nYc_xR_$CIgn@gjUWW)#852WUk9?+P{2l+#-a2Vt#<`2*8lgvwU#LewvxZK$T ztoPPJ49Q!Fmn(MS>Hi+#(F!?ms+EP4(%pi;_$9mwv3`NnFcRph&}Djm8* z6W{MYAn{X(VUOp?L624w&l32ergJU$gWEel zc_ykk9f9SFS}?+Y6rH7Xopm?t<9{+e!R)$_BUYRt+8$a0`G@yF^MQPLUZ(-oZ3S%7 zq9Zs_K>c+lCO+i4k;EkbX43?;_oekwk9IbzZ{DegCyXaeO;n)Yzh6k zdpZ18Vz%cTAF+u8rsKSp5(Y@x5{S#86X)c<(;W+bsr?;je7S z_TErP5qNT$#|HD+;qlBXWEecFKP7sQGaTf8j};i=XNl1fA(H9 ziu5GQNXE=PbfR1abE#blUxoaCj>1}c+*k(Z3%%IIae=r#CS3IPhB`DG{$j>8m3Y;5 zD_&aOUs~3-kz06Ff&K0n_UYnEI$!X1y}i7cs>gWn{A_JrJb60n80rEJ>Hd7o=N)J% zJAlh9*T;q1f8&R81?l9KU$JNP3+%eAL5E-LAZJgEqB|X|=z^*oZf4xUN&^B#E9({E zK*?xWhK3;d_!?XuO@&phXYgi32J}o-uv@+A2bApb!|6Y5rLB`DV_wrvvYs!4H$&D_ zx#5$+^jHjjY1@Q9GR-k_i#Bc0n#5(=ofVIwcvJdw96Mim$)A6v{Sqv#>MY0 zvRgi*h^o<08252Hsy9D?!5d|zt4jRH9eX1_VoVl{@Rea_Jyprb4VAR>eF9b~xrzVW z$+mM2Urv|r{R01O=_Q{OR+4ke-|%dcT0C|99(Go_;fOvus8IVDjwgjebhQRnjc#JG zv7xYJwjvz13+6L~4n@X$U2$s2KUfxans~KzuTJo*jL33KfjgF!QPrW|$Sw>i?{<;6fkXxM2%@GjKdD z`da{=ntmAC*8;Zu*a3SRp3%2z({5y_>Ob6-wZ`s4a5

    -q&1d!$5a59ht;r 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

SnbMX2RJBU()G- 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