openjiuwen_deepsearch.framework.openjiuwen.agent.main_graph_nodes

Main-graph and key subgraph nodes (aligned with current code).

Main graph nodes

StartNode

class StartNode(Start)

Workflow entry: validate/default inputs, init SearchContext (query, session_id, messages, search_mode, report_template), merge agent_config + service_config into runtime config, set thread_id and interrupt_feedback.

EntryNode

class EntryNode(BaseNode)

Language detection/routing via classify_query, normalize locale (zh-CN / en-US); on failure set final_result.exception_info and stop.

GenerateQuestionsNode

class GenerateQuestionsNode(BaseNode)

HITL clarifying questions via query_interpreter with workflow_max_gen_question_retry_num retries; success → search_context.questions; failure → exception_info.

FeedbackHandlerNode

class FeedbackHandlerNode(BaseNode)

Reads user feedback (workflow_feedback_mode cmd/web); FINISH_TASK ends run; invalid input → exception_info.

OutlineNode

class OutlineNode(BaseNode)

Outline generation: report_template present uses outliner_template prompt else outliner; retries via outliner_max_generate_outline_retry_num; streams outline to search_context.current_outline.

DependencyOutlineNode

class DependencyOutlineNode(OutlineNode)

Dependency-aware outline via dep_driving_outliner; same retry/stream behavior as OutlineNode.

OutlineInteractionNode

class OutlineInteractionNode(BaseNode)

Outline HITL: if outline_interaction_enabled is off → EditorTeamNode; if rounds ≥ outline_interaction_max_rounds → notify and continue; reads feedback (cmd/web) as JSON:

{
  "interrupt_feedback": "accepted/revise_comment/revise_outline",
  "feedback": "User text: comments for revise_comment, or new outline for revise_outline"
}

Actions: acceptedEditorTeamNode; revise_comment / revise_outlineOutlineNode; history in search_context.outline_interactions.

DependencyOutlineInteractionNode

class DependencyOutlineInteractionNode(OutlineInteractionNode)

Same as parent; on accepted routes to DependencyEditorTeamNode instead of EditorTeamNode.

EditorTeamNode

class EditorTeamNode(BaseNode)

(editor_team_manager_node.py) Runs concurrent sub-workflows and forwards streamed subgraph output.

DependencyEditorTeamNode

class DependencyEditorTeamNode(EditorTeamNode)

Dependency-layer pipeline: per layer, parallelize previous-layer writing with current-layer reasoning; merges subgraph streams.

ReporterNode

class ReporterNode(BaseNode)

Final report via Reporter.generate_report; failures → exception_info; success → search_context.report and all_classified_contents.

VLMChartGeneratorNode

class VLMChartGeneratorNode(BaseNode)

VLMChartGeneratorNode handles VLM iterative chart generation.

Functions:

  • If vlm_chart_generator_enable is disabled, skip this node.
  • If vlm_chart_generator_enable is enabled:
    • If vlm_chart_generator_max_iterations equals 0, only execute VLM chart generation process without VLM iterative optimization.
    • If vlm_chart_generator_max_iterations is greater than 0, VLM model configuration must be provided; otherwise the system disables this module and skips it.
  • The system selects chart insertion positions, generates charts, and performs corresponding chart optimization.
  • Writes to final_result.chart_messages.
  • Chart generation errors are written to exception_info.

SourceTracerNode

class SourceTracerNode(BaseNode)

SourceTracerNode handles provenance tracing and verification.

Functions:

  • Skip when source_tracer_research_trace_source_switch is disabled.
  • Run citation verification after preprocessing and generate citation information.
  • Write results into final_result.response_content and citation_messages.
  • Insert stable [checked_citation:id] markers into the report body and return matching citation metadata, so the frontend can render and continue interaction based on the latest final_result.
  • Write failures into exception_info.

UserFeedbackProcessorNode

class UserFeedbackProcessorNode(BaseNode)

UserFeedbackProcessorNode handles iterative local rewrite requests after report generation is complete.

