Files
miti99bot/plans/260424-1335-twentyq-game-module/plan.md
T
tiennm99 5b12650906 feat(twentyq): add reverse-Akinator yes/no game module powered by Workers AI
- seeded 54 objects across 6 categories (instrument, animal, food, vehicle, sport, household)
- @cf/google/gemma-4-26b-a4b-it judges via function calling; returns {is_guess, answer, hint}
- pre-AI validator rejects open-ended questions; handler dedups exact repeats
- secret-redacting hint filter as defense-in-depth
- 86 new vitest tests (seeds, state, validator, ai-client, handlers, render)
2026-04-24 14:37:23 +07:00

3.8 KiB

name, status, created, completed, slug, blockedBy, blocks
name status created completed slug blockedBy blocks
twentyq-game-module completed 2026-04-24 2026-04-24 twentyq-game-module

TwentyQ Game Module — miti99bot

A reverse-Akinator yes/no guessing game. Bot picks a secret object from a fixed seeded category list, gives an initial hint. User asks is it ...? style questions; Workers AI (@cf/google/gemma-4-26b-a4b-it) judges each input, returns {is_guess, answer:"yes"|"no", hint}. Round ends on correct guess (is it an organ? matches secret) or /twentyq_giveup. Unlimited tries.

Key external dependency: Workers AI binding env.AI (already wired in wrangler.toml [ai]). Gemma 4 26B A4B chosen for function-calling + reasoning + cheap MoE inference (~4B active params).

Commands

Command Description
/twentyq Show current board (initial hint + Q/A history), or start a round if none
/twentyq <question> Submit a yes/no question OR a final guess (is it ...?)
/twentyq_giveup Reveal the secret and end the round (next /twentyq starts fresh)
/twentyq_stats Show per-subject stats

Example flow

/twentyq
Bot: 🎯 I'm thinking of an instrument.
     Hint: it uses wind to create sound.

/twentyq does it require hands to play?
Bot: ✅ Yes. Hint: most players use both hands at once.

/twentyq is it made of wood?
Bot: ❌ No. Hint: its body is mostly metal pipes.

/twentyq is it an organ?
Bot: 🎉 Correct! It was an organ. Solved in 3 guesses.

Key design decisions

  1. Module name twentyq — picked over doandao/akiverse for English clarity.
  2. English-only replies — single-language prompt simplifies model behavior.
  3. Unlimited turns — solve or giveup ends the round (matches semantle/doantu).
  4. Fixed seed listseeds.js has ~60 objects across 6 categories (instrument, animal, food, vehicle, sport, household). Cheap, deterministic, no AI cost for selection.
  5. AI for answer + hint only — model receives {secret, category, history} each turn; emits structured {is_guess, answer, hint} via function calling.
  6. Pre-validate input — reject open-ended questions (what/how/why/which) client-side. Saves Neurons. Doesn't count toward guess tally.
  7. Same command for ask + guess — AI sets is_guess=true when user asks is it [specific noun matching/close to secret]?. Bot ends round on match.
  8. Visibility: public — appears in Telegram / menu + /help.

Phases

Phase File Focus Est. LOC
1 phase-01-foundation.md Module scaffold, seeds, KV state, prompt templates, env wiring ~220
2 phase-02-ai-client.md Workers AI client + function-calling schema + input validation ~150
3 phase-03-gameplay-handlers.md Command handlers, render, round lifecycle ~280
4 phase-04-tests-docs.md Vitest coverage, README, help integration ~200

Critical files

  • Create: src/modules/twentyq/{index,ai-client,seeds,state,handlers,render,prompts,validate-input}.js + README.md
  • Edit: src/modules/index.js (loader entry), wrangler.toml (MODULES list), .env.deploy.example (MODULES list comment)
  • Test: tests/modules/twentyq/{seeds,state,validate-input,ai-client,handlers,render}.test.js

Open questions

  • Per-chat shared round vs per-subject? Defaulting to per-subject (user id in DMs, chat id in groups) — matches doantu/semantle. Group play uses chat-id scope so all members collaborate on one round.
  • AI temperature? Locking to 0.3 for consistent yes/no determinism — can bump to 0.7 for hint variety in a follow-up tweak.
  • Hint repetition? Initial implementation makes no effort to track hint uniqueness across the round — relying on the model + history context to vary. Add dedup later if observed boring.