Downloads · 30 days
13
26% of all-time downloads
lucataco/gliner2.5-cua-grounder-macos-v2
gliner2.5-cua-grounder-macos-v2 is a text classification model from lucataco. Use it when you need a label for a piece of text. It is set up for gliner2. The card lists the license as apache-2.0.
A local, text-only action chooser beneath a computer-use planner, with a separately trained verified-effect gate. Given one planner step and a short menu of fully specified actions, the frozen selector proposes a supp…
Downloads · 30 days
13
26% of all-time downloads
All-time downloads
50
Public
Parameters
287M
1.2 GB on disk
Likes
1
Public
Click a slice to open those files.
.safetensors1.1 GB · 99%
From the Hugging Face model README
A local, text-only action chooser beneath a computer-use planner, with a separately trained verified-effect gate. Given one planner step and a short menu of fully specified actions, the frozen selector proposes a supplied action ID; the gate estimates whether that proposal will produce the requested application effect, using explicit current-observation evidence.
Fine-tuned from Fastino's GLiNER2.5 Multi.
This repository contains self-contained merged FP32 selector weights, loader assets, and the v2.2 verified-effect gate (gate.json + gate_calibration.json).
Code, training scripts, and detailed experiment artifacts are maintained separately.
| Property | Value |
|---|---|
| Architecture | GLiNER2.5 BoundaryExtractor, mDeBERTa-v3-base encoder |
| Parameters | 287,355,159 |
| Weights | Merged FP32 safetensors, approximately 1.07 GiB |
| Base revision | 235cf92d6d4318da9bfca0d08975c8fa7250d13b |
| Adaptation | Rank-16 LoRA (alpha 32, dropout 0); 2,715,664 trainable parameters; selected step 100 of 400 |
| Gate | 14-feature logistic verified-effect gate, L2 0.001, threshold 0.95 at temperature 1.0; transformer frozen |
| Fine-tuning / evaluation language | English; multilingual grounding untested |
| Candidate bounds | 2–32, including reobserve and abstain |
| Encoded token budget | 4,096, including schema and descriptions |
| Verified runtime | Python 3.12, GLiNER2 2.0.0, PyTorch 2.14.0, Transformers 4.57.6 |
pip install "gliner2[local]==2.0.0" "torch==2.14.0" "transformers==4.57.6" "huggingface-hub==0.36.2" "sentencepiece>=0.2,<1" "protobuf>=4,<8"
Use AutoExtractor, not the legacy span-only GLiNER2 loader. The example uses
GLiNER's public classification scorer and preserves the training task/instruction:
import json
import torch
from huggingface_hub import snapshot_download
from gliner2 import AutoExtractor
from gliner2.classification import Classifier, ClassificationSchema
MODEL_ID = "lucataco/gliner2.5-cua-grounder-macos-v2"
path = snapshot_download(MODEL_ID) # Set revision="<commit SHA>" to pin all files together.
device = "mps" if torch.backends.mps.is_available() else "cpu"
model = AutoExtractor.from_pretrained(path).float().to(device).eval()
chooser = Classifier(model)
instruction = (
"Select the supplied action that performs the current planner instruction on the described control. "
"Match the requested operation, control name, section and value. Choose reobserve when the observation "
"is incomplete or loading. Choose abstain if no supplied action matches. "
"Typing directly targets a field and does not require a separate click."
)
candidates = {
"a1": 'Type "London" into textbox "Departure city"',
"a2": 'Type "London" into textbox "Destination city"',
"a3": 'Type "London" into textbox "Passenger name"',
"reobserve": "Obtain a fresh observation because the current observation is incomplete or loading.",
"abstain": "Do not act because no supplied action matches the planner instruction.",
}
labels = {f"c{i:02d}": description for i, description in enumerate(candidates.values())}
schema = ClassificationSchema().single("driver_action", labels, instruction=instruction)
text = json.dumps(
{"planner_step": "Enter London in the Destination city field."},
ensure_ascii=False, separators=(",", ":"),
)
scores = chooser.score(text, schema)
probabilities = {
candidate_id: scores.probability("driver_action", label)
for candidate_id, label in zip(candidates, labels, strict=True)
}
selected_id = max(probabilities, key=probabilities.get)
print(selected_id) # a2
Keep the model resident across calls. After download, load the local directory
with HF_HUB_OFFLINE=1 for offline inference. Root weights already include the
adapter; no separate base-model download is needed.
Transformers 4.57.6 may emit a spurious Mistral-regex warning for this non-Mistral tokenizer. Preserve the supplied tokenizer; export and scoring parity were verified.
The selector alone has a null execution threshold on its own calibration split: no threshold met the 5% error / 20 accepted-case criterion, so raw selector probabilities must not gate execution. Use the bundled gate with explicit current-observation evidence.
In the v2 source tree today (exact training invocation — this is what the gate's
selector_signature binds):
uv run gliner-cua cua-gate-choose \
--model runs/cua-v2-pilot/train/best \
--gate huggingface/gate.json \
--calibration huggingface/gate_calibration.json --jsonl
Each line must contain the gate envelope (cua.gate_request_v1) with actual current
observation evidence. gliner-cua cua-gate-choose --help documents the envelope fields.
gate.execute_probability estimates requested-effect correctness; the nested choice retains
the selector's original probabilities. Nonready requests return reobserve with no effect
estimate. The gate only covers com.apple.TextEdit and local.browser-forms under the
background-save execution contract; other apps return abstain (unmeasured_application).
Note: this repo names the gate calibration gate_calibration.json
(the training tree calls it calibration.json).
HF-path note: the HF model.safetensors is functionally identical to the training adapter
(334/334 state tensors bit-identical; identical logits, proposals, gate features and
effect probabilities on spot checks), but the current GatedCUAChooser binds
selector_signature to the training path, device (mps), threads (8) and adapter-vs-merged
layout, so loading the gate directly from an HF snapshot path raises
"Gate was trained with a different target selector/deployment" today. The bundled
gate.json / gate_calibration.json verify against the exact invocation above; HF-path
gate loading needs a small loader update to accept merged-weight equivalence.
Planner step → application-owned menu → selector proposes ID → gate estimates effect → Driver executes → verify effect
planner_step, optional regions (structured, already
extracted observations), and recent_outcomes (nonempty history outcome strings).
An optional local semantic context is packed as observation.c00, c01, etc. Escape the description
markers [P], [L], [C], [E], [R], [DESCRIPTION], [EXAMPLE], [OUTPUT]
by replacing square brackets with braces; replace parentheses with braces and
collapse whitespace. The simple example above needs no escaping.driver_action task and instruction above. The selector proposal is the
maximum-logit executable candidate; report softmax probabilities at temperature 1. These are not calibrated
confidence or TypeSafe's separately defined confidence statistic.The tested wire schemas are cua.jev_choice_request_v1 / cua.jev_choice_v1 from
CUA PR 3916, pinned at
201732fffd81a40818be7ce2e04269aec962bc42, wrapped for gating as cua.gate_request_v1 /
cua.gate_decision_v1. This model generates neither coordinates
nor tool calls and does not consume screenshot pixels.
| Model | Overall | Execute | Abstain | Reobserve | 8 / 16 / 32 choices | Warm p50 |
|---|---|---|---|---|---|---|
| v1 selector | 155/256 (60.5%) | 128/165 (77.6%) | 21/31 (67.7%) | 6/60 (10.0%) | 68.6% / 63.5% / 49.4% | 82.0 ms |
| v2 selector | 197/256 (77.0%) | 164/165 (99.4%) | 11/31 (35.5%) | 22/60 (36.7%) | 76.7% / 78.8% / 75.3% | 82.4 ms |
Inputs and acceptable-ID labels match across models. Executable-case accuracy rose from 77.6% to 99.4%, but abstention accuracy fell from 67.7% to 35.5%. Menus include 8/16/32-choice menus, same-name controls across sections, wrong-operation/value alternatives, equivalent duplicates, missing targets, and partial/loading captures. Workflow vocabularies and goal templates are split; construction rules are shared. These are not real-app execution results.
Fitted selector temperature: 1.8424. Selector execution threshold: None (null means reject all executions — no threshold met the 5% error / 20 accepted-case criterion on the dedicated calibration split). Deploy the gate below for execution decisions.
| Set | Requests | Accepted | Wrong accepted effects | Correct-effect coverage |
|---|---|---|---|---|
| Merged test (task-family-disjoint) | 200 | 120 | 0 | 120/200 = 60.0% |
| Fresh confirmation (4 new families, collected after policy freeze) | 80 | 40 | 0 | 40/80 = 50.0% |
| Combined real held-out | 280 | 160 | 0 | 160/160 verified successes accepted, 0/56 verified failures accepted |
Controlled workflows in real TextEdit (background AX insertion + PID-addressed native save,
file-byte verification) and an owned browser form application (isolated profile, DOM-state
callbacks), with both apps in every split. Nonready requests (partial/loading/superseded/expired/unknown)
are deterministic reobserve decisions. Gate calibration: temperature 1.0, threshold 0.95
(correctness-probability floor 1 - max_error), 120/120 accepted with 0 errors on calibration families.
Feature version verified-effect-features-v5-operation-aware; L2 0.001 selected on validation.
The two hard context/operation rules never fired on real held-out data (rule_rejected=0 at calibration).
| Policy | Score |
|---|---|
| v2 selector alone | 197/256 (77.0%) |
| v2 selector + v7 gate | 256/256 (100%) |
The diagnostic told the authors the failure modes were "wrong section" and "wrong operation",
and two of the fixes are hard rules written for exactly those — so 100% confirms the rules do
what they were written to do. The independent evidence is the real held-out table above, which
never degraded and on which the rules never fired. See the iteration record in the source tree
(docs/V22_GATE_ITERATION.md).
12/12 passed (6 TextEdit + 6 browser): successful execution, missing-target abstention,
"any target" instructions, duplicate valid buttons, nonready refusals, and recovery with a real
prior deferral in history. Rejected proposals were not dispatched; successful actions were
independently verified.
Local timings are FP32 Apple MPS with eight CPU threads. Warm timing excludes model loading and the first request. These are not hardware-normalized timings or end-to-end workflow speedups. No Jev outputs were used for training or distillation.
| Setting | Value |
|---|---|
| Owned synthetic train / validation / calibration / test | 960 / 192 / 192 / 256 |
| Objective | Multi-positive listwise cross-entropy (Brier weight 0.0) |
| LoRA | Rank 16, alpha 32, dropout 0 |
| Targets | Encoder query/key/value/dense projections and classification head |
| Batch size / learning rate | 4 / 0.0003 |
| Steps / seed | 400 / 42 |
| Selection | Validation macro-kind accuracy, then NLL; step 100 (later training regressed, final/ not selected) |
| Training time | Approximately 689 seconds on Apple MPS |
| Gate data | 800 verified traces (320 target-app + 480 browser near-miss, task-family-disjoint splits) |
| Gate fit | L2-regularized binary log loss on executed ready proposals; normalization fit on training only |
Menus were resampled, reordered, and rekeyed during training. Labels derive from owned fixture definitions. Live confirmation traces were not used for training. The loss maximizes total probability across all valid candidate IDs. The gate never retrains the transformer.
Export verification (run before upload): all state tensors bit-identical after reloading the
merged checkpoint; test-request logits and selections match the selected adapter; gate +
calibration hashes bind the frozen selector identity (f6414dcb977688e177c38681c0122586348a224151690d9de4248e6be2f3e2fe).
49ec5ea8cc495a5ffb2f8bf99b597cebf8f232ce3f91d5279a617ca485c251c853d8f9209584270bf8d538cc4bf5bed10fabd8fede150c9c2cb30b303e50e640bb41ea6ba15d6a92253a4ff07bef1541dab91dc872fa210b311e648e2a3ce3e1Intended for experimental grounding of short, well-described menus beneath a planner, plus a controlled TextEdit/browser execution gate. Candidate retrieval, visual perception, long-horizon planning, and tool execution are external. Natural planner language, unfamiliar apps, large or ambiguous menus, adversarial UI text, and unannounced state changes need broader testing. The gate is a controlled target-app pilot (two app IDs, scripted workflows, recurring construction patterns), not a guaranteed error bound on arbitrary applications; actual app outcomes must still be checked, and the gate is not a replacement for Driver's capability/refusal checks. Synthetic cases contain explicit textual cues. Out-of-distribution calibration, multilingual grounding, and the base model's general extraction abilities after this fine-tune have not been evaluated. macOS describes the tested integration; inference itself is ordinary PyTorch.
Fine-tune: lucataco. Base model/library:
Fastino AI. Encoder:
Microsoft mDeBERTa-v3-base.
Apache-2.0, with the encoder's MIT license retained in LICENSE.mdeberta.
See NOTICE for modifications. This is an independent experimental release.
@misc{lucataco2026cuagrounderv2,
title = {GLiNER2.5 CUA Grounder for macOS, v2},
author = {lucataco},
year = {2026},
url = {https://huggingface.co/lucataco/gliner2.5-cua-grounder-macos-v2}
}
@misc{zaratiana2025gliner2efficientmultitaskinformation,
title = {GLiNER2: An Efficient Multi-Task Information Extraction System with Schema-Driven Interface},
author = {Urchade Zaratiana and Gil Pasternak and Oliver Boyd and George Hurn-Maloney and Ash Lewis},
year = {2025},
eprint = {2507.18546},
archivePrefix = {arXiv},
url = {https://arxiv.org/abs/2507.18546}
}