Project Plateau
Project Plateau: four glass plates, one living valley, and the road back to camp.
翻訳待ち
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Halloween demo for Fish Audio Agents + Drama 3: call up a spirit on a Ouija board, talk to it by voice, and coax out the secret of how it died.
cp .env.example .env # fill FISH_API_KEY
npm install
npm run provision # creates/publishes the agent; copy SEANCE_AGENT_ID into .env
npm run provision is safe to re-run. It updates the agent in place and only publishes a new version when the config changed.
Cost: agent minutes are billed at about $0.06/min to the workspace that owns the key.
npm start # http://127.0.0.1:8790
npm run audition # optional: render each ghost's first line with Drama 3 into runs/audition/
Ghosts are defined in src/ghosts.ts. Each has a public epitaph and a private secret, clues, a peace condition and an anger trigger. The server only ever sends the browser {id, name, epitaph} and a session token.
npm start, then open http://127.0.0.1:8790 in Chrome and allow the microphone.Add ?debug to the URL to see raw transcript and tool events in a corner panel.
[a thin, frightened whisper…] directions the model writes itself (the platform hides them from the captions).node --env-file=.env scripts/eval-tools.ts [repeat] runs platform tool tests for every ghost against the draft and prints a pass table (see context/research.md R-6). Re-run it after any change to src/ghosts.ts or the tool descriptions in src/agent.ts, then npm run provision.
| Check | Command | Needs | In CI |
|---|---|---|---|
| Typecheck | npm run typecheck | nothing | ✅ unit |
| Unit tests (roster, no secret leaks, spelling sanitizer, board layout) | npm test | nothing | ✅ unit |
| Browser: candles visibly go out | npm run check:browser (server running; PW_CHANNEL=chrome to use local Chrome) | Playwright | ✅ browser |
| Live: a ghost snuffs a candle end to end | node scripts/check-candles.cjs | server + API key, ~30 s of agent time | ❌ manual |
| Ghost tool-use eval | node --env-file=.env scripts/eval-tools.ts [repeat] [ghosts] | API key, ~5–10 min | ❌ manual |
CI (.github/workflows/ci.yml) runs unit and browser on every pull request and on pushes to main. Neither uses secrets. The browser job boots the server with a dummy agent id because no session is ever created.
Vercel detects src/server.ts as a Fastify app automatically, and serves public/ from its CDN. You don't need a build command or vercel.json.
Environment variables (Project → Settings → Environment Variables):
FISH_API_KEYSEANCE_AGENT_ID (e50a415a2d504903be9344809564ed7c)Without SEANCE_AGENT_ID the server refuses to boot.
Rate limiting is built in (on Vercel only; locally the server is bound to localhost), but best effort. POST /api/session allows 4 séances per visitor per 15 minutes and 40 per hour per server instance; past that it returns 429 and the page shows "The spirits are weary". The counts live in memory per instance (src/limit.ts), and Vercel runs several instances that restart, so this stops a looping script but isn't a hard cap. For a hard ceiling on spend, also add a Vercel Firewall rate-limit rule on /api/session, or keep Deployment Protection on. Every séance bills the key's workspace at about $0.06/min.
Mic access works there, because Vercel serves over HTTPS.
Three Vercel-specific constraints, each found from a real failure (see ADR-7):
rewriteRelativeImportExtensions in tsconfig.json. Vercel compiles the TypeScript; without the flag the compiled server.js still imports ./fish.ts (ERR_MODULE_NOT_FOUND).require(). Vercel's loader rejects it, so @fastify/static is pinned to ~9.3. CI runs the server with --no-experimental-require-module to catch this.await in src/server.ts. Vercel intercepts listen(), and an awaited listen hangs every request.