Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ src/routelet/

evaluate.py the Claude LLM baseline (the accuracy ceiling), one call per row
teacher.py shared taxonomy prompt + schema + classify(), used by eval + ingest
serve.py optional FastAPI endpoint (stub; Aegis runs the ONNX in-process)

Scripts/ runnable tools (not library code)
pull_samples.py pull redacted samples from the proxy's R2 -> one JSONL
Expand Down
6 changes: 0 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ train = [
"datasets",
"torch",
]
# Only needed if you build out the optional HTTP endpoint (src/routelet/serve.py).
serve = [
"fastapi",
"uvicorn",
"pydantic",
]

[build-system]
requires = ["hatchling"]
Expand Down
10 changes: 2 additions & 8 deletions src/routelet/export_onnx.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,18 +156,14 @@ def main() -> None:
print(f"ST pooling mode: {pooling_mode}")
print(f"ST modules: {[type(m).__name__ for m in body]}")

# Build the exportable wrapper.
wrapper = EncoderWithPooling(body)
wrapper.eval()

# Export fp32 ONNX.
_export_embedder(wrapper, EMBEDDER_OUT)

# Quantize to int8.
quantize_dynamic(EMBEDDER_OUT, EMBEDDER_INT8_OUT, weight_type=QuantType.QInt8)
print(f"[quantize] saved {EMBEDDER_INT8_OUT}")

# Load fitted temperature T from the file written by train_setfit.py.
# Temperature is fitted and written by train_setfit.py; absent means no scaling.
temp_path = Path(TEMPERATURE_FILE)
if temp_path.exists():
temperature = json.loads(temp_path.read_text())["temperature"]
Expand All @@ -176,7 +172,7 @@ def main() -> None:
temperature = 1.0
print(f"[temperature] {TEMPERATURE_FILE} not found, using T=1.0 (no scaling)")

# Dump LR head to JSON. classes_ order is what argmax maps to.
# classes_ order is the column order the Rust consumer's argmax maps back to labels.
labels = head.classes_.tolist()
head_data = {
"coef": head.coef_.tolist(),
Expand All @@ -194,11 +190,9 @@ def main() -> None:
shutil.copy(f"{SETFIT_DIR}/tokenizer.json", TOKENIZER_OUT)
print(f"[tokenizer] copied -> {TOKENIZER_OUT}")

# Print I/O signature.
fp32_sess = ort.InferenceSession(EMBEDDER_OUT, providers=["CPUExecutionProvider"])
_print_session_info(fp32_sess)

# File sizes.
fp32_bytes = Path(EMBEDDER_OUT).stat().st_size
int8_bytes = Path(EMBEDDER_INT8_OUT).stat().st_size
print("\nfile sizes:")
Expand Down
8 changes: 0 additions & 8 deletions src/routelet/serve.py

This file was deleted.

26 changes: 16 additions & 10 deletions src/routelet/teacher.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,26 @@

# Condensed from docs/taxonomy.md. Kept stable so it caches across the
# per-command calls.
SYSTEM = """You are an intent router. Classify each user command into exactly one of five intents:
SYSTEM = """You are an intent classifier for short voice commands. Classify each into one of five
intents. First strip filler words (um, uh, like) and self-corrections, then classify.

- find_action: locate or operate a UI element on the current screen.
- find_action: locate or operate a named UI element on the current screen.
- integration: one discrete action against an app or service.
- chat: answer from general knowledge or conversation. No app action, no personal data.
- memory: store or recall a personal fact (storing needs an explicit remember/note/save).
- agent: a task needing two or more chained steps or a plan.
- chat: general knowledge or conversation. No app action, no personal data. The default.
- memory: store or recall a personal fact. Storing needs an explicit remember/note/save.
- agent: a task needing two or more steps or a plan.

Tie-breakers for the tricky cases:
- Two or more chained actions ("X and then Y") is agent, not integration.
- A question answered from a stored personal fact is memory; from world knowledge it is chat.
- A UI verb (click/tap/scroll) on a named element is find_action, even if an app is named.
Apply these boundary rules first for the tricky cases:
- Steps: two or more chained actions ("X and then Y"), or an implied multi-step task
needing a plan ("book me a restaurant"), is agent, not integration.
- Source: answered from a stored personal fact is memory; from world knowledge it is chat.
- Storing: "remember/note/save X" is memory even when it looks like another intent.
- A UI verb (click/tap/scroll/select) on a named element is find_action, even if an app is named.
- Playback (skip, pause, next, volume) is integration, not find_action, unless a button is named.
- "explain how to..." or "talk me through..." is chat, even when it names an app action."""
- "Explain how to..." or "talk me through..." is chat, even when it names an app action.

If a command still fits more than one after these rules, pick the first match in this order:
agent, memory, integration, find_action, chat."""

INTENT_SCHEMA = {
"type": "object",
Expand Down
6 changes: 3 additions & 3 deletions src/routelet/train_setfit.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ def calibrate_temperature(
) -> float:
"""Fit a scalar temperature T on calib_examples.

Minimizes NLL of softmax(logits / T) against true labels using
scipy.optimize.minimize_scalar with Brent's method (bounded to [0.05, 20]).
Minimizes NLL of softmax(logits / T) against true labels with
scipy.optimize.minimize_scalar (bounded method) over T in [0.5, 20.0].

Returns T > 0.

Expand Down Expand Up @@ -176,7 +176,7 @@ def threshold_analysis(
n = len(test_examples)

def _print_table(conf: np.ndarray, label: str) -> None:
print(f"\n--- confidence threshold analysis (124-row holdout, {label}) ---")
print(f"\n--- confidence threshold analysis ({n}-row holdout, {label}) ---")
print(
f"{'threshold':>10} {'deferred':>10} {'defer%':>8} "
f"{'kept_acc':>10} {'defer_acc':>10}"
Expand Down
Loading
Loading