Jido.AgentServer.DirectiveExec protocol (Jido v2.0.0-rc.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