import json from app.config import settings from app.llm.client import get_game_setup_prompt, get_llm_client from app.llm.tools import game_setup as game_setup_tool MAX_ROUNDS = 3 MAX_TOKENS = 1024 TOOLS = [{"type": "function", "function": game_setup_tool.TOOL_SCHEMA}] async def run_game_setup_turn(client_messages: list[dict]) -> dict: """Stateless setup-wizard turn: the caller owns conversation history (no DB, no game yet). Returns {"messages": , "assistant_text": str | None, "proposal": {"name": str, "description": str} | None}. """ client = get_llm_client() messages = [{"role": "system", "content": get_game_setup_prompt()}] + client_messages assistant_text: str | None = None proposal: dict | None = None for _ in range(MAX_ROUNDS): response = await client.chat.completions.create( model=settings.dm_model, max_tokens=MAX_TOKENS, messages=messages, tools=TOOLS, ) message = response.choices[0].message if message.content: assistant_text = message.content if not message.tool_calls: messages.append({"role": "assistant", "content": message.content or ""}) break messages.append(message.model_dump(exclude_unset=True)) for tool_call in message.tool_calls: args = json.loads(tool_call.function.arguments) if tool_call.function.name == "propose_game_setup": proposal = {"name": args.get("name", ""), "description": args.get("description", "")} messages.append( { "role": "tool", "tool_call_id": tool_call.id, "content": json.dumps({"status": "ok"}), } ) if proposal: break return {"messages": messages[1:], "assistant_text": assistant_text, "proposal": proposal}