Journeys
Journeys enable multi-step conversational workflows with state tracking, branching, and backtracking. This page explains how the engine manages journey state and selects which step to execute.
The Journey Problem​
Guidelines Are Stateless​
A guideline such as "ask for their order number" has no inherent memory. It either matches the current context or does not. However, real conversations often follow multi-step flows:
- Greet and identify intent
- Collect required information
- Perform the action
- Confirm completion
Tracking position within such a flow presents a challenge. Encoding all the logic into guideline conditions quickly becomes unwieldy:
# This quickly becomes unmanageable
condition="Customer wants to return AND we haven't asked for order number yet"
condition="Customer wants to return AND we asked for order number AND they provided it AND we haven't initiated the return yet"
The Solution: Separate Journey Graphs​
Journeys provide a structured way to define multi-step flows. Instead of encoding state in guideline conditions, the developer defines:
- Nodes: Steps with associated actions (guidelines)
- Edges: Transitions between steps (optionally conditional)
- Activation conditions: The circumstances under which this journey begins
The engine tracks the current node position and handles transitions automatically.
Journey Structure​
Components​
Entry Condition: A guideline whose condition activates the journey:
condition="Customer wants to book a taxi"
Nodes: Each node has an action (what the agent should do at this step):
node_1.action = "Ask for their pickup location"
node_2.action = "Ask for their dropoff location"
Edges: Define transitions between nodes. Edges can be:
- Unconditional: The transition occurs automatically when the current node completes.
- Conditional: The transition occurs only if a specified condition is met.
Root Node: The entry/exit point. Returning to root after visiting other nodes signals journey completion.
Node Guidelines​
Internally, each node's action becomes a guideline with a special ID format:
journey_node:{journey_id}:{node_id}
These "journey node guidelines" are evaluated by the Journey Node Selection batch, which reasons about the full journey state.
Journey State Algorithm​
The engine tracks journey progress in journey_paths:
STATE: journey_paths = {
journey_id: [node_id, node_id, ...]
}
The path is a list of visited nodes, representing the route taken through the journey.
State Transitions​
ALGORITHM: Journey State Update
ON guideline_match(guideline):
IF guideline is journey activation condition:
# New journey activated
journey = find_journey_for(guideline)
journey_paths[journey.id] = [journey.root_id]
IF guideline is journey node (journey_node:{jid}:{nid}):
journey_id, node_id = parse(guideline.id)
current_path = journey_paths[journey_id]
IF node_id IN current_path:
# BACKTRACKING: Customer changed context
# Truncate path to this node
index = current_path.index(node_id)
journey_paths[journey_id] = current_path[:index+1]
ELSE:
# FORWARD PROGRESS: Moving to new node
journey_paths[journey_id].append(node_id)
# Check for completion
IF node_id == journey.root_id AND len(current_path) > 1:
# Returned to root after visiting other nodes
# Journey is complete
DELETE journey_paths[journey_id]
Forward Progress​
In the normal flow, the customer provides information and the journey advances to the next node:
Path: [root] → [root, node_1] → [root, node_1, node_2] → [root, node_1, node_2, node_3]
Each new node is appended to the path as the journey progresses.
Backtracking​
Backtracking occurs when the customer changes their mind or provides conflicting information:
When the customer's new information invalidates previously collected data, the engine detects this and backtracks to the appropriate node.
Completion Detection​
A journey completes when the path returns to root after visiting other nodes:
Path: [root, n1, n2, n3, root]
↑ ↑
Started Completed
Upon completion, the journey is removed from journey_paths and its guidelines no longer match.
Journey Node Selection​
The Challenge​
When a journey is active, multiple nodes might appear relevant:
- The current node (the present position in the journey)
- The next node (the intended destination)
- An earlier node (if backtracking is required)
Journey Node Selection is a specialized guideline matching batch that determines which node should execute.
Selection Algorithm​
ALGORITHM: Journey Node Selection
INPUT: active_journey, current_path, context
OUTPUT: selected_node or NO_MATCH
1. IDENTIFY candidate nodes:
- Current node in path
- Nodes reachable via edges from current node
- Previous nodes in path (for backtracking)
2. EVALUATE each candidate:
- Does the conversation justify this node?
- Is there new information invalidating later nodes?
- Are transition conditions met?
3. DETERMINE action:
IF conversation invalidates current progress:
- BACKTRACK to appropriate earlier node
ELSE IF transition condition to next node is met:
- PROGRESS to next node
ELSE:
- STAY at current node (or re-execute if needed)
4. RETURN selected_node with rationale
Backtracking Signals​
The selection batch identifies signals that require backtracking:
- Contradictory information: "Actually, my pickup is somewhere else"
- Explicit corrections: "No, I said Oak Avenue, not Main Street"
- Context shifts: "Wait, it's not for me, it's for my son"
When such signals are detected, the system selects an earlier node and truncates the path accordingly.
Journey Pruning for Efficiency​
With many journeys defined, evaluating all their guidelines is expensive. Parlant uses prediction to focus evaluation:
Top-K Journey Prediction​
ALGORITHM: Journey Pruning
INPUT: all_journeys, context, active_journeys
OUTPUT: journeys_to_evaluate
1. IF active_journeys exist:
- ALWAYS include all active journey guidelines
- PREDICT Top-K other journeys that might activate
- Include their activation condition guidelines
2. IF no active_journeys:
- PREDICT Top-K journeys by semantic relevance to context
- Only evaluate guidelines for those journeys
3. ALWAYS include:
- Non-journey-scoped (global) guidelines
Two-Pass Matching​
In some cases, tool results activate a journey that was not initially predicted:
1. First Pass: Match with predicted Top-K journeys
2. Tool calls execute, return new information
3. Check: Did any unpredicted journey's condition now match?
4. Second Pass: If yes, evaluate that journey's node guidelines
This mechanism identifies journeys that become relevant due to runtime information.
Journey-Guideline Integration​
Scoping Guidelines to Journeys​
Guidelines can be scoped to only apply during certain journeys:
# This guideline only applies during the returns journey
guideline = await agent.create_guideline(
condition="Customer provides order number",
action="Look up the order and verify it's returnable",
tags=["returns_journey"]
)
When the returns journey is not active, this guideline is excluded from evaluation entirely.
Journey Tools​
Journey nodes can have associated tools:
node = JourneyNode(
action="Verify the order is returnable",
tools=["lookup_order", "check_return_eligibility"]
)
When this node is selected, its tools are considered for execution, following the same tool-enabled guideline flow as regular guidelines.
Why This Design?​
Why Separate Journeys from Guidelines?​
Mixing journey state into guideline conditions creates several problems:
- A combinatorial explosion of conditions
- Difficulty reasoning about the flow
- No clear visualization of the process
Separating journeys from guidelines provides:
- Clean guideline conditions that focus on "what" should happen
- Explicit flow definitions that focus on "when" and "in what order"
- Easier debugging by clearly identifying the current node position
Why Graph-Based?​
Trees are too restrictive because real conversations branch and merge. Full state machines introduce excessive complexity. Directed graphs provide an optimal balance:
- Nodes represent steps in the workflow
- Edges define allowed transitions between nodes
- Conditions on edges enable branching logic
- Backtracking is handled through path analysis
Tradeoffs​
| Choice | Benefit | Cost |
|---|---|---|
| Path tracking | Provides precise position tracking within journeys | Requires memory allocation per active journey |
| Backtracking | Accommodates natural conversation flow | Introduces complex selection logic |
| Top-K pruning | Enables efficient evaluation | May miss unexpected journey activations |
| Two-pass matching | Identifies runtime-activated journeys | Introduces additional latency |
What's Next​
- Tool Calling: How journey nodes trigger tools
- Guideline Matching: Full matching pipeline including journeys
- Debugging: Tracing journey state and transitions