# `Jido.Runic.Examples.Adaptive.AdaptiveResearcher`
[🔗](https://github.com/agentjido/jido_runic/blob/v1.0.0/examples/adaptive/adaptive_researcher.ex#L1)

Adaptive research agent demonstrating dynamic workflow construction.

Unlike the Studio `OrchestratorAgent` which uses a fixed 5-node pipeline,
this agent dynamically selects its Phase 2 writing pipeline based on
Phase 1 research results:

- **Phase 1** — `PlanQueries → SimulateSearch`
- **Phase 2 (rich)** — `BuildOutline → DraftArticle → EditAndAssemble`
- **Phase 2 (thin)** — `DraftArticle → EditAndAssemble`

The agent uses the standard `Jido.Runic.Strategy` with `runic.set_workflow`
to hot-swap workflows between phases.

# `actions`

```elixir
@spec actions() :: [module()]
```

Returns the list of actions from all attached plugins.

# `article`

Extract the final article markdown from run results.

# `build_phase_1`

Build the Phase 1 research workflow: PlanQueries → SimulateSearch.

# `build_phase_2`

Build the Phase 2 writing workflow, dynamically shaped by research results.

When the research summary is rich (>= 500 chars), includes
an outline step. Otherwise skips straight to drafting.

# `capabilities`

```elixir
@spec capabilities() :: [atom()]
```

Returns the union of all capabilities from all mounted plugin instances.

Capabilities are atoms describing what the agent can do based on its
mounted plugins.

## Example

    MyAgent.capabilities()
    # => [:messaging, :channel_management, :chat, :embeddings]

# `category`

```elixir
@spec category() :: String.t() | nil
```

Returns the agent's category.

# `cmd`

```elixir
@spec cmd(Jido.Agent.t(), Jido.Agent.action()) :: Jido.Agent.cmd_result()
```

Execute actions against the agent: `(agent, action) -> {agent, directives}`

This is the core operation. Actions modify state and may perform required
work; directives are runtime-owned external effects.
Execution is delegated to the configured strategy (default: Direct).

## Action Formats

  * `MyAction` - Action module with no params
  * `{MyAction, %{param: 1}}` - Action with params
  * `{MyAction, %{param: 1}, %{context: data}}` - Action with params and context
  * `{MyAction, %{param: 1}, %{}, [timeout: 1000]}` - Action with opts
  * `%Instruction{}` - Full instruction struct
  * `[...]` - List of any of the above (processed in sequence)

## Options

The optional third argument `opts` is a keyword list merged into all instructions:

  * `:timeout` - Maximum time (in ms) for each action to complete
  * `:max_retries` - Maximum retry attempts on failure
  * `:backoff` - Initial backoff time in ms (doubles with each retry)

## Examples

    {agent, directives} = Jido.Runic.Examples.Adaptive.AdaptiveResearcher.cmd(agent, MyAction)
    {agent, directives} = Jido.Runic.Examples.Adaptive.AdaptiveResearcher.cmd(agent, {MyAction, %{value: 42}})
    {agent, directives} = Jido.Runic.Examples.Adaptive.AdaptiveResearcher.cmd(agent, [Action1, Action2])

    # With per-call options (merged into all instructions)
    {agent, directives} = Jido.Runic.Examples.Adaptive.AdaptiveResearcher.cmd(agent, MyAction, timeout: 5000)

# `cmd`

```elixir
@spec cmd(Jido.Agent.t(), Jido.Agent.action(), keyword()) :: Jido.Agent.cmd_result()
```

# `description`

```elixir
@spec description() :: String.t() | nil
```

Returns the agent's description.

# `name`

```elixir
@spec name() :: String.t()
```

Returns the agent's name.

# `new`

```elixir
@spec new(keyword() | map()) :: Jido.Agent.t()
```

Creates a new agent with optional initial state.

The agent is fully initialized including strategy state. For the default
Direct strategy, this is a no-op. For custom strategies, any state
initialization is applied (but directives are only processed by AgentServer).

## Examples

    agent = Jido.Runic.Examples.Adaptive.AdaptiveResearcher.new()
    agent = Jido.Runic.Examples.Adaptive.AdaptiveResearcher.new(id: "custom-id")
    agent = Jido.Runic.Examples.Adaptive.AdaptiveResearcher.new(state: %{counter: 10})

# `plugin_config`

```elixir
@spec plugin_config(module() | {module(), atom()}) :: map() | nil
```

Returns the configuration for a specific plugin.

Accepts either a module or a `{module, as_alias}` tuple for multi-instance plugins.

# `plugin_instances`

```elixir
@spec plugin_instances() :: [Jido.Plugin.Instance.t()]
```

Returns the list of plugin instances attached to this agent.

# `plugin_routes`

```elixir
@spec plugin_routes() :: [{String.t(), module(), integer()}]
```

Returns the expanded and validated plugin routes.

# `plugin_schedules`

```elixir
@spec plugin_schedules() :: [
  Jido.Plugin.Schedules.schedule_spec() | Jido.Agent.Schedules.schedule_spec()
]
```

Returns the expanded plugin and agent schedules.

# `plugin_state`

```elixir
@spec plugin_state(Jido.Agent.t(), module() | {module(), atom()}) :: map() | nil
```

Returns the state slice for a specific plugin.

Accepts either a module or a `{module, as_alias}` tuple for multi-instance plugins.

# `plugins`

```elixir
@spec plugins() :: [module()]
```

Returns the list of plugin modules attached to this agent (deduplicated).

For multi-instance plugins, the module appears once regardless of how many
instances are mounted.

## Example

    MyAgent.plugins()
    # => [MyApp.SlackPlugin, MyApp.OpenAIPlugin]

# `run`

```elixir
@spec run(
  String.t(),
  keyword()
) :: map()
```

Run the full adaptive research pipeline for a topic.

Phase 1 researches the topic, then Phase 2's shape is determined
by how rich the research results are.

## Options

  * `:jido` - Name of a running Jido instance (required)
  * `:timeout` - Timeout in ms for each phase (default: 120_000)
  * `:debug` - Enable debug event buffer (default: true)

## Returns

A map with `:topic`, `:productions`, `:phase_2_type`, `:status`, and `:pid`.

# `schema`

```elixir
@spec schema() :: Zoi.schema() | keyword()
```

Returns the merged schema (base + plugin schemas).

# `set`

```elixir
@spec set(Jido.Agent.t(), map() | keyword()) :: Jido.Agent.agent_result()
```

Updates the agent's state by merging new attributes.

Uses deep merge semantics - nested maps are merged recursively.

## Examples

    {:ok, agent} = Jido.Runic.Examples.Adaptive.AdaptiveResearcher.set(agent, %{status: :running})
    {:ok, agent} = Jido.Runic.Examples.Adaptive.AdaptiveResearcher.set(agent, counter: 5)

# `signal_types`

```elixir
@spec signal_types() :: [String.t()]
```

Returns all expanded route signal types from plugin routes.

These are the fully-prefixed signal types that the agent can handle.

## Example

    MyAgent.signal_types()
    # => ["slack.post", "slack.channels.list", "openai.chat"]

# `strategy`

```elixir
@spec strategy() :: module()
```

Returns the execution strategy module for this agent.

# `strategy_opts`

```elixir
@spec strategy_opts() :: keyword()
```

Returns the strategy options for this agent.

# `strategy_snapshot`

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

Returns a stable, public view of the strategy's execution state.

Use this instead of inspecting `agent.state.__strategy__` directly.
Returns a `Jido.Agent.Strategy.Snapshot` struct with:
- `status` - Coarse execution status
- `done?` - Whether strategy reached terminal state
- `result` - Main output if any
- `details` - Additional strategy-specific metadata

# `tags`

```elixir
@spec tags() :: [String.t()]
```

Returns the agent's tags.

# `validate`

```elixir
@spec validate(
  Jido.Agent.t(),
  keyword()
) :: Jido.Agent.agent_result()
```

Validates the agent's state against its schema.

## Options
  * `:strict` - When true, only schema-defined fields are kept (default: false)

## Examples

    {:ok, agent} = Jido.Runic.Examples.Adaptive.AdaptiveResearcher.validate(agent)
    {:ok, agent} = Jido.Runic.Examples.Adaptive.AdaptiveResearcher.validate(agent, strict: true)

# `vsn`

```elixir
@spec vsn() :: String.t() | nil
```

Returns the agent's version.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