Functions:

  • Decide whether to enable post-report local editing based on user_feedback_processor_enable.
  • On first entry, send a full final_result snapshot to the frontend and use search_context.feedback_snapshot_sent to ensure it is sent only once.
  • Read JSON user feedback and support expand, shorten, polish, supplementary_search, new_task, sync, and finish.
  • Parse and validate rewrite payload fields such as action, rewrite_scope, selected_text, and offsets.
  • Support both selected_only and selected_and_related as rewrite scopes for supplementary_search.
  • Return a lightweight ack for sync, without consuming feedback_interaction_count; successful sync appends a rewrite-history record only when the full report content actually changes.
  • Call UserFeedbackProcessor to complete the local rewrite and update only final_result.response_content.
  • For normal rewrite and supplementary_search actions, maintain search_context.feedback_interaction_count and search_context.rewrite_history, including action type, rewrite scope, and actual replacement range.
  • Keep the existing citation / infer metadata unchanged during the rewrite path, without maintaining extra frontend offset mappings.
  • Keep only the latest 10 sync history records; unchanged sync requests do not create history records.
  • Apply user_feedback_processor_max_interactions only to non-sync actions; end the flow after receiving finish.

SourceTracerInferNode

class SourceTracerInferNode(BaseNode):

Skips if source_tracer_infer_switch is off; builds provenance reasoning artifacts → final_result.infer_messages; failures → exception_info.

EndNode

class EndNode(End)

Emits final_result JSON and "ALL END".


Editor-team subgraph (reasoning_writing_graph/editor_team_nodes.py)

SectionStartNodeResearchPlanReasoningNode → (InfoCollectorNodeResearchPlanReasoningNode)* → SubReporterNodeSubSourceTracerNodeSectionEndNode.


Collector subgraph (collector_graph/)

StartNodeGenerateQueryNodeInfoRetrievalNodeSupervisorNode → (loop)* → SummaryNodeGraphEndNodeEnd.


Dependency reasoning subgraph (dependency_reasoning_team_nodes.py)

SectionReasoningStartNodeDependencyPlanReasoningNode → (DependencyInfoCollectorNodeDependencyPlanReasoningNode)* → SectionReasoningEndNode.


Dependency writing subgraph (dependency_writing_team_nodes.py)

SectionWritingStartNodeSubReporterNodeSubSourceTracerNodeSectionEndNode.


Execution sketches

Parallel main graph

StartNode -> EntryNode -> [GenerateQuestionsNode -> FeedbackHandlerNode] -> OutlineNode
-> [OutlineInteractionNode -> OutlineNode]* -> EditorTeamNode -> ReporterNode -> SourceTracerNode -> EndNode
-> SourceTracerInferNode -> UserFeedbackProcessorNode -> EndNode

Dependency-driven main graph

StartNode -> EntryNode -> [GenerateQuestionsNode -> FeedbackHandlerNode] -> DependencyOutlineNode
-> [DependencyOutlineInteractionNode -> DependencyOutlineNode]*
-> DependencyEditorTeamNode -> ReporterNode -> SourceTracerNode
-> SourceTracerInferNode -> UserFeedbackProcessorNode -> EndNode

DependencyEditorTeamNode pipelines dependency layers (“previous writing + current reasoning” in parallel per layer).

Editor-team subgraph

SectionStartNode -> ResearchPlanReasoningNode -> [InfoCollectorNode -> ResearchPlanReasoningNode]*
-> SubReporterNode -> SubSourceTracerNode -> SectionEndNode

Collector subgraph

StartNode -> GenerateQueryNode -> InfoRetrievalNode -> SupervisorNode
-> [InfoRetrievalNode -> SupervisorNode]* -> SummaryNode -> GraphEndNode -> End

Dependency reasoning subgraph

SectionReasoningStartNode -> DependencyPlanReasoningNode -> [DependencyInfoCollectorNode -> DependencyPlanReasoningNode]*
-> SectionReasoningEndNode

Dependency writing subgraph

SectionWritingStartNode -> SubReporterNode -> SubSourceTracerNode -> SectionEndNode