"""Tacit decisions: one forward pass per decision, optionally escalating the least confident ones to the model's own reasoning. Runs on transformers (default) or vLLM. from transformers.dynamic_module_utils import get_class_from_dynamic_module Tacit = get_class_from_dynamic_module("tacit_decision.Tacit", "morriszjm/Tacit-9B") tacit = Tacit.from_pretrained("morriszjm/Tacit-9B", adaptive=True, tau=0.5, max_cot_share=0.2) # tacit = Tacit.from_pretrained("morriszjm/Tacit-9B", engine="vllm", adaptive=True) d = tacit.decide(state="Order #4471 ...", question="What does the customer want?", options=["track_order", "cancel_order", "refund"]) d["answer"], d["probs"], d["route"] # "cancel_order", {...}, "one_forward" or "cot" One forward: the prompt Tacit was trained on, the next-token distribution read over the option labels (A, B, C... / Yes, No / 1, 2, 3...) and renormalised over them. No tokens are generated. Adaptive (`adaptive=True`): a decision whose margin (log-probability gap between its top two options) is below `tau` is asked again with the model's thinking on; the reasoning ends, "Answer:" is appended, and the answer is read the same way, so an escalated decision also comes with probabilities and never fails to parse. `max_cot_share` caps the share of the last `cot_window` decisions that may be escalated (rounded up), so traffic cannot drift into reasoning, also on a model that serves for days; `cot_window=None` counts every decision since loading, `max_cot_share=None` removes the cap. vLLM (`engine="vllm"`): the labels are read from the top `logprobs` (default 20) log-probabilities of the full vocabulary, a label outside them counting as probability 0; escalated decisions of one batch reason in parallel. `vllm_kwargs` go to `vllm.LLM` (e.g. gpu_memory_utilization, max_model_len, tensor_parallel_size). Qwen3.5-based checkpoints on Hopper need nvcc for vLLM's default gated-delta-rule kernel; without it (`native_gdn=None` detects this) the Triton kernel is used and the engine runs in this process. A vLLM server (`engine="server"`): `vllm serve morriszjm/Tacit-9B`, then `Tacit.from_pretrained("morriszjm/Tacit-9B", engine="server", base_url="http://127.0.0.1:8000/v1")`. Only the tokenizer loads on the client; vLLM is not needed there. Or put an HTTP gateway in front of the server, so every client shares one cap: python tacit_decision.py serve --model morriszjm/Tacit-9B --upstream http://127.0.0.1:8000/v1 --adaptive curl -s 127.0.0.1:8100/v1/decide -d '{"state": "...", "question": "...", "options": ["a", "b"]}' """ from __future__ import annotations import collections import importlib import importlib.util import json import math import os import shutil import string import threading import urllib.error import urllib.request from typing import Any, Dict, List, Optional, Sequence, Tuple import torch LETTERS = string.ascii_uppercase ONE_FORWARD_SYSTEM = ("You are a decision function. You will be given a state and one question. " "Reply with the answer label only: no words, no punctuation, no explanation.") COT_SYSTEM = "You are a careful assistant that answers questions about a given context." KINDS = {"choice": "choice", "yes_no": "yes_no", "noul": "yes_no", "score": "score"} def _labels(kind: str, k: int) -> List[str]: if kind == "yes_no": return ["Yes", "No"] if kind == "score": return [str(i + 1) for i in range(k)] return list(LETTERS[:k]) def _one_forward_user(state: str, question: str, kind: str, options: Sequence[str], labels: Sequence[str]) -> str: prefix = ["State:", state if state else "(empty)", "", "Question: %s" % question] suffix = [] if kind == "yes_no": suffix.append("Answer Yes or No.") elif kind == "score": prefix.append("Pick the level that applies (the levels are ordered):") suffix += ["%s. %s" % (labels[j], o) for j, o in enumerate(options)] suffix.append("Answer with the number only.") else: prefix.append("Options:") suffix += ["%s. %s" % (labels[j], o) for j, o in enumerate(options)] suffix.append("Answer with the letter only.") return "\n".join(prefix) + "\n" + "\n".join(suffix) def _cot_user(state: str, question: str, kind: str, options: Sequence[str], labels: Sequence[str]) -> str: parts = [state.strip(), "", "Question: " + question.strip(), ""] if kind == "yes_no": parts.append("Answer Yes or No.") form = "Answer: Yes or Answer: No" elif kind == "score": parts += ["Levels:"] + ["%s. %s" % (labels[j], o) for j, o in enumerate(options)] form = "Answer: " else: parts += ["Options:"] + ["%s. %s" % (labels[j], o) for j, o in enumerate(options)] form = "Answer: