diff --git a/matrixbot/commands.py b/matrixbot/commands.py index 2717ca8..d55d0f5 100644 --- a/matrixbot/commands.py +++ b/matrixbot/commands.py @@ -1685,8 +1685,10 @@ async def _generate_wyr() -> dict | None: parsed = json.loads(text) a = parsed.get("option_a", "").strip() b = parsed.get("option_b", "").strip() - # Rebuild question from options so it's always well-formed + # Hard cap: truncate options that are too long if a and b: + a = " ".join(a.split()[:10]) + b = " ".join(b.split()[:10]) q = f"Would you rather {a.rstrip('.')} OR {b.rstrip('.')}?" return {"question": q, "option_a": a, "option_b": b} except Exception as e: @@ -1770,16 +1772,22 @@ async def cmd_wyr(client: AsyncClient, room_id: str, sender: str, args: str): # --------------------------------------------------------------------------- _RIDDLE_ACTIVE: dict[str, dict] = {} -_riddle_recent: list[str] = [] +_riddle_recent: list[str] = [] # past riddle texts +_riddle_recent_answers: list[str] = [] # past answers (lowercase) _RIDDLE_RECENT_MAX = 30 async def _generate_riddle() -> dict | None: - avoid_clause = ( - " Do NOT use any of these riddles that were recently asked: " - + "; ".join(f'"{r}"' for r in _riddle_recent[-15:]) + avoid_riddles = ( + " Do NOT reuse any of these recent riddles: " + + "; ".join(f'"{r}"' for r in _riddle_recent[-10:]) + "." ) if _riddle_recent else "" + avoid_answers = ( + " Do NOT use any of these answers that were recently used: " + + ", ".join(f'"{a}"' for a in _riddle_recent_answers[-15:]) + + "." + ) if _riddle_recent_answers else "" system_msg = ( "You are a riddle generator. Always respond with ONLY a JSON object — no markdown fences, no explanation. " 'Format: {"riddle": "the riddle text", "answer": "short answer"}\n' @@ -1787,11 +1795,11 @@ async def _generate_riddle() -> dict | None: "- The answer must be a specific, unambiguous noun (1-3 words). Avoid abstract answers.\n" "- The riddle must describe the answer through metaphor or wordplay — NOT by literally describing it.\n" "- Do NOT include the answer word anywhere in the riddle text.\n" - "- Do NOT end the riddle with 'what am I?' or 'what could it possibly mean?' — the riddle should stand alone.\n" - "- The clues must logically point to ONE specific answer. Test it: would most people agree this answer is correct?\n" - "- Avoid riddles about riddles, shadows, or abstract concepts. Prefer concrete things: candle, mirror, clock, river, echo, stamp, etc." + "- Do NOT end with 'what am I?', 'what could it be?', or any question — the riddle should stand alone as a statement.\n" + "- The clues must logically point to ONE specific answer that most people would agree on.\n" + "- Avoid 'shadow' as an answer. Prefer concrete things: candle, mirror, clock, river, echo, stamp, key, glove, envelope, etc." ) - user_msg = f"Generate a clever, original riddle with a clear unambiguous answer.{avoid_clause}" + user_msg = f"Generate a clever, original riddle with a clear unambiguous answer.{avoid_answers}{avoid_riddles}" try: timeout = aiohttp.ClientTimeout(total=60) async with aiohttp.ClientSession(timeout=timeout) as session: @@ -1820,6 +1828,9 @@ async def _generate_riddle() -> dict | None: _riddle_recent.append(riddle) if len(_riddle_recent) > _RIDDLE_RECENT_MAX: _riddle_recent.pop(0) + _riddle_recent_answers.append(answer.lower()) + if len(_riddle_recent_answers) > _RIDDLE_RECENT_MAX: + _riddle_recent_answers.pop(0) return {"riddle": riddle, "answer": answer} except Exception as e: logger.error(f"riddle generation error: {e}", exc_info=True)