Jido.AgentServer.DirectiveExec protocol (Jido v2.0.0)

View Source

Protocol for executing directives in AgentServer.

Implement this protocol for custom directive types to extend AgentServer with new effect handlers without modifying core code.

Return Values

  • {:ok, state} - Directive executed successfully, continue processing
  • {:async, ref | nil, state} - Async work started (ref for tracking, nil if fire-and-forget)

  • {:stop, reason, state} - Hard stop the agent process (see warning below)

⚠️ WARNING: {:stop, ...} Semantics

{:stop, reason, state} is a hard stop that terminates the AgentServer immediately:

  • Pending directives are dropped - Any directives still in the queue will NOT be executed
  • Async work is orphaned - In-flight tasks may complete but their signals go nowhere
  • Hooks don't run - on_after_cmd/3 and similar callbacks will NOT be invoked
  • State may be incomplete - External pollers may see partial state or get :noproc

When to use {:stop, ...}

Reserved for abnormal or framework-level termination only:

  • Irrecoverable errors during directive execution
  • Framework decisions (e.g., on_parent_death: :stop)
  • Explicit shutdown requests (with reason like :shutdown)

Do NOT use {:stop, ...} for normal completion

For agents that complete their work (e.g., ReAct finishing a conversation):

  1. Set state.status to :completed or :failed in your agent/strategy
  2. Store results in state (e.g., last_answer, final_result)
  3. Let external code poll AgentServer.state/1 and check status
  4. Process stays alive until explicitly stopped or supervised

This matches Elm/Redux semantics where completion is a state concern, not a process lifecycle concern.

Example Implementation

defimpl Jido.AgentServer.DirectiveExec, for: MyApp.Directive.CallLLM do
  def exec(%{model: model, prompt: prompt}, _input_signal, state) do
    Task.Supervisor.start_child(Jido.TaskSupervisor, fn ->
      MyApp.LLM.call(model, prompt)
    end)
    {:async, nil, state}
  end
end

Fallback for Unknown Directives

Unknown directive types are logged and ignored by default. The fallback implementation uses @fallback_to_any true.

Summary

Types

t()

All the types that implement this protocol.

Functions

Execute a directive, returning an updated state.

Types

t()

@type t() :: term()

All the types that implement this protocol.

Functions

exec(directive, input_signal, state)

Execute a directive, returning an updated state.

Parameters

  • directive - The directive struct to execute
  • input_signal - The signal that triggered this directive
  • state - The current AgentServer.State

Returns

  • {:ok, state} - Continue processing with updated state
  • {:async, ref | nil, state} - Async work started

  • {:stop, reason, state} - Stop the agent