AdmiralTaco Claude Opus 4.8 commited on
Commit
6b7cda8
·
1 Parent(s): 60816b0

Traces: publish council traces with per-row model/lab attribution

Browse files

publish_traces.py now drives the real four-engine council (was the old
single ModalLLM), tags every row with engine/model/lab so four labs'
small models can be compared on the same market state, refreshes the
dataset card (council table, field list), and adds an engine-health gate:
empties counted per lab, upload refused (unless --force) when a lab is
fully silent or >25% of responses are empty. Reviewer pass: 1 blocking
finding (constant by-lab row count could not reveal a flaked engine),
fixed; 2 nits applied. Demo shot-list updated for the v4 reel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files changed (2) hide show
  1. scripts/publish_traces.py +76 -19
  2. tasks/demo-shot-list.md +43 -24
scripts/publish_traces.py CHANGED
@@ -1,11 +1,13 @@
1
  """Generate and publish Thousand Token Wood agent traces to the Hub.
2
 
3
- Runs the real small model for a few turns, captures each creature's full prompt,
4
- raw response, parsed actions, and private "thought" for every turn, and uploads
5
- them as a public dataset. This is the "Sharing is Caring" bonus quest: open agent
6
- traces others can learn from.
7
-
8
- Usage (HF_TOKEN must be set, e.g. sourced from .env):
 
 
9
  python scripts/publish_traces.py
10
  python scripts/publish_traces.py --no-upload # just write traces.jsonl
11
  """
@@ -19,9 +21,10 @@ from pathlib import Path
19
  sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
20
 
21
  from ttw.actions import _extract_json, parse_actions
22
- from ttw.agents import make_llm_policy
 
23
  from ttw.events import EventDeck
24
- from ttw.llm import ModalLLM
25
  from ttw.sim import step
26
  from ttw.world import seed_world
27
 
@@ -32,32 +35,58 @@ DATASET_CARD = """\
32
  ---
33
  license: mit
34
  language: [en]
35
- tags: [agent-traces, multi-agent, small-models, gradio, build-small-hackathon]
 
36
  ---
37
 
38
- # Thousand Token Wood -- Agent Traces
39
 
40
  Open agent traces from [Thousand Token Wood](https://huggingface.co/spaces/build-small-hackathon/thousand-token-wood-sim),
41
- a tiny emergent economy where five woodland creatures, each a **Qwen2.5-3B** agent,
42
- trade goods for pebbles, gossip, and react to reskinned market-history "Wood Legends".
43
-
44
- Each row is one creature's turn: the full system + user prompt it saw, its raw JSON
45
- response, its parsed offers and gossip, and its private `thought`. Shared for the
46
- **Sharing is Caring** bonus quest of the Build Small Hackathon.
 
 
 
 
 
 
 
 
 
 
47
 
48
  ## Fields
49
  - `turn` (int), `creature` (str)
 
50
  - `system`, `user` (str): the exact prompt the agent received
51
- - `response` (str): the raw model output
52
  - `thought` (str|null): the agent's private reasoning for the turn
53
- - `offers` (list): parsed `{side, good, price, qty}` actions
54
  - `gossip` (list[str]): rumors the agent broadcast
55
  """
56
 
57
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  def generate(turns: int = 8) -> list[dict]:
59
  world = seed_world()
60
- policy = make_llm_policy(ModalLLM(), temperature=0.7)
 
 
61
  deck = EventDeck(seed=5)
62
  records: list[dict] = []
63
  for _ in range(turns):
@@ -69,10 +98,15 @@ def generate(turns: int = 8) -> list[dict]:
69
  msgs = st["messages"][name]
70
  parsed = _extract_json(raw) or {}
71
  offers, gossip = parse_actions(name, raw)
 
 
