Skip to main content

Actions: Control What Happens Next

Actions are return values from node functions that control graph behavior. The return type determines whether the graph advances, branches, pauses, or terminates.

dict : Update State and Advance

Return a dictionary to update one or more state fields and automatically advance to the next node in the transition chain. This is useful when a node needs to set values based on logic before moving forward.

async def credit_decision(state, ctx):
if state.credit_score >= 700:
return {"decision": "approved"}
return {"decision": "rejected"}

None : Advance to Next Node

Return None (or simply don't return anything) to advance to the next node without modifying any state. This is useful for nodes that only perform side effects like logging or sending notifications.

async def validate(state, ctx):
pass # advances to next node

Route : Jump to a Specific Node

Return a Route to skip the default transition and jump directly to a specific node. You can optionally pass an update dict to modify state at the same time. This is useful for conditional branching within a node.

from videosdk.conversational_graph import Route

async def income_node(state, ctx):
if state.employment_status == "unemployed":
return Route("reject_unemployed", update={"income": 0})
return "Ask for annual income."

END : Terminate the Graph

Return END to stop the conversation and terminate the graph. After this, no further nodes will execute and the graph will be marked as ended.

from videosdk.conversational_graph import END

async def farewell(state, ctx):
await ctx.say("Goodbye!")
return END

Interrupt : Retry Current Node

Return an Interrupt to stay on the current node and re-ask the user. This is commonly used when extraction or validation fails and you need the user to provide the information again.

from videosdk.conversational_graph import Interrupt

async def collect_name(state, ctx):
result = await ctx.extractor.collect(
fields=["name"],
prompt="Ask for the user's full name.",
)
if not result.extracted.name:
return Interrupt(
say="I didn't catch your name. Could you please repeat it?",
id="retry_name",
)
return Route("next_step")

Each Interrupt increments a retry counter. If max_retries (from GraphConfig) is exceeded, the graph ends.

HumanInLoop : Pause for External Input

Return a HumanInLoop to pause the graph and wait for external input, such as human approval, a payment webhook, or a document upload. The graph stays paused until you call resume_with_human_input() with a payload. See Human-in-the-Loop for the full guide.

from videosdk.conversational_graph import HumanInLoop

async def manual_review(state, ctx):
return HumanInLoop(
reason=f"Marginal credit score: {state.credit_score}",
say="Your application is under manual review. Please hold.",
timeout=300,
)

List[Route] : Parallel Execution

Return a list of Route objects to execute multiple nodes concurrently. This is useful when you need to gather independent pieces of information at the same time without waiting for each one sequentially.

async def gather_info(state, ctx):
return [Route("get_weather"), Route("get_horoscope")]

All routes run in parallel and their prompts are concatenated. The StateMachine returns to the common node after completion.

Parallel start nodes : fan-out at the beginning:

graph.add_transition(START, "greet_personal")
graph.add_transition(START, "fun_fact")
graph.add_transition(START, "daily_tip")
note

Returning a str is not allowed, it will throw an NodeExecutionError.

Got a Question? Ask us on discord