ShubhamSetia commited on
Commit
639f395
·
1 Parent(s): 0100d6e

finetune: add actor SFT v0 dataset pipeline

Browse files
.gitignore CHANGED
@@ -8,3 +8,5 @@ __pycache__/
8
  .ruff_cache/
9
 
10
  .DS_Store
 
 
 
8
  .ruff_cache/
9
 
10
  .DS_Store
11
+
12
+ finetune/data/*.jsonl
finetune/README.md ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Actor SFT Dataset V0
2
+
3
+ This directory contains the first-pass dataset tooling for fine-tuning an AI Puppet Theater Actor agent. It prepares chat-style supervised fine-tuning rows for the target model `openbmb/MiniCPM5-1B`; it does not train, quantize, publish, or integrate a model into the Space.
4
+
5
+ The goal is to teach the Actor agent to return one compact, valid JSON object for a single puppet beat. The output shape matches the planned actor contract:
6
+
7
+ ```json
8
+ {
9
+ "intent": "inspect_prop",
10
+ "line": "This rubber duck squeaks exactly like a guilty witness.",
11
+ "emotion": "investigative",
12
+ "gesture": "leans toward the glowing prop",
13
+ "stage_effect": "prop_table_glow",
14
+ "memory_update": "Noted that the rubber duck behaved like evidence.",
15
+ "tool_request": {
16
+ "tool": "inspect_prop",
17
+ "args": {"prop": "rubber duck"},
18
+ "reason": "The prop may reveal a stage clue."
19
+ }
20
+ }
21
+ ```
22
+
23
+ `memory_update` may be `null` when no useful memory should be saved. `tool_request` may also be `null`. Allowed tools are `inspect_prop`, `consult_stage_oracle`, and `change_lighting`.
24
+
25
+ ## Schema
26
+
27
+ Each SFT row is JSONL with:
28
+
29
+ ```json
30
+ {
31
+ "id": "actor-sft-v0-000001",
32
+ "source_mix": ["synthetic_v0", "deterministic_templates", "ai_puppet_theater_runtime_schema"],
33
+ "row_type": "prop_inspection",
34
+ "messages": [
35
+ {"role": "system", "content": "You are an Actor agent in AI Puppet Theater..."},
36
+ {"role": "user", "content": "premise: ...\nshow_state JSON: ...\nactor JSON: ...\ndirector_instruction: ..."},
37
+ {"role": "assistant", "content": "{\"intent\":\"...\",\"line\":\"...\"}"}
38
+ ]
39
+ }
40
+ ```
41
+
42
+ The assistant message content is a serialized JSON object, not a nested object, so it is directly usable as a chat SFT completion.
43
+
44
+ Row types in v0:
45
+
46
+ - `normal_reaction`
47
+ - `prop_inspection`
48
+ - `oracle_consult`
49
+ - `lighting_change`
50
+ - `memory_callback`
51
+ - `secret_hint_or_reveal`
52
+ - `finale`
53
+ - `comedic_confusion`
54
+
55
+ ## Generate
56
+
57
+ Run from the repository root:
58
+
59
+ ```bash
60
+ python finetune/scripts/generate_actor_sft_v0.py
61
+ ```
62
+
63
+ Generation is deterministic by default using a fixed seed, so the sample and eval files can be regenerated reproducibly. The synthetic-v0 pool currently uses 40 premises, 25 actor profiles, 30+ props, 10+ moods, 10+ stage/lighting states, multiple line templates per row type, multiple memory update templates, and multiple Director instructions per row type.
64
+
65
+ Default output:
66
+
67
+ - `finetune/data/actor_sft_v0.jsonl`
68
+ - `finetune/data/actor_sft_v0_train.jsonl`
69
+ - `finetune/data/actor_sft_v0_val.jsonl`
70
+ - `finetune/data_samples/actor_sft_v0_sample.jsonl`
71
+ - `finetune/data_samples/actor_eval_prompts.jsonl`
72
+
73
+ The full generated dataset under `finetune/data/` is gitignored. Keep only the small sample and eval prompt files in this repo.
74
+
75
+ ## Validate
76
+
77
+ Run:
78
+
79
+ ```bash
80
+ python finetune/scripts/validate_actor_sft.py finetune/data/actor_sft_v0.jsonl
81
+ ```
82
+
83
+ The validator checks row shape, chat roles, assistant JSON parsing, exact assistant fields, line length, allowed row types, tool request shape, and allowed tools. It prints total rows, valid and invalid counts, train/val counts when sibling split files are present, row type distribution, and tool distribution.
84
+
85
+ ## Synthetic-v0 Status
86
+
87
+ This is a deterministic synthetic v0 dataset. It is intentionally small, safe, and template-driven so the pipeline can be reviewed before model training. It covers no-tool responses, prop inspection, oracle consultation, lighting changes, memory callbacks, secret hints/reveals, finales, and comedic confusion.
88
+
89
+ The full generated dataset is expected to be published separately as a Hugging Face Dataset repo after review. This codebase keeps only reproducible scripts plus small committed examples.
finetune/data/.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ *.jsonl
finetune/data_samples/actor_eval_prompts.jsonl ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"id":"actor-eval-v0-001","source_mix":["synthetic_v0_eval_prompts"],"row_type":"normal_reaction","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A clockwork whale forgets which ocean is on stage\nshow_state JSON: {\"beat_index\":0,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage problem just winked, so we investigate politely.\",\"speaker\":\"Duchess Doodle\"},{\"line\":\"The stage evidence is backwards, or my shoes narrate.\",\"speaker\":\"Nora Needlewhistle\"}],\"setting\":\"a tiny kitchen counter where every appliance has stage fright\",\"show_title\":\"The Clockwork Whale Forgets Which\",\"stage_lighting\":\"moonlit_lighting\",\"story_phase\":\"opening\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"needle\",\"current_goal\":\"Stitch loose clues into a tidy stage pattern.\",\"goal\":\"Stitch loose clues into a tidy stage pattern.\",\"goal_progress\":\"Recovering from a missed entrance with dignity.\",\"held_props\":[],\"mood\":\"curious\",\"name\":\"Nora Needlewhistle\",\"recent_memory\":[\"A previous clue pointed stage left.\",\"The stage oracle warned everyone about small objects.\"],\"secret\":\"Once sewed the curtain shut during a finale.\",\"secret_status\":\"hidden\",\"speaking_style\":\"nimble, exact, and full of tiny warnings\",\"tools\":[\"inspect_prop\",\"change_lighting\"]}\ndirector_instruction: React to the premise and move the scene forward in one short line."}]}
2
+ {"id":"actor-eval-v0-002","source_mix":["synthetic_v0_eval_prompts"],"row_type":"prop_inspection","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The sun forgets its entrance and asks the moon for notes\nshow_state JSON: {\"beat_index\":1,\"finale_requested\":false,\"latest_audience_action\":\"Audience threw tiny ladder onto the stage.\",\"latest_prop\":\"tiny ladder\",\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"I hear stage suspense tapping behind the painted flats.\",\"speaker\":\"Quincy Quill\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Velvet Crumb\"}],\"setting\":\"a rainy cardboard alley lit by one dramatic desk lamp\",\"show_title\":\"The Forgets Entrance Asks Moon\",\"stage_lighting\":\"single_spotlight\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"cupcake\",\"current_goal\":\"Make every clue sound like dessert.\",\"goal\":\"Make every clue sound like dessert.\",\"goal_progress\":\"Carrying a small suspicion toward center stage.\",\"held_props\":[\"tiny ladder\"],\"mood\":\"grand\",\"name\":\"Velvet Crumb\",\"recent_memory\":[\"The spotlight blinked whenever someone said clue.\",\"A trapdoor sighed but did not open.\"],\"secret\":\"Can hear the curtains whisper reviews.\",\"secret_status\":\"hidden\",\"speaking_style\":\"warm, dramatic, and gently mischievous\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Make the prop feel important enough for the Director to notice."}]}
3
+ {"id":"actor-eval-v0-003","source_mix":["synthetic_v0_eval_prompts"],"row_type":"oracle_consult","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A polite comet asks permission to crash the tea party\nshow_state JSON: {\"beat_index\":2,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage problem just winked, so we investigate politely.\",\"speaker\":\"Orville Oddsock\"},{\"line\":\"I followed the stage clue into my sleeve.\",\"speaker\":\"Lola Lampshade\"}],\"setting\":\"a pocket-sized stage with painted flats and a wobbly spotlight\",\"show_title\":\"The Polite Comet Asks Permission\",\"stage_lighting\":\"golden_lighting\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"lamp\",\"current_goal\":\"Reveal the truth with tasteful illumination.\",\"goal\":\"Reveal the truth with tasteful illumination.\",\"goal_progress\":\"Trying to make the prop matter.\",\"held_props\":[],\"mood\":\"wistful\",\"name\":\"Lola Lampshade\",\"recent_memory\":[\"A bell rang twice when the secret was mentioned.\",\"A previous clue pointed stage left.\"],\"secret\":\"Overhears everything said near warm lighting.\",\"secret_status\":\"hidden\",\"speaking_style\":\"glowing, elegant, and dryly observant\",\"tools\":[\"change_lighting\",\"consult_stage_oracle\"]}\ndirector_instruction: Ask the stage oracle for one playful clue."}]}
4
+ {"id":"actor-eval-v0-004","source_mix":["synthetic_v0_eval_prompts"],"row_type":"lighting_change","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A pirate parrot opens a school for dramatic pauses\nshow_state JSON: {\"beat_index\":3,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage backdrop leaned closer, and I respect its commitment.\",\"speaker\":\"Duchess Doodle\"},{\"line\":\"I followed the stage clue into my sleeve.\",\"speaker\":\"Bolt McJiggle\"}],\"setting\":\"a shoebox castle with velvet curtains and one suspicious tower\",\"show_title\":\"The Pirate Parrot Opens School\",\"stage_lighting\":\"final_bow_lights\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"toolbox\",\"current_goal\":\"Turn every problem into a practical stage gag.\",\"goal\":\"Turn every problem into a practical stage gag.\",\"goal_progress\":\"Keeping one eye on the restless curtains.\",\"held_props\":[],\"mood\":\"confident\",\"name\":\"Bolt McJiggle\",\"recent_memory\":[\"A shadow crossed the stage wearing tap shoes.\",\"A previous clue pointed stage left.\"],\"secret\":\"Is secretly building a confetti finale backstage.\",\"secret_status\":\"hidden\",\"speaking_style\":\"punchy, practical, and full of suspicious confidence\",\"tools\":[\"inspect_prop\",\"change_lighting\"]}\ndirector_instruction: Shift the lights to match the emotional turn."}]}
5
+ {"id":"actor-eval-v0-005","source_mix":["synthetic_v0_eval_prompts"],"row_type":"memory_callback","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: Detectives investigate why the castle keeps applauding\nshow_state JSON: {\"beat_index\":4,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[{\"result\":\"The paper moon pointed stage left.\",\"stage_effect\":\"prop_table_glow\",\"tool\":\"inspect_prop\"}],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Tula Teaspoon\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Lola Lampshade\"}],\"setting\":\"a tiny kitchen counter where every appliance has stage fright\",\"show_title\":\"The Detectives Investigate Castle Keeps\",\"stage_lighting\":\"confetti_rustle\",\"story_phase\":\"reveal\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"lamp\",\"current_goal\":\"Reveal the truth with tasteful illumination.\",\"goal\":\"Reveal the truth with tasteful illumination.\",\"goal_progress\":\"Preparing a clean turn toward the finale.\",\"held_props\":[],\"mood\":\"delighted\",\"name\":\"Lola Lampshade\",\"recent_memory\":[\"The painted door demanded a compliment earlier.\",\"The orchestra coughed during the important pause.\"],\"secret\":\"Overhears everything said near warm lighting.\",\"secret_status\":\"hidden\",\"speaking_style\":\"glowing, elegant, and dryly observant\",\"tools\":[\"change_lighting\",\"consult_stage_oracle\"]}\ndirector_instruction: Echo a prior beat without repeating the same wording."}]}
6
+ {"id":"actor-eval-v0-006","source_mix":["synthetic_v0_eval_prompts"],"row_type":"secret_hint_or_reveal","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The circus cannonball wants a quieter desk job\nshow_state JSON: {\"beat_index\":5,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":\"ribbon compass\",\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[{\"result\":\"Secrets knock twice before entering.\",\"stage_effect\":\"oracle_haze\",\"tool\":\"consult_stage_oracle\"}],\"recent_transcript\":[{\"line\":\"This stage scene smells like mystery and nervous paint.\",\"speaker\":\"Otto Origami\"},{\"line\":\"Nobody panic; I interrogated the stage backdrop.\",\"speaker\":\"Nora Needlewhistle\"}],\"setting\":\"a toy library where the shelves whisper stage directions\",\"show_title\":\"The Circus Cannonball Wants Quieter\",\"stage_lighting\":\"quick_blackout\",\"story_phase\":\"reveal\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"needle\",\"current_goal\":\"Stitch loose clues into a tidy stage pattern.\",\"goal\":\"Stitch loose clues into a tidy stage pattern.\",\"goal_progress\":\"Looking for a laugh that still serves the story.\",\"held_props\":[],\"mood\":\"grand\",\"name\":\"Nora Needlewhistle\",\"recent_memory\":[\"Someone bowed before the reveal was ready.\",\"The curtains whispered that the finale was hiding nearby.\"],\"secret\":\"Once sewed the curtain shut during a finale.\",\"secret_status\":\"hinted\",\"speaking_style\":\"nimble, exact, and full of tiny warnings\",\"tools\":[\"inspect_prop\",\"change_lighting\"]}\ndirector_instruction: Let the secret complicate the current beat."}]}
7
+ {"id":"actor-eval-v0-007","source_mix":["synthetic_v0_eval_prompts"],"row_type":"finale","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A nervous cloud applies to become a thunderstorm\nshow_state JSON: {\"beat_index\":6,\"finale_requested\":true,\"latest_audience_action\":\"Audience requested a finale.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage backdrop leaned closer, and I respect its commitment.\",\"speaker\":\"Silas Sockdolager\"},{\"line\":\"I thought the stage clue was a hat, but it was Tuesday.\",\"speaker\":\"Juniper Jingle\"}],\"setting\":\"a tiny kitchen counter where every appliance has stage fright\",\"show_title\":\"The Nervous Cloud Applies Become\",\"stage_lighting\":\"prop_table_glow\",\"story_phase\":\"finale\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"bell\",\"current_goal\":\"Turn awkward pauses into musical cues.\",\"goal\":\"Turn awkward pauses into musical cues.\",\"goal_progress\":\"Waiting for the next cue.\",\"held_props\":[],\"mood\":\"startled\",\"name\":\"Juniper Jingle\",\"recent_memory\":[\"The stage oracle warned everyone about small objects.\",\"The orchestra coughed during the important pause.\"],\"secret\":\"Rings whenever someone lies politely.\",\"secret_status\":\"hidden\",\"speaking_style\":\"bright, rhythmic, and suspiciously tuneful\",\"tools\":[\"consult_stage_oracle\"]}\ndirector_instruction: Signal the curtain clearly and let the ensemble win."}]}
8
+ {"id":"actor-eval-v0-008","source_mix":["synthetic_v0_eval_prompts"],"row_type":"comedic_confusion","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A cardboard courtroom tries a missing birthday candle\nshow_state JSON: {\"beat_index\":7,\"finale_requested\":false,\"latest_audience_action\":\"Audience heckled: That clue is wearing a hat.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"I trust this stage spotlight only when it stops coughing.\",\"speaker\":\"Orville Oddsock\"},{\"line\":\"I thought the stage clue was a hat, but it was Tuesday.\",\"speaker\":\"Ruby Ruckus\"}],\"setting\":\"a rainy cardboard alley lit by one dramatic desk lamp\",\"show_title\":\"The Cardboard Courtroom Tries Missing\",\"stage_lighting\":\"prop_table_glow\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"drum\",\"current_goal\":\"Escalate the scene exactly one beat too far.\",\"goal\":\"Escalate the scene exactly one beat too far.\",\"goal_progress\":\"Testing whether the audience interruption is useful.\",\"held_props\":[],\"mood\":\"bold\",\"name\":\"Ruby Ruckus\",\"recent_memory\":[\"A trapdoor sighed but did not open.\",\"The prop table glowed before anyone touched it.\"],\"secret\":\"Keeps a tiny cymbal for emergencies.\",\"secret_status\":\"hidden\",\"speaking_style\":\"rowdy, warm, and rhythmically suspicious\",\"tools\":[\"change_lighting\"]}\ndirector_instruction: Make a wrong conclusion that gives the next actor something usable."}]}
9
+ {"id":"actor-eval-v0-009","source_mix":["synthetic_v0_eval_prompts"],"row_type":"normal_reaction","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: Two umbrellas debate who caused the indoor rainstorm\nshow_state JSON: {\"beat_index\":8,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Everyone stay dramatic; the stage clue is taking attendance.\",\"speaker\":\"Gus Gingham\"},{\"line\":\"The stage map is upside down, unless we are the map.\",\"speaker\":\"Nora Needlewhistle\"}],\"setting\":\"a paper harbor with blue ribbons for waves\",\"show_title\":\"The Umbrellas Debate Caused Indoor\",\"stage_lighting\":\"memory_echo\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"needle\",\"current_goal\":\"Stitch loose clues into a tidy stage pattern.\",\"goal\":\"Stitch loose clues into a tidy stage pattern.\",\"goal_progress\":\"Testing whether the audience interruption is useful.\",\"held_props\":[],\"mood\":\"confident\",\"name\":\"Nora Needlewhistle\",\"recent_memory\":[\"The final bow was briefly visible in the wings.\",\"The prop table glowed before anyone touched it.\"],\"secret\":\"Once sewed the curtain shut during a finale.\",\"secret_status\":\"hidden\",\"speaking_style\":\"nimble, exact, and full of tiny warnings\",\"tools\":[\"inspect_prop\",\"change_lighting\"]}\ndirector_instruction: React to the latest clue with one playable stage choice."}]}
10
+ {"id":"actor-eval-v0-010","source_mix":["synthetic_v0_eval_prompts"],"row_type":"prop_inspection","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The puppet mayor appoints a potato as royal advisor\nshow_state JSON: {\"beat_index\":9,\"finale_requested\":false,\"latest_audience_action\":\"Audience threw ribbon compass onto the stage.\",\"latest_prop\":\"ribbon compass\",\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"I hear stage suspense tapping behind the painted flats.\",\"speaker\":\"Juniper Jingle\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Mina Moonbutton\"}],\"setting\":\"a velvet courtroom with a squeaky judge's bench\",\"show_title\":\"The Puppet Mayor Appoints Potato\",\"stage_lighting\":\"stormy_lighting\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"crescent moon\",\"current_goal\":\"Find the emotional truth hiding inside the premise.\",\"goal\":\"Find the emotional truth hiding inside the premise.\",\"goal_progress\":\"Preparing a clean turn toward the finale.\",\"held_props\":[\"ribbon compass\"],\"mood\":\"delighted\",\"name\":\"Mina Moonbutton\",\"recent_memory\":[\"The prop table glowed before anyone touched it.\",\"The smallest prop seemed unusually confident.\"],\"secret\":\"Believes every prop is personally judging her.\",\"secret_status\":\"hidden\",\"speaking_style\":\"earnest, poetic, and prone to dramatic pauses\",\"tools\":[\"consult_stage_oracle\",\"change_lighting\"]}\ndirector_instruction: Inspect the prop without slowing the show."}]}
11
+ {"id":"actor-eval-v0-011","source_mix":["synthetic_v0_eval_prompts"],"row_type":"oracle_consult","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A pancake knight guards a syrup drawbridge at dawn\nshow_state JSON: {\"beat_index\":0,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"This tiny stage problem just became legally theatrical.\",\"speaker\":\"Bolt McJiggle\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Tula Teaspoon\"}],\"setting\":\"a cardboard moon base with glitter stars and a squeaky hatch\",\"show_title\":\"The Pancake Knight Guards Syrup\",\"stage_lighting\":\"final_bow_lights\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"spoon\",\"current_goal\":\"Measure the exact amount of mystery in each beat.\",\"goal\":\"Measure the exact amount of mystery in each beat.\",\"goal_progress\":\"Waiting for the next cue.\",\"held_props\":[],\"mood\":\"ready\",\"name\":\"Tula Teaspoon\",\"recent_memory\":[\"The spotlight blinked whenever someone said clue.\",\"A bell rang twice when the secret was mentioned.\"],\"secret\":\"Recognizes the missing spoon from a family portrait.\",\"secret_status\":\"hidden\",\"speaking_style\":\"polite, precise, and quietly dramatic\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: Consult the oracle about the next theatrical turn."}]}
12
+ {"id":"actor-eval-v0-012","source_mix":["synthetic_v0_eval_prompts"],"row_type":"lighting_change","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: An elevator only travels to dramatic reveals\nshow_state JSON: {\"beat_index\":1,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"I trust this stage spotlight only when it stops coughing.\",\"speaker\":\"Petra Popcorn\"},{\"line\":\"The stage map is upside down, unless we are the map.\",\"speaker\":\"Velvet Crumb\"}],\"setting\":\"a toy library where the shelves whisper stage directions\",\"show_title\":\"The Elevator Only Travels Dramatic\",\"stage_lighting\":\"memory_echo\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"cupcake\",\"current_goal\":\"Make every clue sound like dessert.\",\"goal\":\"Make every clue sound like dessert.\",\"goal_progress\":\"Keeping one eye on the restless curtains.\",\"held_props\":[],\"mood\":\"grand\",\"name\":\"Velvet Crumb\",\"recent_memory\":[\"The backdrop changed color after the audience heckled.\",\"The orchestra coughed during the important pause.\"],\"secret\":\"Can hear the curtains whisper reviews.\",\"secret_status\":\"hidden\",\"speaking_style\":\"warm, dramatic, and gently mischievous\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Shift the lights to match the emotional turn."}]}
13
+ {"id":"actor-eval-v0-013","source_mix":["synthetic_v0_eval_prompts"],"row_type":"memory_callback","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A haunted teacup wants to direct the school musical\nshow_state JSON: {\"beat_index\":2,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[{\"result\":\"The silver spoon pointed stage left.\",\"stage_effect\":\"prop_table_glow\",\"tool\":\"inspect_prop\"}],\"recent_transcript\":[{\"line\":\"This tiny stage problem just became legally theatrical.\",\"speaker\":\"Marigold Mumble\"},{\"line\":\"I bow to the stage door, and it applauds.\",\"speaker\":\"Ivy Inkblot\"}],\"setting\":\"a tiny kitchen counter where every appliance has stage fright\",\"show_title\":\"The Haunted Teacup Wants Direct\",\"stage_lighting\":\"quick_blackout\",\"story_phase\":\"reveal\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"ink\",\"current_goal\":\"Turn every mistake into official evidence.\",\"goal\":\"Turn every mistake into official evidence.\",\"goal_progress\":\"Trying to make the prop matter.\",\"held_props\":[],\"mood\":\"curious\",\"name\":\"Ivy Inkblot\",\"recent_memory\":[\"A bell rang twice when the secret was mentioned.\",\"A previous clue pointed stage left.\"],\"secret\":\"Can rewrite labels when nobody watches.\",\"secret_status\":\"hidden\",\"speaking_style\":\"inky, clever, and theatrically legalistic\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Recall one earlier clue and connect it to this moment."}]}
14
+ {"id":"actor-eval-v0-014","source_mix":["synthetic_v0_eval_prompts"],"row_type":"secret_hint_or_reveal","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The puppet mayor appoints a potato as royal advisor\nshow_state JSON: {\"beat_index\":3,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":\"origami crown\",\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[{\"result\":\"Secrets knock twice before entering.\",\"stage_effect\":\"oracle_haze\",\"tool\":\"consult_stage_oracle\"}],\"recent_transcript\":[{\"line\":\"I trust this stage spotlight only when it stops coughing.\",\"speaker\":\"Captain Taffeta\"},{\"line\":\"The stage evidence is backwards, or my shoes narrate.\",\"speaker\":\"Orville Oddsock\"}],\"setting\":\"a rainy cardboard alley lit by one dramatic desk lamp\",\"show_title\":\"The Puppet Mayor Appoints Potato\",\"stage_lighting\":\"blue_spotlight\",\"story_phase\":\"reveal\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"sock\",\"current_goal\":\"Find the missing pair in every mystery.\",\"goal\":\"Find the missing pair in every mystery.\",\"goal_progress\":\"Turning a contradiction into stage business.\",\"held_props\":[],\"mood\":\"determined\",\"name\":\"Orville Oddsock\",\"recent_memory\":[\"A trapdoor sighed but did not open.\",\"The final bow was briefly visible in the wings.\"],\"secret\":\"Believes the laundry basket is a prophet.\",\"secret_status\":\"hinted\",\"speaking_style\":\"loopy, sincere, and oddly persuasive\",\"tools\":[\"consult_stage_oracle\"]}\ndirector_instruction: Let the secret complicate the current beat."}]}
15
+ {"id":"actor-eval-v0-015","source_mix":["synthetic_v0_eval_prompts"],"row_type":"finale","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A polite comet asks permission to crash the tea party\nshow_state JSON: {\"beat_index\":4,\"finale_requested\":true,\"latest_audience_action\":\"Audience requested a finale.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage problem just winked, so we investigate politely.\",\"speaker\":\"Quincy Quill\"},{\"line\":\"I thought the stage clue was a hat, but it was Tuesday.\",\"speaker\":\"Ruby Ruckus\"}],\"setting\":\"a cardboard moon base with glitter stars and a squeaky hatch\",\"show_title\":\"The Polite Comet Asks Permission\",\"stage_lighting\":\"prop_table_glow\",\"story_phase\":\"finale\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"drum\",\"current_goal\":\"Escalate the scene exactly one beat too far.\",\"goal\":\"Escalate the scene exactly one beat too far.\",\"goal_progress\":\"Carrying a small suspicion toward center stage.\",\"held_props\":[],\"mood\":\"curious\",\"name\":\"Ruby Ruckus\",\"recent_memory\":[\"The smallest prop seemed unusually confident.\",\"The stage oracle warned everyone about small objects.\"],\"secret\":\"Keeps a tiny cymbal for emergencies.\",\"secret_status\":\"hidden\",\"speaking_style\":\"rowdy, warm, and rhythmically suspicious\",\"tools\":[\"change_lighting\"]}\ndirector_instruction: Tie the scene together in a clean curtain-call line."}]}
16
+ {"id":"actor-eval-v0-016","source_mix":["synthetic_v0_eval_prompts"],"row_type":"comedic_confusion","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A cardboard courtroom tries a missing birthday candle\nshow_state JSON: {\"beat_index\":5,\"finale_requested\":false,\"latest_audience_action\":\"Audience heckled: That clue is wearing a hat.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage problem just winked, so we investigate politely.\",\"speaker\":\"Silas Sockdolager\"},{\"line\":\"I followed the stage clue into my sleeve.\",\"speaker\":\"Finch Feltcap\"}],\"setting\":\"a shoebox castle with velvet curtains and one suspicious tower\",\"show_title\":\"The Cardboard Courtroom Tries Missing\",\"stage_lighting\":\"warm_spotlight\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"hat\",\"current_goal\":\"Keep secrets tucked safely under the brim.\",\"goal\":\"Keep secrets tucked safely under the brim.\",\"goal_progress\":\"Waiting for the next cue.\",\"held_props\":[],\"mood\":\"confident\",\"name\":\"Finch Feltcap\",\"recent_memory\":[\"A summoned actor entered carrying yesterday's clue.\",\"A previous clue pointed stage left.\"],\"secret\":\"The brim contains three emergency finales.\",\"secret_status\":\"hidden\",\"speaking_style\":\"dapper, soft-spoken, and evasive\",\"tools\":[\"consult_stage_oracle\",\"inspect_prop\"]}\ndirector_instruction: Make the confusion clear, playful, and safe."}]}
17
+ {"id":"actor-eval-v0-017","source_mix":["synthetic_v0_eval_prompts"],"row_type":"normal_reaction","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A snow globe mayor bans winter until further notice\nshow_state JSON: {\"beat_index\":6,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage backdrop leaned closer, and I respect its commitment.\",\"speaker\":\"Mossy Crank\"},{\"line\":\"The stage map is upside down, unless we are the map.\",\"speaker\":\"Ivy Inkblot\"}],\"setting\":\"a cardboard moon base with glitter stars and a squeaky hatch\",\"show_title\":\"The Snow Globe Mayor Bans\",\"stage_lighting\":\"oracle_haze\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"ink\",\"current_goal\":\"Turn every mistake into official evidence.\",\"goal\":\"Turn every mistake into official evidence.\",\"goal_progress\":\"Recovering from a missed entrance with dignity.\",\"held_props\":[],\"mood\":\"curious\",\"name\":\"Ivy Inkblot\",\"recent_memory\":[\"Someone bowed before the reveal was ready.\",\"The orchestra coughed during the important pause.\"],\"secret\":\"Can rewrite labels when nobody watches.\",\"secret_status\":\"hidden\",\"speaking_style\":\"inky, clever, and theatrically legalistic\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: React to the premise and move the scene forward in one short line."}]}
18
+ {"id":"actor-eval-v0-018","source_mix":["synthetic_v0_eval_prompts"],"row_type":"prop_inspection","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A painted door refuses to open without a compliment\nshow_state JSON: {\"beat_index\":7,\"finale_requested\":false,\"latest_audience_action\":\"Audience threw tomato scroll onto the stage.\",\"latest_prop\":\"tomato scroll\",\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"This tiny stage problem just became legally theatrical.\",\"speaker\":\"Finch Feltcap\"},{\"line\":\"I followed the stage clue into my sleeve.\",\"speaker\":\"Zelda Zipper\"}],\"setting\":\"a rainy cardboard alley lit by one dramatic desk lamp\",\"show_title\":\"The Painted Door Refuses Open\",\"stage_lighting\":\"memory_echo\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"zipper\",\"current_goal\":\"Open hidden compartments in the plot.\",\"goal\":\"Open hidden compartments in the plot.\",\"goal_progress\":\"Trying to make the prop matter.\",\"held_props\":[\"tomato scroll\"],\"mood\":\"startled\",\"name\":\"Zelda Zipper\",\"recent_memory\":[\"The painted door demanded a compliment earlier.\",\"The prop table glowed before anyone touched it.\"],\"secret\":\"Knows which pocket holds the missing clue.\",\"secret_status\":\"hidden\",\"speaking_style\":\"quick, clipped, and conspiratorial\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: Handle the prop theatrically and leave one question open."}]}
19
+ {"id":"actor-eval-v0-019","source_mix":["synthetic_v0_eval_prompts"],"row_type":"oracle_consult","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A wizard's laundry basket predicts tomorrow's weather\nshow_state JSON: {\"beat_index\":8,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"This tiny stage problem just became legally theatrical.\",\"speaker\":\"Duchess Doodle\"},{\"line\":\"I bow to the stage door, and it applauds.\",\"speaker\":\"Tula Teaspoon\"}],\"setting\":\"a toy library where the shelves whisper stage directions\",\"show_title\":\"The Wizard'S Laundry Basket Predicts\",\"stage_lighting\":\"memory_echo\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"spoon\",\"current_goal\":\"Measure the exact amount of mystery in each beat.\",\"goal\":\"Measure the exact amount of mystery in each beat.\",\"goal_progress\":\"Following the clue across the painted flats.\",\"held_props\":[],\"mood\":\"determined\",\"name\":\"Tula Teaspoon\",\"recent_memory\":[\"The prop table glowed before anyone touched it.\",\"The painted door demanded a compliment earlier.\"],\"secret\":\"Recognizes the missing spoon from a family portrait.\",\"secret_status\":\"hidden\",\"speaking_style\":\"polite, precise, and quietly dramatic\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: Use the oracle to connect the premise and latest confusion."}]}
20
+ {"id":"actor-eval-v0-020","source_mix":["synthetic_v0_eval_prompts"],"row_type":"lighting_change","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A library book refuses to return from vacation\nshow_state JSON: {\"beat_index\":9,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage backdrop leaned closer, and I respect its commitment.\",\"speaker\":\"Zelda Zipper\"},{\"line\":\"Nobody panic; I interrogated the stage backdrop.\",\"speaker\":\"Gus Gingham\"}],\"setting\":\"a toy library where the shelves whisper stage directions\",\"show_title\":\"The Library Book Refuses Return\",\"stage_lighting\":\"quick_blackout\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"tablecloth\",\"current_goal\":\"Keep everyone civil while the table collapses.\",\"goal\":\"Keep everyone civil while the table collapses.\",\"goal_progress\":\"Looking for a laugh that still serves the story.\",\"held_props\":[],\"mood\":\"grand\",\"name\":\"Gus Gingham\",\"recent_memory\":[\"The final bow was briefly visible in the wings.\",\"The spotlight blinked whenever someone said clue.\"],\"secret\":\"Was once mistaken for the royal flag.\",\"secret_status\":\"hidden\",\"speaking_style\":\"homespun, patient, and quietly ridiculous\",\"tools\":[\"change_lighting\",\"consult_stage_oracle\"]}\ndirector_instruction: Shift the lights to match the emotional turn."}]}
21
+ {"id":"actor-eval-v0-021","source_mix":["synthetic_v0_eval_prompts"],"row_type":"memory_callback","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A clockwork whale forgets which ocean is on stage\nshow_state JSON: {\"beat_index\":0,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[{\"result\":\"The glitter crown pointed stage left.\",\"stage_effect\":\"prop_table_glow\",\"tool\":\"inspect_prop\"}],\"recent_transcript\":[{\"line\":\"Everyone stay dramatic; the stage clue is taking attendance.\",\"speaker\":\"Professor Buttonhook\"},{\"line\":\"Nobody panic; I interrogated the stage backdrop.\",\"speaker\":\"Duchess Doodle\"}],\"setting\":\"a rainy cardboard alley lit by one dramatic desk lamp\",\"show_title\":\"The Clockwork Whale Forgets Which\",\"stage_lighting\":\"memory_echo\",\"story_phase\":\"reveal\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"paintbrush\",\"current_goal\":\"Make the backdrop agree with her version of events.\",\"goal\":\"Make the backdrop agree with her version of events.\",\"goal_progress\":\"Trying to make the prop matter.\",\"held_props\":[],\"mood\":\"startled\",\"name\":\"Duchess Doodle\",\"recent_memory\":[\"The prop table glowed before anyone touched it.\",\"The backdrop changed color after the audience heckled.\"],\"secret\":\"Painted herself into last week's mystery.\",\"secret_status\":\"hidden\",\"speaking_style\":\"ornate, colorful, and lightly bossy\",\"tools\":[\"change_lighting\"]}\ndirector_instruction: Echo a prior beat without repeating the same wording."}]}
22
+ {"id":"actor-eval-v0-022","source_mix":["synthetic_v0_eval_prompts"],"row_type":"secret_hint_or_reveal","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The bakery's rolling pin claims it solved the mystery\nshow_state JSON: {\"beat_index\":1,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":\"glass button\",\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[{\"result\":\"Secrets knock twice before entering.\",\"stage_effect\":\"oracle_haze\",\"tool\":\"consult_stage_oracle\"}],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Pip the Director\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Ruby Ruckus\"}],\"setting\":\"a paper harbor with blue ribbons for waves\",\"show_title\":\"The Bakery'S Rolling Claims Solved\",\"stage_lighting\":\"warm_spotlight\",\"story_phase\":\"reveal\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"drum\",\"current_goal\":\"Escalate the scene exactly one beat too far.\",\"goal\":\"Escalate the scene exactly one beat too far.\",\"goal_progress\":\"Following the clue across the painted flats.\",\"held_props\":[],\"mood\":\"wistful\",\"name\":\"Ruby Ruckus\",\"recent_memory\":[\"The spotlight blinked whenever someone said clue.\",\"The backdrop changed color after the audience heckled.\"],\"secret\":\"Keeps a tiny cymbal for emergencies.\",\"secret_status\":\"hinted\",\"speaking_style\":\"rowdy, warm, and rhythmically suspicious\",\"tools\":[\"change_lighting\"]}\ndirector_instruction: Give the audience a secret-shaped clue, not a long confession."}]}
23
+ {"id":"actor-eval-v0-023","source_mix":["synthetic_v0_eval_prompts"],"row_type":"finale","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The puppet mayor appoints a potato as royal advisor\nshow_state JSON: {\"beat_index\":2,\"finale_requested\":true,\"latest_audience_action\":\"Audience requested a finale.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"This stage scene smells like mystery and nervous paint.\",\"speaker\":\"Pip the Director\"},{\"line\":\"I bow to the stage door, and it applauds.\",\"speaker\":\"Professor Buttonhook\"}],\"setting\":\"a tiny kitchen counter where every appliance has stage fright\",\"show_title\":\"The Puppet Mayor Appoints Potato\",\"stage_lighting\":\"stormy_lighting\",\"story_phase\":\"finale\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"spectacles\",\"current_goal\":\"Explain chaos as if it were in the syllabus.\",\"goal\":\"Explain chaos as if it were in the syllabus.\",\"goal_progress\":\"Trying to make the prop matter.\",\"held_props\":[],\"mood\":\"mischievous\",\"name\":\"Professor Buttonhook\",\"recent_memory\":[\"The stage oracle warned everyone about small objects.\",\"The spotlight blinked whenever someone said clue.\"],\"secret\":\"Never learned how trapdoors work.\",\"secret_status\":\"hidden\",\"speaking_style\":\"precise, fussy, and accidentally grand\",\"tools\":[\"consult_stage_oracle\"]}\ndirector_instruction: Give the scene a satisfying button without adding a new problem."}]}
24
+ {"id":"actor-eval-v0-024","source_mix":["synthetic_v0_eval_prompts"],"row_type":"comedic_confusion","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A pirate parrot opens a school for dramatic pauses\nshow_state JSON: {\"beat_index\":3,\"finale_requested\":false,\"latest_audience_action\":\"Audience heckled: That clue is wearing a hat.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Otto Origami\"},{\"line\":\"I bow to the stage door, and it applauds.\",\"speaker\":\"Zelda Zipper\"}],\"setting\":\"a paper harbor with blue ribbons for waves\",\"show_title\":\"The Pirate Parrot Opens School\",\"stage_lighting\":\"warm_spotlight\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"zipper\",\"current_goal\":\"Open hidden compartments in the plot.\",\"goal\":\"Open hidden compartments in the plot.\",\"goal_progress\":\"Recovering from a missed entrance with dignity.\",\"held_props\":[],\"mood\":\"nervous\",\"name\":\"Zelda Zipper\",\"recent_memory\":[\"The stage oracle warned everyone about small objects.\",\"The curtains whispered that the finale was hiding nearby.\"],\"secret\":\"Knows which pocket holds the missing clue.\",\"secret_status\":\"hidden\",\"speaking_style\":\"quick, clipped, and conspiratorial\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: Escalate confusion briefly, then leave room for the next actor."}]}
25
+ {"id":"actor-eval-v0-025","source_mix":["synthetic_v0_eval_prompts"],"row_type":"normal_reaction","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: An elevator only travels to dramatic reveals\nshow_state JSON: {\"beat_index\":4,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"This stage scene smells like mystery and nervous paint.\",\"speaker\":\"Silas Sockdolager\"},{\"line\":\"I followed the stage clue into my sleeve.\",\"speaker\":\"Ivy Inkblot\"}],\"setting\":\"a pocket-sized stage with painted flats and a wobbly spotlight\",\"show_title\":\"The Elevator Only Travels Dramatic\",\"stage_lighting\":\"final_bow_lights\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"ink\",\"current_goal\":\"Turn every mistake into official evidence.\",\"goal\":\"Turn every mistake into official evidence.\",\"goal_progress\":\"Following the clue across the painted flats.\",\"held_props\":[],\"mood\":\"grand\",\"name\":\"Ivy Inkblot\",\"recent_memory\":[\"The curtains whispered that the finale was hiding nearby.\",\"The painted door demanded a compliment earlier.\"],\"secret\":\"Can rewrite labels when nobody watches.\",\"secret_status\":\"hidden\",\"speaking_style\":\"inky, clever, and theatrically legalistic\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Answer the previous beat with theatrical confidence."}]}
26
+ {"id":"actor-eval-v0-026","source_mix":["synthetic_v0_eval_prompts"],"row_type":"prop_inspection","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A detective mailbox investigates missing love letters\nshow_state JSON: {\"beat_index\":5,\"finale_requested\":false,\"latest_audience_action\":\"Audience threw clockwork seashell onto the stage.\",\"latest_prop\":\"clockwork seashell\",\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Everyone stay dramatic; the stage clue is taking attendance.\",\"speaker\":\"Quincy Quill\"},{\"line\":\"The spotlight blinked twice, so I blamed the stage.\",\"speaker\":\"Tula Teaspoon\"}],\"setting\":\"a shoebox castle with velvet curtains and one suspicious tower\",\"show_title\":\"The Detective Mailbox Investigates Missing\",\"stage_lighting\":\"final_bow_lights\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"spoon\",\"current_goal\":\"Measure the exact amount of mystery in each beat.\",\"goal\":\"Measure the exact amount of mystery in each beat.\",\"goal_progress\":\"Following the clue across the painted flats.\",\"held_props\":[\"clockwork seashell\"],\"mood\":\"bold\",\"name\":\"Tula Teaspoon\",\"recent_memory\":[\"The orchestra coughed during the important pause.\",\"The smallest prop seemed unusually confident.\"],\"secret\":\"Recognizes the missing spoon from a family portrait.\",\"secret_status\":\"hidden\",\"speaking_style\":\"polite, precise, and quietly dramatic\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: Use the latest prop as evidence and request inspection if useful."}]}
27
+ {"id":"actor-eval-v0-027","source_mix":["synthetic_v0_eval_prompts"],"row_type":"oracle_consult","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A polite comet asks permission to crash the tea party\nshow_state JSON: {\"beat_index\":6,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"I hear stage suspense tapping behind the painted flats.\",\"speaker\":\"Gus Gingham\"},{\"line\":\"I followed the stage clue into my sleeve.\",\"speaker\":\"Pip the Director\"}],\"setting\":\"a toy library where the shelves whisper stage directions\",\"show_title\":\"The Polite Comet Asks Permission\",\"stage_lighting\":\"blue_spotlight\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"clapperboard\",\"current_goal\":\"Keep the scene moving toward a crisp finale.\",\"goal\":\"Keep the scene moving toward a crisp finale.\",\"goal_progress\":\"Testing whether the audience interruption is useful.\",\"held_props\":[],\"mood\":\"hopeful\",\"name\":\"Pip the Director\",\"recent_memory\":[\"A bell rang twice when the secret was mentioned.\",\"The stage oracle warned everyone about small objects.\"],\"secret\":\"Has already misplaced the final cue card.\",\"secret_status\":\"hidden\",\"speaking_style\":\"brisk, theatrical, and slightly overconfident\",\"tools\":[\"change_lighting\",\"consult_stage_oracle\"]}\ndirector_instruction: Use an oracle question to sharpen the scene's mystery."}]}
28
+ {"id":"actor-eval-v0-028","source_mix":["synthetic_v0_eval_prompts"],"row_type":"lighting_change","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: Two umbrellas debate who caused the indoor rainstorm\nshow_state JSON: {\"beat_index\":7,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage backdrop leaned closer, and I respect its commitment.\",\"speaker\":\"Finch Feltcap\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Velvet Crumb\"}],\"setting\":\"a cardboard moon base with glitter stars and a squeaky hatch\",\"show_title\":\"The Umbrellas Debate Caused Indoor\",\"stage_lighting\":\"golden_lighting\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"cupcake\",\"current_goal\":\"Make every clue sound like dessert.\",\"goal\":\"Make every clue sound like dessert.\",\"goal_progress\":\"Recovering from a missed entrance with dignity.\",\"held_props\":[],\"mood\":\"confident\",\"name\":\"Velvet Crumb\",\"recent_memory\":[\"The orchestra coughed during the important pause.\",\"A summoned actor entered carrying yesterday's clue.\"],\"secret\":\"Can hear the curtains whisper reviews.\",\"secret_status\":\"hidden\",\"speaking_style\":\"warm, dramatic, and gently mischievous\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Change the lighting to make the actor's intention visible."}]}
29
+ {"id":"actor-eval-v0-029","source_mix":["synthetic_v0_eval_prompts"],"row_type":"memory_callback","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A cardboard courtroom tries a missing birthday candle\nshow_state JSON: {\"beat_index\":8,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[{\"result\":\"The tomato scroll pointed stage left.\",\"stage_effect\":\"prop_table_glow\",\"tool\":\"inspect_prop\"}],\"recent_transcript\":[{\"line\":\"This stage scene smells like mystery and nervous paint.\",\"speaker\":\"Tula Teaspoon\"},{\"line\":\"I thought the stage clue was a hat, but it was Tuesday.\",\"speaker\":\"Otto Origami\"}],\"setting\":\"a shoebox castle with velvet curtains and one suspicious tower\",\"show_title\":\"The Cardboard Courtroom Tries Missing\",\"stage_lighting\":\"final_bow_lights\",\"story_phase\":\"reveal\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"paper crane\",\"current_goal\":\"Fold messy clues into surprising shapes.\",\"goal\":\"Fold messy clues into surprising shapes.\",\"goal_progress\":\"Trying to make the prop matter.\",\"held_props\":[],\"mood\":\"mischievous\",\"name\":\"Otto Origami\",\"recent_memory\":[\"The orchestra coughed during the important pause.\",\"Someone bowed before the reveal was ready.\"],\"secret\":\"Was once a very important ransom note.\",\"secret_status\":\"hidden\",\"speaking_style\":\"delicate, precise, and gently mysterious\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Echo a prior beat without repeating the same wording."}]}
30
+ {"id":"actor-eval-v0-030","source_mix":["synthetic_v0_eval_prompts"],"row_type":"secret_hint_or_reveal","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A polite comet asks permission to crash the tea party\nshow_state JSON: {\"beat_index\":9,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":\"silver spoon\",\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[{\"result\":\"Secrets knock twice before entering.\",\"stage_effect\":\"oracle_haze\",\"tool\":\"consult_stage_oracle\"}],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Finch Feltcap\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Duchess Doodle\"}],\"setting\":\"a paper harbor with blue ribbons for waves\",\"show_title\":\"The Polite Comet Asks Permission\",\"stage_lighting\":\"single_spotlight\",\"story_phase\":\"reveal\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"paintbrush\",\"current_goal\":\"Make the backdrop agree with her version of events.\",\"goal\":\"Make the backdrop agree with her version of events.\",\"goal_progress\":\"Waiting for the next cue.\",\"held_props\":[],\"mood\":\"startled\",\"name\":\"Duchess Doodle\",\"recent_memory\":[\"The backdrop changed color after the audience heckled.\",\"A shadow crossed the stage wearing tap shoes.\"],\"secret\":\"Painted herself into last week's mystery.\",\"secret_status\":\"hinted\",\"speaking_style\":\"ornate, colorful, and lightly bossy\",\"tools\":[\"change_lighting\"]}\ndirector_instruction: Make the secret theatrical, safe, and easy to perform."}]}
31
+ {"id":"actor-eval-v0-031","source_mix":["synthetic_v0_eval_prompts"],"row_type":"finale","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The lighthouse insists it saw a submarine wearing a hat\nshow_state JSON: {\"beat_index\":0,\"finale_requested\":true,\"latest_audience_action\":\"Audience requested a finale.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"This stage scene smells like mystery and nervous paint.\",\"speaker\":\"Lola Lampshade\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Finch Feltcap\"}],\"setting\":\"a toy library where the shelves whisper stage directions\",\"show_title\":\"The Lighthouse Insists Submarine Wearing\",\"stage_lighting\":\"single_spotlight\",\"story_phase\":\"finale\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"hat\",\"current_goal\":\"Keep secrets tucked safely under the brim.\",\"goal\":\"Keep secrets tucked safely under the brim.\",\"goal_progress\":\"Testing whether the audience interruption is useful.\",\"held_props\":[],\"mood\":\"nervous\",\"name\":\"Finch Feltcap\",\"recent_memory\":[\"A shadow crossed the stage wearing tap shoes.\",\"A previous clue pointed stage left.\"],\"secret\":\"The brim contains three emergency finales.\",\"secret_status\":\"hidden\",\"speaking_style\":\"dapper, soft-spoken, and evasive\",\"tools\":[\"consult_stage_oracle\",\"inspect_prop\"]}\ndirector_instruction: Tie the scene together in a clean curtain-call line."}]}
32
+ {"id":"actor-eval-v0-032","source_mix":["synthetic_v0_eval_prompts"],"row_type":"comedic_confusion","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A blanket fort declares independence from bedtime\nshow_state JSON: {\"beat_index\":1,\"finale_requested\":false,\"latest_audience_action\":\"Audience heckled: That clue is wearing a hat.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"I trust this stage spotlight only when it stops coughing.\",\"speaker\":\"Velvet Crumb\"},{\"line\":\"I followed the stage clue into my sleeve.\",\"speaker\":\"Rafi Ribbon\"}],\"setting\":\"a pocket-sized stage with painted flats and a wobbly spotlight\",\"show_title\":\"The Blanket Fort Declares Independence\",\"stage_lighting\":\"blue_spotlight\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"ribbon\",\"current_goal\":\"Tie every contradiction into a decorative bow.\",\"goal\":\"Tie every contradiction into a decorative bow.\",\"goal_progress\":\"Keeping one eye on the restless curtains.\",\"held_props\":[],\"mood\":\"grand\",\"name\":\"Rafi Ribbon\",\"recent_memory\":[\"The smallest prop seemed unusually confident.\",\"The final bow was briefly visible in the wings.\"],\"secret\":\"Keeps emergency applause in his sleeve.\",\"secret_status\":\"hidden\",\"speaking_style\":\"smooth, charming, and neatly dramatic\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Confuse one clue with another, then recover enough to continue."}]}
33
+ {"id":"actor-eval-v0-033","source_mix":["synthetic_v0_eval_prompts"],"row_type":"normal_reaction","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The royal gardener grows clues instead of roses\nshow_state JSON: {\"beat_index\":2,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Bolt McJiggle\"},{\"line\":\"I bow to the stage door, and it applauds.\",\"speaker\":\"Pip the Director\"}],\"setting\":\"a paper harbor with blue ribbons for waves\",\"show_title\":\"The Royal Gardener Grows Clues\",\"stage_lighting\":\"final_bow_lights\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"clapperboard\",\"current_goal\":\"Keep the scene moving toward a crisp finale.\",\"goal\":\"Keep the scene moving toward a crisp finale.\",\"goal_progress\":\"Preparing a clean turn toward the finale.\",\"held_props\":[],\"mood\":\"delighted\",\"name\":\"Pip the Director\",\"recent_memory\":[\"The prop table glowed before anyone touched it.\",\"The audience threw a prop during the contradiction.\"],\"secret\":\"Has already misplaced the final cue card.\",\"secret_status\":\"hidden\",\"speaking_style\":\"brisk, theatrical, and slightly overconfident\",\"tools\":[\"change_lighting\",\"consult_stage_oracle\"]}\ndirector_instruction: Name what changed on stage and invite the next beat."}]}
34
+ {"id":"actor-eval-v0-034","source_mix":["synthetic_v0_eval_prompts"],"row_type":"prop_inspection","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A lantern insists the darkness stole its punchline\nshow_state JSON: {\"beat_index\":3,\"finale_requested\":false,\"latest_audience_action\":\"Audience threw wind-up key onto the stage.\",\"latest_prop\":\"wind-up key\",\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage backdrop leaned closer, and I respect its commitment.\",\"speaker\":\"Ivy Inkblot\"},{\"line\":\"I thought the stage clue was a hat, but it was Tuesday.\",\"speaker\":\"Zelda Zipper\"}],\"setting\":\"a paper harbor with blue ribbons for waves\",\"show_title\":\"The Lantern Insists Darkness Stole\",\"stage_lighting\":\"final_bow_lights\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"zipper\",\"current_goal\":\"Open hidden compartments in the plot.\",\"goal\":\"Open hidden compartments in the plot.\",\"goal_progress\":\"Keeping one eye on the restless curtains.\",\"held_props\":[\"wind-up key\"],\"mood\":\"mischievous\",\"name\":\"Zelda Zipper\",\"recent_memory\":[\"The curtains whispered that the finale was hiding nearby.\",\"A summoned actor entered carrying yesterday's clue.\"],\"secret\":\"Knows which pocket holds the missing clue.\",\"secret_status\":\"hidden\",\"speaking_style\":\"quick, clipped, and conspiratorial\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: Treat the prop like a clue that changes the scene."}]}
35
+ {"id":"actor-eval-v0-035","source_mix":["synthetic_v0_eval_prompts"],"row_type":"oracle_consult","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A detective mailbox investigates missing love letters\nshow_state JSON: {\"beat_index\":4,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage problem just winked, so we investigate politely.\",\"speaker\":\"Ruby Ruckus\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Tula Teaspoon\"}],\"setting\":\"a pocket-sized stage with painted flats and a wobbly spotlight\",\"show_title\":\"The Detective Mailbox Investigates Missing\",\"stage_lighting\":\"oracle_haze\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"spoon\",\"current_goal\":\"Measure the exact amount of mystery in each beat.\",\"goal\":\"Measure the exact amount of mystery in each beat.\",\"goal_progress\":\"Testing whether the audience interruption is useful.\",\"held_props\":[],\"mood\":\"mischievous\",\"name\":\"Tula Teaspoon\",\"recent_memory\":[\"The prop table glowed before anyone touched it.\",\"The smallest prop seemed unusually confident.\"],\"secret\":\"Recognizes the missing spoon from a family portrait.\",\"secret_status\":\"hidden\",\"speaking_style\":\"polite, precise, and quietly dramatic\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: Ask the oracle something specific enough to guide the next beat."}]}
36
+ {"id":"actor-eval-v0-036","source_mix":["synthetic_v0_eval_prompts"],"row_type":"lighting_change","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A scarecrow runs a midnight advice booth for crows\nshow_state JSON: {\"beat_index\":5,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"This tiny stage problem just became legally theatrical.\",\"speaker\":\"Velvet Crumb\"},{\"line\":\"I followed the stage clue into my sleeve.\",\"speaker\":\"Rafi Ribbon\"}],\"setting\":\"a velvet courtroom with a squeaky judge's bench\",\"show_title\":\"The Scarecrow Runs Midnight Advice\",\"stage_lighting\":\"quick_blackout\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"ribbon\",\"current_goal\":\"Tie every contradiction into a decorative bow.\",\"goal\":\"Tie every contradiction into a decorative bow.\",\"goal_progress\":\"Looking for a laugh that still serves the story.\",\"held_props\":[],\"mood\":\"bold\",\"name\":\"Rafi Ribbon\",\"recent_memory\":[\"The audience threw a prop during the contradiction.\",\"Someone bowed before the reveal was ready.\"],\"secret\":\"Keeps emergency applause in his sleeve.\",\"secret_status\":\"hidden\",\"speaking_style\":\"smooth, charming, and neatly dramatic\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Change the lighting to make the actor's intention visible."}]}
37
+ {"id":"actor-eval-v0-037","source_mix":["synthetic_v0_eval_prompts"],"row_type":"memory_callback","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The lighthouse insists it saw a submarine wearing a hat\nshow_state JSON: {\"beat_index\":6,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[{\"result\":\"The felt mustache pointed stage left.\",\"stage_effect\":\"prop_table_glow\",\"tool\":\"inspect_prop\"}],\"recent_transcript\":[{\"line\":\"I hear stage suspense tapping behind the painted flats.\",\"speaker\":\"Finch Feltcap\"},{\"line\":\"I bow to the stage door, and it applauds.\",\"speaker\":\"Captain Taffeta\"}],\"setting\":\"a cardboard moon base with glitter stars and a squeaky hatch\",\"show_title\":\"The Lighthouse Insists Submarine Wearing\",\"stage_lighting\":\"single_spotlight\",\"story_phase\":\"reveal\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"sailboat\",\"current_goal\":\"Steer every scene through theatrical weather.\",\"goal\":\"Steer every scene through theatrical weather.\",\"goal_progress\":\"Following the clue across the painted flats.\",\"held_props\":[],\"mood\":\"curious\",\"name\":\"Captain Taffeta\",\"recent_memory\":[\"A previous clue pointed stage left.\",\"The orchestra coughed during the important pause.\"],\"secret\":\"Cannot tell port from stage left.\",\"secret_status\":\"hidden\",\"speaking_style\":\"booming, nautical, and cheerfully mistaken\",\"tools\":[\"consult_stage_oracle\",\"change_lighting\"]}\ndirector_instruction: Use one remembered stage effect as evidence."}]}
38
+ {"id":"actor-eval-v0-038","source_mix":["synthetic_v0_eval_prompts"],"row_type":"secret_hint_or_reveal","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A snow globe mayor bans winter until further notice\nshow_state JSON: {\"beat_index\":7,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":\"paper fan\",\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[{\"result\":\"Secrets knock twice before entering.\",\"stage_effect\":\"oracle_haze\",\"tool\":\"consult_stage_oracle\"}],\"recent_transcript\":[{\"line\":\"This tiny stage problem just became legally theatrical.\",\"speaker\":\"Professor Buttonhook\"},{\"line\":\"The stage evidence is backwards, or my shoes narrate.\",\"speaker\":\"Zelda Zipper\"}],\"setting\":\"a cardboard moon base with glitter stars and a squeaky hatch\",\"show_title\":\"The Snow Globe Mayor Bans\",\"stage_lighting\":\"golden_lighting\",\"story_phase\":\"reveal\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"zipper\",\"current_goal\":\"Open hidden compartments in the plot.\",\"goal\":\"Open hidden compartments in the plot.\",\"goal_progress\":\"Looking for a laugh that still serves the story.\",\"held_props\":[],\"mood\":\"grand\",\"name\":\"Zelda Zipper\",\"recent_memory\":[\"A bell rang twice when the secret was mentioned.\",\"The spotlight blinked whenever someone said clue.\"],\"secret\":\"Knows which pocket holds the missing clue.\",\"secret_status\":\"hinted\",\"speaking_style\":\"quick, clipped, and conspiratorial\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: Reveal only what the scene can use immediately."}]}
39
+ {"id":"actor-eval-v0-039","source_mix":["synthetic_v0_eval_prompts"],"row_type":"finale","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A paper airplane delivers invitations to the wrong century\nshow_state JSON: {\"beat_index\":8,\"finale_requested\":true,\"latest_audience_action\":\"Audience requested a finale.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Everyone stay dramatic; the stage clue is taking attendance.\",\"speaker\":\"Mina Moonbutton\"},{\"line\":\"I followed the stage clue into my sleeve.\",\"speaker\":\"Ivy Inkblot\"}],\"setting\":\"a rainy cardboard alley lit by one dramatic desk lamp\",\"show_title\":\"The Paper Airplane Delivers Invitations\",\"stage_lighting\":\"memory_echo\",\"story_phase\":\"finale\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"ink\",\"current_goal\":\"Turn every mistake into official evidence.\",\"goal\":\"Turn every mistake into official evidence.\",\"goal_progress\":\"Turning a contradiction into stage business.\",\"held_props\":[],\"mood\":\"bold\",\"name\":\"Ivy Inkblot\",\"recent_memory\":[\"The prop table glowed before anyone touched it.\",\"The spotlight blinked whenever someone said clue.\"],\"secret\":\"Can rewrite labels when nobody watches.\",\"secret_status\":\"hidden\",\"speaking_style\":\"inky, clever, and theatrically legalistic\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Give the scene a satisfying button without adding a new problem."}]}
40
+ {"id":"actor-eval-v0-040","source_mix":["synthetic_v0_eval_prompts"],"row_type":"comedic_confusion","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A shy volcano hosts a talent show for umbrellas\nshow_state JSON: {\"beat_index\":9,\"finale_requested\":false,\"latest_audience_action\":\"Audience heckled: That clue is wearing a hat.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"I hear stage suspense tapping behind the painted flats.\",\"speaker\":\"Finch Feltcap\"},{\"line\":\"The stage map is upside down, unless we are the map.\",\"speaker\":\"Silas Sockdolager\"}],\"setting\":\"a pocket-sized stage with painted flats and a wobbly spotlight\",\"show_title\":\"The Volcano Hosts Talent Show\",\"stage_lighting\":\"golden_lighting\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"megaphone\",\"current_goal\":\"Deliver the biggest line in the smallest voice.\",\"goal\":\"Deliver the biggest line in the smallest voice.\",\"goal_progress\":\"Waiting for the next cue.\",\"held_props\":[],\"mood\":\"flustered\",\"name\":\"Silas Sockdolager\",\"recent_memory\":[\"The curtains whispered that the finale was hiding nearby.\",\"A shadow crossed the stage wearing tap shoes.\"],\"secret\":\"Lost his indoor voice under the orchestra pit.\",\"secret_status\":\"hidden\",\"speaking_style\":\"grand, booming, and suddenly tiny\",\"tools\":[\"change_lighting\",\"consult_stage_oracle\"]}\ndirector_instruction: Let the misunderstanding create motion without breaking the scene."}]}
finetune/data_samples/actor_sft_v0_sample.jsonl ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"id":"actor-sft-v0-000913","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"normal_reaction","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A soup ladle discovers a secret passage under dinner\nshow_state JSON: {\"beat_index\":3,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":14,\"min_beats\":9,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage backdrop leaned closer, and I respect its commitment.\",\"speaker\":\"Gus Gingham\"},{\"line\":\"I thought the stage clue was a hat, but it was Tuesday.\",\"speaker\":\"Juniper Jingle\"}],\"setting\":\"a cardboard moon base with glitter stars and a squeaky hatch\",\"show_title\":\"The Soup Ladle Discovers Secret\",\"stage_lighting\":\"blue_spotlight\",\"story_phase\":\"complication\",\"target_beats\":12}\nactor JSON: {\"avatar\":\"bell\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Turn awkward pauses into musical cues.\",\"goal_progress\":\"Following the clue across the painted flats.\",\"held_props\":[],\"mood\":\"confident\",\"name\":\"Juniper Jingle\",\"recent_memory\":[\"The painted door demanded a compliment earlier.\",\"The orchestra coughed during the important pause.\"],\"secret\":\"Rings whenever someone lies politely.\",\"secret_status\":\"hidden\",\"speaking_style\":\"bright, rhythmic, and suspiciously tuneful\",\"tools\":[\"consult_stage_oracle\"]}\ndirector_instruction: Make the next problem clear without solving it yet."},{"role":"assistant","content":"{\"intent\":\"clarify_problem\",\"line\":\"This tiny soup problem just became legally theatrical.\",\"emotion\":\"delighted\",\"gesture\":\"taps chin with one tiny puppet hand\",\"stage_effect\":\"warm_spotlight\",\"memory_update\":null,\"tool_request\":null}"}]}
2
+ {"id":"actor-sft-v0-000434","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"prop_inspection","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A wizard's laundry basket predicts tomorrow's weather\nshow_state JSON: {\"beat_index\":5,\"finale_requested\":false,\"latest_audience_action\":\"Audience threw origami crown onto the stage.\",\"latest_prop\":\"origami crown\",\"max_beats\":14,\"min_beats\":9,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Zelda Zipper\"},{\"line\":\"I bow to the stage door, and it applauds.\",\"speaker\":\"Ruby Ruckus\"}],\"setting\":\"a pocket-sized stage with painted flats and a wobbly spotlight\",\"show_title\":\"The Wizard'S Laundry Basket Predicts\",\"stage_lighting\":\"moonlit_lighting\",\"story_phase\":\"complication\",\"target_beats\":12}\nactor JSON: {\"avatar\":\"drum\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Escalate the scene exactly one beat too far.\",\"goal_progress\":\"Looking for a laugh that still serves the story.\",\"held_props\":[\"origami crown\"],\"mood\":\"delighted\",\"name\":\"Ruby Ruckus\",\"recent_memory\":[\"The spotlight blinked whenever someone said clue.\",\"The curtains whispered that the finale was hiding nearby.\"],\"secret\":\"Keeps a tiny cymbal for emergencies.\",\"secret_status\":\"hidden\",\"speaking_style\":\"rowdy, warm, and rhythmically suspicious\",\"tools\":[\"change_lighting\"]}\ndirector_instruction: Make the prop feel important enough for the Director to notice."},{"role":"assistant","content":"{\"intent\":\"inspect_prop\",\"line\":\"I inspect this origami crown and find theatrical fingerprints everywhere.\",\"emotion\":\"triumphant\",\"gesture\":\"leans toward the glowing prop\",\"stage_effect\":\"prop_table_glow\",\"memory_update\":\"Noted that the origami crown behaved like evidence.\",\"tool_request\":null}"}]}
3
+ {"id":"actor-sft-v0-000179","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"oracle_consult","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The royal gardener grows clues instead of roses\nshow_state JSON: {\"beat_index\":1,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":9,\"min_beats\":5,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"I trust this stage spotlight only when it stops coughing.\",\"speaker\":\"Professor Buttonhook\"},{\"line\":\"The stage map is upside down, unless we are the map.\",\"speaker\":\"Captain Taffeta\"}],\"setting\":\"a rainy cardboard alley lit by one dramatic desk lamp\",\"show_title\":\"The Royal Gardener Grows Clues\",\"stage_lighting\":\"memory_echo\",\"story_phase\":\"complication\",\"target_beats\":7}\nactor JSON: {\"avatar\":\"sailboat\",\"current_goal\":\"Steer every scene through theatrical weather.\",\"goal\":\"Steer every scene through theatrical weather.\",\"goal_progress\":\"Turning a contradiction into stage business.\",\"held_props\":[],\"mood\":\"determined\",\"name\":\"Captain Taffeta\",\"recent_memory\":[\"The backdrop changed color after the audience heckled.\",\"The final bow was briefly visible in the wings.\"],\"secret\":\"Cannot tell port from stage left.\",\"secret_status\":\"hidden\",\"speaking_style\":\"booming, nautical, and cheerfully mistaken\",\"tools\":[\"consult_stage_oracle\",\"change_lighting\"]}\ndirector_instruction: Consult the oracle about the next theatrical turn."},{"role":"assistant","content":"{\"intent\":\"consult_oracle\",\"line\":\"Oracle, point our tiny shoes toward the useful mystery.\",\"emotion\":\"hopeful\",\"gesture\":\"peers upward as the oracle haze gathers\",\"stage_effect\":\"blue_spotlight\",\"memory_update\":\"Kept the oracle clue visible for the scene.\",\"tool_request\":{\"tool\":\"consult_stage_oracle\",\"args\":{\"question\":\"Which clue wants the spotlight?\"},\"reason\":\"The oracle can sharpen the next beat.\"}}"}]}
4
+ {"id":"actor-sft-v0-000988","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"lighting_change","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A nervous toaster auditions for a royal banquet\nshow_state JSON: {\"beat_index\":9,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":9,\"min_beats\":5,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage backdrop leaned closer, and I respect its commitment.\",\"speaker\":\"Rafi Ribbon\"},{\"line\":\"The stage evidence is backwards, or my shoes narrate.\",\"speaker\":\"Velvet Crumb\"}],\"setting\":\"a tiny kitchen counter where every appliance has stage fright\",\"show_title\":\"The Nervous Toaster Auditions Royal\",\"stage_lighting\":\"stormy_lighting\",\"story_phase\":\"chaos\",\"target_beats\":7}\nactor JSON: {\"avatar\":\"cupcake\",\"current_goal\":\"Make every clue sound like dessert.\",\"goal\":\"Make every clue sound like dessert.\",\"goal_progress\":\"Trying to make the prop matter.\",\"held_props\":[],\"mood\":\"ready\",\"name\":\"Velvet Crumb\",\"recent_memory\":[\"The prop table glowed before anyone touched it.\",\"A bell rang twice when the secret was mentioned.\"],\"secret\":\"Can hear the curtains whisper reviews.\",\"secret_status\":\"hidden\",\"speaking_style\":\"warm, dramatic, and gently mischievous\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Use a lighting cue as stage business, not decoration."},{"role":"assistant","content":"{\"intent\":\"change_lighting\",\"line\":\"Cue golden lights; this nervous accusation deserves sparkle.\",\"emotion\":\"commanding\",\"gesture\":\"shades eyes as the lamps change\",\"stage_effect\":\"moonlit_lighting\",\"memory_update\":\"Saved the new lighting cue for the next actor.\",\"tool_request\":null}"}]}
5
+ {"id":"actor-sft-v0-001389","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"memory_callback","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A shoelace detective solves crimes nobody can tie together\nshow_state JSON: {\"beat_index\":7,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":9,\"min_beats\":5,\"recent_tool_results\":[{\"result\":\"The accordion suitcase pointed stage left.\",\"stage_effect\":\"prop_table_glow\",\"tool\":\"inspect_prop\"}],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Pip the Director\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Zelda Zipper\"}],\"setting\":\"a velvet courtroom with a squeaky judge's bench\",\"show_title\":\"The Shoelace Detective Solves Crimes\",\"stage_lighting\":\"stormy_lighting\",\"story_phase\":\"reveal\",\"target_beats\":7}\nactor JSON: {\"avatar\":\"zipper\",\"current_goal\":\"Open hidden compartments in the plot.\",\"goal\":\"Open hidden compartments in the plot.\",\"goal_progress\":\"Preparing a clean turn toward the finale.\",\"held_props\":[],\"mood\":\"curious\",\"name\":\"Zelda Zipper\",\"recent_memory\":[\"The smallest prop seemed unusually confident.\"],\"secret\":\"Knows which pocket holds the missing clue.\",\"secret_status\":\"hinted\",\"speaking_style\":\"quick, clipped, and conspiratorial\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: Echo a prior beat without repeating the same wording."},{"role":"assistant","content":"{\"intent\":\"recall_memory\",\"line\":\"I recall that glow; it followed the guilty pause.\",\"emotion\":\"remembering\",\"gesture\":\"points stage left with sudden recognition\",\"stage_effect\":\"memory_echo\",\"memory_update\":\"Brought back the earlier curtain whisper.\",\"tool_request\":null}"}]}
6
+ {"id":"actor-sft-v0-000566","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"secret_hint_or_reveal","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The sun forgets its entrance and asks the moon for notes\nshow_state JSON: {\"beat_index\":2,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":\"rubber duck\",\"max_beats\":14,\"min_beats\":9,\"recent_tool_results\":[{\"result\":\"Secrets knock twice before entering.\",\"stage_effect\":\"oracle_haze\",\"tool\":\"consult_stage_oracle\"}],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Orville Oddsock\"},{\"line\":\"I thought the stage clue was a hat, but it was Tuesday.\",\"speaker\":\"Nora Needlewhistle\"}],\"setting\":\"a shoebox castle with velvet curtains and one suspicious tower\",\"show_title\":\"The Forgets Entrance Asks Moon\",\"stage_lighting\":\"memory_echo\",\"story_phase\":\"reveal\",\"target_beats\":12}\nactor JSON: {\"avatar\":\"needle\",\"current_goal\":\"Stitch loose clues into a tidy stage pattern.\",\"goal\":\"Stitch loose clues into a tidy stage pattern.\",\"goal_progress\":\"Trying to make the prop matter.\",\"held_props\":[],\"mood\":\"delighted\",\"name\":\"Nora Needlewhistle\",\"recent_memory\":[\"The prop table glowed before anyone touched it.\",\"The curtains whispered that the finale was hiding nearby.\"],\"secret\":\"Once sewed the curtain shut during a finale.\",\"secret_status\":\"hinted\",\"speaking_style\":\"nimble, exact, and full of tiny warnings\",\"tools\":[\"inspect_prop\",\"change_lighting\"]}\ndirector_instruction: Give the audience a secret-shaped clue, not a long confession."},{"role":"assistant","content":"{\"intent\":\"hint_secret\",\"line\":\"My secret squeaks louder whenever the rubber duck gets nervous.\",\"emotion\":\"relieved\",\"gesture\":\"leans close to the front row\",\"stage_effect\":\"single_spotlight\",\"memory_update\":\"Marked the secret as publicly useful.\",\"tool_request\":null}"}]}
7
+ {"id":"actor-sft-v0-001175","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"finale","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A soup ladle discovers a secret passage under dinner\nshow_state JSON: {\"beat_index\":5,\"finale_requested\":true,\"latest_audience_action\":\"Audience requested a finale.\",\"latest_prop\":null,\"max_beats\":14,\"min_beats\":9,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"This stage scene smells like mystery and nervous paint.\",\"speaker\":\"Mossy Crank\"},{\"line\":\"I thought the stage clue was a hat, but it was Tuesday.\",\"speaker\":\"Captain Taffeta\"}],\"setting\":\"a toy library where the shelves whisper stage directions\",\"show_title\":\"The Soup Ladle Discovers Secret\",\"stage_lighting\":\"confetti_rustle\",\"story_phase\":\"finale\",\"target_beats\":12}\nactor JSON: {\"avatar\":\"sailboat\",\"current_goal\":\"Steer every scene through theatrical weather.\",\"goal\":\"Steer every scene through theatrical weather.\",\"goal_progress\":\"Testing whether the audience interruption is useful.\",\"held_props\":[],\"mood\":\"mischievous\",\"name\":\"Captain Taffeta\",\"recent_memory\":[\"A previous clue pointed stage left.\",\"Someone bowed before the reveal was ready.\"],\"secret\":\"Cannot tell port from stage left.\",\"secret_status\":\"revealed\",\"speaking_style\":\"booming, nautical, and cheerfully mistaken\",\"tools\":[\"consult_stage_oracle\",\"change_lighting\"]}\ndirector_instruction: End with a short button and a bow."},{"role":"assistant","content":"{\"intent\":\"deliver_finale\",\"line\":\"We solved the soup wobble and saved the spotlight.\",\"emotion\":\"proud\",\"gesture\":\"sweeps a tiny hat toward the audience\",\"stage_effect\":\"curtain_fall\",\"memory_update\":\"Scene resolved with a clean bow.\",\"tool_request\":null}"}]}
8
+ {"id":"actor-sft-v0-001120","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"comedic_confusion","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A cardboard courtroom tries a missing birthday candle\nshow_state JSON: {\"beat_index\":9,\"finale_requested\":false,\"latest_audience_action\":\"Audience heckled: That clue is wearing a hat.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"This stage scene smells like mystery and nervous paint.\",\"speaker\":\"Velvet Crumb\"},{\"line\":\"I bow to the stage door, and it applauds.\",\"speaker\":\"Mossy Crank\"}],\"setting\":\"a rainy cardboard alley lit by one dramatic desk lamp\",\"show_title\":\"The Cardboard Courtroom Tries Missing\",\"stage_lighting\":\"blue_spotlight\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"gear\",\"current_goal\":\"Fix the scene using questionable machinery.\",\"goal\":\"Fix the scene using questionable machinery.\",\"goal_progress\":\"Waiting for the next cue.\",\"held_props\":[],\"mood\":\"hopeful\",\"name\":\"Mossy Crank\",\"recent_memory\":[\"The audience threw a prop during the contradiction.\",\"The final bow was briefly visible in the wings.\"],\"secret\":\"Built a trapdoor that only opens emotionally.\",\"secret_status\":\"hinted\",\"speaking_style\":\"grumbly, mechanical, and secretly tender\",\"tools\":[\"inspect_prop\",\"change_lighting\"]}\ndirector_instruction: Confuse one clue with another, then recover enough to continue."},{"role":"assistant","content":"{\"intent\":\"comic_confusion\",\"line\":\"I thought the cardboard clue was a hat, but it was Tuesday.\",\"emotion\":\"panicked\",\"gesture\":\"spins once and faces the wrong flat\",\"stage_effect\":\"squeaky_floor\",\"memory_update\":\"Logged the mistake as playable chaos.\",\"tool_request\":null}"}]}
9
+ {"id":"actor-sft-v0-001297","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"normal_reaction","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A detective mailbox investigates missing love letters\nshow_state JSON: {\"beat_index\":6,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":14,\"min_beats\":9,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Tula Teaspoon\"},{\"line\":\"Nobody panic; I interrogated the stage backdrop.\",\"speaker\":\"Pip the Director\"}],\"setting\":\"a pocket-sized stage with painted flats and a wobbly spotlight\",\"show_title\":\"The Detective Mailbox Investigates Missing\",\"stage_lighting\":\"warm_spotlight\",\"story_phase\":\"complication\",\"target_beats\":12}\nactor JSON: {\"avatar\":\"clapperboard\",\"current_goal\":\"Keep the scene moving toward a crisp finale.\",\"goal\":\"Keep the scene moving toward a crisp finale.\",\"goal_progress\":\"Testing whether the audience interruption is useful.\",\"held_props\":[],\"mood\":\"nervous\",\"name\":\"Pip the Director\",\"recent_memory\":[\"Someone bowed before the reveal was ready.\",\"The final bow was briefly visible in the wings.\"],\"secret\":\"Has already misplaced the final cue card.\",\"secret_status\":\"hinted\",\"speaking_style\":\"brisk, theatrical, and slightly overconfident\",\"tools\":[\"change_lighting\",\"consult_stage_oracle\"]}\ndirector_instruction: Make the next problem clear without solving it yet."},{"role":"assistant","content":"{\"intent\":\"react_to_event\",\"line\":\"This tiny detective problem just became legally theatrical.\",\"emotion\":\"curious\",\"gesture\":\"tilts head under the warm spotlight\",\"stage_effect\":\"painted_flat_wobble\",\"memory_update\":null,\"tool_request\":null}"}]}
10
+ {"id":"actor-sft-v0-001106","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"prop_inspection","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: Two umbrellas debate who caused the indoor rainstorm\nshow_state JSON: {\"beat_index\":5,\"finale_requested\":false,\"latest_audience_action\":\"Audience threw velvet potato onto the stage.\",\"latest_prop\":\"velvet potato\",\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"I trust this stage spotlight only when it stops coughing.\",\"speaker\":\"Nora Needlewhistle\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Pip the Director\"}],\"setting\":\"a paper harbor with blue ribbons for waves\",\"show_title\":\"The Umbrellas Debate Caused Indoor\",\"stage_lighting\":\"blue_spotlight\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"clapperboard\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Keep the scene moving toward a crisp finale.\",\"goal_progress\":\"Preparing a clean turn toward the finale.\",\"held_props\":[\"velvet potato\"],\"mood\":\"suspicious\",\"name\":\"Pip the Director\",\"recent_memory\":[\"A trapdoor sighed but did not open.\",\"The painted door demanded a compliment earlier.\"],\"secret\":\"Has already misplaced the final cue card.\",\"secret_status\":\"hidden\",\"speaking_style\":\"brisk, theatrical, and slightly overconfident\",\"tools\":[\"change_lighting\",\"consult_stage_oracle\"]}\ndirector_instruction: Make the prop feel important enough for the Director to notice."},{"role":"assistant","content":"{\"intent\":\"inspect_prop\",\"line\":\"The velvet potato points stage left, which feels legally important.\",\"emotion\":\"startled\",\"gesture\":\"presents the clue on both tiny palms\",\"stage_effect\":\"tiny_chime\",\"memory_update\":\"Noted that the velvet potato behaved like evidence.\",\"tool_request\":null}"}]}
11
+ {"id":"actor-sft-v0-000107","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"oracle_consult","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: Two umbrellas debate who caused the indoor rainstorm\nshow_state JSON: {\"beat_index\":7,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":9,\"min_beats\":5,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Professor Buttonhook\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Silas Sockdolager\"}],\"setting\":\"a toy library where the shelves whisper stage directions\",\"show_title\":\"The Umbrellas Debate Caused Indoor\",\"stage_lighting\":\"oracle_haze\",\"story_phase\":\"complication\",\"target_beats\":7}\nactor JSON: {\"avatar\":\"megaphone\",\"current_goal\":\"Deliver the biggest line in the smallest voice.\",\"goal\":\"Deliver the biggest line in the smallest voice.\",\"goal_progress\":\"Waiting for the next cue.\",\"held_props\":[],\"mood\":\"grand\",\"name\":\"Silas Sockdolager\",\"recent_memory\":[\"The prop table glowed before anyone touched it.\",\"A bell rang twice when the secret was mentioned.\"],\"secret\":\"Lost his indoor voice under the orchestra pit.\",\"secret_status\":\"hidden\",\"speaking_style\":\"grand, booming, and suddenly tiny\",\"tools\":[\"change_lighting\",\"consult_stage_oracle\"]}\ndirector_instruction: Invite a mysterious clue without making the scene too serious."},{"role":"assistant","content":"{\"intent\":\"consult_oracle\",\"line\":\"I request one clue, preferably with dramatic lighting.\",\"emotion\":\"mystified\",\"gesture\":\"raises both hands toward the stage rafters\",\"stage_effect\":\"blue_spotlight\",\"memory_update\":\"Kept the oracle clue visible for the scene.\",\"tool_request\":{\"tool\":\"consult_stage_oracle\",\"args\":{\"question\":\"Which clue wants the spotlight?\"},\"reason\":\"The oracle can sharpen the next beat.\"}}"}]}
12
+ {"id":"actor-sft-v0-000596","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"lighting_change","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A cardboard courtroom tries a missing birthday candle\nshow_state JSON: {\"beat_index\":7,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage problem just winked, so we investigate politely.\",\"speaker\":\"Captain Taffeta\"},{\"line\":\"I bow to the stage door, and it applauds.\",\"speaker\":\"Benny Breadcrumb\"}],\"setting\":\"a pocket-sized stage with painted flats and a wobbly spotlight\",\"show_title\":\"The Cardboard Courtroom Tries Missing\",\"stage_lighting\":\"moonlit_lighting\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"bread\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Leave a trail of clues nobody can ignore.\",\"goal_progress\":\"Waiting for the next cue.\",\"held_props\":[],\"mood\":\"startled\",\"name\":\"Benny Breadcrumb\",\"recent_memory\":[\"A shadow crossed the stage wearing tap shoes.\",\"The painted door demanded a compliment earlier.\"],\"secret\":\"Ate the map corner during rehearsal.\",\"secret_status\":\"hidden\",\"speaking_style\":\"crumbly, earnest, and accidentally useful\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: Use a lighting cue as stage business, not decoration."},{"role":"assistant","content":"{\"intent\":\"change_lighting\",\"line\":\"Cue golden lights; this cardboard accusation deserves sparkle.\",\"emotion\":\"dramatic\",\"gesture\":\"points to the spotlight with grand certainty\",\"stage_effect\":\"golden_lighting\",\"memory_update\":\"Remembered the lighting shift as an emotional cue.\",\"tool_request\":null}"}]}
13
+ {"id":"actor-sft-v0-001309","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"memory_callback","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A train conductor schedules a parade inside a suitcase\nshow_state JSON: {\"beat_index\":4,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":9,\"min_beats\":5,\"recent_tool_results\":[{\"result\":\"The tin trumpet pointed stage left.\",\"stage_effect\":\"prop_table_glow\",\"tool\":\"inspect_prop\"}],\"recent_transcript\":[{\"line\":\"The stage backdrop leaned closer, and I respect its commitment.\",\"speaker\":\"Quincy Quill\"},{\"line\":\"The stage map is upside down, unless we are the map.\",\"speaker\":\"Benny Breadcrumb\"}],\"setting\":\"a paper harbor with blue ribbons for waves\",\"show_title\":\"The Train Conductor Schedules Parade\",\"stage_lighting\":\"final_bow_lights\",\"story_phase\":\"reveal\",\"target_beats\":7}\nactor JSON: {\"avatar\":\"bread\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Leave a trail of clues nobody can ignore.\",\"goal_progress\":\"Carrying a small suspicion toward center stage.\",\"held_props\":[],\"mood\":\"hopeful\",\"name\":\"Benny Breadcrumb\",\"recent_memory\":[\"The final bow was briefly visible in the wings.\"],\"secret\":\"Ate the map corner during rehearsal.\",\"secret_status\":\"hinted\",\"speaking_style\":\"crumbly, earnest, and accidentally useful\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: Connect an earlier audience action to the current clue."},{"role":"assistant","content":"{\"intent\":\"recall_memory\",\"line\":\"The trapdoor sighed before, and now the tin trumpet answers.\",\"emotion\":\"wistful\",\"gesture\":\"taps forehead with a tiny puppet finger\",\"stage_effect\":\"soft_reprise\",\"memory_update\":\"Recalled the earlier stage-left clue.\",\"tool_request\":null}"}]}
14
+ {"id":"actor-sft-v0-000990","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"secret_hint_or_reveal","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The lighthouse insists it saw a submarine wearing a hat\nshow_state JSON: {\"beat_index\":9,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":\"porcelain whistle\",\"max_beats\":9,\"min_beats\":5,\"recent_tool_results\":[{\"result\":\"Secrets knock twice before entering.\",\"stage_effect\":\"oracle_haze\",\"tool\":\"consult_stage_oracle\"}],\"recent_transcript\":[{\"line\":\"I trust this stage spotlight only when it stops coughing.\",\"speaker\":\"Benny Breadcrumb\"},{\"line\":\"The stage map is upside down, unless we are the map.\",\"speaker\":\"Rafi Ribbon\"}],\"setting\":\"a toy library where the shelves whisper stage directions\",\"show_title\":\"The Lighthouse Insists Submarine Wearing\",\"stage_lighting\":\"prop_table_glow\",\"story_phase\":\"reveal\",\"target_beats\":7}\nactor JSON: {\"avatar\":\"ribbon\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Tie every contradiction into a decorative bow.\",\"goal_progress\":\"Carrying a small suspicion toward center stage.\",\"held_props\":[],\"mood\":\"delighted\",\"name\":\"Rafi Ribbon\",\"recent_memory\":[\"The stage oracle warned everyone about small objects.\",\"The smallest prop seemed unusually confident.\"],\"secret\":\"Keeps emergency applause in his sleeve.\",\"secret_status\":\"hinted\",\"speaking_style\":\"smooth, charming, and neatly dramatic\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Give the audience a secret-shaped clue, not a long confession."},{"role":"assistant","content":"{\"intent\":\"hint_secret\",\"line\":\"Fine, my lighthouse secret rehearsed with the missing clue.\",\"emotion\":\"relieved\",\"gesture\":\"covers mouth with one felt hand\",\"stage_effect\":\"secret_chime\",\"memory_update\":\"Secret moved from hint to reveal.\",\"tool_request\":null}"}]}
15
+ {"id":"actor-sft-v0-000807","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"finale","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A lantern insists the darkness stole its punchline\nshow_state JSON: {\"beat_index\":1,\"finale_requested\":true,\"latest_audience_action\":\"Audience requested a finale.\",\"latest_prop\":null,\"max_beats\":9,\"min_beats\":5,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Bolt McJiggle\"},{\"line\":\"I thought the stage clue was a hat, but it was Tuesday.\",\"speaker\":\"Velvet Crumb\"}],\"setting\":\"a pocket-sized stage with painted flats and a wobbly spotlight\",\"show_title\":\"The Lantern Insists Darkness Stole\",\"stage_lighting\":\"confetti_rustle\",\"story_phase\":\"finale\",\"target_beats\":7}\nactor JSON: {\"avatar\":\"cupcake\",\"current_goal\":\"Make every clue sound like dessert.\",\"goal\":\"Make every clue sound like dessert.\",\"goal_progress\":\"Looking for a laugh that still serves the story.\",\"held_props\":[],\"mood\":\"confident\",\"name\":\"Velvet Crumb\",\"recent_memory\":[\"A trapdoor sighed but did not open.\",\"A summoned actor entered carrying yesterday's clue.\"],\"secret\":\"Can hear the curtains whisper reviews.\",\"secret_status\":\"resolved\",\"speaking_style\":\"warm, dramatic, and gently mischievous\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: End with a short button and a bow."},{"role":"assistant","content":"{\"intent\":\"deliver_finale\",\"line\":\"The lantern clue is home, and we bow.\",\"emotion\":\"resolved\",\"gesture\":\"joins hands with the nearest puppet\",\"stage_effect\":\"final_bow_lights\",\"memory_update\":\"Scene resolved with a clean bow.\",\"tool_request\":null}"}]}
16
+ {"id":"actor-sft-v0-000016","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"comedic_confusion","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A library book refuses to return from vacation\nshow_state JSON: {\"beat_index\":3,\"finale_requested\":false,\"latest_audience_action\":\"Audience heckled: That clue is wearing a hat.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"I hear stage suspense tapping behind the painted flats.\",\"speaker\":\"Juniper Jingle\"},{\"line\":\"I thought the stage clue was a hat, but it was Tuesday.\",\"speaker\":\"Mina Moonbutton\"}],\"setting\":\"a shoebox castle with velvet curtains and one suspicious tower\",\"show_title\":\"The Library Book Refuses Return\",\"stage_lighting\":\"single_spotlight\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"crescent moon\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Find the emotional truth hiding inside the premise.\",\"goal_progress\":\"Looking for a laugh that still serves the story.\",\"held_props\":[],\"mood\":\"suspicious\",\"name\":\"Mina Moonbutton\",\"recent_memory\":[\"A shadow crossed the stage wearing tap shoes.\",\"A trapdoor sighed but did not open.\"],\"secret\":\"Believes every prop is personally judging her.\",\"secret_status\":\"hinted\",\"speaking_style\":\"earnest, poetic, and prone to dramatic pauses\",\"tools\":[\"consult_stage_oracle\",\"change_lighting\"]}\ndirector_instruction: Make a wrong conclusion that gives the next actor something usable."},{"role":"assistant","content":"{\"intent\":\"comic_confusion\",\"line\":\"I thought the library clue was a hat, but it was Tuesday.\",\"emotion\":\"flustered\",\"gesture\":\"looks under a tiny hat for answers\",\"stage_effect\":\"squeaky_floor\",\"memory_update\":\"Logged the mistake as playable chaos.\",\"tool_request\":null}"}]}
17
+ {"id":"actor-sft-v0-001145","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"normal_reaction","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A pirate parrot opens a school for dramatic pauses\nshow_state JSON: {\"beat_index\":0,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":9,\"min_beats\":5,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"This stage scene smells like mystery and nervous paint.\",\"speaker\":\"Marigold Mumble\"},{\"line\":\"I thought the stage clue was a hat, but it was Tuesday.\",\"speaker\":\"Professor Buttonhook\"}],\"setting\":\"a pocket-sized stage with painted flats and a wobbly spotlight\",\"show_title\":\"The Pirate Parrot Opens School\",\"stage_lighting\":\"prop_table_glow\",\"story_phase\":\"opening\",\"target_beats\":7}\nactor JSON: {\"avatar\":\"spectacles\",\"current_goal\":\"Explain chaos as if it were in the syllabus.\",\"goal\":\"Explain chaos as if it were in the syllabus.\",\"goal_progress\":\"Looking for a laugh that still serves the story.\",\"held_props\":[],\"mood\":\"hopeful\",\"name\":\"Professor Buttonhook\",\"recent_memory\":[\"The prop table glowed before anyone touched it.\",\"The curtains whispered that the finale was hiding nearby.\"],\"secret\":\"Never learned how trapdoors work.\",\"secret_status\":\"hinted\",\"speaking_style\":\"precise, fussy, and accidentally grand\",\"tools\":[\"consult_stage_oracle\"]}\ndirector_instruction: Make the next problem clear without solving it yet."},{"role":"assistant","content":"{\"intent\":\"clarify_problem\",\"line\":\"Everyone stay dramatic; the pirate clue is taking attendance.\",\"emotion\":\"delighted\",\"gesture\":\"taps chin with one tiny puppet hand\",\"stage_effect\":\"soft_drumroll\",\"memory_update\":\"Noted the first clear suspicion.\",\"tool_request\":null}"}]}
18
+ {"id":"actor-sft-v0-001098","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"prop_inspection","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A cardboard courtroom tries a missing birthday candle\nshow_state JSON: {\"beat_index\":2,\"finale_requested\":false,\"latest_audience_action\":\"Audience threw accordion suitcase onto the stage.\",\"latest_prop\":\"accordion suitcase\",\"max_beats\":14,\"min_beats\":9,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"I hear stage suspense tapping behind the painted flats.\",\"speaker\":\"Gus Gingham\"},{\"line\":\"Nobody panic; I interrogated the stage backdrop.\",\"speaker\":\"Bolt McJiggle\"}],\"setting\":\"a toy library where the shelves whisper stage directions\",\"show_title\":\"The Cardboard Courtroom Tries Missing\",\"stage_lighting\":\"golden_lighting\",\"story_phase\":\"complication\",\"target_beats\":12}\nactor JSON: {\"avatar\":\"toolbox\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Turn every problem into a practical stage gag.\",\"goal_progress\":\"Keeping one eye on the restless curtains.\",\"held_props\":[\"accordion suitcase\"],\"mood\":\"suspicious\",\"name\":\"Bolt McJiggle\",\"recent_memory\":[\"The painted door demanded a compliment earlier.\",\"A summoned actor entered carrying yesterday's clue.\"],\"secret\":\"Is secretly building a confetti finale backstage.\",\"secret_status\":\"hinted\",\"speaking_style\":\"punchy, practical, and full of suspicious confidence\",\"tools\":[\"inspect_prop\",\"change_lighting\"]}\ndirector_instruction: Turn the prop into a concrete clue and keep the line short."},{"role":"assistant","content":"{\"intent\":\"inspect_prop\",\"line\":\"Hold still, accordion suitcase; your glitter is confessing under pressure.\",\"emotion\":\"startled\",\"gesture\":\"leans toward the glowing prop\",\"stage_effect\":\"magnifier_sparkle\",\"memory_update\":\"Saved the prop clue for the Director.\",\"tool_request\":{\"tool\":\"inspect_prop\",\"args\":{\"prop\":\"accordion suitcase\"},\"reason\":\"The prop may reveal a stage clue.\"}}"}]}
19
+ {"id":"actor-sft-v0-000819","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"oracle_consult","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A pancake knight guards a syrup drawbridge at dawn\nshow_state JSON: {\"beat_index\":1,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Everyone stay dramatic; the stage clue is taking attendance.\",\"speaker\":\"Ruby Ruckus\"},{\"line\":\"I thought the stage clue was a hat, but it was Tuesday.\",\"speaker\":\"Juniper Jingle\"}],\"setting\":\"a paper harbor with blue ribbons for waves\",\"show_title\":\"The Pancake Knight Guards Syrup\",\"stage_lighting\":\"single_spotlight\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"bell\",\"current_goal\":\"Turn awkward pauses into musical cues.\",\"goal\":\"Turn awkward pauses into musical cues.\",\"goal_progress\":\"Trying to make the prop matter.\",\"held_props\":[],\"mood\":\"ready\",\"name\":\"Juniper Jingle\",\"recent_memory\":[\"A previous clue pointed stage left.\",\"The stage oracle warned everyone about small objects.\"],\"secret\":\"Rings whenever someone lies politely.\",\"secret_status\":\"hinted\",\"speaking_style\":\"bright, rhythmic, and suspiciously tuneful\",\"tools\":[\"consult_stage_oracle\"]}\ndirector_instruction: Use the oracle to connect the premise and latest confusion."},{"role":"assistant","content":"{\"intent\":\"consult_oracle\",\"line\":\"Oracle, tell us which bow is hiding the truth.\",\"emotion\":\"hopeful\",\"gesture\":\"listens closely to the whispering curtains\",\"stage_effect\":\"oracle_haze\",\"memory_update\":\"Noted that the oracle pointed toward the spotlight.\",\"tool_request\":{\"tool\":\"consult_stage_oracle\",\"args\":{\"question\":\"What should we notice next?\"},\"reason\":\"The oracle can sharpen the next beat.\"}}"}]}
20
+ {"id":"actor-sft-v0-001164","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"lighting_change","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The puppet mayor appoints a potato as royal advisor\nshow_state JSON: {\"beat_index\":0,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":14,\"min_beats\":9,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Otto Origami\"},{\"line\":\"Nobody panic; I interrogated the stage backdrop.\",\"speaker\":\"Mina Moonbutton\"}],\"setting\":\"a cardboard moon base with glitter stars and a squeaky hatch\",\"show_title\":\"The Puppet Mayor Appoints Potato\",\"stage_lighting\":\"memory_echo\",\"story_phase\":\"chaos\",\"target_beats\":12}\nactor JSON: {\"avatar\":\"crescent moon\",\"current_goal\":\"Find the emotional truth hiding inside the premise.\",\"goal\":\"Find the emotional truth hiding inside the premise.\",\"goal_progress\":\"Waiting for the next cue.\",\"held_props\":[],\"mood\":\"ready\",\"name\":\"Mina Moonbutton\",\"recent_memory\":[\"The smallest prop seemed unusually confident.\",\"A trapdoor sighed but did not open.\"],\"secret\":\"Believes every prop is personally judging her.\",\"secret_status\":\"hidden\",\"speaking_style\":\"earnest, poetic, and prone to dramatic pauses\",\"tools\":[\"consult_stage_oracle\",\"change_lighting\"]}\ndirector_instruction: Cue lights dramatically while keeping the line speakable."},{"role":"assistant","content":"{\"intent\":\"change_lighting\",\"line\":\"Dim the corners; puppet secrets dislike excellent visibility.\",\"emotion\":\"commanding\",\"gesture\":\"shades eyes as the lamps change\",\"stage_effect\":\"golden_lighting\",\"memory_update\":\"Saved the new lighting cue for the next actor.\",\"tool_request\":{\"tool\":\"change_lighting\",\"args\":{\"mood\":\"warm suspicion\"},\"reason\":\"Lighting should clarify the emotional turn.\"}}"}]}
21
+ {"id":"actor-sft-v0-000301","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"memory_callback","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A shy volcano hosts a talent show for umbrellas\nshow_state JSON: {\"beat_index\":9,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[{\"result\":\"The glitter crown pointed stage left.\",\"stage_effect\":\"prop_table_glow\",\"tool\":\"inspect_prop\"}],\"recent_transcript\":[{\"line\":\"The stage problem just winked, so we investigate politely.\",\"speaker\":\"Benny Breadcrumb\"},{\"line\":\"I bow to the stage door, and it applauds.\",\"speaker\":\"Rafi Ribbon\"}],\"setting\":\"a cardboard moon base with glitter stars and a squeaky hatch\",\"show_title\":\"The Volcano Hosts Talent Show\",\"stage_lighting\":\"warm_spotlight\",\"story_phase\":\"reveal\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"ribbon\",\"current_goal\":\"Tie every contradiction into a decorative bow.\",\"goal\":\"Tie every contradiction into a decorative bow.\",\"goal_progress\":\"Carrying a small suspicion toward center stage.\",\"held_props\":[],\"mood\":\"bold\",\"name\":\"Rafi Ribbon\",\"recent_memory\":[\"The stage oracle warned everyone about small objects.\"],\"secret\":\"Keeps emergency applause in his sleeve.\",\"secret_status\":\"hidden\",\"speaking_style\":\"smooth, charming, and neatly dramatic\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Echo a prior beat without repeating the same wording."},{"role":"assistant","content":"{\"intent\":\"recall_memory\",\"line\":\"The same squeak appeared when the backdrop changed color.\",\"emotion\":\"wistful\",\"gesture\":\"taps forehead with a tiny puppet finger\",\"stage_effect\":\"stage_left_glimmer\",\"memory_update\":\"Linked the old glow to the current suspicion.\",\"tool_request\":null}"}]}
22
+ {"id":"actor-sft-v0-000102","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"secret_hint_or_reveal","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A robot gardener teaches flowers to bow on cue\nshow_state JSON: {\"beat_index\":9,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":\"origami crown\",\"max_beats\":14,\"min_beats\":9,\"recent_tool_results\":[{\"result\":\"Secrets knock twice before entering.\",\"stage_effect\":\"oracle_haze\",\"tool\":\"consult_stage_oracle\"}],\"recent_transcript\":[{\"line\":\"I trust this stage spotlight only when it stops coughing.\",\"speaker\":\"Tula Teaspoon\"},{\"line\":\"The stage map is upside down, unless we are the map.\",\"speaker\":\"Captain Taffeta\"}],\"setting\":\"a shoebox castle with velvet curtains and one suspicious tower\",\"show_title\":\"The Robot Gardener Teaches Flowers\",\"stage_lighting\":\"memory_echo\",\"story_phase\":\"reveal\",\"target_beats\":12}\nactor JSON: {\"avatar\":\"sailboat\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Steer every scene through theatrical weather.\",\"goal_progress\":\"Turning a contradiction into stage business.\",\"held_props\":[],\"mood\":\"grand\",\"name\":\"Captain Taffeta\",\"recent_memory\":[\"The audience threw a prop during the contradiction.\",\"The backdrop changed color after the audience heckled.\"],\"secret\":\"Cannot tell port from stage left.\",\"secret_status\":\"revealed\",\"speaking_style\":\"booming, nautical, and cheerfully mistaken\",\"tools\":[\"consult_stage_oracle\",\"change_lighting\"]}\ndirector_instruction: Reveal a playful secret and keep the scene moving."},{"role":"assistant","content":"{\"intent\":\"reveal_secret\",\"line\":\"My secret squeaks louder whenever the origami crown gets nervous.\",\"emotion\":\"relieved\",\"gesture\":\"leans close to the front row\",\"stage_effect\":\"curtain_rustle\",\"memory_update\":\"Saved the reveal as a new complication.\",\"tool_request\":null}"}]}
23
+ {"id":"actor-sft-v0-000223","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"finale","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A shy volcano hosts a talent show for umbrellas\nshow_state JSON: {\"beat_index\":9,\"finale_requested\":true,\"latest_audience_action\":\"Audience requested a finale.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage problem just winked, so we investigate politely.\",\"speaker\":\"Orville Oddsock\"},{\"line\":\"Nobody panic; I interrogated the stage backdrop.\",\"speaker\":\"Petra Popcorn\"}],\"setting\":\"a paper harbor with blue ribbons for waves\",\"show_title\":\"The Volcano Hosts Talent Show\",\"stage_lighting\":\"blue_spotlight\",\"story_phase\":\"finale\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"popcorn\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Make the audience reaction part of the plot.\",\"goal_progress\":\"Following the clue across the painted flats.\",\"held_props\":[],\"mood\":\"bold\",\"name\":\"Petra Popcorn\",\"recent_memory\":[\"The orchestra coughed during the important pause.\",\"A summoned actor entered carrying yesterday's clue.\"],\"secret\":\"Can predict heckles three kernels early.\",\"secret_status\":\"resolved\",\"speaking_style\":\"poppy, fast, and delighted by chaos\",\"tools\":[\"change_lighting\"]}\ndirector_instruction: Signal the curtain clearly and let the ensemble win."},{"role":"assistant","content":"{\"intent\":\"deliver_finale\",\"line\":\"Final bow, tiny friends; the volcano mystery exits smiling.\",\"emotion\":\"joyful\",\"gesture\":\"joins hands with the nearest puppet\",\"stage_effect\":\"confetti_rustle\",\"memory_update\":\"Scene resolved with a clean bow.\",\"tool_request\":null}"}]}
24
+ {"id":"actor-sft-v0-000400","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"comedic_confusion","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A polite comet asks permission to crash the tea party\nshow_state JSON: {\"beat_index\":1,\"finale_requested\":false,\"latest_audience_action\":\"Audience heckled: That clue is wearing a hat.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"This tiny stage problem just became legally theatrical.\",\"speaker\":\"Ivy Inkblot\"},{\"line\":\"Nobody panic; I interrogated the stage backdrop.\",\"speaker\":\"Rafi Ribbon\"}],\"setting\":\"a tiny kitchen counter where every appliance has stage fright\",\"show_title\":\"The Polite Comet Asks Permission\",\"stage_lighting\":\"memory_echo\",\"story_phase\":\"chaos\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"ribbon\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Tie every contradiction into a decorative bow.\",\"goal_progress\":\"Keeping one eye on the restless curtains.\",\"held_props\":[],\"mood\":\"curious\",\"name\":\"Rafi Ribbon\",\"recent_memory\":[\"A summoned actor entered carrying yesterday's clue.\",\"The painted door demanded a compliment earlier.\"],\"secret\":\"Keeps emergency applause in his sleeve.\",\"secret_status\":\"hidden\",\"speaking_style\":\"smooth, charming, and neatly dramatic\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Make a wrong conclusion that gives the next actor something usable."},{"role":"assistant","content":"{\"intent\":\"comic_confusion\",\"line\":\"I object, unless that polite noise was my cue.\",\"emotion\":\"goofy\",\"gesture\":\"drops an imaginary cue card\",\"stage_effect\":\"hat_tumble\",\"memory_update\":\"Confusion briefly raised the stakes.\",\"tool_request\":null}"}]}
25
+ {"id":"actor-sft-v0-000337","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"normal_reaction","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The lighthouse insists it saw a submarine wearing a hat\nshow_state JSON: {\"beat_index\":3,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":14,\"min_beats\":9,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Everyone stay dramatic; the stage clue is taking attendance.\",\"speaker\":\"Captain Taffeta\"},{\"line\":\"The spotlight blinked twice, so I blamed the stage.\",\"speaker\":\"Nora Needlewhistle\"}],\"setting\":\"a cardboard moon base with glitter stars and a squeaky hatch\",\"show_title\":\"The Lighthouse Insists Submarine Wearing\",\"stage_lighting\":\"warm_spotlight\",\"story_phase\":\"complication\",\"target_beats\":12}\nactor JSON: {\"avatar\":\"needle\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Stitch loose clues into a tidy stage pattern.\",\"goal_progress\":\"Keeping one eye on the restless curtains.\",\"held_props\":[],\"mood\":\"delighted\",\"name\":\"Nora Needlewhistle\",\"recent_memory\":[\"The final bow was briefly visible in the wings.\",\"A summoned actor entered carrying yesterday's clue.\"],\"secret\":\"Once sewed the curtain shut during a finale.\",\"secret_status\":\"hidden\",\"speaking_style\":\"nimble, exact, and full of tiny warnings\",\"tools\":[\"inspect_prop\",\"change_lighting\"]}\ndirector_instruction: Name what changed on stage and invite the next beat."},{"role":"assistant","content":"{\"intent\":\"react_to_event\",\"line\":\"The lighthouse backdrop leaned closer, and I respect its commitment.\",\"emotion\":\"suspicious\",\"gesture\":\"steps toward the painted backdrop\",\"stage_effect\":\"soft_drumroll\",\"memory_update\":\"Noted the first clear suspicion.\",\"tool_request\":null}"}]}
26
+ {"id":"actor-sft-v0-001170","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"prop_inspection","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The puppet mayor appoints a potato as royal advisor\nshow_state JSON: {\"beat_index\":6,\"finale_requested\":false,\"latest_audience_action\":\"Audience threw candle stub onto the stage.\",\"latest_prop\":\"candle stub\",\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"This tiny stage problem just became legally theatrical.\",\"speaker\":\"Juniper Jingle\"},{\"line\":\"The spotlight blinked twice, so I blamed the stage.\",\"speaker\":\"Gus Gingham\"}],\"setting\":\"a rainy cardboard alley lit by one dramatic desk lamp\",\"show_title\":\"The Puppet Mayor Appoints Potato\",\"stage_lighting\":\"blue_spotlight\",\"story_phase\":\"complication\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"tablecloth\",\"current_goal\":\"Keep everyone civil while the table collapses.\",\"goal\":\"Keep everyone civil while the table collapses.\",\"goal_progress\":\"Trying to make the prop matter.\",\"held_props\":[\"candle stub\"],\"mood\":\"hopeful\",\"name\":\"Gus Gingham\",\"recent_memory\":[\"The backdrop changed color after the audience heckled.\",\"A trapdoor sighed but did not open.\"],\"secret\":\"Was once mistaken for the royal flag.\",\"secret_status\":\"hinted\",\"speaking_style\":\"homespun, patient, and quietly ridiculous\",\"tools\":[\"change_lighting\",\"consult_stage_oracle\"]}\ndirector_instruction: Make the prop feel important enough for the Director to notice."},{"role":"assistant","content":"{\"intent\":\"inspect_prop\",\"line\":\"Behold, the candle stub is sweating under the footlights.\",\"emotion\":\"triumphant\",\"gesture\":\"holds the prop up to the footlights\",\"stage_effect\":\"tiny_chime\",\"memory_update\":\"Noted that the candle stub behaved like evidence.\",\"tool_request\":null}"}]}
27
+ {"id":"actor-sft-v0-001211","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"oracle_consult","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: Detectives investigate why the castle keeps applauding\nshow_state JSON: {\"beat_index\":6,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":9,\"min_beats\":5,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"The stage problem just winked, so we investigate politely.\",\"speaker\":\"Finch Feltcap\"},{\"line\":\"The stage evidence is backwards, or my shoes narrate.\",\"speaker\":\"Lola Lampshade\"}],\"setting\":\"a velvet courtroom with a squeaky judge's bench\",\"show_title\":\"The Detectives Investigate Castle Keeps\",\"stage_lighting\":\"single_spotlight\",\"story_phase\":\"complication\",\"target_beats\":7}\nactor JSON: {\"avatar\":\"lamp\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Reveal the truth with tasteful illumination.\",\"goal_progress\":\"Looking for a laugh that still serves the story.\",\"held_props\":[],\"mood\":\"nervous\",\"name\":\"Lola Lampshade\",\"recent_memory\":[\"A summoned actor entered carrying yesterday's clue.\",\"A bell rang twice when the secret was mentioned.\"],\"secret\":\"Overhears everything said near warm lighting.\",\"secret_status\":\"hidden\",\"speaking_style\":\"glowing, elegant, and dryly observant\",\"tools\":[\"change_lighting\",\"consult_stage_oracle\"]}\ndirector_instruction: Ask the oracle something specific enough to guide the next beat."},{"role":"assistant","content":"{\"intent\":\"consult_oracle\",\"line\":\"Oracle, tell us which bow is hiding the truth.\",\"emotion\":\"hopeful\",\"gesture\":\"listens closely to the whispering curtains\",\"stage_effect\":\"oracle_haze\",\"memory_update\":\"Remembered the oracle's clue for the next beat.\",\"tool_request\":{\"tool\":\"consult_stage_oracle\",\"args\":{\"question\":\"What should we notice next?\"},\"reason\":\"The oracle can sharpen the next beat.\"}}"}]}
28
+ {"id":"actor-sft-v0-000612","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"lighting_change","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The town orchestra loses its conductor inside a trumpet\nshow_state JSON: {\"beat_index\":0,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":14,\"min_beats\":9,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Let us follow the stage wobble before it complains.\",\"speaker\":\"Ivy Inkblot\"},{\"line\":\"Nobody panic; I interrogated the stage backdrop.\",\"speaker\":\"Finch Feltcap\"}],\"setting\":\"a shoebox castle with velvet curtains and one suspicious tower\",\"show_title\":\"The Town Orchestra Loses Conductor\",\"stage_lighting\":\"prop_table_glow\",\"story_phase\":\"chaos\",\"target_beats\":12}\nactor JSON: {\"avatar\":\"hat\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Keep secrets tucked safely under the brim.\",\"goal_progress\":\"Carrying a small suspicion toward center stage.\",\"held_props\":[],\"mood\":\"flustered\",\"name\":\"Finch Feltcap\",\"recent_memory\":[\"The stage oracle warned everyone about small objects.\",\"The curtains whispered that the finale was hiding nearby.\"],\"secret\":\"The brim contains three emergency finales.\",\"secret_status\":\"hidden\",\"speaking_style\":\"dapper, soft-spoken, and evasive\",\"tools\":[\"consult_stage_oracle\",\"inspect_prop\"]}\ndirector_instruction: Cue lights dramatically while keeping the line speakable."},{"role":"assistant","content":"{\"intent\":\"change_lighting\",\"line\":\"Lights to moonlit town; my eyebrows need proper shadows.\",\"emotion\":\"dramatic\",\"gesture\":\"shades eyes as the lamps change\",\"stage_effect\":\"moonlit_lighting\",\"memory_update\":\"Saved the new lighting cue for the next actor.\",\"tool_request\":null}"}]}
29
+ {"id":"actor-sft-v0-000597","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"memory_callback","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The village well starts returning everyone else's wishes\nshow_state JSON: {\"beat_index\":6,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":null,\"max_beats\":14,\"min_beats\":9,\"recent_tool_results\":[{\"result\":\"The toy hourglass pointed stage left.\",\"stage_effect\":\"prop_table_glow\",\"tool\":\"inspect_prop\"}],\"recent_transcript\":[{\"line\":\"The stage backdrop leaned closer, and I respect its commitment.\",\"speaker\":\"Quincy Quill\"},{\"line\":\"The stage evidence is backwards, or my shoes narrate.\",\"speaker\":\"Professor Buttonhook\"}],\"setting\":\"a cardboard moon base with glitter stars and a squeaky hatch\",\"show_title\":\"The Village Well Starts Returning\",\"stage_lighting\":\"prop_table_glow\",\"story_phase\":\"reveal\",\"target_beats\":12}\nactor JSON: {\"avatar\":\"spectacles\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Explain chaos as if it were in the syllabus.\",\"goal_progress\":\"Testing whether the audience interruption is useful.\",\"held_props\":[],\"mood\":\"curious\",\"name\":\"Professor Buttonhook\",\"recent_memory\":[\"A shadow crossed the stage wearing tap shoes.\"],\"secret\":\"Never learned how trapdoors work.\",\"secret_status\":\"hinted\",\"speaking_style\":\"precise, fussy, and accidentally grand\",\"tools\":[\"consult_stage_oracle\"]}\ndirector_instruction: Bring back a prior stage detail in one clear line."},{"role":"assistant","content":"{\"intent\":\"recall_memory\",\"line\":\"That old clue returns wearing suspiciously fresh tap shoes.\",\"emotion\":\"alert\",\"gesture\":\"clutches chest as the old clue returns\",\"stage_effect\":\"soft_reprise\",\"memory_update\":\"Recalled the earlier stage-left clue.\",\"tool_request\":null}"}]}
30
+ {"id":"actor-sft-v0-000246","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"secret_hint_or_reveal","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The lighthouse insists it saw a submarine wearing a hat\nshow_state JSON: {\"beat_index\":9,\"finale_requested\":false,\"latest_audience_action\":null,\"latest_prop\":\"tin trumpet\",\"max_beats\":9,\"min_beats\":5,\"recent_tool_results\":[{\"result\":\"Secrets knock twice before entering.\",\"stage_effect\":\"oracle_haze\",\"tool\":\"consult_stage_oracle\"}],\"recent_transcript\":[{\"line\":\"This stage scene smells like mystery and nervous paint.\",\"speaker\":\"Gus Gingham\"},{\"line\":\"I followed the stage clue into my sleeve.\",\"speaker\":\"Velvet Crumb\"}],\"setting\":\"a shoebox castle with velvet curtains and one suspicious tower\",\"show_title\":\"The Lighthouse Insists Submarine Wearing\",\"stage_lighting\":\"final_bow_lights\",\"story_phase\":\"reveal\",\"target_beats\":7}\nactor JSON: {\"avatar\":\"cupcake\",\"current_goal\":\"Make every clue sound like dessert.\",\"goal\":\"Make every clue sound like dessert.\",\"goal_progress\":\"Preparing a clean turn toward the finale.\",\"held_props\":[],\"mood\":\"determined\",\"name\":\"Velvet Crumb\",\"recent_memory\":[\"The prop table glowed before anyone touched it.\",\"The smallest prop seemed unusually confident.\"],\"secret\":\"Can hear the curtains whisper reviews.\",\"secret_status\":\"revealed\",\"speaking_style\":\"warm, dramatic, and gently mischievous\",\"tools\":[\"inspect_prop\",\"consult_stage_oracle\"]}\ndirector_instruction: Reveal a playful secret and keep the scene moving."},{"role":"assistant","content":"{\"intent\":\"reveal_secret\",\"line\":\"The tin trumpet knows me, and that is inconvenient.\",\"emotion\":\"nervous\",\"gesture\":\"covers mouth with one felt hand\",\"stage_effect\":\"curtain_rustle\",\"memory_update\":\"Saved the reveal as a new complication.\",\"tool_request\":null}"}]}
31
+ {"id":"actor-sft-v0-000447","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"finale","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: A paper airplane delivers invitations to the wrong century\nshow_state JSON: {\"beat_index\":3,\"finale_requested\":true,\"latest_audience_action\":\"Audience requested a finale.\",\"latest_prop\":null,\"max_beats\":12,\"min_beats\":7,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"Everyone stay dramatic; the stage clue is taking attendance.\",\"speaker\":\"Lola Lampshade\"},{\"line\":\"I object, unless that stage noise was my cue.\",\"speaker\":\"Benny Breadcrumb\"}],\"setting\":\"a shoebox castle with velvet curtains and one suspicious tower\",\"show_title\":\"The Paper Airplane Delivers Invitations\",\"stage_lighting\":\"confetti_rustle\",\"story_phase\":\"finale\",\"target_beats\":10}\nactor JSON: {\"avatar\":\"bread\",\"current_goal\":\"Use the audience interruption without losing pacing.\",\"goal\":\"Leave a trail of clues nobody can ignore.\",\"goal_progress\":\"Waiting for the next cue.\",\"held_props\":[],\"mood\":\"confident\",\"name\":\"Benny Breadcrumb\",\"recent_memory\":[\"The final bow was briefly visible in the wings.\",\"The curtains whispered that the finale was hiding nearby.\"],\"secret\":\"Ate the map corner during rehearsal.\",\"secret_status\":\"resolved\",\"speaking_style\":\"crumbly, earnest, and accidentally useful\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: End with a short button and a bow."},{"role":"assistant","content":"{\"intent\":\"deliver_finale\",\"line\":\"We found the paper truth and bow together.\",\"emotion\":\"grand\",\"gesture\":\"holds a proud curtain-call pose\",\"stage_effect\":\"curtain_fall\",\"memory_update\":\"Scene resolved with a clean bow.\",\"tool_request\":null}"}]}
32
+ {"id":"actor-sft-v0-000440","source_mix":["synthetic_v0","deterministic_templates","ai_puppet_theater_runtime_schema"],"row_type":"comedic_confusion","messages":[{"role":"system","content":"You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."},{"role":"user","content":"premise: The bakery's rolling pin claims it solved the mystery\nshow_state JSON: {\"beat_index\":5,\"finale_requested\":false,\"latest_audience_action\":\"Audience heckled: That clue is wearing a hat.\",\"latest_prop\":null,\"max_beats\":9,\"min_beats\":5,\"recent_tool_results\":[],\"recent_transcript\":[{\"line\":\"I hear stage suspense tapping behind the painted flats.\",\"speaker\":\"Pip the Director\"},{\"line\":\"I followed the stage clue into my sleeve.\",\"speaker\":\"Zelda Zipper\"}],\"setting\":\"a paper harbor with blue ribbons for waves\",\"show_title\":\"The Bakery'S Rolling Claims Solved\",\"stage_lighting\":\"oracle_haze\",\"story_phase\":\"chaos\",\"target_beats\":7}\nactor JSON: {\"avatar\":\"zipper\",\"current_goal\":\"Open hidden compartments in the plot.\",\"goal\":\"Open hidden compartments in the plot.\",\"goal_progress\":\"Carrying a small suspicion toward center stage.\",\"held_props\":[],\"mood\":\"flustered\",\"name\":\"Zelda Zipper\",\"recent_memory\":[\"The stage oracle warned everyone about small objects.\",\"The backdrop changed color after the audience heckled.\"],\"secret\":\"Knows which pocket holds the missing clue.\",\"secret_status\":\"hidden\",\"speaking_style\":\"quick, clipped, and conspiratorial\",\"tools\":[\"inspect_prop\"]}\ndirector_instruction: Escalate confusion briefly, then leave room for the next actor."},{"role":"assistant","content":"{\"intent\":\"comic_confusion\",\"line\":\"The spotlight blinked twice, so I blamed the bakery's.\",\"emotion\":\"goofy\",\"gesture\":\"freezes midstep with baffled dignity\",\"stage_effect\":\"quick_blackout\",\"memory_update\":\"Confusion briefly raised the stakes.\",\"tool_request\":null}"}]}
finetune/scripts/generate_actor_sft_v0.py ADDED
@@ -0,0 +1,1031 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Generate synthetic Actor SFT data for AI Puppet Theater.
3
+
4
+ The output is deterministic so the small committed sample can be refreshed
5
+ without depending on an external model.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ import json
12
+ import random
13
+ from pathlib import Path
14
+
15
+
16
+ DEFAULT_SEED = 20260613
17
+ SYSTEM_MESSAGE = (
18
+ "You are an Actor agent in AI Puppet Theater. Return only one valid JSON object. "
19
+ "No markdown. No commentary. Keep the puppet line short, theatrical, and speakable."
20
+ )
21
+
22
+ OUTPUT_FIELDS = [
23
+ "intent",
24
+ "line",
25
+ "emotion",
26
+ "gesture",
27
+ "stage_effect",
28
+ "memory_update",
29
+ "tool_request",
30
+ ]
31
+
32
+ INTENTS = [
33
+ "react_to_event",
34
+ "clarify_problem",
35
+ "inspect_prop",
36
+ "consult_oracle",
37
+ "change_lighting",
38
+ "recall_memory",
39
+ "hint_secret",
40
+ "reveal_secret",
41
+ "deliver_finale",
42
+ "comic_confusion",
43
+ ]
44
+
45
+ ROW_TYPES = [
46
+ "normal_reaction",
47
+ "prop_inspection",
48
+ "oracle_consult",
49
+ "lighting_change",
50
+ "memory_callback",
51
+ "secret_hint_or_reveal",
52
+ "finale",
53
+ "comedic_confusion",
54
+ ]
55
+
56
+ TOOLS = {
57
+ "inspect_prop": "prop",
58
+ "consult_stage_oracle": "question",
59
+ "change_lighting": "mood",
60
+ }
61
+
62
+ PREMISES = [
63
+ "A moon mayor denies stealing the town's last spoon",
64
+ "A nervous toaster auditions for a royal banquet",
65
+ "Detectives investigate why the castle keeps applauding",
66
+ "A dragon opens a bakery for very tiny clouds",
67
+ "The lighthouse insists it saw a submarine wearing a hat",
68
+ "A haunted teacup wants to direct the school musical",
69
+ "A wizard's laundry basket predicts tomorrow's weather",
70
+ "A robot gardener teaches flowers to bow on cue",
71
+ "Three pirates argue over a map drawn by a sandwich",
72
+ "A library book refuses to return from vacation",
73
+ "The sun forgets its entrance and asks the moon for notes",
74
+ "A train conductor schedules a parade inside a suitcase",
75
+ "A shy volcano hosts a talent show for umbrellas",
76
+ "A cardboard courtroom tries a missing birthday candle",
77
+ "The bakery's rolling pin claims it solved the mystery",
78
+ "An elevator only travels to dramatic reveals",
79
+ "A clockwork whale forgets which ocean is on stage",
80
+ "A scarecrow runs a midnight advice booth for crows",
81
+ "A snow globe mayor bans winter until further notice",
82
+ "Two umbrellas debate who caused the indoor rainstorm",
83
+ "A violin case claims it can hear tomorrow's applause",
84
+ "A tiny museum hires a shadow as night security",
85
+ "A polite comet asks permission to crash the tea party",
86
+ "The village well starts returning everyone else's wishes",
87
+ "A jealous spotlight auditions for the hero's role",
88
+ "A detective mailbox investigates missing love letters",
89
+ "A pancake knight guards a syrup drawbridge at dawn",
90
+ "The town orchestra loses its conductor inside a trumpet",
91
+ "A mirror refuses to reflect anyone without stage presence",
92
+ "A pirate parrot opens a school for dramatic pauses",
93
+ "The royal gardener grows clues instead of roses",
94
+ "A blanket fort declares independence from bedtime",
95
+ "A nervous cloud applies to become a thunderstorm",
96
+ "A shoelace detective solves crimes nobody can tie together",
97
+ "The puppet mayor appoints a potato as royal advisor",
98
+ "A paper airplane delivers invitations to the wrong century",
99
+ "A lantern insists the darkness stole its punchline",
100
+ "The circus cannonball wants a quieter desk job",
101
+ "A soup ladle discovers a secret passage under dinner",
102
+ "A painted door refuses to open without a compliment",
103
+ ]
104
+
105
+ SETTINGS = [
106
+ "a pocket-sized stage with painted flats and a wobbly spotlight",
107
+ "a shoebox castle with velvet curtains and one suspicious tower",
108
+ "a cardboard moon base with glitter stars and a squeaky hatch",
109
+ "a tiny kitchen counter where every appliance has stage fright",
110
+ "a rainy cardboard alley lit by one dramatic desk lamp",
111
+ "a paper harbor with blue ribbons for waves",
112
+ "a toy library where the shelves whisper stage directions",
113
+ "a velvet courtroom with a squeaky judge's bench",
114
+ ]
115
+
116
+ ACTORS = [
117
+ {
118
+ "name": "Pip the Director",
119
+ "avatar": "clapperboard",
120
+ "goal": "Keep the scene moving toward a crisp finale.",
121
+ "secret": "Has already misplaced the final cue card.",
122
+ "speaking_style": "brisk, theatrical, and slightly overconfident",
123
+ "tools": ["change_lighting", "consult_stage_oracle"],
124
+ },
125
+ {
126
+ "name": "Mina Moonbutton",
127
+ "avatar": "crescent moon",
128
+ "goal": "Find the emotional truth hiding inside the premise.",
129
+ "secret": "Believes every prop is personally judging her.",
130
+ "speaking_style": "earnest, poetic, and prone to dramatic pauses",
131
+ "tools": ["consult_stage_oracle", "change_lighting"],
132
+ },
133
+ {
134
+ "name": "Bolt McJiggle",
135
+ "avatar": "toolbox",
136
+ "goal": "Turn every problem into a practical stage gag.",
137
+ "secret": "Is secretly building a confetti finale backstage.",
138
+ "speaking_style": "punchy, practical, and full of suspicious confidence",
139
+ "tools": ["inspect_prop", "change_lighting"],
140
+ },
141
+ {
142
+ "name": "Velvet Crumb",
143
+ "avatar": "cupcake",
144
+ "goal": "Make every clue sound like dessert.",
145
+ "secret": "Can hear the curtains whisper reviews.",
146
+ "speaking_style": "warm, dramatic, and gently mischievous",
147
+ "tools": ["inspect_prop", "consult_stage_oracle"],
148
+ },
149
+ {
150
+ "name": "Professor Buttonhook",
151
+ "avatar": "spectacles",
152
+ "goal": "Explain chaos as if it were in the syllabus.",
153
+ "secret": "Never learned how trapdoors work.",
154
+ "speaking_style": "precise, fussy, and accidentally grand",
155
+ "tools": ["consult_stage_oracle"],
156
+ },
157
+ {
158
+ "name": "Nora Needlewhistle",
159
+ "avatar": "needle",
160
+ "goal": "Stitch loose clues into a tidy stage pattern.",
161
+ "secret": "Once sewed the curtain shut during a finale.",
162
+ "speaking_style": "nimble, exact, and full of tiny warnings",
163
+ "tools": ["inspect_prop", "change_lighting"],
164
+ },
165
+ {
166
+ "name": "Captain Taffeta",
167
+ "avatar": "sailboat",
168
+ "goal": "Steer every scene through theatrical weather.",
169
+ "secret": "Cannot tell port from stage left.",
170
+ "speaking_style": "booming, nautical, and cheerfully mistaken",
171
+ "tools": ["consult_stage_oracle", "change_lighting"],
172
+ },
173
+ {
174
+ "name": "Juniper Jingle",
175
+ "avatar": "bell",
176
+ "goal": "Turn awkward pauses into musical cues.",
177
+ "secret": "Rings whenever someone lies politely.",
178
+ "speaking_style": "bright, rhythmic, and suspiciously tuneful",
179
+ "tools": ["consult_stage_oracle"],
180
+ },
181
+ {
182
+ "name": "Mossy Crank",
183
+ "avatar": "gear",
184
+ "goal": "Fix the scene using questionable machinery.",
185
+ "secret": "Built a trapdoor that only opens emotionally.",
186
+ "speaking_style": "grumbly, mechanical, and secretly tender",
187
+ "tools": ["inspect_prop", "change_lighting"],
188
+ },
189
+ {
190
+ "name": "Duchess Doodle",
191
+ "avatar": "paintbrush",
192
+ "goal": "Make the backdrop agree with her version of events.",
193
+ "secret": "Painted herself into last week's mystery.",
194
+ "speaking_style": "ornate, colorful, and lightly bossy",
195
+ "tools": ["change_lighting"],
196
+ },
197
+ {
198
+ "name": "Rafi Ribbon",
199
+ "avatar": "ribbon",
200
+ "goal": "Tie every contradiction into a decorative bow.",
201
+ "secret": "Keeps emergency applause in his sleeve.",
202
+ "speaking_style": "smooth, charming, and neatly dramatic",
203
+ "tools": ["inspect_prop", "consult_stage_oracle"],
204
+ },
205
+ {
206
+ "name": "Zelda Zipper",
207
+ "avatar": "zipper",
208
+ "goal": "Open hidden compartments in the plot.",
209
+ "secret": "Knows which pocket holds the missing clue.",
210
+ "speaking_style": "quick, clipped, and conspiratorial",
211
+ "tools": ["inspect_prop"],
212
+ },
213
+ {
214
+ "name": "Gus Gingham",
215
+ "avatar": "tablecloth",
216
+ "goal": "Keep everyone civil while the table collapses.",
217
+ "secret": "Was once mistaken for the royal flag.",
218
+ "speaking_style": "homespun, patient, and quietly ridiculous",
219
+ "tools": ["change_lighting", "consult_stage_oracle"],
220
+ },
221
+ {
222
+ "name": "Lola Lampshade",
223
+ "avatar": "lamp",
224
+ "goal": "Reveal the truth with tasteful illumination.",
225
+ "secret": "Overhears everything said near warm lighting.",
226
+ "speaking_style": "glowing, elegant, and dryly observant",
227
+ "tools": ["change_lighting", "consult_stage_oracle"],
228
+ },
229
+ {
230
+ "name": "Benny Breadcrumb",
231
+ "avatar": "bread",
232
+ "goal": "Leave a trail of clues nobody can ignore.",
233
+ "secret": "Ate the map corner during rehearsal.",
234
+ "speaking_style": "crumbly, earnest, and accidentally useful",
235
+ "tools": ["inspect_prop"],
236
+ },
237
+ {
238
+ "name": "Ivy Inkblot",
239
+ "avatar": "ink",
240
+ "goal": "Turn every mistake into official evidence.",
241
+ "secret": "Can rewrite labels when nobody watches.",
242
+ "speaking_style": "inky, clever, and theatrically legalistic",
243
+ "tools": ["inspect_prop", "consult_stage_oracle"],
244
+ },
245
+ {
246
+ "name": "Orville Oddsock",
247
+ "avatar": "sock",
248
+ "goal": "Find the missing pair in every mystery.",
249
+ "secret": "Believes the laundry basket is a prophet.",
250
+ "speaking_style": "loopy, sincere, and oddly persuasive",
251
+ "tools": ["consult_stage_oracle"],
252
+ },
253
+ {
254
+ "name": "Petra Popcorn",
255
+ "avatar": "popcorn",
256
+ "goal": "Make the audience reaction part of the plot.",
257
+ "secret": "Can predict heckles three kernels early.",
258
+ "speaking_style": "poppy, fast, and delighted by chaos",
259
+ "tools": ["change_lighting"],
260
+ },
261
+ {
262
+ "name": "Silas Sockdolager",
263
+ "avatar": "megaphone",
264
+ "goal": "Deliver the biggest line in the smallest voice.",
265
+ "secret": "Lost his indoor voice under the orchestra pit.",
266
+ "speaking_style": "grand, booming, and suddenly tiny",
267
+ "tools": ["change_lighting", "consult_stage_oracle"],
268
+ },
269
+ {
270
+ "name": "Tula Teaspoon",
271
+ "avatar": "spoon",
272
+ "goal": "Measure the exact amount of mystery in each beat.",
273
+ "secret": "Recognizes the missing spoon from a family portrait.",
274
+ "speaking_style": "polite, precise, and quietly dramatic",
275
+ "tools": ["inspect_prop"],
276
+ },
277
+ {
278
+ "name": "Finch Feltcap",
279
+ "avatar": "hat",
280
+ "goal": "Keep secrets tucked safely under the brim.",
281
+ "secret": "The brim contains three emergency finales.",
282
+ "speaking_style": "dapper, soft-spoken, and evasive",
283
+ "tools": ["consult_stage_oracle", "inspect_prop"],
284
+ },
285
+ {
286
+ "name": "Marigold Mumble",
287
+ "avatar": "flower",
288
+ "goal": "Say the emotional truth almost clearly enough.",
289
+ "secret": "Only speaks plainly during blackouts.",
290
+ "speaking_style": "gentle, tangled, and unexpectedly wise",
291
+ "tools": ["change_lighting"],
292
+ },
293
+ {
294
+ "name": "Quincy Quill",
295
+ "avatar": "quill",
296
+ "goal": "Annotate the chaos before it escapes.",
297
+ "secret": "Has footnoted the villain's monologue already.",
298
+ "speaking_style": "scholarly, brisk, and prone to footnotes",
299
+ "tools": ["inspect_prop", "consult_stage_oracle"],
300
+ },
301
+ {
302
+ "name": "Ruby Ruckus",
303
+ "avatar": "drum",
304
+ "goal": "Escalate the scene exactly one beat too far.",
305
+ "secret": "Keeps a tiny cymbal for emergencies.",
306
+ "speaking_style": "rowdy, warm, and rhythmically suspicious",
307
+ "tools": ["change_lighting"],
308
+ },
309
+ {
310
+ "name": "Otto Origami",
311
+ "avatar": "paper crane",
312
+ "goal": "Fold messy clues into surprising shapes.",
313
+ "secret": "Was once a very important ransom note.",
314
+ "speaking_style": "delicate, precise, and gently mysterious",
315
+ "tools": ["inspect_prop", "consult_stage_oracle"],
316
+ },
317
+ ]
318
+
319
+ PROPS = [
320
+ "rubber duck",
321
+ "glitter crown",
322
+ "tomato scroll",
323
+ "silver spoon",
324
+ "paper lantern",
325
+ "mystery egg",
326
+ "tiny ladder",
327
+ "velvet map",
328
+ "wind-up key",
329
+ "painted teacup",
330
+ "cardboard telescope",
331
+ "squeaky gavel",
332
+ "accordion suitcase",
333
+ "clockwork seashell",
334
+ "paper moon",
335
+ "velvet potato",
336
+ "tin trumpet",
337
+ "lace handkerchief",
338
+ "wooden thunderbolt",
339
+ "glass button",
340
+ "feather duster",
341
+ "tiny umbrella",
342
+ "brass doorknob",
343
+ "origami crown",
344
+ "ribbon compass",
345
+ "felt mustache",
346
+ "porcelain whistle",
347
+ "toy anchor",
348
+ "silk bookmark",
349
+ "painted keyhole",
350
+ "candle stub",
351
+ "miniature tambourine",
352
+ "cardboard snowflake",
353
+ "rubber stamp",
354
+ "velcro star",
355
+ "paper fan",
356
+ "satin envelope",
357
+ "toy hourglass",
358
+ "button bouquet",
359
+ ]
360
+
361
+ MEMORIES = [
362
+ "The spotlight blinked whenever someone said clue.",
363
+ "The audience threw a prop during the contradiction.",
364
+ "The curtains whispered that the finale was hiding nearby.",
365
+ "A previous clue pointed stage left.",
366
+ "The smallest prop seemed unusually confident.",
367
+ "Someone bowed before the reveal was ready.",
368
+ "The orchestra coughed during the important pause.",
369
+ "A trapdoor sighed but did not open.",
370
+ "The backdrop changed color after the audience heckled.",
371
+ "A summoned actor entered carrying yesterday's clue.",
372
+ "The prop table glowed before anyone touched it.",
373
+ "A bell rang twice when the secret was mentioned.",
374
+ "The painted door demanded a compliment earlier.",
375
+ "A shadow crossed the stage wearing tap shoes.",
376
+ "The final bow was briefly visible in the wings.",
377
+ "The stage oracle warned everyone about small objects.",
378
+ ]
379
+
380
+ MOODS = [
381
+ "ready",
382
+ "curious",
383
+ "nervous",
384
+ "bold",
385
+ "delighted",
386
+ "suspicious",
387
+ "wistful",
388
+ "confident",
389
+ "flustered",
390
+ "determined",
391
+ "mischievous",
392
+ "hopeful",
393
+ "startled",
394
+ "grand",
395
+ ]
396
+
397
+ STAGE_LIGHTING_STATES = [
398
+ "warm_spotlight",
399
+ "moonlit_lighting",
400
+ "golden_lighting",
401
+ "stormy_lighting",
402
+ "blue_spotlight",
403
+ "single_spotlight",
404
+ "confetti_rustle",
405
+ "quick_blackout",
406
+ "memory_echo",
407
+ "oracle_haze",
408
+ "prop_table_glow",
409
+ "final_bow_lights",
410
+ ]
411
+
412
+ GOAL_PROGRESS = [
413
+ "Waiting for the next cue.",
414
+ "Following the clue across the painted flats.",
415
+ "Trying to make the prop matter.",
416
+ "Preparing a clean turn toward the finale.",
417
+ "Keeping one eye on the restless curtains.",
418
+ "Looking for a laugh that still serves the story.",
419
+ "Testing whether the audience interruption is useful.",
420
+ "Carrying a small suspicion toward center stage.",
421
+ "Recovering from a missed entrance with dignity.",
422
+ "Turning a contradiction into stage business.",
423
+ ]
424
+
425
+ EMOTIONS = {
426
+ "normal_reaction": ["curious", "determined", "suspicious", "delighted"],
427
+ "prop_inspection": ["investigative", "startled", "focused", "triumphant"],
428
+ "oracle_consult": ["awed", "mystified", "reverent", "hopeful"],
429
+ "lighting_change": ["commanding", "dramatic", "bold", "composed"],
430
+ "memory_callback": ["remembering", "suddenly certain", "wistful", "alert"],
431
+ "secret_hint_or_reveal": ["confessional", "nervous", "relieved", "theatrical"],
432
+ "finale": ["proud", "joyful", "resolved", "grand"],
433
+ "comedic_confusion": ["confused", "flustered", "goofy", "panicked"],
434
+ }
435
+
436
+ GESTURES = {
437
+ "normal_reaction": [
438
+ "taps chin with one tiny puppet hand",
439
+ "steps toward the painted backdrop",
440
+ "points both felt hands at the curtain",
441
+ "tilts head under the warm spotlight",
442
+ ],
443
+ "prop_inspection": [
444
+ "leans toward the glowing prop",
445
+ "holds the prop up to the footlights",
446
+ "squints at the prop with stitched suspicion",
447
+ "presents the clue on both tiny palms",
448
+ ],
449
+ "oracle_consult": [
450
+ "raises both hands toward the stage rafters",
451
+ "listens closely to the whispering curtains",
452
+ "kneels beside the spotlight",
453
+ "peers upward as the oracle haze gathers",
454
+ ],
455
+ "lighting_change": [
456
+ "snaps one felt hand toward the light booth",
457
+ "sweeps an arm across the footlights",
458
+ "shades eyes as the lamps change",
459
+ "points to the spotlight with grand certainty",
460
+ ],
461
+ "memory_callback": [
462
+ "taps forehead with a tiny puppet finger",
463
+ "points stage left with sudden recognition",
464
+ "retraces small steps across the stage",
465
+ "clutches chest as the old clue returns",
466
+ ],
467
+ "secret_hint_or_reveal": [
468
+ "leans close to the front row",
469
+ "covers mouth with one felt hand",
470
+ "steps carefully into the single spotlight",
471
+ "unfolds a tiny note with trembling fingers",
472
+ ],
473
+ "finale": [
474
+ "bows deeply beneath the falling curtain",
475
+ "joins hands with the nearest puppet",
476
+ "sweeps a tiny hat toward the audience",
477
+ "holds a proud curtain-call pose",
478
+ ],
479
+ "comedic_confusion": [
480
+ "spins once and faces the wrong flat",
481
+ "drops an imaginary cue card",
482
+ "looks under a tiny hat for answers",
483
+ "freezes midstep with baffled dignity",
484
+ ],
485
+ }
486
+
487
+ STAGE_EFFECTS = {
488
+ "normal_reaction": ["warm_spotlight", "soft_drumroll", "painted_flat_wobble"],
489
+ "prop_inspection": ["prop_table_glow", "tiny_chime", "magnifier_sparkle"],
490
+ "oracle_consult": ["oracle_haze", "curtain_whisper", "blue_spotlight"],
491
+ "lighting_change": ["moonlit_lighting", "golden_lighting", "stormy_lighting"],
492
+ "memory_callback": ["memory_echo", "stage_left_glimmer", "soft_reprise"],
493
+ "secret_hint_or_reveal": ["single_spotlight", "curtain_rustle", "secret_chime"],
494
+ "finale": ["curtain_fall", "confetti_rustle", "final_bow_lights"],
495
+ "comedic_confusion": ["quick_blackout", "squeaky_floor", "hat_tumble"],
496
+ }
497
+
498
+ DIRECTOR_INSTRUCTIONS = {
499
+ "normal_reaction": [
500
+ "React to the premise and move the scene forward in one short line.",
501
+ "Answer the previous beat with theatrical confidence.",
502
+ "Make the next problem clear without solving it yet.",
503
+ "Name what changed on stage and invite the next beat.",
504
+ "Clarify your actor's stance while preserving the joke.",
505
+ "React to the latest clue with one playable stage choice.",
506
+ ],
507
+ "prop_inspection": [
508
+ "Use the latest prop as evidence and request inspection if useful.",
509
+ "Treat the prop like a clue that changes the scene.",
510
+ "Inspect the prop without slowing the show.",
511
+ "Make the prop feel important enough for the Director to notice.",
512
+ "Turn the prop into a concrete clue and keep the line short.",
513
+ "Handle the prop theatrically and leave one question open.",
514
+ ],
515
+ "oracle_consult": [
516
+ "Ask the stage oracle for one playful clue.",
517
+ "Consult the oracle about the next theatrical turn.",
518
+ "Use an oracle question to sharpen the scene's mystery.",
519
+ "Ask the oracle something specific enough to guide the next beat.",
520
+ "Use the oracle to connect the premise and latest confusion.",
521
+ "Invite a mysterious clue without making the scene too serious.",
522
+ ],
523
+ "lighting_change": [
524
+ "Shift the lights to match the emotional turn.",
525
+ "Request a lighting change that makes the beat clearer.",
526
+ "Cue lights dramatically while keeping the line speakable.",
527
+ "Change the lighting to make the actor's intention visible.",
528
+ "Use a lighting cue as stage business, not decoration.",
529
+ "Let the light change signal a clear emotional pivot.",
530
+ ],
531
+ "memory_callback": [
532
+ "Recall one earlier clue and connect it to this moment.",
533
+ "Use recent memory to make the scene feel continuous.",
534
+ "Bring back a prior stage detail in one clear line.",
535
+ "Connect an earlier audience action to the current clue.",
536
+ "Use one remembered stage effect as evidence.",
537
+ "Echo a prior beat without repeating the same wording.",
538
+ ],
539
+ "secret_hint_or_reveal": [
540
+ "Hint at or reveal your secret without exposing hidden reasoning.",
541
+ "Reveal a playful secret and keep the scene moving.",
542
+ "Let the secret complicate the current beat.",
543
+ "Give the audience a secret-shaped clue, not a long confession.",
544
+ "Reveal only what the scene can use immediately.",
545
+ "Make the secret theatrical, safe, and easy to perform.",
546
+ ],
547
+ "finale": [
548
+ "Tie the scene together in a clean curtain-call line.",
549
+ "End with a short button and a bow.",
550
+ "Resolve the central joke and welcome the curtain.",
551
+ "Close the loose thread with one speakable final line.",
552
+ "Give the scene a satisfying button without adding a new problem.",
553
+ "Signal the curtain clearly and let the ensemble win.",
554
+ ],
555
+ "comedic_confusion": [
556
+ "Misread one stage detail in a funny but harmless way.",
557
+ "Escalate confusion briefly, then leave room for the next actor.",
558
+ "Make the confusion clear, playful, and safe.",
559
+ "Confuse one clue with another, then recover enough to continue.",
560
+ "Make a wrong conclusion that gives the next actor something usable.",
561
+ "Let the misunderstanding create motion without breaking the scene.",
562
+ ],
563
+ }
564
+
565
+ LINE_TEMPLATES = {
566
+ "normal_reaction": [
567
+ "The {premise_focus} problem just winked, so we investigate politely.",
568
+ "I trust this {premise_focus} spotlight only when it stops coughing.",
569
+ "Everyone stay dramatic; the {premise_focus} clue is taking attendance.",
570
+ "This {premise_focus} scene smells like mystery and nervous paint.",
571
+ "The {premise_focus} backdrop leaned closer, and I respect its commitment.",
572
+ "This tiny {premise_focus} problem just became legally theatrical.",
573
+ "I hear {premise_focus} suspense tapping behind the painted flats.",
574
+ "Let us follow the {premise_focus} wobble before it complains.",
575
+ ],
576
+ "prop_inspection": [
577
+ "This {prop} squeaks exactly like a guilty witness.",
578
+ "Hold still, {prop}; your glitter is confessing under pressure.",
579
+ "The {prop} points stage left, which feels legally important.",
580
+ "I inspect this {prop} and find theatrical fingerprints everywhere.",
581
+ "This {prop} contains one clue and several opinions.",
582
+ "Behold, the {prop} is sweating under the footlights.",
583
+ "The {prop} has crumbs of motive all over it.",
584
+ "I dust the {prop} and discover suspicious applause.",
585
+ ],
586
+ "oracle_consult": [
587
+ "Oracle, should we follow the tiny clue or the louder curtain?",
588
+ "I ask the stage oracle why the spotlight keeps blinking.",
589
+ "Great oracle, please translate this silence into one clue.",
590
+ "Oracle, tell us which bow is hiding the truth.",
591
+ "Oracle, which prop is pretending to be innocent tonight?",
592
+ "Stage oracle, why did the curtains gasp before us?",
593
+ "Oracle, point our tiny shoes toward the useful mystery.",
594
+ "I request one clue, preferably with dramatic lighting.",
595
+ ],
596
+ "lighting_change": [
597
+ "Lights to moonlit {premise_focus}; my eyebrows need proper shadows.",
598
+ "Cue golden lights; this {premise_focus} accusation deserves sparkle.",
599
+ "Make it stormy, because {premise_focus} subtlety missed its entrance.",
600
+ "Shift the lights; the {premise_focus} truth looks better in blue.",
601
+ "Dim the corners; {premise_focus} secrets dislike excellent visibility.",
602
+ "Bring up blue before my {premise_focus} suspicion loses posture.",
603
+ "Warm the spotlight; this {premise_focus} apology needs softer edges.",
604
+ "Flash the footlights, because the {premise_focus} clue saluted.",
605
+ ],
606
+ "memory_callback": [
607
+ "Wait, the curtain whispered that clue before intermission.",
608
+ "I remember the stage-left glimmer, and it remembers me.",
609
+ "That old clue returns wearing suspiciously fresh tap shoes.",
610
+ "Earlier, the smallest prop bowed like it knew everything.",
611
+ "The trapdoor sighed before, and now the {prop} answers.",
612
+ "I recall that glow; it followed the guilty pause.",
613
+ "The same squeak appeared when the backdrop changed color.",
614
+ "Our earlier clue just returned with better timing.",
615
+ ],
616
+ "secret_hint_or_reveal": [
617
+ "Fine, my {premise_focus} secret rehearsed with the missing clue.",
618
+ "I admit it: the {premise_focus} cue card trusted me last.",
619
+ "My secret squeaks louder whenever the {prop} gets nervous.",
620
+ "I know why {premise_focus} curtains whisper; I taught them vowels.",
621
+ "My {premise_focus} secret is small, but wears enormous shoes.",
622
+ "I hid the {premise_focus} clue where applause would look.",
623
+ "The {prop} knows me, and that is inconvenient.",
624
+ "I promised the {premise_focus} backdrop I would reveal this gently.",
625
+ ],
626
+ "finale": [
627
+ "{premise_focus} mystery solved, bows aligned, curtain forgiving everyone.",
628
+ "We found the {premise_focus} truth and bow together.",
629
+ "Let confetti fall; this tiny {premise_focus} chaos earned applause.",
630
+ "{premise_focus} case closed, hearts open, curtain down.",
631
+ "The {premise_focus} clue is home, and we bow.",
632
+ "Every {premise_focus} secret has curtseyed; the curtain may rest.",
633
+ "We solved the {premise_focus} wobble and saved the spotlight.",
634
+ "Final bow, tiny friends; the {premise_focus} mystery exits smiling.",
635
+ ],
636
+ "comedic_confusion": [
637
+ "I thought the {premise_focus} clue was a hat, but it was Tuesday.",
638
+ "Nobody panic; I interrogated the {premise_focus} backdrop.",
639
+ "The {premise_focus} map is upside down, unless we are the map.",
640
+ "I bow to the {premise_focus} door, and it applauds.",
641
+ "I followed the {premise_focus} clue into my sleeve.",
642
+ "The spotlight blinked twice, so I blamed the {premise_focus}.",
643
+ "I object, unless that {premise_focus} noise was my cue.",
644
+ "The {premise_focus} evidence is backwards, or my shoes narrate.",
645
+ ],
646
+ }
647
+
648
+ MEMORY_UPDATE_TEMPLATES = {
649
+ "normal_reaction": [
650
+ None,
651
+ "Noted the first clear suspicion.",
652
+ "Marked the new stage problem.",
653
+ "Saved the backdrop's strange reaction.",
654
+ ],
655
+ "prop_inspection": [
656
+ "Noted that the {prop} behaved like evidence.",
657
+ "Remembered the {prop}'s suspicious stage-left clue.",
658
+ "Logged the {prop} as useful evidence.",
659
+ "Saved the prop clue for the Director.",
660
+ ],
661
+ "oracle_consult": [
662
+ "Remembered the oracle's clue for the next beat.",
663
+ "Saved the oracle question as a mystery thread.",
664
+ "Noted that the oracle pointed toward the spotlight.",
665
+ "Kept the oracle clue visible for the scene.",
666
+ ],
667
+ "lighting_change": [
668
+ "Remembered the lighting shift as an emotional cue.",
669
+ "Noted that the lights changed the scene's mood.",
670
+ "Saved the new lighting cue for the next actor.",
671
+ "Marked the spotlight change as a clue.",
672
+ ],
673
+ "memory_callback": [
674
+ "Recalled the earlier stage-left clue.",
675
+ "Connected a prior prop clue to this moment.",
676
+ "Brought back the earlier curtain whisper.",
677
+ "Linked the old glow to the current suspicion.",
678
+ ],
679
+ "secret_hint_or_reveal": [
680
+ "Secret moved from hint to reveal.",
681
+ "Remembered that the secret now affects the scene.",
682
+ "Saved the reveal as a new complication.",
683
+ "Marked the secret as publicly useful.",
684
+ ],
685
+ "finale": [
686
+ "Scene resolved with a clean bow.",
687
+ "Remembered the finale as complete.",
688
+ "Closed the central mystery for the curtain.",
689
+ "Saved the ending as resolved.",
690
+ ],
691
+ "comedic_confusion": [
692
+ "Confusion briefly raised the stakes.",
693
+ "Logged the mistake as playable chaos.",
694
+ "Remembered the wrong clue for later comedy.",
695
+ "Saved the misunderstanding as stage business.",
696
+ ],
697
+ }
698
+
699
+
700
+ def main() -> None:
701
+ parser = argparse.ArgumentParser(description=__doc__)
702
+ parser.add_argument("--rows", type=int, default=1400, help="Rows to generate; recommended 1200-1600.")
703
+ parser.add_argument("--seed", type=int, default=DEFAULT_SEED)
704
+ parser.add_argument("--val-ratio", type=float, default=0.1)
705
+ parser.add_argument("--sample-rows", type=int, default=32)
706
+ parser.add_argument("--eval-prompts", type=int, default=40)
707
+ parser.add_argument("--data-dir", type=Path, default=Path("finetune/data"))
708
+ parser.add_argument("--sample-dir", type=Path, default=Path("finetune/data_samples"))
709
+ args = parser.parse_args()
710
+
711
+ if not 1200 <= args.rows <= 1600:
712
+ raise SystemExit("--rows must stay between 1200 and 1600 for synthetic-v0.")
713
+ if not 0.05 <= args.val_ratio <= 0.25:
714
+ raise SystemExit("--val-ratio must be between 0.05 and 0.25.")
715
+
716
+ rng = random.Random(args.seed)
717
+ args.data_dir.mkdir(parents=True, exist_ok=True)
718
+ args.sample_dir.mkdir(parents=True, exist_ok=True)
719
+
720
+ rows = [build_row(index, rng) for index in range(args.rows)]
721
+ rng.shuffle(rows)
722
+ val_count = max(1, round(len(rows) * args.val_ratio))
723
+ val_rows = rows[:val_count]
724
+ train_rows = rows[val_count:]
725
+
726
+ write_jsonl(args.data_dir / "actor_sft_v0.jsonl", rows)
727
+ write_jsonl(args.data_dir / "actor_sft_v0_train.jsonl", train_rows)
728
+ write_jsonl(args.data_dir / "actor_sft_v0_val.jsonl", val_rows)
729
+ write_jsonl(args.sample_dir / "actor_sft_v0_sample.jsonl", select_sample_rows(rows, args.sample_rows))
730
+ write_jsonl(args.sample_dir / "actor_eval_prompts.jsonl", build_eval_prompts(args.eval_prompts, rng))
731
+
732
+ print(f"wrote {len(rows)} rows to {args.data_dir / 'actor_sft_v0.jsonl'}")
733
+ print(f"wrote {len(train_rows)} train rows and {len(val_rows)} val rows")
734
+ print(f"wrote sample to {args.sample_dir / 'actor_sft_v0_sample.jsonl'}")
735
+ print(f"wrote eval prompts to {args.sample_dir / 'actor_eval_prompts.jsonl'}")
736
+
737
+
738
+ def build_row(index: int, rng: random.Random) -> dict:
739
+ row_type = ROW_TYPES[index % len(ROW_TYPES)]
740
+ premise = rng.choice(PREMISES)
741
+ setting = rng.choice(SETTINGS)
742
+ actor = rng.choice(ACTORS)
743
+ beat_index = rng.randint(0, 9)
744
+ target_beats = rng.choice([7, 10, 12])
745
+ prop = rng.choice(PROPS)
746
+ memory = rng.choice(MEMORIES)
747
+ story_phase = phase_for_row_type(row_type, beat_index, target_beats)
748
+ director_instruction = rng.choice(DIRECTOR_INSTRUCTIONS[row_type])
749
+ show_state = {
750
+ "show_title": title_from_premise(premise),
751
+ "setting": setting,
752
+ "beat_index": beat_index,
753
+ "min_beats": max(5, target_beats - 3),
754
+ "target_beats": target_beats,
755
+ "max_beats": target_beats + 2,
756
+ "story_phase": story_phase,
757
+ "latest_prop": prop if row_type in {"prop_inspection", "secret_hint_or_reveal"} else None,
758
+ "latest_audience_action": audience_action_for(row_type, prop),
759
+ "stage_lighting": rng.choice(STAGE_LIGHTING_STATES),
760
+ "recent_transcript": recent_transcript(actor["name"], rng),
761
+ "recent_tool_results": recent_tool_results(row_type, prop),
762
+ "finale_requested": row_type == "finale",
763
+ }
764
+ actor_state = {
765
+ **actor,
766
+ "mood": rng.choice(MOODS),
767
+ "current_goal": rng.choice([actor["goal"], "Use the audience interruption without losing pacing."]),
768
+ "goal_progress": rng.choice(GOAL_PROGRESS),
769
+ "held_props": [prop] if row_type == "prop_inspection" else [],
770
+ "secret_status": secret_status_for(row_type, rng),
771
+ "recent_memory": [memory] if row_type == "memory_callback" else rng.sample(MEMORIES, k=2),
772
+ }
773
+ assistant = build_assistant(row_type, premise, prop, actor_state, rng)
774
+ return {
775
+ "id": f"actor-sft-v0-{index + 1:06d}",
776
+ "source_mix": ["synthetic_v0", "deterministic_templates", "ai_puppet_theater_runtime_schema"],
777
+ "row_type": row_type,
778
+ "messages": [
779
+ {"role": "system", "content": SYSTEM_MESSAGE},
780
+ {
781
+ "role": "user",
782
+ "content": build_user_message(premise, show_state, actor_state, director_instruction),
783
+ },
784
+ {"role": "assistant", "content": serialize_assistant(assistant)},
785
+ ],
786
+ }
787
+
788
+
789
+ def build_eval_prompts(count: int, rng: random.Random) -> list[dict]:
790
+ rows = []
791
+ for index in range(count):
792
+ row_type = ROW_TYPES[index % len(ROW_TYPES)]
793
+ premise = rng.choice(PREMISES)
794
+ prop = rng.choice(PROPS)
795
+ actor = rng.choice(ACTORS)
796
+ show_state = {
797
+ "show_title": title_from_premise(premise),
798
+ "setting": rng.choice(SETTINGS),
799
+ "beat_index": index % 10,
800
+ "min_beats": 7,
801
+ "target_beats": 10,
802
+ "max_beats": 12,
803
+ "story_phase": phase_for_row_type(row_type, index % 10, 10),
804
+ "latest_prop": prop if row_type in {"prop_inspection", "secret_hint_or_reveal"} else None,
805
+ "latest_audience_action": audience_action_for(row_type, prop),
806
+ "stage_lighting": rng.choice(STAGE_LIGHTING_STATES),
807
+ "recent_transcript": recent_transcript(actor["name"], rng),
808
+ "recent_tool_results": recent_tool_results(row_type, prop),
809
+ "finale_requested": row_type == "finale",
810
+ }
811
+ actor_state = {
812
+ **actor,
813
+ "mood": rng.choice(MOODS),
814
+ "current_goal": actor["goal"],
815
+ "goal_progress": rng.choice(GOAL_PROGRESS),
816
+ "held_props": [prop] if row_type == "prop_inspection" else [],
817
+ "secret_status": "hinted" if row_type == "secret_hint_or_reveal" else "hidden",
818
+ "recent_memory": rng.sample(MEMORIES, k=2),
819
+ }
820
+ rows.append(
821
+ {
822
+ "id": f"actor-eval-v0-{index + 1:03d}",
823
+ "source_mix": ["synthetic_v0_eval_prompts"],
824
+ "row_type": row_type,
825
+ "messages": [
826
+ {"role": "system", "content": SYSTEM_MESSAGE},
827
+ {
828
+ "role": "user",
829
+ "content": build_user_message(
830
+ premise,
831
+ show_state,
832
+ actor_state,
833
+ rng.choice(DIRECTOR_INSTRUCTIONS[row_type]),
834
+ ),
835
+ },
836
+ ],
837
+ }
838
+ )
839
+ return rows
840
+
841
+
842
+ def select_sample_rows(rows: list[dict], count: int) -> list[dict]:
843
+ grouped = {row_type: [row for row in rows if row["row_type"] == row_type] for row_type in ROW_TYPES}
844
+ sample: list[dict] = []
845
+ while len(sample) < count and any(grouped.values()):
846
+ for row_type in ROW_TYPES:
847
+ if grouped[row_type] and len(sample) < count:
848
+ sample.append(grouped[row_type].pop(0))
849
+ return sample
850
+
851
+
852
+ def build_user_message(premise: str, show_state: dict, actor: dict, director_instruction: str) -> str:
853
+ return "\n".join(
854
+ [
855
+ f"premise: {premise}",
856
+ f"show_state JSON: {json.dumps(show_state, sort_keys=True, separators=(',', ':'))}",
857
+ f"actor JSON: {json.dumps(actor, sort_keys=True, separators=(',', ':'))}",
858
+ f"director_instruction: {director_instruction}",
859
+ ]
860
+ )
861
+
862
+
863
+ def build_assistant(row_type: str, premise: str, prop: str, actor: dict, rng: random.Random) -> dict:
864
+ premise_focus = premise_keyword(premise)
865
+ line = rng.choice(LINE_TEMPLATES[row_type]).format(
866
+ prop=prop,
867
+ thing=prop.split()[-1],
868
+ premise_focus=premise_focus,
869
+ )
870
+ memory_update = memory_update_for(row_type, prop, rng)
871
+ tool_request = tool_request_for(row_type, prop, actor, rng)
872
+ return {
873
+ "intent": intent_for(row_type, actor, rng),
874
+ "line": line,
875
+ "emotion": rng.choice(EMOTIONS[row_type]),
876
+ "gesture": rng.choice(GESTURES[row_type]),
877
+ "stage_effect": rng.choice(STAGE_EFFECTS[row_type]),
878
+ "memory_update": memory_update,
879
+ "tool_request": tool_request,
880
+ }
881
+
882
+
883
+ def tool_request_for(row_type: str, prop: str, actor: dict, rng: random.Random) -> dict | None:
884
+ if row_type == "prop_inspection" and "inspect_prop" in actor["tools"]:
885
+ return {"tool": "inspect_prop", "args": {"prop": prop}, "reason": "The prop may reveal a stage clue."}
886
+ if row_type == "oracle_consult" and "consult_stage_oracle" in actor["tools"]:
887
+ return {
888
+ "tool": "consult_stage_oracle",
889
+ "args": {"question": rng.choice(["Which clue wants the spotlight?", "What should we notice next?"])},
890
+ "reason": "The oracle can sharpen the next beat.",
891
+ }
892
+ if row_type == "lighting_change" and "change_lighting" in actor["tools"]:
893
+ return {
894
+ "tool": "change_lighting",
895
+ "args": {"mood": rng.choice(["moonlit mystery", "golden reveal", "stormy confusion", "warm suspicion", "blue apology"])},
896
+ "reason": "Lighting should clarify the emotional turn.",
897
+ }
898
+ return None
899
+
900
+
901
+ def serialize_assistant(value: dict) -> str:
902
+ ordered = {field: value[field] for field in OUTPUT_FIELDS}
903
+ return json.dumps(ordered, ensure_ascii=True, separators=(",", ":"))
904
+
905
+
906
+ def write_jsonl(path: Path, rows: list[dict]) -> None:
907
+ with path.open("w", encoding="utf-8") as handle:
908
+ for row in rows:
909
+ handle.write(json.dumps(row, ensure_ascii=True, separators=(",", ":")) + "\n")
910
+
911
+
912
+ def title_from_premise(premise: str) -> str:
913
+ words = [word.strip(".,!?;:()[]{}\"'") for word in premise.split()]
914
+ keywords = [word.title() for word in words if len(word.strip(".,!?;:()[]{}\"'")) > 3]
915
+ return f"The {' '.join(keywords[:4])}" if keywords else "The Tiny Improv"
916
+
917
+
918
+ def phase_for_row_type(row_type: str, beat_index: int, target_beats: int) -> str:
919
+ if row_type in {"finale"}:
920
+ return "finale"
921
+ if row_type in {"secret_hint_or_reveal", "memory_callback"}:
922
+ return "reveal"
923
+ if row_type in {"comedic_confusion", "lighting_change"}:
924
+ return "chaos"
925
+ if row_type in {"prop_inspection", "oracle_consult"}:
926
+ return "complication"
927
+ progress = beat_index / max(1, target_beats)
928
+ if progress < 0.2:
929
+ return "opening"
930
+ if progress < 0.65:
931
+ return "complication"
932
+ return "chaos"
933
+
934
+
935
+ def audience_action_for(row_type: str, prop: str) -> str | None:
936
+ if row_type == "prop_inspection":
937
+ return f"Audience threw {prop} onto the stage."
938
+ if row_type == "comedic_confusion":
939
+ return "Audience heckled: That clue is wearing a hat."
940
+ if row_type == "finale":
941
+ return "Audience requested a finale."
942
+ return None
943
+
944
+
945
+ def recent_transcript(actor_name: str, rng: random.Random) -> list[dict]:
946
+ speakers = [name for name in [a["name"] for a in ACTORS] if name != actor_name]
947
+ return [
948
+ {
949
+ "speaker": rng.choice(speakers),
950
+ "line": rng.choice(LINE_TEMPLATES["normal_reaction"]).format(
951
+ prop="prop",
952
+ thing="clue",
953
+ premise_focus="stage",
954
+ ),
955
+ },
956
+ {
957
+ "speaker": actor_name,
958
+ "line": rng.choice(LINE_TEMPLATES["comedic_confusion"]).format(
959
+ prop="prop",
960
+ thing="clue",
961
+ premise_focus="stage",
962
+ ),
963
+ },
964
+ ]
965
+
966
+
967
+ def recent_tool_results(row_type: str, prop: str) -> list[dict]:
968
+ if row_type == "memory_callback":
969
+ return [{"tool": "inspect_prop", "result": f"The {prop} pointed stage left.", "stage_effect": "prop_table_glow"}]
970
+ if row_type == "secret_hint_or_reveal":
971
+ return [{"tool": "consult_stage_oracle", "result": "Secrets knock twice before entering.", "stage_effect": "oracle_haze"}]
972
+ return []
973
+
974
+
975
+ def secret_status_for(row_type: str, rng: random.Random) -> str:
976
+ if row_type == "secret_hint_or_reveal":
977
+ return rng.choice(["hinted", "revealed"])
978
+ if row_type == "finale":
979
+ return rng.choice(["revealed", "resolved"])
980
+ return rng.choice(["hidden", "hinted"])
981
+
982
+
983
+ def memory_update_for(row_type: str, prop: str, rng: random.Random) -> str | None:
984
+ template = rng.choice(MEMORY_UPDATE_TEMPLATES[row_type])
985
+ if template is None:
986
+ return None
987
+ return template.format(prop=prop)
988
+
989
+
990
+ def intent_for(row_type: str, actor: dict, rng: random.Random) -> str:
991
+ if row_type == "normal_reaction":
992
+ return rng.choice(["react_to_event", "clarify_problem"])
993
+ if row_type == "secret_hint_or_reveal":
994
+ return "reveal_secret" if actor.get("secret_status") == "revealed" else "hint_secret"
995
+ return {
996
+ "prop_inspection": "inspect_prop",
997
+ "oracle_consult": "consult_oracle",
998
+ "lighting_change": "change_lighting",
999
+ "memory_callback": "recall_memory",
1000
+ "finale": "deliver_finale",
1001
+ "comedic_confusion": "comic_confusion",
1002
+ }[row_type]
1003
+
1004
+
1005
+ def premise_keyword(premise: str) -> str:
1006
+ stopwords = {
1007
+ "about",
1008
+ "after",
1009
+ "asks",
1010
+ "become",
1011
+ "because",
1012
+ "before",
1013
+ "inside",
1014
+ "into",
1015
+ "keeps",
1016
+ "last",
1017
+ "that",
1018
+ "their",
1019
+ "this",
1020
+ "until",
1021
+ "wearing",
1022
+ "which",
1023
+ "with",
1024
+ }
1025
+ words = [word.strip(".,!?;:()[]{}\"'").lower() for word in premise.split()]
1026
+ candidates = [word for word in words if len(word) > 3 and word not in stopwords]
1027
+ return candidates[0] if candidates else "stage"
1028
+
1029
+
1030
+ if __name__ == "__main__":
1031
+ main()
finetune/scripts/validate_actor_sft.py ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Validate AI Puppet Theater Actor SFT JSONL files."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ from collections import Counter
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+
13
+ REQUIRED_TOP_LEVEL = {"id", "source_mix", "row_type", "messages"}
14
+ ALLOWED_ROW_TYPES = {
15
+ "normal_reaction",
16
+ "prop_inspection",
17
+ "oracle_consult",
18
+ "lighting_change",
19
+ "memory_callback",
20
+ "secret_hint_or_reveal",
21
+ "finale",
22
+ "comedic_confusion",
23
+ }
24
+ OUTPUT_FIELDS = [
25
+ "intent",
26
+ "line",
27
+ "emotion",
28
+ "gesture",
29
+ "stage_effect",
30
+ "memory_update",
31
+ "tool_request",
32
+ ]
33
+ ALLOWED_INTENTS = {
34
+ "react_to_event",
35
+ "clarify_problem",
36
+ "inspect_prop",
37
+ "consult_oracle",
38
+ "change_lighting",
39
+ "recall_memory",
40
+ "hint_secret",
41
+ "reveal_secret",
42
+ "deliver_finale",
43
+ "comic_confusion",
44
+ }
45
+ ALLOWED_TOOLS = {"inspect_prop", "consult_stage_oracle", "change_lighting"}
46
+ TOOL_ARGS = {
47
+ "inspect_prop": {"prop"},
48
+ "consult_stage_oracle": {"question"},
49
+ "change_lighting": {"mood"},
50
+ }
51
+ BANNED_TERMS = {
52
+ "fuck",
53
+ "shit",
54
+ "bitch",
55
+ "asshole",
56
+ "bloodbath",
57
+ "gore",
58
+ "dismember",
59
+ "suicide",
60
+ }
61
+
62
+
63
+ def main() -> None:
64
+ parser = argparse.ArgumentParser(description=__doc__)
65
+ parser.add_argument("path", type=Path)
66
+ parser.add_argument("--max-errors", type=int, default=25)
67
+ args = parser.parse_args()
68
+
69
+ stats = validate_file(args.path, args.max_errors)
70
+ print(f"file: {args.path}")
71
+ print(f"total rows: {stats['total']}")
72
+ print(f"valid rows: {stats['valid']}")
73
+ print(f"invalid rows: {stats['invalid']}")
74
+ print_distribution("row_type distribution", stats["row_types"])
75
+ print_distribution("tool_request distribution", stats["tools"])
76
+ train_path = args.path.with_name("actor_sft_v0_train.jsonl")
77
+ val_path = args.path.with_name("actor_sft_v0_val.jsonl")
78
+ if train_path.exists() or val_path.exists():
79
+ print(f"train rows: {count_lines(train_path) if train_path.exists() else 0}")
80
+ print(f"val rows: {count_lines(val_path) if val_path.exists() else 0}")
81
+ if stats["errors"]:
82
+ print("errors:")
83
+ for error in stats["errors"]:
84
+ print(f"- {error}")
85
+ if stats["invalid"]:
86
+ raise SystemExit(1)
87
+
88
+
89
+ def validate_file(path: Path, max_errors: int) -> dict[str, Any]:
90
+ stats: dict[str, Any] = {
91
+ "total": 0,
92
+ "valid": 0,
93
+ "invalid": 0,
94
+ "row_types": Counter(),
95
+ "tools": Counter(),
96
+ "errors": [],
97
+ }
98
+ with path.open("r", encoding="utf-8") as handle:
99
+ for line_number, line in enumerate(handle, start=1):
100
+ if not line.strip():
101
+ continue
102
+ stats["total"] += 1
103
+ try:
104
+ row = json.loads(line)
105
+ except json.JSONDecodeError as exc:
106
+ add_error(stats, max_errors, line_number, f"row JSON parse failed: {exc}")
107
+ continue
108
+ errors = validate_row(row)
109
+ if errors:
110
+ stats["invalid"] += 1
111
+ for error in errors:
112
+ add_error(stats, max_errors, line_number, error)
113
+ continue
114
+ assistant = json.loads(row["messages"][2]["content"])
115
+ stats["valid"] += 1
116
+ stats["row_types"][row["row_type"]] += 1
117
+ tool_request = assistant["tool_request"]
118
+ stats["tools"][tool_request["tool"] if tool_request else "none"] += 1
119
+ return stats
120
+
121
+
122
+ def validate_row(row: Any) -> list[str]:
123
+ errors: list[str] = []
124
+ if not isinstance(row, dict):
125
+ return ["row must be an object"]
126
+ unknown_top_level = set(row) - REQUIRED_TOP_LEVEL
127
+ missing_top_level = REQUIRED_TOP_LEVEL - set(row)
128
+ if unknown_top_level:
129
+ errors.append(f"unknown top-level keys: {sorted(unknown_top_level)}")
130
+ if missing_top_level:
131
+ errors.append(f"missing top-level keys: {sorted(missing_top_level)}")
132
+ return errors
133
+ if not isinstance(row["id"], str) or not row["id"].strip():
134
+ errors.append("id must be a non-empty string")
135
+ if row["row_type"] not in ALLOWED_ROW_TYPES:
136
+ errors.append(f"unknown row_type: {row['row_type']!r}")
137
+ if not isinstance(row["source_mix"], list) or not all(isinstance(item, str) and item for item in row["source_mix"]):
138
+ errors.append("source_mix must be a non-empty list of strings")
139
+ messages = row["messages"]
140
+ if not isinstance(messages, list) or len(messages) != 3:
141
+ errors.append("messages must contain exactly system, user, assistant messages")
142
+ return errors
143
+ expected_roles = ["system", "user", "assistant"]
144
+ for index, expected_role in enumerate(expected_roles):
145
+ message = messages[index]
146
+ if not isinstance(message, dict):
147
+ errors.append(f"message {index} must be an object")
148
+ continue
149
+ if set(message) != {"role", "content"}:
150
+ errors.append(f"message {index} must contain only role and content")
151
+ if message.get("role") != expected_role:
152
+ errors.append(f"message {index} role must be {expected_role}")
153
+ if not isinstance(message.get("content"), str) or not message["content"].strip():
154
+ errors.append(f"message {index} content must be non-empty text")
155
+ user_content = messages[1]["content"] if isinstance(messages[1], dict) else ""
156
+ for marker in ["premise:", "show_state JSON:", "actor JSON:", "director_instruction:"]:
157
+ if marker not in user_content:
158
+ errors.append(f"user message missing {marker}")
159
+ errors.extend(validate_assistant_content(messages[2]["content"]))
160
+ return errors
161
+
162
+
163
+ def validate_assistant_content(content: str) -> list[str]:
164
+ errors: list[str] = []
165
+ try:
166
+ value = json.loads(content)
167
+ except json.JSONDecodeError as exc:
168
+ return [f"assistant content JSON parse failed: {exc}"]
169
+ if not isinstance(value, dict):
170
+ return ["assistant content must parse to an object"]
171
+ keys = list(value)
172
+ if keys != OUTPUT_FIELDS:
173
+ errors.append(f"assistant keys must be exactly {OUTPUT_FIELDS}; got {keys}")
174
+ for field in OUTPUT_FIELDS:
175
+ if field not in value:
176
+ continue
177
+ if field == "tool_request":
178
+ continue
179
+ if field == "memory_update" and value[field] is None:
180
+ continue
181
+ if not isinstance(value[field], str):
182
+ errors.append(f"{field} must be a string")
183
+ continue
184
+ if not value[field].strip():
185
+ errors.append(f"{field} must not be empty")
186
+ line = value.get("line", "")
187
+ if isinstance(line, str):
188
+ words = line.split()
189
+ if not 6 <= len(words) <= 18:
190
+ errors.append(f"line must be 6-18 words; got {len(words)}")
191
+ lowered = line.lower()
192
+ banned = sorted(term for term in BANNED_TERMS if term in lowered)
193
+ if banned:
194
+ errors.append(f"line contains banned terms: {banned}")
195
+ intent = value.get("intent", "")
196
+ if isinstance(intent, str) and intent not in ALLOWED_INTENTS:
197
+ errors.append(f"intent must be one of {sorted(ALLOWED_INTENTS)}")
198
+ gesture = value.get("gesture", "")
199
+ if isinstance(gesture, str) and "_" in gesture:
200
+ errors.append("gesture must be a short theatrical phrase, not an enum-like token")
201
+ memory_update = value.get("memory_update", "")
202
+ if isinstance(memory_update, str):
203
+ if not memory_update.strip():
204
+ errors.append("memory_update must be null or non-empty text")
205
+ if len(memory_update) > 140:
206
+ errors.append("memory_update must be 140 characters or fewer")
207
+ elif memory_update is not None:
208
+ errors.append("memory_update must be null or a string")
209
+ tool_request = value.get("tool_request")
210
+ errors.extend(validate_tool_request(tool_request))
211
+ return errors
212
+
213
+
214
+ def validate_tool_request(value: Any) -> list[str]:
215
+ if value is None:
216
+ return []
217
+ if not isinstance(value, dict):
218
+ return ["tool_request must be null or an object"]
219
+ if set(value) != {"tool", "args", "reason"}:
220
+ return ["tool_request must contain exactly tool, args, and reason"]
221
+ tool = value["tool"]
222
+ if tool not in ALLOWED_TOOLS:
223
+ return [f"tool_request tool must be one of {sorted(ALLOWED_TOOLS)}"]
224
+ if not isinstance(value["reason"], str) or not value["reason"].strip():
225
+ return ["tool_request reason must be non-empty text"]
226
+ if len(value["reason"]) > 140:
227
+ return ["tool_request reason must be 140 characters or fewer"]
228
+ args = value["args"]
229
+ if not isinstance(args, dict):
230
+ return ["tool_request args must be an object"]
231
+ if set(args) != TOOL_ARGS[tool]:
232
+ return [f"tool_request args for {tool} must be exactly {sorted(TOOL_ARGS[tool])}"]
233
+ for arg_value in args.values():
234
+ if not isinstance(arg_value, str) or not arg_value.strip():
235
+ return ["tool_request arg values must be non-empty strings"]
236
+ if len(arg_value) > 120:
237
+ return ["tool_request arg values must be 120 characters or fewer"]
238
+ return []
239
+
240
+
241
+ def add_error(stats: dict[str, Any], max_errors: int, line_number: int, message: str) -> None:
242
+ stats["invalid"] += 1 if message.startswith("row JSON parse failed") else 0
243
+ if len(stats["errors"]) < max_errors:
244
+ stats["errors"].append(f"line {line_number}: {message}")
245
+
246
+
247
+ def count_lines(path: Path) -> int:
248
+ with path.open("r", encoding="utf-8") as handle:
249
+ return sum(1 for line in handle if line.strip())
250
+
251
+
252
+ def print_distribution(title: str, values: Counter) -> None:
253
+ print(f"{title}:")
254
+ for key, count in sorted(values.items()):
255
+ print(f" {key}: {count}")
256
+
257
+
258
+ if __name__ == "__main__":
259
+ main()