""" ResearchPilot AI — Planner Node Reads user query → creates structured TODO list + detects topic type. """ import time import json from graph.state import ResearchState from graph.llm_factory import get_llm def planner_node(state: ResearchState) -> dict: t0 = time.time() query = state["query"] logs = list(state.get("agent_logs", [])) logs.append("[Planner] Analysing query and creating research plan...") llm = get_llm(temperature=0.3) prompt = f"""You are a research planner. Given a query, produce a structured research plan. Query: {query} Return ONLY valid JSON (no markdown, no backticks): {{ "topic_domain": "", "research_plan": "<2-3 sentence overview of the research approach>", "todos": [ {{"agent": "search_agent", "task": ""}}, {{"agent": "analysis_agent", "task": ""}}, {{"agent": "examples_agent", "task": ""}} ] }}""" response = llm.invoke(prompt) raw = response.content.strip() # Strip markdown fences if present if raw.startswith("```"): raw = raw.split("```")[1] if raw.startswith("json"): raw = raw[4:] raw = raw.strip() try: data = json.loads(raw) except Exception: # Fallback defaults data = { "topic_domain": "general", "research_plan": f"Research {query} comprehensively.", "todos": [ {"agent": "search_agent", "task": f"Search for information about {query}"}, {"agent": "analysis_agent", "task": f"Analyse key findings about {query}"}, {"agent": "examples_agent", "task": f"Find real-world examples related to {query}"}, ] } todos = data.get("todos", []) domain = data.get("topic_domain", "general") plan = data.get("research_plan", "") logs.append(f"[Planner] Domain detected: {domain}") logs.append(f"[Planner] Created {len(todos)} tasks") timings = dict(state.get("agent_timings", {})) timings["planner"] = round(time.time() - t0, 2) return { "todos": todos, "topic_domain": domain, "research_plan": plan, "agent_logs": logs, "agent_timings": timings, "virtual_files": state.get("virtual_files", {}), "structured_data": {}, "citations": [], "chart_json": [], "thumbnail_svg": None, "final_report": "", "quality_score": 0.0, "retry_count": state.get("retry_count", 0), "active_agents": [], "generate_thumbnail": state.get("generate_thumbnail", False), }