THX-02 / thx02 /engine.py
doofz's picture
Add files using upload-large-folder tool
b7b8d59 verified
Raw History Blame Contribute Delete
3.67 kB
"""Request planning shared by the local runtime and the server: option-order averaging, the joint-read rule and
the pieces of self-gated thinking (gate question, think prompt, re-read with the thought)."""
from __future__ import annotations
import json
import math
from .protocol import DEFAULT_INSTRUCTIONS, describe, options
THINK_SYSTEM = "You reason briefly about decisions. Think in at most 60 words, only what decides the answer."
THOUGHT_NOTE = "\n\nReasoning notes (may contain mistakes): "
GATE_QUESTION = ("Would a careful person need to work this out step by step (calculation, logic puzzle, code tracing, "
"multi-hop reasoning) rather than just read, recognise or classify it?")
# thinking presets: "auto" = Decision Index setting (thinks only when unsure and the question needs reasoning),
# True = think on nearly every question
AUTO = {"tau": 0.6, "gate": 0.2, "alpha": 0.7, "cap": 96}
ALWAYS = {"tau": 0.97, "gate": 0.0, "alpha": 0.5, "cap": 320}
def orders(n: int, k: int) -> list[list[int]]:
"""Identity, reversed, then cyclic shifts of n options; the first k distinct orders."""
out = [list(range(n)), list(range(n))[::-1]] + [[(i + s) % n for i in range(n)] for s in range(1, n)]
seen, uniq = set(), []
for o in out:
if tuple(o) not in seen:
seen.add(tuple(o))
uniq.append(o)
return uniq[:k]
def facet_joint(questions: dict) -> bool:
"""Read jointly when several questions apply the same criteria to different items with plain-text instructions
(select-all candidates, aspect/sentiment pairs, per-entity labels); otherwise one question per request."""
v = list(questions.values())
return (len(v) > 1 and all(isinstance(q.get("instructions"), str) for q in v) and len({q.get("type") for q in v}) == 1
and len({json.dumps(q.get("criteria"), sort_keys=True) for q in v}) == 1)
def permuted(q: dict, order: list[int]) -> dict:
crit = q["criteria"]
keys, vals = list(crit), list(crit.values())
return {**q, "criteria": {keys[i]: vals[i] for i in order}}
def distribution(a: dict, keys: list[str]) -> list[float]:
if a["type"] == "noul":
return [a["noul"] if x == "true" else 1 - a["noul"] for x in keys]
return [a["probabilities"][x] for x in keys]
def geo_mean(ps: list[list[float]]) -> list[float]:
m = [math.exp(sum(math.log(max(p[i], 1e-9)) for p in ps) / len(ps)) for i in range(len(ps[0]))]
z = sum(m)
return [x / z for x in m]
def gate_request(state, q: dict) -> dict:
"""Cheap yes/no request: does question q need step-by-step reasoning? Uses a short state excerpt."""
_, desc = options(q)
text = ("Question: " + describe(q.get("instructions") or "Choose the best matching option.") + "\nOptions:\n" +
"\n".join(str(x)[:200] for x in desc[:12]) + "\n\nContext excerpt:\n" + describe(state)[:1200])
return {"state": text, "questions": {"g": {"type": "noul", "instructions": GATE_QUESTION}}}
def think_body(enc, request: dict) -> str:
"""User text of the think pass (the format the think adapter was trained on): state, one question, coded options."""
(key, q), = request["questions"].items()
_, desc = options(q)
return ("State:\n" + enc._text(request["state"]) + "\n\nQuestion:\n" + enc._text(q.get("instructions") or DEFAULT_INSTRUCTIONS)
+ "\nOptions:\n" + "\n".join(f"{c}: {enc._text(t)}" for c, t in zip(enc.codes, desc)))
def with_thought(q: dict, thought: str) -> dict:
q = dict(q)
q["instructions"] = describe(q.get("instructions") or "Choose the best matching option.") + THOUGHT_NOTE + thought.strip()
return q