Multi-turn LLM streaming loop with tool execution:
NodeSpec( id="research", name="Research Node", description="Search and analyze information", node_type="event_loop", system_prompt="You are a research assistant.", input_keys=["topic"], output_keys=["findings"], tools=["web_search", "fetch_url"],)
NodeSpec( id="processor", input_keys=["request", "context"], # Reads from shared memory output_keys=["response", "metadata"], # Writes to shared memory nullable_output_keys=["metadata"], # Optional outputs)
nullable_output_keys allows outputs to remain unset without triggering validation errors. Useful for mutually exclusive outputs (e.g., success_result or error_message).
For LLM nodes (event_loop, gcu), provide instructions:
NodeSpec( id="intake", node_type="event_loop", system_prompt="""You are a research intake specialist. Your job is to:1. Ask the user what they want to research2. Clarify their specific questions3. Set research_topic and research_questions outputsBe concise and professional.""", output_keys=["research_topic", "research_questions"],)
NodeSpec( id="research", node_type="event_loop", tools=[ "web_search", # Search the web "fetch_url", # Fetch webpage content "save_data", # Save to disk "load_data", # Load from disk ],)
Here’s a complete node configuration from the framework:
from framework.graph import NodeSpec# Intake node - gathers requirementsintake_node = NodeSpec( id="intake", name="Research Intake", description="Gather research requirements from user", node_type="event_loop", system_prompt="""You are a research intake specialist.STEP 1: Ask the user what they want to research.STEP 2: Clarify their specific questions and depth (shallow or deep).STEP 3: Call set_output with research_topic and research_questions.""", input_keys=[], output_keys=["research_topic", "research_questions"], client_facing=True,)# Research node - autonomous workerresearch_node = NodeSpec( id="research", name="Research Executor", description="Search and analyze sources", node_type="event_loop", system_prompt="""You are a rigorous research agent.1. Search for authoritative sources on the topic2. Fetch and analyze source content3. Extract key findings with citations4. Call set_output with findings and sources""", input_keys=["research_topic", "research_questions"], output_keys=["findings", "sources"], tools=["web_search", "fetch_url", "save_data"], client_facing=False, # Autonomous work)# Review node - checkpoint with userreview_node = NodeSpec( id="review", name="Review Findings", description="Present findings to user for review", node_type="event_loop", system_prompt="""Present the research findings to the user.Show:- Key findings- Sources discovered- Coverage of research questionsAsk if they want more research or are ready for the final report.Set needs_more_research to True or False.""", input_keys=["findings", "sources"], output_keys=["needs_more_research"], client_facing=True,)# Report node - generates final outputreport_node = NodeSpec( id="report", name="Generate Report", description="Create final research report", node_type="event_loop", system_prompt="""Generate a comprehensive research report.Format:- Executive summary- Detailed findings with [1], [2], etc. citations- Source listEvery factual claim MUST cite a source.""", input_keys=["findings", "sources"], output_keys=["report", "next_action"], client_facing=True,)
NodeSpec( id="quality_check", node_type="event_loop", success_criteria="""The quality check is complete when:- All validation tests have passed- No critical issues remain- The user has approved the results""",)
When success_criteria is set, the implicit judge upgrades to Level 2:
First, output keys must be satisfied
Then, a fast LLM evaluates whether the conversation meets the criteria
The event_loop node type handles most scenarios - tool use, multi-turn conversations, and complex reasoning. Reserve gcu for browser automation and router for simple branching.
Keep System Prompts Focused
Each node should have a single, clear purpose. Avoid cramming multiple responsibilities into one node - split into multiple nodes instead.
Be Explicit About I/O
Clearly define input_keys and output_keys. This makes data flow visible and enables validation.
Use client_facing Sparingly
Only set client_facing=True for nodes that genuinely need user interaction. Worker nodes should run autonomously.
Validate Critical Outputs
Use output_model with Pydantic for structured outputs that downstream nodes depend on.