72
  records.append(
73
  {
74
  "turn": world.turn,
75
  "creature": name,
 
 
 
76
  "system": msgs[0]["content"],
77
  "user": msgs[1]["content"],
78
  "response": raw,
@@ -88,13 +122,36 @@ def main():
88
  ap = argparse.ArgumentParser()
89
  ap.add_argument("--turns", type=int, default=8)
90
  ap.add_argument("--no-upload", action="store_true")
 
 
91
  args = ap.parse_args()
92
 
93
  records = generate(args.turns)
94
  OUT.write_text(
95
  "\n".join(json.dumps(r, ensure_ascii=False) for r in records), encoding="utf-8"
96
  )
 
 
 
 
 
 
 
 
 
 
 
 
97
  print(f"wrote {len(records)} trace records to {OUT}")
 
 
 
 
 
 
 
 
 
98
 
99
  if args.no_upload:
100
  return
 
1
  """Generate and publish Thousand Token Wood agent traces to the Hub.
2
 
3
+ Runs the real multi-model COUNCIL for a few turns, captures each creature's full
4
+ prompt, raw response, parsed actions, and private "thought" for every turn --
5
+ tagged with which lab's model produced it -- and uploads them as a public
6
+ dataset. This is the "Sharing is Caring" bonus quest: open agent traces others
7
+ can learn from, and a side-by-side of four labs' small models deciding in the
8
+ same market.
9
+
10
+ Usage (HF_TOKEN must be set, e.g. sourced from .env; engines deployed):
11
  python scripts/publish_traces.py
12
  python scripts/publish_traces.py --no-upload # just write traces.jsonl
13
  """
 
21
  sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
22
 
23
  from ttw.actions import _extract_json, parse_actions
24
+ from ttw.agents import make_council_policy
25
+ from ttw.council import CREATURE_ENGINE, ENGINE_LABELS, ENGINES
26
  from ttw.events import EventDeck
27
+ from ttw.llm import build_council_clients
28
  from ttw.sim import step
29
  from ttw.world import seed_world
30
 
 
35
  ---
36
  license: mit
37
  language: [en]
38
+ tags: [agent-traces, multi-agent, small-models, gradio, build-small-hackathon,
39
+ minicpm, nemotron, gpt-oss]
40
  ---
41
 
42
+ # Thousand Token Wood -- Council Agent Traces
43
 
44
  Open agent traces from [Thousand Token Wood](https://huggingface.co/spaces/build-small-hackathon/thousand-token-wood-sim),
45
+ a tiny emergent economy where five woodland creatures trade goods for pebbles,
46
+ gossip, and react to reskinned market-history "Wood Legends". Each creature
47
+ thinks on a **different lab's small model** (distinct-engine budget 29.5B <= 32B):
48
+
49
+ | Creature | Model | Lab |
50
+ |---|---|---|
51
+ | Oona (owl) | openai/gpt-oss-20b | OpenAI |
52
+ | Bramble (squirrel) | openbmb/MiniCPM3-4B | OpenBMB |
53
+ | Fenn (fox) | nvidia/Nemotron-Mini-4B-Instruct | NVIDIA |
54
+ | Mossback (tortoise) + Pip (mouse) | AdmiralTaco/ttw-trader-0.5b | fine-tuned (ours) |
55
+
56
+ Each row is one creature's turn: the exact system + user prompt it saw, its raw
57
+ JSON response, its parsed offers and gossip, its private `thought`, and the
58
+ model/lab that produced it -- so you can compare how four labs' small models
59
+ read the *same* market state and choose differently. Shared for the **Sharing
60
+ is Caring** bonus quest of the Build Small Hackathon.
61
 
62
  ## Fields
63
  - `turn` (int), `creature` (str)
64
+ - `engine` (str), `model` (str), `lab` (str): which council engine produced the row
65
  - `system`, `user` (str): the exact prompt the agent received
66
+ - `response` (str): the raw model output (normalized; harmony channels stripped)
67
  - `thought` (str|null): the agent's private reasoning for the turn
68
+ - `offers` (list): parsed `{creature, side, good, price, qty}` actions
69
  - `gossip` (list[str]): rumors the agent broadcast
70
  """
71
 
72
 
73
+ def _warm_engines(clients) -> None:
74
+ """Ping every engine once so none cold-starts mid-run (a cold engine can
75
+ hard-timeout and its creatures would sit the turn out)."""
76
+ ping = [[{"role": "user", "content": "ready?"}]]
77
+ for eid, client in clients.items():
78
+ try:
79
+ client.chat_batch(ping, max_tokens=8)
80
+ print(f" warmed {eid}")
81
+ except Exception as e: # noqa: BLE001
82
+ print(f" warm {eid} failed (continuing): {e!r}")
83
+
84
+
85
  def generate(turns: int = 8) -> list[dict]:
86
  world = seed_world()
87
+ clients = build_council_clients()
88
+ _warm_engines(clients)
89
+ policy = make_council_policy(clients, temperature=0.7)
90
  deck = EventDeck(seed=5)
91
  records: list[dict] = []
92
  for _ in range(turns):
 
98
  msgs = st["messages"][name]
99
  parsed = _extract_json(raw) or {}
100
  offers, gossip = parse_actions(name, raw)
101
+ eid = CREATURE_ENGINE.get(name, "")
102
+ model_label, lab = ENGINE_LABELS.get(eid, ("", ""))
103
  records.append(
104
  {
105
  "turn": world.turn,
106
  "creature": name,
107
+ "engine": eid,
108
+ "model": ENGINES[eid].model if eid in ENGINES else model_label,
109
+ "lab": lab,
110
  "system": msgs[0]["content"],
111
  "user": msgs[1]["content"],
112
  "response": raw,
 
122
  ap = argparse.ArgumentParser()
123
  ap.add_argument("--turns", type=int, default=8)
124
  ap.add_argument("--no-upload", action="store_true")
125
+ ap.add_argument("--force", action="store_true",
126
+ help="publish even if the engine-health gate trips")
127
  args = ap.parse_args()
128
 
129
  records = generate(args.turns)
130
  OUT.write_text(
131
  "\n".join(json.dumps(r, ensure_ascii=False) for r in records), encoding="utf-8"
132
  )
133
+ # Engine-health gate: empties per lab, not rows per lab (row counts are a
134
+ # constant of the cast and can never reveal a flaked engine). Scattered
135
+ # empties are expected (e.g. gpt-oss truncation); a whole lab silent or a
136
+ # large empty fraction means the dataset's "four labs side-by-side" claim
137
+ # would be false -- refuse to publish that.
138
+ total = {r["lab"]: 0 for r in records}
139
+ empty = dict.fromkeys(total, 0)
140
+ for r in records:
141
+ total[r["lab"]] += 1
142
+ if not r["response"].strip():
143
+ empty[r["lab"]] += 1
144
+ n_empty = sum(empty.values())
145
  print(f"wrote {len(records)} trace records to {OUT}")
146
+ print(" empties by lab: " + ", ".join(
147
+ f"{lab}: {empty[lab]}/{total[lab]}" for lab in total))
148
+ dead_labs = [lab for lab in total if empty[lab] == total[lab]]
149
+ too_empty = records and n_empty / len(records) > 0.25
150
+ if (dead_labs or too_empty) and not args.force:
151
+ print(f"ABORTING upload: dead labs {dead_labs or 'none'}, "
152
+ f"empty fraction {n_empty}/{len(records)}. "
153
+ "Fix the engines (or rerun with --force to publish anyway).")
154
+ sys.exit(1)
155
 
156
  if args.no_upload:
157
  return
tasks/demo-shot-list.md CHANGED
@@ -1,30 +1,49 @@
1
- # Thousand Token Wood — demo video shot-list (~75s)
2
 
3
- The recorded attract run already tells the whole story, so the easiest high-quality
4
- demo is: keep-warm the engines, open the Space, hit "▶ Watch the saga", and narrate
5
- over it. Target 60-90s. Money shot in the first 10 seconds.
 
6
 
7
- Before filming: run `python scripts/keep_warm.py` so the live council is hot, and
8
- open the Space fresh so the attract opening frame is already on screen.
 
9
 
10
- | Time | On screen | Say (voiceover) |
 
 
 
 
 
 
 
 
 
11
  |---|---|---|
12
- | 0:00-0:08 | Space loads — the town square is ALREADY alive (recorded opening), five creature cards each tagged with a different lab's model. | "Five woodland creatures. Each one thinks on a different lab's small modelOpenAI, NVIDIA, OpenBMB, and my own fine-tuned half-billion." |
13
- | 0:08-0:18 | Click **▶ Watch the saga**. Cards update, thoughts (💭) change per creature, Wood Street Journal headline animates. | "You're the Patron a shadow financier. You whisper insider tips, short the market, bribe, and broker alliances." |
14
- | 0:18-0:32 | The legend frame: "The Run on Oona's Hoard"; honey price line dives on the chart; headline "Patron's Sweet Gambit…". | "Whisper a true tip, short the crop, and spring the panichoney crashes exactly as you planned." |
15
- | 0:32-0:45 | Heat bar slams toward the red; crosses Heron's line (70). Headline turns to the inquiry. | "But every dirty win raises your heat. Cross the Magistrate's line and Heron opens an investigation." |
16
- | 0:45-0:55 | Verdict lands the fine; purse drops; heat clamps back. Relationship matrix shows grudges/alliances shifting. | "Caught. A hundred-pebble fine and the creatures remember how you treated them, and scheme back." |
17
- | 0:55-1:05 | Stop the replay; press **Step** once to show it's live — a real council turn computes, new thoughts appear. | "And it's all live every thought here is a real small model deciding in real time, not a script." |
18
- | 1:05-1:15 | Pull back to the full console. | "Thousand Token Wood. Five labs, five minds, one emergent economy running entirely on small models." |
 
 
 
 
 
19
 
20
  ## Tips
21
- - Record at 1080p+, browser zoomed so the creature cards + their model badges and 💭 thoughts are legible.
22
- - If a live Step is slow on camera, pre-warm harder or just cut to it; the attract replay carries the demo on its own.
23
- - The two cleanest headlines in the recording: "Patron's Sweet Gambit: Shorting Honey and Bribing Fenn…" and "Honey Prices Crash; Acorn Trade Tightens the Ties."
24
- - Do NOT name the TV show that inspired the drama in the video.
25
-
26
- ## Sponsor framing (for the written submission, not the video)
27
- Name each creature's model explicitly so the OpenAI / NVIDIA / OpenBMB tracks see
28
- their model in use: Oona = gpt-oss-20B (OpenAI), Fenn = Nemotron-Mini-4B (NVIDIA),
29
- Bramble = MiniCPM3-4B (OpenBMB), Mossback + Pip = AdmiralTaco/ttw-trader-0.5B
30
- (fine-tuned). Distinct-engine budget 29.5B 32B.
 
 
 
 
1
+ # Thousand Token Wood — demo video script (v4 "the wood fights back")
2
 
3
+ Target **75-90s**. Money shot in the first 8 seconds. Official rule: "Film a demo
4
+ selling your Space no humility." It just has to show the app working (so judges can
5
+ score it even if a live run hits GPU limits) and be hosted on YouTube / uploaded to the
6
+ Space / public.
7
 
8
+ The recorded attract reel already tells the whole v4 arc, so the easiest high-quality
9
+ demo is: open the Space, hit **▶ Watch the saga**, and narrate over it, then one live
10
+ **Step** at the end to prove it is real.
11
 
12
+ ## Before filming
13
+ - (Optional) `python scripts/keep_warm.py` so the closing live Step is instant on camera.
14
+ - Open the Space fresh so the attract opening frame (the town square, already alive) is on
15
+ screen before you start.
16
+ - 1080p+, browser zoomed so the creature cards, their **lab-model badges**, the 💭
17
+ thoughts, the **Gambit exposure** meter, and the **price chart** are all legible.
18
+
19
+ ## The script
20
+
21
+ | Beat | On screen (the reel) | Say (voiceover) |
22
  |---|---|---|
23
+ | **Hook** 0:00-0:08 | Town square already alive. Five creature cards, each badged with a different lab's model. | "Five small models, five different labs, one living economy and you are the financier trying to rig it." |
24
+ | **Setup** 0:08-0:20 | Click **▶ Watch the saga**. Cards update, 💭 thoughts change per creature, the Wood Street Journal headline animates. | "You are the Patron: a shadow financier. You whisper insider tips, short the market, bribe, and broker alliances. The chart is your scoreboard." |
25
+ | **Gambit pays** 0:20-0:34 | Legend "The Run on Oona's Hoard." Honey's price line **dives**. Headline: "Honey Maker Shuttered…". Ticker: "the gambit pays **+39p**." | "Short the honey, whisper the panic, spring the runand the crash pays. Thirty-nine pebbles, clean. Exactly as authored." |
26
+ | **The wood remembers** 0:34-0:52 | Wariness gauge fills **0/5 → 3/5 ▮▮▮▯▯**. Ticker: "the wood murmurs to Heron: 3 soured creatures come forward." The **Gambit exposure** meter forecast drops **+48p → +13p**. | "But the wood remembers. Burn the same creatures and they turn on you — they hoard against your crash and they testify to the magistrate. Watch your expected payoff collapse before you even move." |
27
+ | **Same move, blunted** 0:52-1:02 | Run the identical gambit. Ticker: "the wood braces… the crash is blunted." Honey barely dips where it cratered before. Payoff **+1p**. | "Run the exact same gambit, and the wood stands on the other side. Forty-eight pebbles of edge — down to one. A trick you repeat is a trick that dies." |
28
+ | **Caught** 1:02-1:12 | Verdict frame: "Heron's verdict: **exile for Oona**." Purse/heat react. | "And now you are caught. The magistrate exiles Oona, the honey-keeper. Your greed cost the wood its owl." |
29
+ | **It's live** 1:12-1:25 | Stop the replay; press **Step** once — a real council turn computes, fresh 💭 thoughts appear. Pull back to the full console. | "And every thought here is a real small model deciding live — not a script. Five labs, five minds, an economy that fights back. Thousand Token Wood." |
30
+
31
+ ## 30-second cut (if you want a short version too)
32
+ Hook (0-6) → gambit pays +39 (6-14) → "but the wood remembers — same move, blunted to +1,
33
+ and Heron exiles the owl" over the wariness gauge + exposure meter (14-26) → "all live small
34
+ models" close (26-30).
35
 
36
  ## Tips
37
+ - The single best 5-second clip is the **exposure meter dropping +48 +13** next to the
38
+ **wariness gauge filling** that is the v4 thesis in one frame. Make sure it is on screen.
39
+ - Cleanest headlines in the reel: "Honey Maker Shuttered: Market Buzzes with Rumors" and
40
+ "Patron's Sweet Gamble: Oona's 40p Bribe Fuels a Honey-Market Tumble."
41
+ - If a live Step is slow on camera, pre-warm harder or just cut to it; the attract replay
42
+ carries the demo on its own.
43
+ - **Do NOT name the TV show that inspired the drama** in the video.
44
+
45
+ ## Sponsor framing (for the written README / social post, not the voiceover)
46
+ Name each creature's model so the OpenAI / NVIDIA / OpenBMB tracks see their model in use:
47
+ Oona = gpt-oss-20B (OpenAI), Fenn = Nemotron-Mini-4B (NVIDIA), Bramble = MiniCPM3-4B
48
+ (OpenBMB), Mossback + Pip = AdmiralTaco/ttw-trader-0.5B (fine-tuned). Distinct-engine
49
+ budget 29.5B ≤ 32B.