File size: 2,382 Bytes
3865888
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
"""Render + validate prompt templates (prompts/templates.json).

Rules enforced: every template declares system/user/schema/temperature/
max_tokens; every render fills all placeholders; every parsed output must
contain the schema keys (validated by callers via check_output).
"""
import json
import os
import string
from typing import Any, Dict

TEMPLATE_PATH = os.path.join("prompts", "templates.json")


def load_templates(path: str = TEMPLATE_PATH) -> Dict[str, Any]:
    with open(path, encoding="utf-8") as f:
        data = json.load(f)
    assert "version" in data and isinstance(data["version"], str)
    return data


def render(name: str, templates: Dict[str, Any], **kwargs) -> Dict[str, Any]:
    if name not in templates or not isinstance(templates[name], dict):
        raise KeyError(f"unknown template {name!r}")
    t = templates[name]
    for field in ("system", "user", "schema", "temperature", "max_tokens"):
        if field not in t:
            raise ValueError(f"template {name!r} missing {field!r}")
    needed = {n for _, n, _, _ in string.Formatter().parse(t["user"]) if n}
    missing = needed - set(kwargs)
    if missing:
        raise ValueError(f"template {name!r} missing params {sorted(missing)}")
    return {"system": t["system"], "user": t["user"].format(**kwargs),
            "schema": list(t["schema"]), "temperature": float(t["temperature"]),
            "max_tokens": int(t["max_tokens"]), "template_version": templates["version"]}


def extract_json(text: str, key: str) -> Dict[str, Any]:
    """Last-balanced-object extraction for thinking models."""
    start = text.rfind('{"' + key + '"')
    if start < 0:
        start = text.find("{")
    depth, end = 0, -1
    for i in range(max(start, 0), len(text)):
        if text[i] == "{":
            depth += 1
        elif text[i] == "}":
            depth -= 1
            if depth == 0:
                end = i + 1
                break
    if start < 0 or end <= start:
        raise ValueError(f"no JSON with {key!r} in output")
    data = json.loads(text[start:end])
    if key not in data:
        raise ValueError(f"output missing {key!r}")
    return data


def check_output(data: Dict[str, Any], schema: list) -> Dict[str, Any]:
    missing = [k for k in schema if k not in data]
    if missing:
        raise ValueError(f"output missing schema keys {missing}")
    return data