File size: 3,190 Bytes
4397e12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
66
67
68
69
70
71
72
73
74
75
76
"""Watch the model work: it gets a freshly generated fake project (configs, code, tests, docs, logs,
CSVs) in a sandbox directory and a question about it, and solves it with bash/read/edit/write/submit.

  python scripts/demo.py --model rl                       # random task kind
  python scripts/demo.py --model rl --kind fix_test --seed 7
  python scripts/demo.py --model rl --question "Which service has the most replicas?"

--model is a directory with model.safetensors + config.json (e.g. the `rl` or `base` folder of
the Hugging Face repo) or a training checkpoint (.pt). Runs on CPU, Intel XPU or CUDA.
"""
import argparse
import dataclasses
import json
import os
import random
import sys

import torch
from tokenizers import Tokenizer

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from tiny_agent.checkpoint import load_model  # noqa: E402
from tiny_agent.rollout import make_roller  # noqa: E402
from tiny_agent.tasks import KINDS, make_task  # noqa: E402


def device_auto():
    if hasattr(torch, "xpu") and torch.xpu.is_available():
        return "xpu"
    return "cuda" if torch.cuda.is_available() else "cpu"


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--model", default="rl")
    ap.add_argument("--tokenizer", default="tokenizer.json")
    ap.add_argument("--kind", default=None, help=f"one of {', '.join(KINDS)}")
    ap.add_argument("--question", default=None, help="ask your own question about the generated project")
    ap.add_argument("--seed", type=int, default=None)
    ap.add_argument("--temperature", type=float, default=0.7)
    ap.add_argument("--device", default=None)
    a = ap.parse_args()
    dev = a.device or device_auto()
    seed = a.seed if a.seed is not None else random.randrange(10**6)
    rng = random.Random(seed)
    task = make_task(rng, a.kind or rng.choice(KINDS))
    if a.question:
        task = dataclasses.replace(task, question=a.question, answer="?")
    print(f"seed {seed} | kind {task.kind} | device {dev}\nproject files: {', '.join(sorted(task.files))}\n")
    print(f"USER: {task.question}\n")
    tok = Tokenizer.from_file(a.tokenizer)
    model = load_model(a.model, device=dev, dtype=torch.bfloat16 if dev != "cpu" else torch.float32).eval()
    roller = make_roller("lockstep", model, tok, device=dev, max_len=4096, temperature=a.temperature)
    ep = roller.run([task])[0]
    for m in ep.messages[2:]:
        if m["role"] == "assistant":
            if m.get("think"):
                print(f"  think: {m['think']}")
            if m.get("content"):
                print(f"  say:   {m['content']}")
            for c in m.get("tool_calls") or []:
                print(f"  call:  {json.dumps(c)}")
        elif m["role"] == "tool":
            for r in m["results"]:
                body = r if len(r) < 600 else r[:600] + f"\n  ... ({len(r)} chars)"
                print("  result: " + body.replace("\n", "\n          "))
        print()
    if a.question:
        print(f"submitted: {ep.ws.submitted!r}")
    else:
        print(f"submitted: {ep.ws.submitted!r} | expected: {task.answer!r} | correct: {ep.correct}")


if __name__ == "__main__":
    main()