| """Run the wood on the real small model via the deployed Modal endpoint. |
| |
| Doubles as the 3B reliability gate: it reports how often the model emits a |
| parseable JSON object and at least one valid offer. If 3B holds up, we keep |
| Tiny Titan eligibility; if not, fall back to 7B (set TTW_MODEL and redeploy). |
| |
| Run (after `python -m modal deploy serve.py`): |
| python scripts/run_llm.py |
| """ |
|
|
| import sys |
| from pathlib import Path |
|
|
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) |
|
|
| from ttw.actions import parse_actions |
| from ttw.agents import make_llm_policy |
| from ttw.events import EventDeck |
| from ttw.llm import ModalLLM |
| from ttw.market import gini |
| from ttw.sim import step |
| from ttw.world import seed_world |
|
|
|
|
| def main(turns: int = 15) -> None: |
| world = seed_world() |
| client = ModalLLM() |
| policy = make_llm_policy(client, temperature=0.7) |
| deck = EventDeck(seed=7) |
|
|
| parsed_ok = 0 |
| json_ok = 0 |
| total = 0 |
|
|
| for _ in range(turns): |
| |
| if world.turn in (4, 9, 13): |
| legend = deck.draw(world) |
| print(f"\n*** WOOD LEGEND: {legend.title} ***") |
| print(f" {legend.flavor} (inspired by: {legend.inspired_by})") |
|
|
| events = step(world, policy) |
| raw = policy.state["raw"] |
|
|
| |
| for name, text in raw.items(): |
| total += 1 |
| offers, _ = parse_actions(name, text) |
| from ttw.actions import _extract_json |
|
|
| if _extract_json(text) is not None: |
| json_ok += 1 |
| if offers: |
| parsed_ok += 1 |
|
|
| trades = [e for e in events if e["type"] == "trade"] |
| gossip = [e for e in events if e["type"] == "gossip"] |
| prices = " ".join(f"{g}={p:.0f}" for g, p in world.last_price.items()) |
| nets = [c.net_worth(world.last_price) for c in world.alive()] |
| print(f"\n=== turn {world.turn} | {len(trades)} trades | gini {gini(nets):.2f} | {prices}") |
| for t in trades: |
| print(f" {t['buyer']} bought {t['qty']} {t['good']} from {t['seller']} @ {t['price']}") |
| for g in gossip: |
| print(f" [rumor] {g['creature']}: {g['message']}") |
|
|
| |
| sample_name = next(iter(policy.state["raw"])) |
| print(f"\n--- sample reasoning trace ({sample_name}, last turn) ---") |
| print(policy.state["raw"][sample_name].strip()[:500]) |
|
|
| print("\n=== RELIABILITY ===") |
| print(f"valid JSON object: {json_ok}/{total} ({100*json_ok/total:.0f}%)") |
| print(f"yielded >=1 valid offer: {parsed_ok}/{total} ({100*parsed_ok/total:.0f}%)") |
| print("\nFinal standings:") |
| for c in sorted(world.alive(), key=lambda x: -x.net_worth(world.last_price)): |
| print(f" {c.name:<9} pebbles={c.pebbles:>4} wellbeing={c.wellbeing} net={c.net_worth(world.last_price):.0f}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|