Skip to main content

Result Handlers

Result handlers define how agents respond to step outcomes using step.on() methods. They enable conditional logic and workflow control based on step results.

What are Result Handlers?

Result handlers allow you to:
  • React to step outcomes (success, failure, specific conditions)
  • Implement conditional logic based on step results
  • Chain actions based on different scenarios
  • Handle errors gracefully with fallback strategies
  • Control workflow flow dynamically

Basic Usage

from erdo import Agent, state
from erdo.actions import llm, memory, utils
from erdo.conditions import IsSuccess, IsError, GreaterThan, TextContains

agent = Agent(name="analysis_agent")

analysis_step = agent.step(
    llm.message(
        model="claude-sonnet-4",
        query=f"Analyze this data: {state.input_data}",
        response_format={
            "Type": "json_schema",
            "Schema": {
                "type": "object",
                "properties": {
                    "confidence": {"type": "number"},
                    "insights": {"type": "array"},
                    "risk_level": {"type": "string"}
                }
            }
        }
    )
)

# Handle successful results
analysis_step.on(
    IsSuccess() & GreaterThan("confidence", "0.8"),
    memory.store(memory={
        "content": analysis_step.output.insights,
        "type": "high_confidence_analysis",
        "tags": ["analysis", "validated"]
    })
)

# Handle errors
analysis_step.on(
    IsError(),
    utils.send_status(
        status="failed",
        message=f"Analysis failed: {analysis_step.error.message}"
    )
)

Multiple Action Handlers

Chain multiple actions in a single handler:
# Single action handler
analysis_step.on(
    IsSuccess() & GreaterThan("confidence", "0.9"),
    utils.send_status(status="excellent", message="Excellent analysis results")
)

# Multiple action handler
analysis_step.on(
    IsSuccess() & GreaterThan("confidence", "0.9"),
    utils.send_status(status="excellent", message="Excellent analysis results"),
    memory.store(memory={
        "content": "{{analysis_step.output.insights}}",
        "type": "excellent_analysis"
    }),
    utils.echo(message="Analysis stored successfully")
)

# Handle critical risk levels
analysis_step.on(
    IsSuccess() & TextContains("risk_level", "critical"),
    utils.send_status(
        status="critical_alert",
        message="CRITICAL RISK DETECTED - Immediate attention required",
        priority="urgent"
    )
)

# Simple error handling
analysis_step.on(
    IsError(),
    utils.send_status(status="failed", message="Analysis failed, retrying...")
)

Conditional Logic

Basic Conditions

from erdo.conditions import (
    IsSuccess, IsError, GreaterThan, LessThan,
    TextContains, TextEquals
)

# Success/failure
step.on(IsSuccess(), memory.store(memory={"content": step.output.data}))
step.on(IsError(), utils.send_status(status="failed"))

# Numeric comparisons
step.on(GreaterThan("score", "0.8"), utils.send_status(status="high_score"))
step.on(LessThan("score", "0.3"), utils.send_status(status="low_score"))

# Text conditions
step.on(TextContains("category", "urgent"), utils.send_status(priority="high"))
step.on(TextEquals("status", "completed"), memory.store(memory={"content": "Done"}))

Combining Conditions

Use & (and), | (or), and ~ (not) operators:
# AND - both conditions must be true
step.on(
    IsSuccess() & GreaterThan("confidence", "0.8"),
    memory.store(memory={"content": "High confidence result"})
)

# OR - either condition can be true
step.on(
    TextContains("priority", "urgent") | TextContains("priority", "critical"),
    utils.send_status(status="escalated")
)

# NOT - condition must be false
step.on(
    IsSuccess() & ~TextContains("status", "incomplete"),
    memory.store(memory={"content": "Complete analysis"})
)

# Complex combinations
step.on(
    IsSuccess() & (GreaterThan("score", "0.8") | TextContains("category", "priority")),
    utils.send_status(status="important_result")
)

