CompactAI commited on
Commit
35700de
·
verified ·
1 Parent(s): 449596d

Upload 11 files

Browse files
Files changed (11) hide show
  1. README.md +226 -3
  2. config.json +28 -0
  3. infer.py +115 -0
  4. model.safetensors +3 -0
  5. modeling.py +198 -0
  6. policy.json +34 -0
  7. policy.py +239 -0
  8. refund_examples.txt +6 -0
  9. requirements.txt +3 -0
  10. scores.json +179 -0
  11. tokenizer.json +0 -0
README.md CHANGED
@@ -1,3 +1,226 @@
1
- ---
2
- license: mit
3
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Glint-Router-1M
2
+
3
+ a prompt router in 985,826 parameters. you hand it a user request, it hands back a domain, a complexity score, code/math/reasoning flags, and which model tier should take the job. one forward pass, around 0.06 ms on a gpu, 0.2 ms on cpu. the release: weights, tokenizer, two inference files, the routing policy as an editable json document, every score we measured. no training code, no pipeline, no framework. `pip install torch tokenizers safetensors` and you are routing.
4
+
5
+ the target was SupraLabs/Supra-Router-51M, which does the same job with 51,786,240 parameters. we came in at 1/52nd the size and beat it on data neither model had seen.
6
+
7
+ ## what it actually is
8
+
9
+ - a bidirectional encoder with typed heads. 3 layers, dim 128, 8 heads, ffn hidden 208, 4096-token bpe vocab, 256-token context.
10
+ - the heads: domain over a closed 25-class taxonomy, complexity 1 to 5 as an ordinal head, four binary flags (code, math, reasoning, long_output), a routing head, and a 64-d projection used to add your own categories later.
11
+ - 985,826 parameters. the embedding table is 524,288 of them, the three blocks are 418,560, the heads are the remaining 25k.
12
+ - everything comes out of one forward pass. there is no decode loop and nothing to parse.
13
+
14
+ ## why an encoder
15
+
16
+ supra generates its answer as text: `Domain: Programming | Complexity: 3 | Math: F | Code: T | Route: big model | Justification: ...`. about 40 greedy decode steps, one argmax at a time, under a causal mask.
17
+
18
+ the causal mask is the expensive part. read "write a short poem about a Python" and the decision is already forming; the word "snake" arrives afterward and cannot reach back. an encoder reads the whole prompt before it commits. that is the entire architectural argument, and the trap slice below is where you can see it pay.
19
+
20
+ the rest follows from dropping generation. no output format to malform, so no parse failures. probabilities instead of tokens, so the routing decision can be arithmetic. 40 sequential steps collapse to 1.
21
+
22
+ ## the numbers
23
+
24
+ house rule, same as always: real scores, no dressing, including the ones that make us look bad.
25
+
26
+ both obvious comparisons are rigged and we are going to say so before showing them. our own validation set uses our label pipeline, which this model trained on and supra never saw. supra's 992-row dataset is supra's training data, so scoring it there is asking a model to recite. neither answers the question.
27
+
28
+ so the verdict comes from a set neither model has ever seen: dolly-15k, MBPP, HumanEval and AQuA-RAT, 4,272 prompts, labels taken from dataset provenance alone. every MBPP row is a code task because it is in MBPP. every AQuA row is math because it is in AQuA. no hand labelling, no model in the loop.
29
+
30
+ ### neutral holdout, 4,272 unseen prompts
31
+
32
+ | | Glint-Router-1M | Supra-Router-51M |
33
+ |---|---|---|
34
+ | parameters | **985,826** | 51,786,240 |
35
+ | route accuracy | **94.41** | 90.37 |
36
+ | math detection | **95.26** | 92.07 |
37
+ | code detection | **97.51** | 96.43 |
38
+ | complexity within 1 | **95.90** | 91.63 |
39
+ | complexity exact | **46.28** | 39.06 |
40
+ | ms per prompt | **0.06** | 14.33 |
41
+ | parse failures | **0** | 4 |
42
+
43
+ 239x faster, 52x smaller, ahead on every field.
44
+
45
+ one caveat we owe you: the complexity *label rule* on that holdout is ours, so the two complexity rows lean our way. route, code and math do not. the route rule is supra's own published one, copied verbatim, and code/math come from which dataset a row lives in.
46
+
47
+ ### the other two views, for completeness
48
+
49
+ on our own validation split (7,617 rows, our labels, we are in-distribution):
50
+
51
+ | | Glint | Supra |
52
+ |---|---|---|
53
+ | route | **93.96** | 85.76 |
54
+ | code | **99.15** | 97.61 |
55
+ | math | **97.81** | 94.00 |
56
+ | complexity exact | **79.23** | 46.29 |
57
+
58
+ on supra's own 992 rows, held out of our training, which are supra's training data:
59
+
60
+ | | Glint | Supra |
61
+ |---|---|---|
62
+ | route | 89.01 | **96.70** |
63
+ | code | 90.11 | **100.00** |
64
+ | math | 81.32 | **97.80** |
65
+ | complexity exact | 50.55 | **85.71** |
66
+
67
+ supra wins that table because it is reciting the set it was fine-tuned on. we publish it because leaving it out would be dressing.
68
+
69
+ ## the keyword trap
70
+
71
+ supra's model card claims "keyword-trap evasion" and never measures it. a keyword trap is a prompt that mentions a technical token while being trivial: "write a short poem about a Python snake in the garden" is a poem, not a coding job.
72
+
73
+ we generated 3,000 counterfactual pairs, trained on them, and scored the held-out slice separately because at 4% of the corpus it vanishes into any aggregate.
74
+
75
+ | trap slice, 230 held-out prompts | Glint | Supra |
76
+ |---|---|---|
77
+ | route | **100.00** | 90.87 |
78
+ | code | **100.00** | 98.70 |
79
+ | complexity within 1 | **100.00** | 83.91 |
80
+
81
+ 100 is a suspicious number and it should be read as one. we generated those traps from templates, so the family was in training even though the specific rows were not. supra faces them completely cold. take it as evidence that traps are learnable, not that the problem is solved.
82
+
83
+ ## calibration
84
+
85
+ the routing decision is expected-cost arithmetic over the model's probabilities, so those probabilities have to mean what they say. a head that is 90% confident should be right 90% of the time.
86
+
87
+ after 42 epochs it was not. temperature scaling, fitted on held-out data after training, one scalar per head group:
88
+
89
+ ```
90
+ expected calibration error, routing head
91
+ raw 0.0556
92
+ calibrated 0.0203
93
+ ```
94
+
95
+ the fitted temperature on the routing head is 4.71, which is a blunt statement about how overconfident a small model gets when you let it see the same 95k rows forty times. the scalars ship inside the weights and `calibrated()` applies them for you.
96
+
97
+ ## routing is a policy, not a threshold
98
+
99
+ supra decides with a boolean baked into its weights: complexity >= 3, or code, or math, means big model. two tiers. want three, or a different threshold, or "legal always goes to the frontier model"? you are collecting data and retraining 51M parameters.
100
+
101
+ here the model stops at calibrated probabilities about the prompt. what to do with them is `policy.json`, which you own:
102
+
103
+ ```json
104
+ {
105
+ "tiers": [
106
+ {"name": "local", "cost": 0.0, "capability": 0.35, "tools": false},
107
+ {"name": "mid", "cost": 1.0, "capability": 0.65, "tools": false},
108
+ {"name": "frontier", "cost": 8.0, "capability": 0.95, "tools": true}
109
+ ],
110
+ "failure_penalty": 50.0,
111
+ "sharpness": 20.0,
112
+ "abstain_margin": 0.05,
113
+ "overrides": []
114
+ }
115
+ ```
116
+
117
+ the decision is `argmin over tiers of cost + failure_penalty * P(tier fails)`, where P(fail) is a logistic in the gap between prompt difficulty and tier capability. n tiers, not 2. an abstain band escalates ties instead of coin-flipping them. overrides short-circuit the arithmetic on any predicted field:
118
+
119
+ ```json
120
+ {"overrides": [{"when": {"domain": "legal"}, "tier": "frontier"},
121
+ {"when": {"code": true, "complexity_min": 4}, "tier": "frontier"}]}
122
+ ```
123
+
124
+ two constants in there were tuned the hard way and we left the reasoning in the file. `failure_penalty` has to be several times the priciest call, or "pay least" beats "try hardest" when every tier is likely to fail, and the router quietly sends its hardest prompts to its weakest model. `sharpness` has to be steep: at 12, a free local tier still carries a 2.6% residual failure rate, which priced at the penalty is 1.33 and loses to the mid tier's flat cost of 1.0. the free tier won nothing until that was fixed.
125
+
126
+ ## adding a category it never trained on
127
+
128
+ the 64-d projection head is trained alongside the classifier, so prompts that route alike land near each other. a new category is the mean of a handful of examples:
129
+
130
+ ```
131
+ python infer.py --add-category refunds refund_examples.txt
132
+ ```
133
+
134
+ six example prompts, one forward pass, no optimizer, no gradients. after that `decision.category` comes back as `refunds` on matching prompts and you can route on it with an override. this is the thing a 51M generator cannot do at all without a fine-tune.
135
+
136
+ ## where it fails
137
+
138
+ a 1M parameter model has edges and we would rather you learn them here than in production.
139
+
140
+ **math phrased without numbers or symbols.** the math training data is GSM8K word problems and LaTeX. symbol-free proofs read as easy:
141
+
142
+ ```
143
+ "Prove that every finite integral domain is a field." -> math 0.01, complexity 2, local
144
+ "Natalia sold clips to 48 friends in April, and half
145
+ as many in May. How many clips altogether?" -> math 0.99, complexity 3, frontier
146
+ "Compute the integral of x^2 sin(x) dx from 0 to pi." -> math 0.95, frontier
147
+ ```
148
+
149
+ the first one is wrong and it is wrong for a boring reason: nothing in 95k rows looks like it.
150
+
151
+ **word problems with an unusual question verb.** "a train leaves at 3pm going 60mph, another at 4pm going 80mph, when do they meet?" scores math 0.03 and routes local. move it to "how far apart are they at 6pm" and it behaves. the corpus taught it "how many" and "calculate" and did not teach it "when do they meet".
152
+
153
+ **raw code with no instruction.** HumanEval is our worst slice at 56.7% code detection, and supra's second worst at 67.7%. a bare function stub with a docstring has no instruction verb anywhere in it. neither of us handles it and we are not going to pretend the gap is small.
154
+
155
+ **very short factual prompts.** "what is the capital of France" comes back domain `programming`, complexity 1, routed local. the routing is right and the domain label is noise. domain accuracy on prompts under six tokens is the weakest part of the model.
156
+
157
+ both data gaps are one more training round away. the model shipped here got one 15-minute round and that was the whole budget.
158
+
159
+ ## how it was trained
160
+
161
+ one round, 15 minutes, one RTX 3060 Ti, 14,479 steps, learning rate fully annealed inside the budget. the schedule measures its own step rate before it starts and sizes the cosine decay to fit, so the run finishes annealed instead of stopping mid-schedule. best-on-validation weights, not last-step weights.
162
+
163
+ the biggest gap versus supra is on the data side. supra fine-tuned on 992 rows. we built 95,221 and never hand-labelled one of them:
164
+
165
+ | source | rows | what it labels for free |
166
+ |---|---|---|
167
+ | alpaca | 35,000 | mixed domains, complexity from answer length |
168
+ | code_instructions | 18,000 | code = true |
169
+ | squad | 15,000 | factual, complexity 1 |
170
+ | no_robots | 9,500 | human-written task category |
171
+ | gsm8k | 7,473 | math = true |
172
+ | hendrycks_math | 6,256 | math = true, complexity from level |
173
+ | generated traps | 3,000 | keyword counterfactuals |
174
+ | supra's own set | 992 | its labels, verbatim |
175
+
176
+ labels come from provenance and from the reference answer, never from a human and never from a model. a row in MBPP is a code task. a 1,200-character reference answer means long_output. the model predicts those labels from the prompt alone and never sees the answer.
177
+
178
+ the routing label is supra's published override rule copied exactly, so a head-to-head measures prediction quality rather than two people disagreeing about what "big model" means. our route split came out 51/49; supra's own set is 75/25.
179
+
180
+ the tokenizer is a 4096-vocab bpe trained on routing prompts rather than on web prose, because `{`, `::`, `\frac` and `SELECT` are the evidence and a FineWeb vocabulary shreds all four into bytes.
181
+
182
+ ## files
183
+
184
+ ```
185
+ model.safetensors the weights (3.9 MB)
186
+ config.json architecture and label space
187
+ tokenizer.json 4096-vocab bpe, trained on routing prompts
188
+ modeling.py the model, standalone, torch only
189
+ policy.py tiers, expected-cost decision, overrides, prototypes
190
+ policy.json the default 3-tier policy, edit this one
191
+ infer.py cli: route, batch, add a category
192
+ scores.json every number on this page, machine readable
193
+ requirements.txt torch, tokenizers, safetensors
194
+ README.md you are here
195
+ ```
196
+
197
+ ## quickstart
198
+
199
+ ```
200
+ pip install torch tokenizers safetensors
201
+
202
+ python infer.py --demo
203
+ python infer.py "write a python function that reverses a linked list"
204
+ python infer.py --file prompts.txt
205
+ python infer.py --policy my_policy.json "summarize this thread"
206
+ python infer.py --add-category refunds refund_examples.txt
207
+ ```
208
+
209
+ in code:
210
+
211
+ ```python
212
+ from modeling import encode_batch, load_router
213
+ from policy import Policy, decide
214
+
215
+ model, tokenizer = load_router()
216
+ tokens = encode_batch(tokenizer, ["fix this SQL query"], model.config.max_len)
217
+ decision = decide(model, tokens, "fix this SQL query", Policy.load("policy.json"))
218
+ print(decision.tier, decision.domain, decision.complexity)
219
+ ```
220
+
221
+ `decision.as_line()` prints supra's exact output format if you are swapping one for the other.
222
+
223
+ runs on cpu. the model is 3.9 MB. it is smaller than the favicon budget of most websites.
224
+
225
+ /lane
226
+ glint research, 2026, 985,826 parameters, one 15-minute round on a 3060 Ti, 239x faster than the 51M model it beats, 0 parse failures, 3 known failure modes documented above
config.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "Glint-Router-1M",
3
+ "author": "Glint-Research",
4
+ "task": "prompt routing / request triage",
5
+ "parameters": 985826,
6
+ "model": {
7
+ "vocab_size": 4096,
8
+ "dim": 128,
9
+ "n_heads": 8,
10
+ "layers": 3,
11
+ "ffn_hidden": 208,
12
+ "max_len": 256,
13
+ "rope_base": 10000.0,
14
+ "proj_dim": 64,
15
+ "n_domains": 25
16
+ },
17
+ "labels": {
18
+ "domains": 25,
19
+ "complexity": "ordinal 1-5 (CORAL)",
20
+ "binary": [
21
+ "code",
22
+ "math",
23
+ "reasoning",
24
+ "long_output"
25
+ ],
26
+ "route": "binary big/small, plus N-tier expected-cost policy"
27
+ }
28
+ }
infer.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """glint-router-1m: route prompts, edit the policy, teach it new categories.
2
+
3
+ python infer.py "write a python function that reverses a linked list"
4
+ python infer.py --file prompts.txt
5
+ python infer.py --policy my_policy.json "summarize this thread"
6
+ python infer.py --add-category refunds examples.txt
7
+ python infer.py --demo
8
+
9
+ everything runs on cpu. one forward pass per prompt, around 0.2 ms.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import sys
15
+ import time
16
+ from pathlib import Path
17
+
18
+ import torch
19
+
20
+ from modeling import encode_batch, load_router
21
+ from policy import Policy, Prototypes, decide
22
+
23
+ HERE = Path(__file__).parent
24
+ PROTOTYPES = HERE / "prototypes.json"
25
+
26
+
27
+ def route(prompts: list[str], policy_path: Path | None = None,
28
+ prototypes_path: Path | None = None, device: str = "cpu"):
29
+ model, tokenizer = load_router(HERE, device)
30
+ policy = Policy.load(policy_path or HERE / "policy.json")
31
+ prototypes = Prototypes.load(prototypes_path)
32
+ tokens = encode_batch(tokenizer, prompts, model.config.max_len).to(device)
33
+ return [decide(model, tokens[i:i + 1], prompts[i], policy, prototypes)
34
+ for i in range(len(prompts))]
35
+
36
+
37
+ def add_category(name: str, examples: list[str], device: str = "cpu") -> None:
38
+ """teach it a label it was never trained on. one forward pass, no optimizer."""
39
+ model, tokenizer = load_router(HERE, device)
40
+ tokens = encode_batch(tokenizer, examples, model.config.max_len).to(device)
41
+ with torch.no_grad():
42
+ projections = model(tokens)["proj"]
43
+ prototypes = Prototypes.load(PROTOTYPES)
44
+ prototypes.add(name, projections)
45
+ prototypes.save(PROTOTYPES)
46
+ print(f"added category {name!r} from {len(examples)} examples -> {PROTOTYPES}")
47
+
48
+
49
+ def show(decisions, prompts) -> None:
50
+ for decision, prompt in zip(decisions, prompts, strict=True):
51
+ flags = [k for k, v in decision.signals.items() if v]
52
+ head = prompt if len(prompt) <= 58 else prompt[:55] + "..."
53
+ print(f"{decision.tier:<9} {decision.domain:<20} c={decision.complexity} "
54
+ f"d={decision.difficulty:.2f} {head}")
55
+ print(f" {decision.reason}"
56
+ + (f" | signals={flags}" if flags else "")
57
+ + (f" | category={decision.category}" if decision.category else ""))
58
+
59
+
60
+ DEMO = [
61
+ "What's the capital of France?",
62
+ "Write a short poem about a Python snake in the garden.",
63
+ "Write a Python function that reverses a linked list in place.",
64
+ "A train leaves at 3pm going 60mph, another at 4pm going 80mph, when do they meet?",
65
+ "Summarize this email thread in two sentences.",
66
+ "What are the latest news headlines today?",
67
+ "Explain the difference between a mutex and a semaphore, with an example.",
68
+ ]
69
+
70
+
71
+ def main() -> int:
72
+ args = sys.argv[1:]
73
+ if not args or args[0] in ("-h", "--help"):
74
+ print(__doc__)
75
+ return 0
76
+
77
+ if args[0] == "--demo":
78
+ started = time.perf_counter()
79
+ decisions = route(DEMO)
80
+ elapsed = time.perf_counter() - started
81
+ show(decisions, DEMO)
82
+ print(f"\n{len(DEMO)} prompts in {elapsed * 1000:.0f} ms "
83
+ f"({elapsed * 1000 / len(DEMO):.2f} ms each, cpu, includes model load)")
84
+ return 0
85
+
86
+ if args[0] == "--add-category":
87
+ if len(args) < 3:
88
+ print("usage: python infer.py --add-category <name> <examples.txt>")
89
+ return 1
90
+ examples = [line.strip() for line in Path(args[2]).read_text().splitlines()
91
+ if line.strip()]
92
+ add_category(args[1], examples)
93
+ return 0
94
+
95
+ policy_path = None
96
+ if args[0] == "--policy":
97
+ policy_path, args = Path(args[1]), args[2:]
98
+
99
+ if args and args[0] == "--file":
100
+ prompts = [line.strip() for line in Path(args[1]).read_text().splitlines()
101
+ if line.strip()]
102
+ else:
103
+ prompts = [" ".join(args)]
104
+
105
+ decisions = route(prompts, policy_path,
106
+ PROTOTYPES if PROTOTYPES.is_file() else None)
107
+ show(decisions, prompts)
108
+ if len(prompts) == 1:
109
+ print()
110
+ print(decisions[0].as_line())
111
+ return 0
112
+
113
+
114
+ if __name__ == "__main__":
115
+ raise SystemExit(main())
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1e49b3aef312902c7af0044336b17f97f7d5dd57075ae1d7d769adafea6018a4
3
+ size 3946036
modeling.py ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """glint-router-1m: standalone inference. torch + tokenizers + safetensors, nothing else.
2
+
3
+ one forward pass over the prompt gives you every field at once: domain,
4
+ complexity, code, math, reasoning, long_output, route, and a 64-d projection
5
+ used for user-defined categories. no decoding loop, no output parsing.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import math
12
+ from dataclasses import dataclass
13
+ from pathlib import Path
14
+
15
+ import torch
16
+ from torch import Tensor, nn
17
+ from torch.nn import functional
18
+
19
+ HERE = Path(__file__).parent
20
+ PAD_ID = 0
21
+ BOS_ID = 1
22
+ BINARY_FIELDS = ("code", "math", "reasoning", "long_output")
23
+ COMPLEXITY_LEVELS = 5
24
+
25
+ DOMAINS = (
26
+ "programming", "web_dev", "databases", "devops_sysadmin", "security",
27
+ "data_science_ml", "math", "science", "engineering", "reasoning_puzzle",
28
+ "creative_writing", "professional_writing", "editing_grammar", "translation",
29
+ "factual_qa", "education", "business", "finance", "legal", "health",
30
+ "travel", "food", "entertainment", "lifestyle", "other",
31
+ )
32
+
33
+
34
+ @dataclass(frozen=True)
35
+ class RouterConfig:
36
+ vocab_size: int = 4096
37
+ dim: int = 128
38
+ n_heads: int = 8
39
+ layers: int = 3
40
+ ffn_hidden: int = 208
41
+ max_len: int = 256
42
+ rope_base: float = 10_000.0
43
+ proj_dim: int = 64
44
+ n_domains: int = len(DOMAINS)
45
+
46
+
47
+ def build_rope_cache(config: RouterConfig) -> tuple[Tensor, Tensor]:
48
+ head_dim = config.dim // config.n_heads
49
+ positions = torch.arange(config.max_len, dtype=torch.float32)
50
+ inv_freq = 1.0 / (config.rope_base ** (torch.arange(0, head_dim, 2).float() / head_dim))
51
+ angles = torch.outer(positions, inv_freq)
52
+ return torch.cos(angles), torch.sin(angles)
53
+
54
+
55
+ def apply_rope(x: Tensor, cos: Tensor, sin: Tensor) -> Tensor:
56
+ x_even, x_odd = x[..., 0::2], x[..., 1::2]
57
+ rotated_even = x_even * cos - x_odd * sin
58
+ rotated_odd = x_even * sin + x_odd * cos
59
+ return torch.stack((rotated_even, rotated_odd), dim=-1).flatten(-2)
60
+
61
+
62
+ class SwiGlu(nn.Module):
63
+ def __init__(self, dim: int, hidden: int) -> None:
64
+ super().__init__()
65
+ self.gate_up = nn.Linear(dim, 2 * hidden, bias=False)
66
+ self.down = nn.Linear(hidden, dim, bias=False)
67
+
68
+ def forward(self, x: Tensor) -> Tensor:
69
+ gate, up = self.gate_up(x).chunk(2, dim=-1)
70
+ return self.down(functional.silu(gate) * up)
71
+
72
+
73
+ class RouterAttention(nn.Module):
74
+ def __init__(self, config: RouterConfig) -> None:
75
+ super().__init__()
76
+ self.n_heads = config.n_heads
77
+ self.head_dim = config.dim // config.n_heads
78
+ self.qkv = nn.Linear(config.dim, 3 * config.dim, bias=False)
79
+ self.out = nn.Linear(config.dim, config.dim, bias=False)
80
+
81
+ def forward(self, x: Tensor, cos: Tensor, sin: Tensor, attn_mask: Tensor) -> Tensor:
82
+ batch, seq_len, dim = x.shape
83
+ q, k, v = self.qkv(x).split(dim, dim=-1)
84
+ shape = (batch, seq_len, self.n_heads, self.head_dim)
85
+ q = apply_rope(q.view(shape).transpose(1, 2), cos, sin)
86
+ k = apply_rope(k.view(shape).transpose(1, 2), cos, sin)
87
+ v = v.view(shape).transpose(1, 2)
88
+ attended = functional.scaled_dot_product_attention(q, k, v, attn_mask=attn_mask)
89
+ return self.out(attended.transpose(1, 2).reshape(batch, seq_len, dim))
90
+
91
+
92
+ class RouterBlock(nn.Module):
93
+ def __init__(self, config: RouterConfig) -> None:
94
+ super().__init__()
95
+ self.attn_norm = nn.RMSNorm(config.dim)
96
+ self.attn = RouterAttention(config)
97
+ self.ffn_norm = nn.RMSNorm(config.dim)
98
+ self.ffn = SwiGlu(config.dim, config.ffn_hidden)
99
+
100
+ def forward(self, x: Tensor, cos: Tensor, sin: Tensor, attn_mask: Tensor) -> Tensor:
101
+ x = x + self.attn(self.attn_norm(x), cos, sin, attn_mask)
102
+ return x + self.ffn(self.ffn_norm(x))
103
+
104
+
105
+ class GlintRouter(nn.Module):
106
+ def __init__(self, config: RouterConfig | None = None) -> None:
107
+ super().__init__()
108
+ config = config or RouterConfig()
109
+ self.config = config
110
+ self.embed = nn.Embedding(config.vocab_size, config.dim, padding_idx=PAD_ID)
111
+ self.blocks = nn.ModuleList(RouterBlock(config) for _ in range(config.layers))
112
+ self.final_norm = nn.RMSNorm(config.dim)
113
+ cos, sin = build_rope_cache(config)
114
+ self.register_buffer("rope_cos", cos, persistent=False)
115
+ self.register_buffer("rope_sin", sin, persistent=False)
116
+
117
+ pooled = 2 * config.dim
118
+ self.domain_head = nn.Linear(pooled, config.n_domains)
119
+ self.complexity_dir = nn.Linear(pooled, 1, bias=False)
120
+ self.complexity_bias = nn.Parameter(torch.zeros(COMPLEXITY_LEVELS - 1))
121
+ self.binary_head = nn.Linear(pooled, len(BINARY_FIELDS))
122
+ self.route_head = nn.Linear(pooled, 1)
123
+ self.proj_head = nn.Linear(pooled, config.proj_dim)
124
+ self.register_buffer("temperature", torch.ones(3), persistent=True)
125
+
126
+ def encode(self, tokens: Tensor) -> Tensor:
127
+ valid = tokens != PAD_ID
128
+ seq_len = tokens.shape[1]
129
+ cos = self.rope_cos[:seq_len].to(self.embed.weight.dtype)
130
+ sin = self.rope_sin[:seq_len].to(self.embed.weight.dtype)
131
+ attn_mask = torch.zeros(tokens.shape, dtype=self.embed.weight.dtype,
132
+ device=tokens.device)
133
+ attn_mask = attn_mask.masked_fill(~valid, float("-inf"))[:, None, None, :]
134
+ x = self.embed(tokens)
135
+ for block in self.blocks:
136
+ x = block(x, cos, sin, attn_mask)
137
+ x = self.final_norm(x)
138
+ mask = valid.unsqueeze(-1)
139
+ mean = (x * mask).sum(dim=1) / mask.sum(dim=1).clamp(min=1)
140
+ maximum = torch.nan_to_num(x.masked_fill(~mask, float("-inf")).max(dim=1).values,
141
+ neginf=0.0)
142
+ return torch.cat((mean, maximum), dim=-1)
143
+
144
+ def forward(self, tokens: Tensor) -> dict[str, Tensor]:
145
+ pooled = self.encode(tokens)
146
+ return {
147
+ "domain": self.domain_head(pooled),
148
+ "complexity": self.complexity_dir(pooled) + self.complexity_bias,
149
+ "binary": self.binary_head(pooled),
150
+ "route": self.route_head(pooled).squeeze(-1),
151
+ "proj": functional.normalize(self.proj_head(pooled), dim=-1),
152
+ }
153
+
154
+ def calibrated(self, tokens: Tensor) -> dict[str, Tensor]:
155
+ """probabilities with the fitted temperatures applied. the routing
156
+ arithmetic in policy.py runs on these numbers, so they have to mean
157
+ something. temperatures were fitted on held-out data after training."""
158
+ out = self.forward(tokens)
159
+ route_t, complexity_t, binary_t = self.temperature.unbind()
160
+ return {
161
+ "domain": out["domain"].softmax(dim=-1),
162
+ "complexity": (out["complexity"] / complexity_t).sigmoid(),
163
+ "binary": (out["binary"] / binary_t).sigmoid(),
164
+ "route": (out["route"] / route_t).sigmoid(),
165
+ "proj": out["proj"],
166
+ }
167
+
168
+
169
+ def complexity_from_cumulative(probabilities: Tensor) -> Tensor:
170
+ """coral decode. level = 1 + how many thresholds the prompt clears."""
171
+ return 1 + (probabilities > 0.5).sum(dim=-1)
172
+
173
+
174
+ def encode_batch(tokenizer, texts: list[str], max_len: int) -> Tensor:
175
+ """bos-prefixed, right-padded. long prompts lose their tail, because the
176
+ instruction verb lives at the front and the pasted context lives at the back."""
177
+ out = torch.full((len(texts), max_len), PAD_ID, dtype=torch.long)
178
+ for row, text in enumerate(texts):
179
+ ids = [BOS_ID] + tokenizer.encode(text).ids[: max_len - 1]
180
+ out[row, : len(ids)] = torch.tensor(ids, dtype=torch.long)
181
+ return out
182
+
183
+
184
+ def load_router(directory: Path = HERE, device: str = "cpu"):
185
+ """returns (model, tokenizer). reads config.json + model.safetensors + tokenizer.json."""
186
+ from safetensors.torch import load_file
187
+ from tokenizers import Tokenizer
188
+
189
+ directory = Path(directory)
190
+ config = RouterConfig(**json.loads((directory / "config.json").read_text())["model"])
191
+ model = GlintRouter(config).to(device)
192
+ model.load_state_dict(load_file(directory / "model.safetensors", device=device))
193
+ model.eval()
194
+ return model, Tokenizer.from_file(str(directory / "tokenizer.json"))
195
+
196
+
197
+ def count_parameters(model: nn.Module) -> int:
198
+ return sum(p.numel() for p in model.parameters())
policy.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "tiers": [
3
+ {
4
+ "name": "local",
5
+ "cost": 0.0,
6
+ "capability": 0.35,
7
+ "tools": false
8
+ },
9
+ {
10
+ "name": "mid",
11
+ "cost": 1.0,
12
+ "capability": 0.65,
13
+ "tools": false
14
+ },
15
+ {
16
+ "name": "frontier",
17
+ "cost": 8.0,
18
+ "capability": 0.95,
19
+ "tools": true
20
+ }
21
+ ],
22
+ "failure_penalty": 50.0,
23
+ "sharpness": 20.0,
24
+ "abstain_margin": 0.05,
25
+ "difficulty_weights": [
26
+ 0.6,
27
+ 0.3,
28
+ 0.1
29
+ ],
30
+ "overrides": [],
31
+ "freshness_needs_tools": true,
32
+ "multilingual_threshold": 0.05,
33
+ "prototype_threshold": 0.55
34
+ }
policy.py ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Routing policy: everything you can change without touching the weights.
2
+
3
+ Supra-Router-51M bakes its decision into the model. two tiers, one threshold,
4
+ one domain vocabulary, all frozen at fine-tune time. Changing "route legal work
5
+ to the frontier model regardless of complexity" means collecting data and
6
+ retraining a 51M model.
7
+
8
+ Here the model's job stops at *calibrated probabilities about the prompt*. What
9
+ to do with them is this file, driven by a JSON document the user owns:
10
+
11
+ * N tiers, not 2, each with a cost and a capability
12
+ * expected-cost arithmetic instead of a hard-coded boolean
13
+ * an abstain band that escalates ties rather than coin-flipping them
14
+ * hard overrides on any predicted field
15
+ * user-defined categories matched by prototype, no retraining
16
+
17
+ Also here: the freshness / tool-use / multilingual signals. Those are keyword
18
+ and character-class rules. a learned head for them would only be memorising
19
+ the regex below, which costs parameters and teaches nothing. They live where a
20
+ rule belongs, and the user can edit them.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import json
26
+ import re
27
+ from dataclasses import asdict, dataclass, field
28
+ from pathlib import Path
29
+
30
+ import torch
31
+ from torch import Tensor
32
+
33
+ from modeling import BINARY_FIELDS, DOMAINS, GlintRouter, complexity_from_cumulative
34
+
35
+ FRESHNESS = re.compile(
36
+ r"\b(today|tonight|current|currently|latest|right now|this (week|month|year)|"
37
+ r"recent|news|stock price|weather|who won|as of \d{4}|202\d|203\d)\b", re.I)
38
+ TOOL_USE = re.compile(
39
+ r"\b(search the web|look ?up|browse|run this|execute|call the api|fetch|"
40
+ r"my file|this (csv|pdf|spreadsheet|repo)|book a|send an email|schedule)\b", re.I)
41
+
42
+
43
+ def non_ascii_ratio(text: str) -> float:
44
+ letters = [c for c in text if c.isalpha()]
45
+ if not letters:
46
+ return 0.0
47
+ return sum(1 for c in letters if ord(c) > 127) / len(letters)
48
+
49
+
50
+ @dataclass
51
+ class Tier:
52
+ name: str
53
+ cost: float # relative price of one call, any unit you like
54
+ capability: float # 0..1; the difficulty this tier handles before it starts failing
55
+ tools: bool = False # can this tier search / execute?
56
+
57
+
58
+ @dataclass
59
+ class Policy:
60
+ tiers: list[Tier] = field(default_factory=lambda: [
61
+ Tier("local", cost=0.0, capability=0.35),
62
+ Tier("mid", cost=1.0, capability=0.65),
63
+ Tier("frontier", cost=8.0, capability=0.95, tools=True),
64
+ ])
65
+ # A wrong answer must cost several times the most expensive call, or the
66
+ # arithmetic degenerates: when every tier is likely to fail, "pay least"
67
+ # beats "try hardest", and the router quietly sends its hardest prompts to
68
+ # the weakest model. Penalty >> max(cost) is what makes escalation rational.
69
+ failure_penalty: float = 50.0 # what a wrong answer costs, in the same units as `cost`
70
+ # Sharpness sets the residual failure rate a tier carries on prompts well
71
+ # inside its capability, and it has to be steep. At sharpness 12 the local
72
+ # tier still shows a 2.6% failure rate on a difficulty-0.05 prompt, which
73
+ # priced at `failure_penalty` (1.33) loses to the mid tier's flat cost of
74
+ # 1.0, so a free tier that handles the prompt perfectly never gets used.
75
+ # 20 puts that residual at 0.25% and the cheap tier wins what it should.
76
+ sharpness: float = 20.0
77
+ abstain_margin: float = 0.05 # ties inside this band escalate instead of coin-flipping
78
+ difficulty_weights: tuple[float, float, float] = (0.6, 0.3, 0.1) # route, complexity, code/math
79
+ # {"when": {...}, "tier": "frontier"}. first match wins, checked before the arithmetic.
80
+ overrides: list[dict] = field(default_factory=list)
81
+ freshness_needs_tools: bool = True
82
+ multilingual_threshold: float = 0.05
83
+ prototype_threshold: float = 0.55
84
+
85
+ @classmethod
86
+ def load(cls, path: Path | None) -> Policy:
87
+ if path is None:
88
+ return cls()
89
+ blob = json.loads(Path(path).read_text())
90
+ tiers = [Tier(**t) for t in blob.pop("tiers", [])]
91
+ policy = cls(**blob)
92
+ if tiers:
93
+ policy.tiers = tiers
94
+ return policy
95
+
96
+ def save(self, path: Path) -> None:
97
+ Path(path).write_text(json.dumps(asdict(self), indent=2))
98
+
99
+
100
+ @dataclass
101
+ class Decision:
102
+ tier: str
103
+ domain: str
104
+ complexity: int
105
+ difficulty: float
106
+ probabilities: dict[str, float]
107
+ signals: dict[str, bool]
108
+ reason: str
109
+ category: str | None = None
110
+ escalated: bool = False
111
+
112
+ def as_line(self) -> str:
113
+ """Supra's output format, so the two are directly comparable."""
114
+ p = self.probabilities
115
+ return (f"Domain: {self.domain} | Complexity: {self.complexity} | "
116
+ f"Math: {'T' if p['math'] > 0.5 else 'F'} | "
117
+ f"Code: {'T' if p['code'] > 0.5 else 'F'} | "
118
+ f"Route: {self.tier} | Justification: {self.reason}")
119
+
120
+
121
+ class Prototypes:
122
+ """User-defined categories, added from a handful of examples at runtime.
123
+
124
+ The projection head is trained jointly with the classifier, so prompts that
125
+ share a routing-relevant character land near each other. A new category is
126
+ the mean of its examples' projections. adding one is a forward pass over
127
+ 5-10 prompts, not a training run.
128
+ """
129
+
130
+ def __init__(self, vectors: dict[str, list[float]] | None = None) -> None:
131
+ self.vectors = {k: torch.tensor(v) for k, v in (vectors or {}).items()}
132
+
133
+ def add(self, name: str, projections: Tensor) -> None:
134
+ centroid = projections.mean(dim=0)
135
+ self.vectors[name] = centroid / centroid.norm().clamp(min=1e-6)
136
+
137
+ def match(self, projection: Tensor, threshold: float) -> tuple[str | None, float]:
138
+ if not self.vectors:
139
+ return None, 0.0
140
+ names = list(self.vectors)
141
+ bank = torch.stack([self.vectors[n] for n in names]).to(projection.device)
142
+ scores = bank @ projection
143
+ best = int(scores.argmax())
144
+ score = float(scores[best])
145
+ return (names[best], score) if score >= threshold else (None, score)
146
+
147
+ def save(self, path: Path) -> None:
148
+ Path(path).write_text(json.dumps({k: v.tolist() for k, v in self.vectors.items()}))
149
+
150
+ @classmethod
151
+ def load(cls, path: Path | None) -> Prototypes:
152
+ if path is None or not Path(path).is_file():
153
+ return cls()
154
+ return cls(json.loads(Path(path).read_text()))
155
+
156
+
157
+ def difficulty_of(route_p: float, complexity: float, code_p: float, math_p: float,
158
+ weights: tuple[float, float, float]) -> float:
159
+ w_route, w_complexity, w_technical = weights
160
+ scaled_complexity = (complexity - 1.0) / 4.0
161
+ technical = max(code_p, math_p)
162
+ total = w_route + w_complexity + w_technical
163
+ return (w_route * route_p + w_complexity * scaled_complexity
164
+ + w_technical * technical) / max(total, 1e-6)
165
+
166
+
167
+ def _override_hit(rule: dict, domain: str, complexity: int, probs: dict[str, float],
168
+ signals: dict[str, bool], category: str | None) -> bool:
169
+ when = rule.get("when", {})
170
+ if "domain" in when and when["domain"] != domain:
171
+ return False
172
+ if "category" in when and when["category"] != category:
173
+ return False
174
+ if "complexity_min" in when and complexity < when["complexity_min"]:
175
+ return False
176
+ if "complexity_max" in when and complexity > when["complexity_max"]:
177
+ return False
178
+ for f in BINARY_FIELDS:
179
+ if f in when and bool(when[f]) != (probs[f] > 0.5):
180
+ return False
181
+ for s in ("freshness", "tool_use", "multilingual"):
182
+ if s in when and bool(when[s]) != signals[s]:
183
+ return False
184
+ return True
185
+
186
+
187
+ def decide(model: GlintRouter, tokens: Tensor, text: str, policy: Policy,
188
+ prototypes: Prototypes | None = None) -> Decision:
189
+ """One prompt -> one routing decision. `tokens` is a (1, seq) batch."""
190
+ with torch.no_grad():
191
+ out = model.calibrated(tokens)
192
+ probs = {f: float(out["binary"][0, i]) for i, f in enumerate(BINARY_FIELDS)}
193
+ probs["route_big"] = float(out["route"][0])
194
+ domain = DOMAINS[int(out["domain"][0].argmax())]
195
+ complexity_p = out["complexity"][0]
196
+ complexity = int(complexity_from_cumulative(complexity_p))
197
+ expected_complexity = 1.0 + float(complexity_p.sum())
198
+
199
+ signals = {
200
+ "freshness": bool(FRESHNESS.search(text)),
201
+ "tool_use": bool(TOOL_USE.search(text)),
202
+ "multilingual": non_ascii_ratio(text) > policy.multilingual_threshold,
203
+ }
204
+ category, _ = (prototypes.match(out["proj"][0], policy.prototype_threshold)
205
+ if prototypes else (None, 0.0))
206
+
207
+ for rule in policy.overrides:
208
+ if _override_hit(rule, domain, complexity, probs, signals, category):
209
+ return Decision(rule["tier"], domain, complexity, 0.0, probs, signals,
210
+ f"override: {json.dumps(rule.get('when', {}))}", category)
211
+
212
+ difficulty = difficulty_of(probs["route_big"], expected_complexity,
213
+ probs["code"], probs["math"], policy.difficulty_weights)
214
+
215
+ tiers = policy.tiers
216
+ if (signals["freshness"] or signals["tool_use"]) and policy.freshness_needs_tools:
217
+ with_tools = [t for t in tiers if t.tools]
218
+ if with_tools:
219
+ tiers = with_tools
220
+
221
+ costs = []
222
+ for tier in tiers:
223
+ fail = torch.sigmoid(torch.tensor(
224
+ (difficulty - tier.capability) * policy.sharpness)).item()
225
+ costs.append((tier.cost + policy.failure_penalty * fail, tier))
226
+ costs.sort(key=lambda pair: pair[0])
227
+
228
+ best_cost, best = costs[0]
229
+ escalated = False
230
+ if len(costs) > 1 and (costs[1][0] - best_cost) <= policy.abstain_margin * best_cost:
231
+ runner_up = costs[1][1]
232
+ if runner_up.capability > best.capability:
233
+ best, escalated = runner_up, True
234
+
235
+ reason = (f"difficulty={difficulty:.2f} complexity={complexity} "
236
+ f"code={probs['code']:.2f} math={probs['math']:.2f}"
237
+ + (" (escalated: tie inside abstain band)" if escalated else ""))
238
+ return Decision(best.name, domain, complexity, difficulty, probs, signals,
239
+ reason, category, escalated)
refund_examples.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ I want a refund for my order, it arrived broken.
2
+ How do I return this item and get my money back?
3
+ My package never showed up, can I be refunded?
4
+ Cancel my subscription and refund last month.
5
+ The product is defective, I demand a refund.
6
+ Requesting reimbursement for a duplicate charge.
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ torch
2
+ tokenizers
3
+ safetensors
scores.json ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "Glint-Router-1M",
3
+ "author": "Glint-Research",
4
+ "parameters": 985826,
5
+ "baseline": "SupraLabs/Supra-Router-51M (51,786,240 params)",
6
+ "training": {
7
+ "params": 985826,
8
+ "train_rows": 87604,
9
+ "val_rows": 7617,
10
+ "steps": 14479,
11
+ "minutes": 15.0,
12
+ "domain": 0.9464356045687279,
13
+ "route": 0.939608769856899,
14
+ "complexity": 0.7923066824209006,
15
+ "code": 0.991466456610214,
16
+ "math": 0.978075357752396,
17
+ "reasoning": 0.8949717736641722,
18
+ "long_output": 0.9516870158855192,
19
+ "ece_raw": 0.05564934242829622,
20
+ "ece_calibrated": 0.02029288645098859,
21
+ "hardware": "RTX 3060 Ti",
22
+ "rounds": 1,
23
+ "wall_clock_minutes": 15.0,
24
+ "corpus_rows": 95221
25
+ },
26
+ "neutral_holdout": {
27
+ "val_rows": 3418,
28
+ "slice_rows": {
29
+ "aqua_rat": 254,
30
+ "dolly": 2500,
31
+ "humaneval": 164,
32
+ "mbpp": 500
33
+ },
34
+ "glint": {
35
+ "route_accuracy": 0.9441193680514921,
36
+ "code_accuracy": 0.9751316559391457,
37
+ "math_accuracy": 0.9526038619075483,
38
+ "complexity_exact": 0.46284376828554713,
39
+ "complexity_within_1": 0.9590403744880047,
40
+ "ms_per_prompt": 0.05992146021082586,
41
+ "parse_failures": 0
42
+ },
43
+ "glint_aqua_rat": {
44
+ "route_accuracy": 0.9094488188976378,
45
+ "code_accuracy": 0.9960629921259843,
46
+ "math_accuracy": 0.889763779527559,
47
+ "complexity_exact": 0.1141732283464567,
48
+ "complexity_within_1": 0.8070866141732284,
49
+ "ms_per_prompt": 0.05992146021082586,
50
+ "parse_failures": 0
51
+ },
52
+ "glint_dolly": {
53
+ "route_accuracy": 0.9424,
54
+ "code_accuracy": 0.9956,
55
+ "math_accuracy": 0.9612,
56
+ "complexity_exact": 0.5688,
57
+ "complexity_within_1": 0.9944,
58
+ "ms_per_prompt": 0.05992146021082586,
59
+ "parse_failures": 0
60
+ },
61
+ "glint_humaneval": {
62
+ "route_accuracy": 0.8719512195121951,
63
+ "code_accuracy": 0.5670731707317073,
64
+ "math_accuracy": 0.9024390243902439,
65
+ "complexity_exact": 0.4451219512195122,
66
+ "complexity_within_1": 0.9817073170731707,
67
+ "ms_per_prompt": 0.05992146021082586,
68
+ "parse_failures": 0
69
+ },
70
+ "glint_mbpp": {
71
+ "route_accuracy": 0.994,
72
+ "code_accuracy": 0.996,
73
+ "math_accuracy": 0.958,
74
+ "complexity_exact": 0.116,
75
+ "complexity_within_1": 0.852,
76
+ "ms_per_prompt": 0.05992146021082586,
77
+ "parse_failures": 0
78
+ },
79
+ "supra": {
80
+ "route_accuracy": 0.903744880046811,
81
+ "code_accuracy": 0.9643066120538326,
82
+ "math_accuracy": 0.9207138677589234,
83
+ "complexity_exact": 0.3905792861322411,
84
+ "complexity_within_1": 0.9163253364540667,
85
+ "ms_per_prompt": 14.334112498536923,
86
+ "parse_failures": 4
87
+ },
88
+ "supra_aqua_rat": {
89
+ "route_accuracy": 0.9133858267716536,
90
+ "code_accuracy": 1.0,
91
+ "math_accuracy": 0.9094488188976378,
92
+ "complexity_exact": 0.0,
93
+ "complexity_within_1": 0.09448818897637795,
94
+ "ms_per_prompt": 14.334112498536923,
95
+ "parse_failures": 4
96
+ },
97
+ "supra_dolly": {
98
+ "route_accuracy": 0.8896,
99
+ "code_accuracy": 0.996,
100
+ "math_accuracy": 0.9428,
101
+ "complexity_exact": 0.482,
102
+ "complexity_within_1": 0.9776,
103
+ "ms_per_prompt": 14.334112498536923,
104
+ "parse_failures": 4
105
+ },
106
+ "supra_humaneval": {
107
+ "route_accuracy": 0.8292682926829268,
108
+ "code_accuracy": 0.676829268292683,
109
+ "math_accuracy": 0.8414634146341463,
110
+ "complexity_exact": 0.16463414634146342,
111
+ "complexity_within_1": 1.0,
112
+ "ms_per_prompt": 14.334112498536923,
113
+ "parse_failures": 4
114
+ },
115
+ "supra_mbpp": {
116
+ "route_accuracy": 0.994,
117
+ "code_accuracy": 0.882,
118
+ "math_accuracy": 0.842,
119
+ "complexity_exact": 0.206,
120
+ "complexity_within_1": 1.0,
121
+ "ms_per_prompt": 14.334112498536923,
122
+ "parse_failures": 4
123
+ }
124
+ },
125
+ "in_corpus_val": {
126
+ "val_rows": 7617,
127
+ "glint": {
128
+ "route_accuracy": 0.939608769856899,
129
+ "code_accuracy": 0.991466456610214,
130
+ "math_accuracy": 0.978075357752396,
131
+ "complexity_exact": 0.7923066824209006,
132
+ "complexity_within_1": 0.9883156098201391,
133
+ "ms_per_prompt": 0.0748591950898926,
134
+ "parse_failures": 0
135
+ },
136
+ "glint_trap": {
137
+ "route_accuracy": 1.0,
138
+ "code_accuracy": 1.0,
139
+ "math_accuracy": 1.0,
140
+ "complexity_exact": 1.0,
141
+ "complexity_within_1": 1.0,
142
+ "parse_failures": 0
143
+ },
144
+ "supra": {
145
+ "route_accuracy": 0.8575554680320336,
146
+ "code_accuracy": 0.9761060785085992,
147
+ "math_accuracy": 0.9400026257056584,
148
+ "complexity_exact": 0.4629119075751608,
149
+ "complexity_within_1": 0.923723250623605,
150
+ "ms_per_prompt": 14.768008985689887,
151
+ "parse_failures": 1
152
+ },
153
+ "supra_trap": {
154
+ "route_accuracy": 0.908695652173913,
155
+ "code_accuracy": 0.9869565217391304,
156
+ "math_accuracy": 1.0,
157
+ "complexity_exact": 0.33043478260869563,
158
+ "complexity_within_1": 0.8391304347826087,
159
+ "parse_failures": 1
160
+ },
161
+ "note": "labels from the glint pipeline. glint is in-distribution here, supra is not. read the holdout numbers for the fair comparison."
162
+ },
163
+ "supra_own_rows": {
164
+ "val_rows": 91,
165
+ "glint": {
166
+ "route_accuracy": 0.8901098901098901,
167
+ "code_accuracy": 0.9010989010989011,
168
+ "math_accuracy": 0.8131868131868132,
169
+ "complexity_exact": 0.5054945054945055
170
+ },
171
+ "supra": {
172
+ "route_accuracy": 0.967032967032967,
173
+ "code_accuracy": 1.0,
174
+ "math_accuracy": 0.978021978021978,
175
+ "complexity_exact": 0.8571428571428571
176
+ },
177
+ "note": "supra's own 992-row dataset, held out of glint training. these rows are supra's TRAINING data, so supra is scoring a memorised set. published because leaving it out would be dishonest."
178
+ }
179
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff