Skip to content

Agent executor

agent_executor

Protocol and types for unified agent execution.

This module defines the AgentExecutorProtocol and supporting types for executing any ADK agent type (generator, critic, reflection) with consistent behavior, session management, and result handling.

ATTRIBUTE DESCRIPTION
ExecutionStatus

Status of agent execution (SUCCESS/FAILED/TIMEOUT).

TYPE: enum

ExecutionResult

Result of an agent execution.

TYPE: dataclass

AgentExecutorProtocol

Protocol for unified agent execution.

TYPE: protocol

Examples:

Using an executor:

from gepa_adk.ports.agent_executor import (
    AgentExecutorProtocol,
    ExecutionResult,
    ExecutionStatus,
)

executor: AgentExecutorProtocol = AgentExecutor()
result = await executor.execute_agent(
    agent=my_agent,
    input_text="Hello",
    timeout_seconds=60,
)
if result.status == ExecutionStatus.SUCCESS:
    print(result.extracted_value)
See Also
Note

This module follows hexagonal architecture principles. The protocol is defined here in the ports layer, while implementations live in the adapters layer.

ExecutionStatus

Bases: str, Enum


              flowchart TD
              gepa_adk.ports.agent_executor.ExecutionStatus[ExecutionStatus]

              

              click gepa_adk.ports.agent_executor.ExecutionStatus href "" "gepa_adk.ports.agent_executor.ExecutionStatus"
            

Status of agent execution.

This enum represents the outcome status of an agent execution, used by ExecutionResult to indicate how the execution completed.

ATTRIBUTE DESCRIPTION
SUCCESS

Agent completed execution normally with valid output.

FAILED

Agent encountered an error during execution.

TIMEOUT

Agent execution exceeded configured timeout.

Examples:

Checking execution status:

from gepa_adk.ports.agent_executor import ExecutionStatus

if result.status == ExecutionStatus.SUCCESS:
    print(f"Output: {result.extracted_value}")
elif result.status == ExecutionStatus.TIMEOUT:
    print(f"Timed out after {result.execution_time_seconds}s")
elif result.status == ExecutionStatus.FAILED:
    print(f"Error: {result.error_message}")
Note

All status values reflect execution outcome, not output quality. A successful execution may still produce low-quality output that fails scoring.

Source code in src/gepa_adk/ports/agent_executor.py
class ExecutionStatus(str, Enum):
    """Status of agent execution.

    This enum represents the outcome status of an agent execution,
    used by ExecutionResult to indicate how the execution completed.

    Attributes:
        SUCCESS: Agent completed execution normally with valid output.
        FAILED: Agent encountered an error during execution.
        TIMEOUT: Agent execution exceeded configured timeout.

    Examples:
        Checking execution status:

        ```python
        from gepa_adk.ports.agent_executor import ExecutionStatus

        if result.status == ExecutionStatus.SUCCESS:
            print(f"Output: {result.extracted_value}")
        elif result.status == ExecutionStatus.TIMEOUT:
            print(f"Timed out after {result.execution_time_seconds}s")
        elif result.status == ExecutionStatus.FAILED:
            print(f"Error: {result.error_message}")
        ```

    Note:
        All status values reflect execution outcome, not output quality.
        A successful execution may still produce low-quality output
        that fails scoring.
    """

    SUCCESS = "success"
    FAILED = "failed"
    TIMEOUT = "timeout"

ExecutionResult dataclass

Result of an agent execution.

Provides consistent return type across all agent types (generator, critic, reflection) with status, output, timing, and debugging information.

ATTRIBUTE DESCRIPTION
status

Outcome status of the execution.

TYPE: ExecutionStatus

session_id

ADK session identifier used for this execution.

TYPE: str

extracted_value

Output text extracted from agent response. None if agent produced no output or execution failed.

TYPE: str | None

error_message

Error details if status is FAILED or TIMEOUT. None for successful executions.

TYPE: str | None

execution_time_seconds

Duration of execution in seconds.

TYPE: float

captured_events

ADK events captured during execution for debugging and trajectory analysis. None if event capture disabled.

TYPE: list[Any] | None

Examples:

Successful execution:

result = ExecutionResult(
    status=ExecutionStatus.SUCCESS,
    session_id="sess_123",
    extracted_value="Hello, world!",
    execution_time_seconds=1.5,
)

Failed execution:

result = ExecutionResult(
    status=ExecutionStatus.FAILED,
    session_id="sess_456",
    error_message="Model rate limit exceeded",
    execution_time_seconds=0.2,
)
Note

All captured_events contain raw ADK Event objects for debugging and trajectory recording. Events are captured even on timeout or failure.

Source code in src/gepa_adk/ports/agent_executor.py
@dataclass
class ExecutionResult:
    """Result of an agent execution.

    Provides consistent return type across all agent types (generator, critic,
    reflection) with status, output, timing, and debugging information.

    Attributes:
        status (ExecutionStatus): Outcome status of the execution.
        session_id (str): ADK session identifier used for this execution.
        extracted_value (str | None): Output text extracted from agent response. None if
            agent produced no output or execution failed.
        error_message (str | None): Error details if status is FAILED or TIMEOUT. None
            for successful executions.
        execution_time_seconds (float): Duration of execution in seconds.
        captured_events (list[Any] | None): ADK events captured during execution for debugging
            and trajectory analysis. None if event capture disabled.

    Examples:
        Successful execution:

        ```python
        result = ExecutionResult(
            status=ExecutionStatus.SUCCESS,
            session_id="sess_123",
            extracted_value="Hello, world!",
            execution_time_seconds=1.5,
        )
        ```

        Failed execution:

        ```python
        result = ExecutionResult(
            status=ExecutionStatus.FAILED,
            session_id="sess_456",
            error_message="Model rate limit exceeded",
            execution_time_seconds=0.2,
        )
        ```

    Note:
        All captured_events contain raw ADK Event objects for debugging
        and trajectory recording. Events are captured even on timeout
        or failure.
    """

    status: ExecutionStatus
    session_id: str
    extracted_value: str | None = None
    error_message: str | None = None
    execution_time_seconds: float = 0.0
    captured_events: list[Any] | None = field(default=None)

AgentExecutorProtocol

Bases: Protocol


              flowchart TD
              gepa_adk.ports.agent_executor.AgentExecutorProtocol[AgentExecutorProtocol]

              

              click gepa_adk.ports.agent_executor.AgentExecutorProtocol href "" "gepa_adk.ports.agent_executor.AgentExecutorProtocol"
            

Protocol for unified agent execution.

Defines the interface for executing any ADK agent type (LlmAgent, workflow agents) with consistent behavior, session management, and result handling.

This protocol enables: - Feature parity across generator, critic, and reflection agents - Dependency injection for testing - Single point of change for new ADK features

Examples:

Using an executor:

executor: AgentExecutorProtocol = AgentExecutor()

result = await executor.execute_agent(
    agent=my_agent,
    input_text="Hello",
    timeout_seconds=60,
)

if result.status == ExecutionStatus.SUCCESS:
    print(result.extracted_value)

With instruction override (for evolution):

result = await executor.execute_agent(
    agent=my_agent,
    input_text="Hello",
    instruction_override="You are a helpful assistant.",
)
See Also
Note

All implementations should validate that the agent parameter is a valid ADK LlmAgent. The Any type is used here to avoid coupling the ports layer to ADK types.

Source code in src/gepa_adk/ports/agent_executor.py
@runtime_checkable
class AgentExecutorProtocol(Protocol):
    """Protocol for unified agent execution.

    Defines the interface for executing any ADK agent type (LlmAgent,
    workflow agents) with consistent behavior, session management, and
    result handling.

    This protocol enables:
    - Feature parity across generator, critic, and reflection agents
    - Dependency injection for testing
    - Single point of change for new ADK features

    Examples:
        Using an executor:

        ```python
        executor: AgentExecutorProtocol = AgentExecutor()

        result = await executor.execute_agent(
            agent=my_agent,
            input_text="Hello",
            timeout_seconds=60,
        )

        if result.status == ExecutionStatus.SUCCESS:
            print(result.extracted_value)
        ```

        With instruction override (for evolution):

        ```python
        result = await executor.execute_agent(
            agent=my_agent,
            input_text="Hello",
            instruction_override="You are a helpful assistant.",
        )
        ```

    See Also:
        - [`ExecutionResult`][gepa_adk.ports.agent_executor.ExecutionResult]:
            Return type for execute_agent.
        - [`ExecutionStatus`][gepa_adk.ports.agent_executor.ExecutionStatus]:
            Status enum for execution outcomes.

    Note:
        All implementations should validate that the agent parameter is a
        valid ADK LlmAgent. The Any type is used here to avoid coupling
        the ports layer to ADK types.
    """

    async def execute_agent(
        self,
        agent: Any,
        input_text: str,
        *,
        input_content: Any | None = None,
        instruction_override: str | None = None,
        output_schema_override: Any | None = None,
        session_state: dict[str, Any] | None = None,
        existing_session_id: str | None = None,
        timeout_seconds: int = 300,
    ) -> ExecutionResult:
        """Execute an agent and return structured result.

        Runs the specified agent with the given input, optionally applying
        instruction or schema overrides for evolution scenarios. Manages
        session lifecycle and captures execution events.

        Args:
            agent: ADK LlmAgent to execute. The agent's tools, output_key,
                and other ADK features are preserved during execution.
            input_text: User message to send to the agent. Used as fallback
                if input_content is not provided.
            input_content: Optional ADK Content object for multimodal input
                (e.g., video parts). If provided, takes precedence over input_text.
            instruction_override: If provided, replaces the agent's instruction
                for this execution only. Original agent is not modified.
            output_schema_override: If provided, replaces the agent's output
                schema for this execution only (type[BaseModel]). Used for schema evolution.
            session_state: Initial state to inject into the session. Used for
                template variable substitution (e.g., {component_text}).
            existing_session_id: If provided, reuses an existing session instead
                of creating a new one. Useful for critic accessing generator state.
            timeout_seconds: Maximum execution time in seconds. Defaults to 300.
                Execution terminates with TIMEOUT status if exceeded.

        Returns:
            ExecutionResult with status, output, and debugging information.

        Raises:
            SessionNotFoundError: If existing_session_id is provided but session
                does not exist.

        Examples:
            Basic execution:

            ```python
            result = await executor.execute_agent(
                agent=greeter,
                input_text="Hello!",
            )
            print(result.extracted_value)  # "Hello! How can I help?"
            ```

            With session state for reflection:

            ```python
            result = await executor.execute_agent(
                agent=reflector,
                input_text="Improve the instruction",
                session_state={
                    "component_text": "Be helpful.",
                    "trials": '[{"score": 0.5}]',
                },
            )
            ```

            Session sharing between agents:

            ```python
            # Generator creates session
            gen_result = await executor.execute_agent(
                agent=generator,
                input_text="Write a story.",
            )

            # Critic reuses generator's session
            critic_result = await executor.execute_agent(
                agent=critic,
                input_text=f"Evaluate: {gen_result.extracted_value}",
                existing_session_id=gen_result.session_id,
            )
            ```

        Note:
            The agent parameter is typed as Any to avoid coupling to ADK types
            in the ports layer. Implementations should validate that the agent
            is a valid LlmAgent.
        """
        ...

execute_agent async

execute_agent(
    agent: Any,
    input_text: str,
    *,
    input_content: Any | None = None,
    instruction_override: str | None = None,
    output_schema_override: Any | None = None,
    session_state: dict[str, Any] | None = None,
    existing_session_id: str | None = None,
    timeout_seconds: int = 300,
) -> ExecutionResult

Execute an agent and return structured result.

Runs the specified agent with the given input, optionally applying instruction or schema overrides for evolution scenarios. Manages session lifecycle and captures execution events.

PARAMETER DESCRIPTION
agent

ADK LlmAgent to execute. The agent's tools, output_key, and other ADK features are preserved during execution.

TYPE: Any

input_text

User message to send to the agent. Used as fallback if input_content is not provided.

TYPE: str

input_content

Optional ADK Content object for multimodal input (e.g., video parts). If provided, takes precedence over input_text.

TYPE: Any | None DEFAULT: None

instruction_override

If provided, replaces the agent's instruction for this execution only. Original agent is not modified.

TYPE: str | None DEFAULT: None

output_schema_override

If provided, replaces the agent's output schema for this execution only (type[BaseModel]). Used for schema evolution.

TYPE: Any | None DEFAULT: None

session_state

Initial state to inject into the session. Used for template variable substitution (e.g., {component_text}).

TYPE: dict[str, Any] | None DEFAULT: None

existing_session_id

If provided, reuses an existing session instead of creating a new one. Useful for critic accessing generator state.

TYPE: str | None DEFAULT: None

timeout_seconds

Maximum execution time in seconds. Defaults to 300. Execution terminates with TIMEOUT status if exceeded.

TYPE: int DEFAULT: 300

RETURNS DESCRIPTION
ExecutionResult

ExecutionResult with status, output, and debugging information.

RAISES DESCRIPTION
SessionNotFoundError

If existing_session_id is provided but session does not exist.

Examples:

Basic execution:

result = await executor.execute_agent(
    agent=greeter,
    input_text="Hello!",
)
print(result.extracted_value)  # "Hello! How can I help?"

With session state for reflection:

result = await executor.execute_agent(
    agent=reflector,
    input_text="Improve the instruction",
    session_state={
        "component_text": "Be helpful.",
        "trials": '[{"score": 0.5}]',
    },
)

Session sharing between agents:

# Generator creates session
gen_result = await executor.execute_agent(
    agent=generator,
    input_text="Write a story.",
)

# Critic reuses generator's session
critic_result = await executor.execute_agent(
    agent=critic,
    input_text=f"Evaluate: {gen_result.extracted_value}",
    existing_session_id=gen_result.session_id,
)
Note

The agent parameter is typed as Any to avoid coupling to ADK types in the ports layer. Implementations should validate that the agent is a valid LlmAgent.

Source code in src/gepa_adk/ports/agent_executor.py
async def execute_agent(
    self,
    agent: Any,
    input_text: str,
    *,
    input_content: Any | None = None,
    instruction_override: str | None = None,
    output_schema_override: Any | None = None,
    session_state: dict[str, Any] | None = None,
    existing_session_id: str | None = None,
    timeout_seconds: int = 300,
) -> ExecutionResult:
    """Execute an agent and return structured result.

    Runs the specified agent with the given input, optionally applying
    instruction or schema overrides for evolution scenarios. Manages
    session lifecycle and captures execution events.

    Args:
        agent: ADK LlmAgent to execute. The agent's tools, output_key,
            and other ADK features are preserved during execution.
        input_text: User message to send to the agent. Used as fallback
            if input_content is not provided.
        input_content: Optional ADK Content object for multimodal input
            (e.g., video parts). If provided, takes precedence over input_text.
        instruction_override: If provided, replaces the agent's instruction
            for this execution only. Original agent is not modified.
        output_schema_override: If provided, replaces the agent's output
            schema for this execution only (type[BaseModel]). Used for schema evolution.
        session_state: Initial state to inject into the session. Used for
            template variable substitution (e.g., {component_text}).
        existing_session_id: If provided, reuses an existing session instead
            of creating a new one. Useful for critic accessing generator state.
        timeout_seconds: Maximum execution time in seconds. Defaults to 300.
            Execution terminates with TIMEOUT status if exceeded.

    Returns:
        ExecutionResult with status, output, and debugging information.

    Raises:
        SessionNotFoundError: If existing_session_id is provided but session
            does not exist.

    Examples:
        Basic execution:

        ```python
        result = await executor.execute_agent(
            agent=greeter,
            input_text="Hello!",
        )
        print(result.extracted_value)  # "Hello! How can I help?"
        ```

        With session state for reflection:

        ```python
        result = await executor.execute_agent(
            agent=reflector,
            input_text="Improve the instruction",
            session_state={
                "component_text": "Be helpful.",
                "trials": '[{"score": 0.5}]',
            },
        )
        ```

        Session sharing between agents:

        ```python
        # Generator creates session
        gen_result = await executor.execute_agent(
            agent=generator,
            input_text="Write a story.",
        )

        # Critic reuses generator's session
        critic_result = await executor.execute_agent(
            agent=critic,
            input_text=f"Evaluate: {gen_result.extracted_value}",
            existing_session_id=gen_result.session_id,
        )
        ```

    Note:
        The agent parameter is typed as Any to avoid coupling to ADK types
        in the ports layer. Implementations should validate that the agent
        is a valid LlmAgent.
    """
    ...