Upload README.md with huggingface_hub
Browse files
README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
library_name: interlock
|
| 4 |
+
pipeline_tag: text-classification
|
| 5 |
+
tags:
|
| 6 |
+
- agent-safety
|
| 7 |
+
- tool-use
|
| 8 |
+
- guardrails
|
| 9 |
+
- ai-safety
|
| 10 |
+
language:
|
| 11 |
+
- en
|
| 12 |
+
---
|
| 13 |
+
|
| 14 |
+
# Interlock
|
| 15 |
+
|
| 16 |
+
Interlock judges a *proposed agent tool call* against *what the user actually
|
| 17 |
+
asked for*. Content shields read the request and ask whether it is harmful.
|
| 18 |
+
Interlock reads the request/action pair and asks a different question: is this
|
| 19 |
+
call **more** than what was asked?
|
| 20 |
+
|
| 21 |
+
It is deliberately blind to where a deviation came from. A widened `path`
|
| 22 |
+
argument looks the same whether it originated in a prompt injection, a
|
| 23 |
+
jailbreak, or an ordinary model mistake, and the defence is the same either
|
| 24 |
+
way.
|
| 25 |
+
|
| 26 |
+
## Output
|
| 27 |
+
|
| 28 |
+
Three-valued, never binary:
|
| 29 |
+
|
| 30 |
+
| decision | meaning |
|
| 31 |
+
|-----------|---------|
|
| 32 |
+
| `allow` | the call stays within what the request asked for |
|
| 33 |
+
| `confirm` | the call should be put to the user before it runs |
|
| 34 |
+
| `block` | the call goes materially beyond the request |
|
| 35 |
+
|
| 36 |
+
The three decisions are `allow`, `confirm`, `block`. Alongside the decision the model
|
| 37 |
+
predicts a deviation type, one of `none`, `scope_expansion`, `unrequested_action`, `irreversible_unconfirmed`, `target_mismatch`, `out_of_scope`, `privilege_escalation`.
|
| 38 |
+
|
| 39 |
+
`confirm` is a first-class outcome. Collapsing it into `block` would trade a
|
| 40 |
+
question for a refusal on exactly the cases where the request is ambiguous.
|
| 41 |
+
|
| 42 |
+
## Two tiers
|
| 43 |
+
|
| 44 |
+
**Tier 1 -- linear (1080 parameters).** A two-headed multinomial
|
| 45 |
+
logistic regression over 107 structured request/action alignment
|
| 46 |
+
features. Pure NumPy at inference: no tokeniser, no torch. This is the tier
|
| 47 |
+
that runs on every agent turn. Shipped as `interlock_linear.npz`, with the
|
| 48 |
+
fitted operating point in `policy.json`.
|
| 49 |
+
|
| 50 |
+
**Tier 2 -- encoder (optional).** ModernBERT-base with a decision head and a
|
| 51 |
+
deviation head, reading a role-annotated text rendering of the same pair. More
|
| 52 |
+
accurate where the wording rather than the structure carries the signal, and
|
| 53 |
+
correspondingly slower. Shipped as `interlock.onnx` when it has been trained
|
| 54 |
+
and exported; the export is verified against the torch model to within 1e-3 on
|
| 55 |
+
the raw logits before it is published.
|
| 56 |
+
|
| 57 |
+
A third file, `interlock-linear.gguf`, is a weight container for tier 1 with
|
| 58 |
+
its feature names and operating point attached. It is not a runtime: llama.cpp
|
| 59 |
+
has no architecture for this classification head and cannot serve it. The
|
| 60 |
+
verified runtimes are NumPy for tier 1 and ONNX Runtime for tier 2.
|
| 61 |
+
|
| 62 |
+
## Evaluation, and the split that makes it mean something
|
| 63 |
+
|
| 64 |
+
The train/test split is taken at **tool family** granularity, not at row
|
| 65 |
+
granularity. Training and validation draw on `fs, shell, mail, calendar, issues`.
|
| 66 |
+
The held-out split draws on `browser, crm, storage, db` -- every tool schema
|
| 67 |
+
in it is one the model has never seen. The split is verified against the files
|
| 68 |
+
on disk, not just asserted in code.
|
| 69 |
+
|
| 70 |
+
Measured for tier 1:
|
| 71 |
+
|
| 72 |
+
| split | over-blocking | deviation detection |
|
| 73 |
+
|-------|---------------|---------------------|
|
| 74 |
+
| validation (seen families, unseen world) | 2.9% | 88.0% |
|
| 75 |
+
| held-out families (unseen tool schemas) | 1.8% | 79.3% |
|
| 76 |
+
|
| 77 |
+
Over-blocking is the fraction of *legitimate* calls that were interrupted, and
|
| 78 |
+
it is the headline number. A shield that interrupts real work gets switched
|
| 79 |
+
off, and a switched-off shield detects nothing. Detection is reported second
|
| 80 |
+
for that reason, not first.
|
| 81 |
+
|
| 82 |
+
Latency, timing a full check per call including encoding: 0.247 ms mean, 0.663 ms p95 over 400 single-threaded calls on arm64.
|
| 83 |
+
Timing the model's arithmetic alone would understate what a deployment pays.
|
| 84 |
+
|
| 85 |
+
## Intended use
|
| 86 |
+
|
| 87 |
+
Interlock sits between an agent's proposed tool call and its execution. Given
|
| 88 |
+
the user's request, the proposed call and the tool's schema, it returns a
|
| 89 |
+
verdict that a harness can act on: proceed, ask the user, or refuse. It is
|
| 90 |
+
designed for agent runtimes where tool schemas are declared and where a
|
| 91 |
+
confirmation prompt is a cheaper failure than an unwanted side effect.
|
| 92 |
+
|
| 93 |
+
```python
|
| 94 |
+
from interlock.model import load_shield
|
| 95 |
+
|
| 96 |
+
shield = load_shield("artifacts")
|
| 97 |
+
verdict = shield.check("archive the Q3 notes", {"tool": "fs.delete_file", "arguments": {"path": "notes/"}})
|
| 98 |
+
print(verdict.decision, verdict.deviation)
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
It is not a content moderation model, not a prompt-injection detector, and not
|
| 102 |
+
a substitute for sandboxing or for asking the user.
|
| 103 |
+
|
| 104 |
+
## Limitations
|
| 105 |
+
|
| 106 |
+
- **Synthetic data.** Every episode, tool schema and deviation in training is
|
| 107 |
+
generated. The tool families model common operation shapes rather than any
|
| 108 |
+
particular product's API, and no real service was contacted at any point.
|
| 109 |
+
Performance on production agent traffic is unmeasured here.
|
| 110 |
+
- **English only.** Requests and tool descriptions are English. Nothing has
|
| 111 |
+
been measured in any other language.
|
| 112 |
+
- **One layer among several.** Interlock reads the correspondence between a
|
| 113 |
+
request and a call. It does not read the content of a payload for harm, does
|
| 114 |
+
not sandbox anything, and cannot see effects that occur outside the tool
|
| 115 |
+
call it is shown.
|
| 116 |
+
- **It does not guarantee safety.** An `allow` verdict means this shield found
|
| 117 |
+
no boundary deviation, which is a weaker statement than "this call is safe".
|
| 118 |
+
Deploy it beside content shields, sandboxing and human confirmation, not
|
| 119 |
+
instead of them.
|
| 120 |
+
- **Unseen tools cost accuracy.** Detection falls from 88.0% to
|
| 121 |
+
79.3% on held-out tool families. The over-blocking rate holds, so
|
| 122 |
+
the degradation shows up as missed deviations rather than as new
|
| 123 |
+
interruptions, but it is real.
|
| 124 |
+
- **The operating point is a choice.** Thresholds were fitted against an
|
| 125 |
+
explicit over-blocking budget on validation data. A deployment with a
|
| 126 |
+
different tolerance for interruption should refit them rather than inherit
|
| 127 |
+
these.
|
| 128 |
+
|
| 129 |
+
## Files
|
| 130 |
+
|
| 131 |
+
| file | what it is |
|
| 132 |
+
|------|------------|
|
| 133 |
+
| `interlock_linear.npz` | tier-1 weights, the default serving path |
|
| 134 |
+
| `policy.json` | fitted decision thresholds |
|
| 135 |
+
| `train_report_linear.json` | measured metrics for tier 1 |
|
| 136 |
+
| `interlock.onnx` | tier-2 graph, when the encoder has been trained |
|
| 137 |
+
| `interlock-linear.gguf` | tier-1 weight container, not a runtime |
|
| 138 |
+
| `latency.json` | measured per-call latency and peak RSS |
|
| 139 |
+
|
| 140 |
+
Card generated 2026-08-30T01:25:20+00:00 for `NagaYu/interlock`.
|