# `Jido.Agent.Strategy`
[🔗](https://github.com/agentjido/jido/blob/v2.3.0/lib/jido/agent/strategy.ex#L1)

Behaviour for agent execution strategies.

A Strategy decides how to execute actions in `cmd/2`. The default strategy
(`Direct`) simply executes actions immediately. Advanced strategies can
implement behavior trees, LLM chains of thought, or other execution patterns.

## Core Contract

Strategies implement these callbacks:

    cmd(agent, action, context) :: {agent, directives}
    init(agent, context) :: {agent, directives}
    tick(agent, context) :: {agent, directives}
    snapshot(agent, context) :: Strategy.Snapshot.t()

The `cmd/3` callback is required. Others are optional with default implementations.

## Lifecycle

- `init/2` - Called by AgentServer after `MyAgent.new/1` and before the first `cmd/2`.
  Use this to initialize strategy-specific state.
- `cmd/3` - Called by `MyAgent.cmd/2` to execute actions.
- `tick/2` - Called by AgentServer when a strategy has scheduled a tick
  (via `{:schedule, ms, :strategy_tick}`). Use for multi-step execution.

## Snapshot Interface

To avoid agents inspecting strategy internals, strategies expose their state
through `snapshot/2` which returns a `Strategy.Snapshot` struct:

    snap = MyStrategy.snapshot(agent, ctx)
    if snap.done?, do: snap.result

This provides a stable interface regardless of internal implementation.

## Usage

Set strategy at compile time:

    defmodule MyAgent do
      use Jido.Agent,
        name: "my_agent",
        strategy: Jido.Agent.Strategy.Direct  # default
    end

    # Or with options:
    defmodule MyBTAgent do
      use Jido.Agent,
        name: "bt_agent",
        strategy: {MyBehaviorTreeStrategy, max_depth: 5}
    end

## Built-in Strategies

- `Jido.Agent.Strategy.Direct` - Execute actions immediately (default)

## Custom Strategies

Use the module and implement the required `cmd/3` callback:

    defmodule MyCustomStrategy do
      use Jido.Agent.Strategy

      @impl true
      def cmd(agent, action, ctx) do
        # Custom execution logic
        # Must return {updated_agent, directives}
      end

      # Optionally override init/2, tick/2, snapshot/2
    end

Strategy state should live inside `agent.state` under the reserved key
`:__strategy__`. Use `Jido.Agent.Strategy.State` helpers to manage it.

# `action_spec`

```elixir
@type action_spec() :: %{
  optional(:schema) =&gt; Zoi.schema() | keyword(),
  optional(:doc) =&gt; String.t(),
  optional(:name) =&gt; String.t()
}
```

# `context`

```elixir
@type context() :: %{
  :agent_module =&gt; module(),
  :strategy_opts =&gt; keyword(),
  optional(:jido_instance) =&gt; atom() | nil,
  optional(:partition) =&gt; term() | nil
}
```

# `signal_target`

```elixir
@type signal_target() ::
  {:strategy_cmd, action :: term()} | {:strategy_tick} | {:custom, term()}
```

# `status`

```elixir
@type status() :: :idle | :running | :waiting | :success | :failure
```

# `action_spec`
*optional* 

```elixir
@callback action_spec(action :: term()) :: action_spec() | nil
```

Returns the schema/spec for a strategy action.

When a strategy handles internal actions (like `:react_start`), this callback
provides the schema for parameter normalization. If the action has a schema,
params will be coerced/normalized before the strategy receives them.

Return `nil` for actions that don't need normalization.

## Parameters

  * `action` - The action atom or module

## Returns

  * `action_spec()` - Map with optional `:schema`, `:doc`, `:name` keys
  * `nil` - If no normalization needed

# `cmd`

```elixir
@callback cmd(
  agent :: Jido.Agent.t(),
  instructions :: [Jido.Instruction.t()],
  ctx :: context()
) ::
  {Jido.Agent.t(), [Jido.Agent.directive()]}
```

Execute instructions against the agent.

Called by `MyAgent.cmd/2` after normalization. Receives a list of
already-normalized `Instruction` structs. Must return the updated agent
and any external directives.

## Parameters

  * `agent` - The current agent struct
  * `instructions` - List of normalized `Instruction` structs
  * `context` - Execution context with `:agent_module` and `:strategy_opts`

## Returns

  * `{updated_agent, directives}` - The new agent state and external effects

# `init`
*optional* 

```elixir
@callback init(agent :: Jido.Agent.t(), ctx :: context()) ::
  {Jido.Agent.t(), [Jido.Agent.directive()]}
```

Initialize strategy-specific state for a freshly created Agent.

Called in two contexts:
1. By `MyAgent.new/1` to initialize strategy state (directives are dropped)
2. By `AgentServer` during startup to capture and process init directives

Since this may be called twice, implementations should be **idempotent** for
state changes. The second call should return the same state (or recognize
it's already initialized) while still emitting any desired directives.

Default implementation is a no-op.

## Parameters

  * `agent` - The agent struct (may already have strategy state from `new/1`)
  * `context` - Execution context with `:agent_module` and `:strategy_opts`

## Returns

  * `{updated_agent, directives}` - The agent with initialized strategy state

# `signal_routes`
*optional* 

```elixir
@callback signal_routes(ctx :: context()) :: [
  {String.t(), signal_target()}
  | {String.t(), signal_target(), integer()}
  | {String.t(), (Jido.Signal.t() -&gt; boolean()), signal_target()}
  | {String.t(), (Jido.Signal.t() -&gt; boolean()), signal_target(), integer()}
]
```

Declares signal routes handled by this strategy.

Returns a list of route specs that map signal types to strategy commands.
AgentServer consults this to route incoming signals to the appropriate actions.

## Route Targets

- `{:strategy_cmd, action}` - Call `cmd(agent, [{action, signal.data}])`
- `{:strategy_tick}` - Schedule a strategy tick
- `{:custom, term}` - Custom handling (for extension)

## Parameters

  * `context` - Execution context with `:agent_module` and `:strategy_opts`

## Returns

List of route specs:
- `{signal_type, target}` - Route with default priority
- `{signal_type, target, priority}` - Route with custom priority
- `{signal_type, match_fn, target}` - Route with pattern matching
- `{signal_type, match_fn, target, priority}` - Full route spec

## Examples

    def signal_routes(_ctx) do
      [
        {"react.user_query", {:strategy_cmd, :react_start}},
        {"ai.llm_result", {:strategy_cmd, :react_llm_result}},
        {"ai.tool_result", {:strategy_cmd, :react_tool_result}}
      ]
    end

# `snapshot`
*optional* 

```elixir
@callback snapshot(agent :: Jido.Agent.t(), ctx :: context()) ::
  Jido.Agent.Strategy.Snapshot.t()
```

Returns a stable snapshot of the strategy state.

Strategies should map any internal fields (status enums, final answers, etc.)
into a `Strategy.Snapshot` struct. Callers must not depend on internal
`__strategy__` state shape.

Default implementation uses `Strategy.State` helpers.

## Parameters

  * `agent` - The current agent struct
  * `context` - Execution context

## Returns

  * `Strategy.Snapshot.t()` - Snapshot of strategy state

# `tick`
*optional* 

```elixir
@callback tick(agent :: Jido.Agent.t(), ctx :: context()) ::
  {Jido.Agent.t(), [Jido.Agent.directive()]}
```

Tick-based continuation for multi-step or long-running strategies.

Called by AgentServer when a strategy has indicated it wants to be ticked
(via a schedule directive like `{:schedule, ms, :strategy_tick}`).
Default implementation is a no-op.

## Parameters

  * `agent` - The current agent struct
  * `context` - Execution context with `:agent_module` and `:strategy_opts`

## Returns

  * `{updated_agent, directives}` - The new agent state and external effects

# `default_snapshot`

```elixir
@spec default_snapshot(Jido.Agent.t()) :: Jido.Agent.Strategy.Snapshot.t()
```

Default snapshot implementation using Strategy.State helpers.

Reads status from state and determines terminal status.

# `normalize_instruction`

```elixir
@spec normalize_instruction(module(), Jido.Instruction.t(), context()) ::
  Jido.Instruction.t()
```

Normalizes instruction params using the strategy's action_spec.

If the strategy implements `action_spec/1` and returns a schema for the
action, params are normalized (string keys → atoms, type coercion via Zoi).
Otherwise, only basic string-to-atom key conversion is performed.

## Parameters

  * `strategy_mod` - The strategy module
  * `instruction` - The instruction to normalize
  * `ctx` - Execution context

## Returns

  * Updated instruction with normalized params

