feat(voice): /game/call — runtime rings NPC

The runtime triggers a scenario phone call: POST /game/call?number=18
[&step=STEP_X] rings the PLIP handset with the chosen NPC (resolved via
the boards registry) and sets the current step so the NPC disguises that
step's hint. Completes the game->phone trigger path (chantier #2).
This commit is contained in:
clement
2026-06-18 12:40:04 +02:00
parent 5d7550b993
commit 892fb13bb3
+28
View File
@@ -2248,3 +2248,31 @@ async def game_step(request: Request, step: str | None = None,
cur = getattr(request.app.state, "current_step", INITIAL_STEP)
return {"step": cur, "scene": STEP_SCENE.get(cur or "", ""),
"has_hints": bool(SCENE_HINTS.get(STEP_SCENE.get(cur or "", ""), {}))}
@app.post("/game/call")
async def game_call(request: Request, number: str, board: str = "plip",
step: str | None = None,
_: None = Depends(require_token)) -> dict:
"""Make a phone (board) ring with a scenario NPC. The runtime calls this when
the scenario reaches a 'phone rings' event: it rings the handset with the
chosen number and (optionally) sets the current step so the NPC disguises
THAT step's hint. POST /game/call?number=18[&board=plip][&step=STEP_X]."""
if number not in PHONE_DIRECTORY:
raise HTTPException(404, f"unknown phone number '{number}'")
if step:
if STEP_SCENE and step not in STEP_SCENE:
raise HTTPException(404, f"unknown step '{step}'")
request.app.state.current_step = step
route = resolve_board_route(board)
http: httpx.AsyncClient = request.app.state.http
try:
r = await http.get(f"{route.base_url}/debug/ring", params={"number": number}, timeout=5.0)
r.raise_for_status()
except Exception as exc: # noqa: BLE001
raise HTTPException(502, f"ring failed on {board} ({route.base_url}): {type(exc).__name__}") from exc
logging.info("game call: ring %s on %s (number %s, step %s)",
PHONE_DIRECTORY[number].get("label", number), board, number,
getattr(request.app.state, "current_step", None))
return {"ok": True, "ringing": number, "npc": PHONE_DIRECTORY[number].get("label"),
"board": board, "step": getattr(request.app.state, "current_step", None)}