# Keeping the demo video fresh

The demo video is generated by a scripted Playwright runner that drives a real
Telegram Web session against a fake ACP agent. Everything — timing, messages,
agent responses — is declared in a single JSON file. To update the video you
mostly only touch that file.

## How it works

```
demo_story.json          ← the only file you normally edit
      │
      ▼
telegram_web_demo.py     ← Playwright driver (opens browser, types, clicks)
      │
      ▼
run_demo_bot.py          ← Telegram bot + fake ACP agent wired together
      │
      ▼
fake_acp_agent.py        ← replays agent_routes from demo_story.json
```

`telegram_web_demo.py` reads the story, opens a persistent Chromium profile
logged into Telegram Web, and executes each `user_steps` entry in order.
After each step it waits for a `wait_for_text` pattern to appear before
typing the next message — this keeps the pacing locked to actual bot
responses rather than fixed sleeps.

The fake agent (`fake_acp_agent.py`) receives the bot's ACP prompts and
replays whichever `agent_routes` entry matches the prompt text.  It emits
tool events with configurable delays, then sends the final text/images/files.

## Recording a new video

### One-time login

```bash
uv run scripts/demo/telegram_web_demo.py --mode login
```

Scan the QR code that appears in the browser. The session is saved in
`.cache/telegram-web-profile/` and reused on every subsequent run.

### Record

```bash
cp .env.demo .env   # set TELEGRAM_BOT_TOKEN, TELEGRAM_ALLOWED_USER_IDS, etc.
uv run scripts/demo/telegram_web_demo.py
```

The recording is saved under `artifacts/demo-videos/<timestamp>/`.
Pass `--no-record` to run without recording (useful for testing timing).

## Changing the script

Open `scripts/demo/demo_story.json`. The structure is:

```
runtime            — global typing speed and final pause duration
assets             — image/file payloads referenced by agent_routes
user_steps         — what the "user" types, in order
agent_routes       — what the fake agent replies to each prompt
```

### Editing user messages

Each entry in `user_steps` has:

| field | meaning |
|---|---|
| `text` | the message that gets typed into Telegram |
| `wait_for_text.pattern` | regex that must appear on screen before typing |
| `wait_for_text.timeout_seconds` | how long to wait before giving up and continuing |
| `wait_for_text.after_ms` | extra pause after the pattern appears |
| `actions` | list of UI actions after sending: `click_send_now` or `click_resume_choice` |

### Editing agent responses

Each entry in `agent_routes` has:

| field | meaning |
|---|---|
| `match_any` | list of substrings; the first route where any substring matches the prompt wins |
| `events` | tool events to emit (kind, title, text, delay_ms) |
| `final_text` | plain-text message sent after all events |
| `final_images` | list of asset IDs to send as photos |
| `final_files` | list of asset IDs to send as file attachments |
| `cancel_reply_text` | reply sent if the agent is interrupted mid-route |

### Timing knobs

- `delay_ms` on each event — pause before that tool event is emitted.
- `wait_for_text.after_ms` — pause on the user side after the pattern appears.
- `runtime.typing_delay_ms` — per-character typing speed.
- `runtime.final_pause_seconds` — how long the browser stays open after the
  last step (gives time for the final messages to settle before closing).

Increase `wait_for_text.timeout_seconds` if a step keeps timing out in CI or
on slow machines; increase `after_ms` if the next message arrives before the
previous reply has finished rendering.

## Adding a new demo scenario

1. Add a new `agent_routes` entry with a unique `id` and `match_any` keywords.
2. Add a `user_steps` entry whose `text` contains one of those keywords.
3. Add a `wait_for_text` so the next step waits for the agent's reply.
4. If the route sends an image or file, add the asset to the `assets` map and
   put the asset file in `scripts/demo/`.
5. Run with `--no-record` first to verify timing, then record.

## File reference

| file | purpose |
|---|---|
| `scripts/demo/demo_story.json` | declarative script — edit this |
| `scripts/demo/telegram_web_demo.py` | Playwright driver |
| `scripts/demo/fake_acp_agent.py` | scripted ACP agent |
| `scripts/demo/demo_scenario.py` | typed dataclass parser for the JSON |
| `scripts/demo/run_demo_bot.py` | wires the bot + fake agent together |
| `scripts/demo/demo.png` | webcam photo asset |
| `scripts/demo/release-diagnostics.pdf` | PDF attachment asset |
| `.cache/telegram-web-profile/` | persistent Chromium login session (gitignored) |
| `artifacts/demo-videos/` | recorded `.webm` files (gitignored) |
