feat: add analysis step type for non-code reasoning tasks (#677) (#723)

Add a new "analysis" step type to handle reasoning and synthesis tasks
that don't require code execution, addressing the concern that routing
all non-search tasks to the coder agent was inappropriate.

Changes:
- Add ANALYSIS enum value to StepType in planner_model.py
- Create analyst_node for pure LLM reasoning without tools
- Update graph routing to route analysis steps to analyst agent
- Add analyst agent to AGENT_LLM_MAP configuration
- Create analyst prompts (English and Chinese)
- Update planner prompts with guidance on choosing between
  analysis (reasoning/synthesis) and processing (code execution)
- Change default step_type inference from "processing" to "analysis"
  when need_search=false

Co-authored-by: Willem Jiang <143703838+willem-bd@users.noreply.github.com>
This commit is contained in:
Willem Jiang
2025-11-29 09:46:55 +08:00
committed by GitHub
parent 2cc19d6309
commit 2e010a4619
10 changed files with 264 additions and 67 deletions

View File

@@ -7,6 +7,7 @@ from langgraph.graph import END, START, StateGraph
from src.prompts.planner_model import StepType
from .nodes import (
analyst_node,
background_investigation_node,
coder_node,
coordinator_node,
@@ -39,6 +40,8 @@ def continue_to_running_research_team(state: State):
if incomplete_step.step_type == StepType.RESEARCH:
return "researcher"
if incomplete_step.step_type == StepType.ANALYSIS:
return "analyst"
if incomplete_step.step_type == StepType.PROCESSING:
return "coder"
return "planner"
@@ -54,13 +57,14 @@ def _build_base_graph():
builder.add_node("reporter", reporter_node)
builder.add_node("research_team", research_team_node)
builder.add_node("researcher", researcher_node)
builder.add_node("analyst", analyst_node)
builder.add_node("coder", coder_node)
builder.add_node("human_feedback", human_feedback_node)
builder.add_edge("background_investigator", "planner")
builder.add_conditional_edges(
"research_team",
continue_to_running_research_team,
["planner", "researcher", "coder"],
["planner", "researcher", "analyst", "coder"],
)
builder.add_edge("reporter", END)
return builder

View File

@@ -135,7 +135,8 @@ def validate_and_fix_plan(plan: dict, enforce_web_search: bool = False) -> dict:
# Check if step_type is missing or empty
if "step_type" not in step or not step.get("step_type"):
# Infer step_type based on need_search value
inferred_type = "research" if step.get("need_search", False) else "processing"
# Default to "analysis" for non-search steps (Issue #677: not all processing needs code)
inferred_type = "research" if step.get("need_search", False) else "analysis"
step["step_type"] = inferred_type
logger.info(
f"Repaired missing step_type for step {idx} ({step.get('title', 'Untitled')}): "
@@ -1209,3 +1210,27 @@ async def coder_node(
"coder",
[python_repl_tool],
)
async def analyst_node(
state: State, config: RunnableConfig
) -> Command[Literal["research_team"]]:
"""Analyst node that performs reasoning and analysis without code execution.
This node handles tasks like:
- Cross-validating information from multiple sources
- Synthesizing research findings
- Comparative analysis
- Pattern recognition and trend analysis
- General reasoning tasks that don't require code
"""
logger.info("Analyst node is analyzing.")
logger.debug(f"[analyst_node] Starting analyst agent for reasoning/analysis tasks")
# Analyst uses no tools - pure LLM reasoning
return await _setup_and_execute_agent_step(
state,
config,
"analyst",
[], # No tools - pure reasoning
)