Multiple Actions

Chain multiple actions in a single handler:
# Multiple actions in one handler
analysis_step.on(
    IsSuccess() & GreaterThan("confidence", "0.9"),
    utils.send_status(status="excellent", message="Great results!"),
    memory.store(memory={
        "content": analysis_step.output.insights,
        "type": "excellent_analysis"
    }),
    utils.echo(message="Analysis stored successfully")
)

Result Handlers with Step Metadata

When result handlers need step-level configuration, use the step_metadata parameter:
from erdo import Agent, StepMetadata
from erdo.actions import llm, utils
from erdo.conditions import IsSuccess, IsError

agent = Agent(name="analysis_agent")

analysis_step = agent.step(
    llm.message(
        model="claude-sonnet-4",
        query="Analyze the data",
        response_format={"type": "json_schema", "schema": {...}}
    )
)

# Result handler with step metadata
analysis_step.on(
    IsSuccess(),
    utils.send_status(
        status="completed",
        message="Analysis successful",
        step_metadata=StepMetadata(
            key="success_handler",
            depends_on=["analysis_step"],
            user_output_visibility="visible",
            running_status="Processing result...",
            finished_status="Result processed"
        )
    )
)

analysis_step.on(
    IsError(),
    utils.raise_error(
        message="Analysis failed",
        status="error",
        step_metadata=StepMetadata(
            key="error_handler",
            user_output_visibility="visible",
            bot_output_visibility="hidden"
        )
    )
)

Step Metadata Configuration

The StepMetadata object supports all step-level configuration:
from erdo import StepMetadata, ExecutionMode, OutputVisibility

# Basic step metadata
step_metadata = StepMetadata(
    key="handler_step",
    depends_on=["previous_step"]
)

# Full configuration options
step_metadata = StepMetadata(
    key="detailed_handler",
    depends_on=["step1", "step2"],
    execution_mode=ExecutionMode.PARALLEL,
    user_output_visibility=OutputVisibility.VISIBLE,
    bot_output_visibility=OutputVisibility.HIDDEN,
    output_content_type="json",
    running_status="Processing result...",
    finished_status="Result processed"
)

# Use in result handler
main_step.on(
    IsSuccess(),
    llm.message(
        model="claude-sonnet-4",
        query="Process the successful result",
        step_metadata=step_metadata
    )
)

Common Patterns

Quality-Based Handling

# Store high-quality results
step.on(
    IsSuccess() & GreaterThan("confidence", "0.8"),
    memory.store(memory={"content": step.output.data, "type": "validated"})
)

# Flag low-quality results for review
step.on(
    IsSuccess() & LessThan("confidence", "0.5"),
    utils.send_status(status="review_needed", message="Low confidence - needs review")
)

Error Recovery

# Retry on specific errors
step.on(
    IsError() & TextContains("error.type", "timeout"),
    utils.send_status(status="retrying", message="Timeout occurred, retrying...")
)

# Fallback for failures
step.on(
    IsError(),
    utils.send_status(status="failed", message="Using fallback processing")
)

Conditional Workflows

# Different paths based on results
classification_step.on(
    IsSuccess() & TextEquals("category", "urgent"),
    llm.message(model="claude-sonnet-4", query="Handle urgent case")
)

classification_step.on(
    IsSuccess() & TextEquals("category", "routine"),
    utils.send_status(status="queued", message="Added to routine processing")
)

Available Conditions

ConditionDescriptionExample
IsSuccess()Step completed successfullyIsSuccess()
IsError()Step failed with errorIsError()
GreaterThan(field, value)Numeric field > valueGreaterThan("score", "0.8")
LessThan(field, value)Numeric field < valueLessThan("confidence", "0.5")
TextContains(field, text)Field contains textTextContains("status", "complete")
TextEquals(field, text)Field exactly equals textTextEquals("type", "urgent")