Text Classification
PEFT
lora
document-question-answering
structured-decisions
calibration
synthetic-evaluation
Instructions to use botp/Solomon with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use botp/Solomon with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
| """Public document-state API and four-state answer semantics.""" | |
| import copy | |
| import json | |
| import math | |
| from pathlib import Path | |
| from ._vendor.contract import _state_parts, decision, parse_questions, present | |
| from ._vendor.prompts import boolean_block, label_block, listwise_block | |
| from ._vendor.semantics import listed_probs, p_yes | |
| from .artifacts import digest, sha256 | |
| TASKS = ("boolean", "single", "ordered", "multilabel", "entity") | |
| def branches(spec): | |
| task, req = spec["task"], spec["request"] | |
| if task == "boolean": | |
| return [(boolean_block(req["question"]), 4, "boolean/state4")] | |
| if task in ("single", "ordered"): | |
| block, width = listwise_block( | |
| req["question"], req["options"], ordered=task == "ordered", reserved=task == "single" | |
| ) | |
| return [(block, width, task + ("/choiceR" if task == "single" else "/choiceS"))] | |
| if task == "entity": | |
| return [ | |
| (boolean_block(req["template"].replace("{entity}", c)), 4, "entity/state4") | |
| for c in req["entities"] | |
| ] | |
| return [(*label_block(req["question"], c), "multilabel/state4") for c in req["labels"]] | |
| def distributions(spec, rows, temperature): | |
| if spec["task"] in ("boolean", "entity", "multilabel"): | |
| values = [p_yes(r["letter_logits"], temperature) for r in rows] | |
| return [[p, 1 - p] for p in values] | |
| return [listed_probs(rows[0]["letter_logits"], len(spec["texts"]), temperature).tolist()] | |
| def ordering_score(values): | |
| """Product of per-unit top probabilities; not a calibrated joint probability.""" | |
| if not values: | |
| raise ValueError("At least one answer unit is required") | |
| for p in values: | |
| if len(p) < 2 or not all(math.isfinite(v) and v >= 0 for v in p) or abs(sum(p) - 1) > 1e-6: | |
| raise ValueError("Invalid answer distribution") | |
| return math.prod(max(p) for p in values) | |
| class DocumentState: | |
| def __init__(self, owner, data): | |
| self._owner, self._data, self.closed = owner, data, False | |
| self.image_hashes = {p["image"]: sha256(p["image"]) for p in data["parts"] if "image" in p} | |
| def prefix_tokens(self): | |
| self._check() | |
| return len(self._data["prefix_ids"]) | |
| def _check(self): | |
| if self.closed: | |
| raise ValueError("Document state is closed") | |
| if any(sha256(path) != value for path, value in self.image_hashes.items()): | |
| raise ValueError("Document image changed after prefill") | |
| def save(self, path): | |
| """Save a source-bound replay recipe, never pickle executable cache objects.""" | |
| self._check() | |
| body = { | |
| "format": "solomon-mlx-replay-v1", | |
| "runtime": self._owner.identity["fingerprint"], | |
| "parts": self._data["parts"], | |
| "image_hashes": self.image_hashes, | |
| "prefix_ids_sha256": digest(self._data["prefix_ids"]), | |
| } | |
| Path(path).write_text(json.dumps({**body, "sha256": digest(body)}, indent=2)) | |
| def close(self): | |
| with self._owner.engine.lock: | |
| self._data.clear() | |
| self.closed = True | |
| def __enter__(self): | |
| self._check() | |
| return self | |
| def __exit__(self, *args): | |
| self.close() | |
| class Solomon: | |
| def load( | |
| cls, | |
| model_dir, | |
| profile="quality", | |
| *, | |
| chunk_size=2048, | |
| max_tokens=40960, | |
| page_selector=None, | |
| calibration=None, | |
| ): | |
| if profile != "quality": | |
| raise ValueError("Only full BF16 quality is implemented; quantization is secondary") | |
| from .engine import Engine | |
| return cls( | |
| Engine(model_dir, chunk_size=chunk_size, max_tokens=max_tokens), | |
| page_selector=page_selector, | |
| calibration=calibration, | |
| ) | |
| def __init__(self, engine, *, page_selector=None, calibration=None): | |
| self.engine, self.identity, self.page_selector = engine, engine.identity, page_selector | |
| self.temperatures = dict.fromkeys(TASKS, 1.0) | |
| self.calibration_status = "uncalibrated" | |
| if calibration is not None: | |
| artifact = json.loads(Path(calibration).read_text()) | |
| payload = {k: v for k, v in artifact.items() if k != "sha256"} | |
| if ( | |
| artifact.get("sha256") != digest(payload) | |
| or artifact["runtime"] != self.identity["fingerprint"] | |
| ): | |
| raise ValueError("Calibration checksum or MLX runtime identity mismatch") | |
| temps = artifact["temperatures"] | |
| if set(temps) != set(TASKS) or any( | |
| isinstance(v, bool) | |
| or not isinstance(v, (int, float)) | |
| or not math.isfinite(v) | |
| or not 0 < v <= 20 | |
| for v in temps.values() | |
| ): | |
| raise ValueError("Invalid temperatures") | |
| self.temperatures, self.calibration_status = temps, "profile_fitted" | |
| def prefill(self, document): | |
| parts = copy.deepcopy(_state_parts(document)) | |
| if not parts: | |
| parts = [{"text": ""}] | |
| for p in parts: | |
| if not isinstance(p, dict) or set(p) not in ({"text"}, {"image"}): | |
| raise ValueError("Each document part must contain only text or image") | |
| if "text" in p and not isinstance(p["text"], str): | |
| raise ValueError("Text parts must be strings") | |
| if "image" in p: | |
| p["image"] = str(Path(p["image"]).resolve(strict=True)) | |
| hashes = {p["image"]: sha256(p["image"]) for p in parts if "image" in p} | |
| state = DocumentState(self, self.engine.prefill(parts)) | |
| if state.image_hashes != hashes: | |
| state.close() | |
| raise ValueError("Image changed while document was being prefilled") | |
| return state | |
| def replay(self, path): | |
| body = json.loads(Path(path).read_text()) | |
| expected = body.pop("sha256") | |
| if ( | |
| digest(body) != expected | |
| or body["format"] != "solomon-mlx-replay-v1" | |
| or body["runtime"] != self.identity["fingerprint"] | |
| ): | |
| raise ValueError("Replay checksum or runtime mismatch") | |
| if any(sha256(p) != h for p, h in body["image_hashes"].items()): | |
| raise ValueError("Replay image changed") | |
| state = self.prefill(body["parts"]) | |
| if digest(state._data["prefix_ids"]) != body["prefix_ids_sha256"]: | |
| state.close() | |
| raise ValueError("Replay tokenization differs") | |
| return state | |
| def _answer(self, state, spec, execution="cached"): | |
| rows = [self.engine.ask(state._data, b, n, h, execution=execution) for b, n, h in branches(spec)] | |
| dists = distributions(spec, rows, self.temperatures[spec["task"]]) | |
| return { | |
| **present(spec, dists), | |
| "ordering_score": ordering_score(dists), | |
| "temperature": self.temperatures[spec["task"]], | |
| }, rows | |
| def decide( | |
| self, | |
| *, | |
| state, | |
| questions, | |
| evidence="support", | |
| evidence_max_calls=64, | |
| execution="cached", | |
| diagnostics=False, | |
| ): | |
| if not isinstance(state, DocumentState) or state._owner is not self: | |
| raise ValueError("State belongs to a different model instance") | |
| if evidence not in ("none", "support", "sufficiency", "removal"): | |
| raise ValueError("Invalid evidence level") | |
| if type(evidence_max_calls) is not int or not 0 <= evidence_max_calls <= 512: | |
| raise ValueError("Invalid evidence call budget") | |
| specs = parse_questions(questions) | |
| with self.engine.lock: | |
| state._check() | |
| answers, usage = {}, {"branches": 0, "input_tokens": 0, "evidence_calls": 0} | |
| for spec in specs: | |
| answer, rows = self._answer(state, spec, execution) | |
| body = self._evidence(state, spec, answer, evidence, evidence_max_calls) | |
| answer.update( | |
| evidence=body["references"], evidence_status=body["status"], evidence_detail=body | |
| ) | |
| if diagnostics: | |
| answer["branches"] = rows | |
| answers[spec["id"]] = answer | |
| usage["branches"] += len(rows) | |
| usage["input_tokens"] += sum( | |
| r["branch_tokens"] if execution == "cached" else r["prompt_tokens"] for r in rows | |
| ) | |
| usage["evidence_calls"] += body.get("calls", 0) | |
| return { | |
| "answers": answers, | |
| "usage": usage, | |
| "runtime": self.identity, | |
| "calibration_status": self.calibration_status, | |
| "answer_policy": "always_answers", | |
| } | |
| def _fresh(self, document, spec): | |
| with self.prefill(document) as state: | |
| answer, _ = self._answer(state, spec) | |
| return decision(spec, answer) | |
| def _evidence(self, state, spec, answer, level, budget): | |
| from ._vendor import evidence_v3 as v3 | |
| from ._vendor.evidence import image_pages, validate_pages, validate_spans | |
| from ._vendor.retrieval import lexical_select, remove | |
| body = { | |
| "references": [], | |
| "status": "not_requested", | |
| "calls": 0, | |
| "verification": "none", | |
| "faithfulness_established": False, | |
| } | |
| if level == "none": | |
| return body | |
| parts, req = state._data["parts"], spec["request"] | |
| task = spec["task"] | |
| if task == "entity": | |
| questions = [req["template"].replace("{entity}", c) for c in req["entities"]] | |
| elif task == "multilabel": | |
| questions = [req["question"] + " Label: " + c for c in req["labels"]] | |
| else: | |
| questions = [req["question"] + (" " + " ".join(req["options"]) if "options" in req else "")] | |
| images = [p["image"] for p in parts if "image" in p] | |
| needed = (1 if images else len(questions)) if level in ("sufficiency", "removal") else 0 | |
| needed += int(level == "removal") | |
| if needed > budget: | |
| return {**body, "status": "budget_exhausted", "required_calls": needed} | |
| baseline = decision(spec, answer) | |
| if images: | |
| if self.page_selector is None: | |
| return {**body, "status": "unsupported_page_selector", "pages_available": len(images)} | |
| pages = image_pages(images) | |
| selector = self.page_selector | |
| plan = None | |
| if hasattr(selector, "plan"): | |
| plan = selector.plan( | |
| pages, questions, **({"task": task} if getattr(selector, "task_aware", False) else {}) | |
| ) | |
| if type(plan.get("calls")) is not int or plan["calls"] < 0: | |
| raise ValueError("Invalid page selector call estimate") | |
| if needed + plan["calls"] > budget: | |
| return {**body, "status": "budget_exhausted", "required_calls": needed + plan["calls"]} | |
| selection = ( | |
| selector.execute(plan) if plan is not None else selector(copy.deepcopy(pages), questions) | |
| ) | |
| calls = selection.get("cost", {}).get("calls", 0) | |
| if calls != (plan["calls"] if plan is not None else 0): | |
| raise ValueError("Page selector exceeded its declared call budget") | |
| refs = validate_pages(pages, selection["evidence"]) | |
| body["calls"] = calls | |
| selected = {r["page"] for r in refs} | |
| page, remainder = 0, [] | |
| for part in parts: | |
| if "image" in part: | |
| page += 1 | |
| if page in selected: | |
| continue | |
| remainder.append(part) | |
| subsets = [([{"image": r["path"]} for r in refs], spec)] | |
| else: | |
| text = "".join(p["text"] for p in parts) | |
| selection = lexical_select(text, questions) | |
| refs = validate_spans(text, selection["evidence"]) | |
| structure = v3.Structure(text) | |
| packages, subsets = [], [] | |
| for i, q in enumerate(questions): | |
| subject = req["entities"][i] if task == "entity" else None | |
| package = v3.build(text, q, refs, subject=subject, structure=structure) | |
| unit = copy.deepcopy(spec) | |
| if "candidates" in spec: | |
| candidate = spec["candidates"][i] | |
| unit["candidates"] = [candidate] | |
| unit["request"]["entities" if task == "entity" else "labels"] = [candidate] | |
| subsets.append((package["text"], unit)) | |
| packages.append({k: v for k, v in package.items() if k != "text"}) | |
| body["packages"] = packages | |
| remainder = remove(text, refs) | |
| body.update( | |
| references=refs, status="found" if refs else "no_support_found", verification="retrieval_only" | |
| ) | |
| if level in ("sufficiency", "removal"): | |
| predictions = [self._fresh(doc, unit) for doc, unit in subsets] | |
| assembled = ( | |
| {k: v for d in predictions for k, v in d.items()} | |
| if "candidates" in spec and not images | |
| else predictions[0] | |
| ) | |
| body["evidence_only"] = {"prediction": assembled, "agrees_with_full": assembled == baseline} | |
| body["calls"] += len(subsets) | |
| body["verification"] = "fresh_source_reencoding" | |
| if level == "removal": | |
| removed = self._fresh(remainder, spec) | |
| body["evidence_removed"] = {"prediction": removed, "agrees_with_full": removed == baseline} | |
| body["calls"] += 1 | |
| return body | |