"""Custom backend — round-robin agent discussion with tool support.""" import json import os import sys import yaml from meeting_room.api_client import chat, chat_stream, init_providers from meeting_room.scenario_loader import load_scenario from meeting_room.tools import set_workdir, get_tool_schemas, execute_tool # ANSI colors COLORS = { "moderator": "\033[96m", "skeptic": "\033[91m", "idea_generator": "\033[92m", "analyst": "\033[93m", } TOOL_COLOR = "\033[90m" RESET = "\033[0m" BOLD = "\033[1m" DIM = "\033[2m" MAX_TOOL_ITERATIONS = 5 def _format_conversation(conversation: list[dict]) -> str: return "\n\n".join(f"[{msg['name']}]: {msg['content']}" for msg in conversation) def _run_agent_turn(role_config, problem, conversation, is_first_message): """Run one agent turn with tool support. Returns final text response.""" system_msg = {"role": "system", "content": role_config["system_prompt"].strip()} if is_first_message: context_msg = { "role": "user", "content": ( f"Проблема для обсуждения:\n{problem}\n\n" "Обсуди её с другими участниками. Выскажи свою позицию. " "При необходимости используй инструменты." ), } else: context_msg = { "role": "user", "content": ( f"Вот что уже обсудили:\n\n{_format_conversation(conversation)}\n\n" "Продолжи обсуждение. Ответь на аргументы, предложи своё. " "При необходимости используй инструменты." ), } messages = [system_msg, context_msg] tool_schemas = get_tool_schemas(role_config.get("tools", "none")) has_tools = len(tool_schemas) > 0 for _ in range(MAX_TOOL_ITERATIONS): if has_tools: result = chat( provider=role_config["provider"], model=role_config["model"], messages=messages, temperature=role_config.get("temperature", 0.7), tools=tool_schemas, ) else: content = chat_stream( provider=role_config["provider"], model=role_config["model"], messages=messages, temperature=role_config.get("temperature", 0.7), ) return content if result["tool_calls"]: for tc in result["tool_calls"]: print(f"\n{TOOL_COLOR} -> {tc['name']}({tc['arguments']}){RESET}") messages.append({ "role": "assistant", "content": result["content"] or None, "tool_calls": [ { "id": tc["id"], "type": "function", "function": {"name": tc["name"], "arguments": tc["arguments"]}, } for tc in result["tool_calls"] ], }) for tc in result["tool_calls"]: try: args = json.loads(tc["arguments"]) if isinstance(tc["arguments"], str) else tc["arguments"] except json.JSONDecodeError: args = {} tool_result = execute_tool(tc["name"], args) preview = tool_result[:200].replace("\n", " ") print(f"{TOOL_COLOR} <- {preview}{'...' if len(tool_result) > 200 else ''}{RESET}") messages.append({ "role": "tool", "tool_call_id": tc["id"], "content": tool_result, }) continue if result["content"]: print(result["content"]) return result["content"] return result.get("content", "") def run(scenario_path: str, config: dict): init_providers(config) scenario = load_scenario(scenario_path) roles_config = config["roles"] problem = scenario["problem"] participants = scenario.get("participants", list(roles_config.keys())) max_rounds = scenario.get("max_rounds", config["defaults"]["max_rounds"]) set_workdir(config["defaults"].get("workdir", ".")) conversation = [] print(f"\n{BOLD}{'='*60}") print(f" MEETING ROOM — {scenario['name']}") print(f"{'='*60}{RESET}\n") print(f"{BOLD}Problem:{RESET}") for line in problem.split("\n")[:5]: print(f" {line}") if problem.count("\n") > 5: print(" ...") print() print(f"{BOLD}Participants:{RESET}") for rid in participants: r = roles_config[rid] print(f" {r['name']} — {r['provider']}/{r['model']} [tools: {r.get('tools', 'none')}]") print(f"\n{BOLD}Rounds:{RESET} {max_rounds}") print(f"{DIM}{'─'*60}{RESET}\n") for round_num in range(1, max_rounds + 1): print(f"{BOLD}[Round {round_num}/{max_rounds}]{RESET}\n") for role_id in participants: role = roles_config[role_id] color = COLORS.get(role_id, "") name = role["name"] is_first = len(conversation) == 0 print(f"{color}{BOLD} {name}:{RESET}", end=" ") try: content = _run_agent_turn(role, problem, conversation, is_first) except Exception as e: content = f"[Error: {e}]" print(content) conversation.append({"role_id": role_id, "name": name, "content": content}) print() print(f"{DIM}{'─'*60}{RESET}\n") print(f"\n{BOLD}{'='*60}") print(f" DISCUSSION COMPLETE — {len(conversation)} messages") print(f"{'='*60}{RESET}\n") return conversation