# `Jido.Messaging.Demo.ChatAgent`
[🔗](https://github.com/agentjido/jido_messaging/blob/v1.0.0/lib/jido_messaging/demo/chat_agent.ex#L1)

A ReAct-based chat agent that participates in bridged conversations.

This agent demonstrates end-to-end agentic chat by:
1. Listening for messages on the Signal Bus
2. Processing messages through a ReAct reasoning loop
3. Responding with contextual, tool-augmented replies

## Usage

Start with the bridge demo:

    # In config or env
    export TELEGRAM_BOT_TOKEN="your_token"
    export TELEGRAM_CHAT_ID="your_chat_id"
    export DISCORD_BOT_TOKEN="your_token"
    export DISCORD_CHANNEL_ID="your_channel_id"

    # Start the demo with agent
    Jido.Messaging.Demo.Supervisor.start_link(
      mode: :agent,
      telegram_chat_id: "...",
      discord_channel_id: "..."
    )

The agent will respond when mentioned with @ChatAgent or when messages
contain questions it can help with.

# `actions`

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

Returns the list of actions from all attached plugins.

# `ask`

```elixir
@spec ask(
  pid() | atom() | {:via, module(), term()},
  String.t() | [ReqLLM.Message.ContentPart.t()],
  keyword()
) :: {:ok, Jido.AI.Request.Handle.t()} | {:error, term()}
```

Send a query to the agent asynchronously.

Returns `{:ok, %Request{}}` immediately. Use `await/2` to wait for the result.

## Options

- `:tool_context` - Additional context map merged with agent's tool_context
- `:tools` - Request-scoped tool registry override for this run only
- `:allowed_tools` - Request-scoped allowlist of tool names
- `:request_transformer` - Module implementing per-turn ReAct request shaping
- `:max_iterations` - Request-scoped maximum reasoning iterations
- `:stream_timeout_ms` - Request-scoped runtime inactivity timeout.
  `:stream_receive_timeout_ms` is accepted as a compatibility alias.
- `:req_http_options` - Per-request Req HTTP options forwarded to ReAct runtime
- `:llm_opts` - Per-request ReqLLM generation options forwarded to ReAct runtime
- `:file_id` / `:file_ids` / `:file_reference` / `:file_references` - Uploaded
  file references appended to the user query as ReqLLM content parts when supported by the ReqLLM version
- `:output` - `:raw` to bypass structured output or a request-scoped output config
- `:stream_to` - Optional request-scoped runtime event sink, currently `{:pid, pid}`
- `:timeout` - Timeout for the underlying cast (default: no timeout)

## Examples

    {:ok, request} = MyAgent.ask(pid, "What is 2+2?")
    {:ok, result} = MyAgent.await(request)

# `ask_stream`

```elixir
@spec ask_stream(
  pid() | atom() | {:via, module(), term()},
  String.t() | [ReqLLM.Message.ContentPart.t()],
  keyword()
) ::
  {:ok, %{request: Jido.AI.Request.Handle.t(), events: Enumerable.t()}}
  | {:error, term()}
```

Send a query and return both its request handle and runtime event stream.

The returned enumerable yields canonical ReAct runtime events until the
request emits `:request_completed`, `:request_failed`, or
`:request_cancelled`.

## Options

Accepts the same options as `ask/3`, plus:
- `:stream_event_timeout_ms` - Optional mailbox receive timeout for the enumerable

## Examples

    {:ok, %{request: request, events: events}} = MyAgent.ask_stream(pid, "What is 2+2?")
    for event <- events do
      IO.inspect(event.kind)
    end
    {:ok, result} = MyAgent.await(request)

# `ask_sync`

```elixir
@spec ask_sync(
  pid() | atom() | {:via, module(), term()},
  String.t() | [ReqLLM.Message.ContentPart.t()],
  keyword()
) :: {:ok, any()} | {:error, term()}
```

Send a query and wait for the result synchronously.

Convenience wrapper that combines `ask/3` and `await/2`.

## Options

- `:tool_context` - Additional context map merged with agent's tool_context
- `:tools` - Request-scoped tool registry override for this run only
- `:allowed_tools` - Request-scoped allowlist of tool names
- `:request_transformer` - Module implementing per-turn ReAct request shaping
- `:max_iterations` - Request-scoped maximum reasoning iterations
- `:stream_timeout_ms` - Request-scoped runtime inactivity timeout.
  `:stream_receive_timeout_ms` is accepted as a compatibility alias.
- `:req_http_options` - Per-request Req HTTP options forwarded to ReAct runtime
- `:llm_opts` - Per-request ReqLLM generation options forwarded to ReAct runtime
- `:file_id` / `:file_ids` / `:file_reference` / `:file_references` - Uploaded
  file references appended to the user query as ReqLLM content parts when supported by the ReqLLM version
- `:output` - `:raw` to bypass structured output or a request-scoped output config
- `:timeout` - How long to wait in milliseconds (default: 30_000)

## Examples

    {:ok, result} = MyAgent.ask_sync(pid, "What is 2+2?", timeout: 10_000)

# `await`

```elixir
@spec await(
  Jido.AI.Request.Handle.t(),
  keyword()
) :: {:ok, any()} | {:error, term()}
```

Await the result of a specific request.

Blocks until the request completes, fails, or times out.

## Options

- `:timeout` - How long to wait in milliseconds (default: 30_000)

## Returns

- `{:ok, result}` - Request completed successfully
- `{:error, :timeout}` - Request didn't complete in time
- `{:error, reason}` - Request failed

## Examples

    {:ok, request} = MyAgent.ask(pid, "What is 2+2?")
    {:ok, "4"} = MyAgent.await(request, timeout: 10_000)

# `cancel`

```elixir
@spec cancel(
  pid() | atom() | {:via, module(), term()},
  keyword()
) :: :ok | {:error, term()}
```

Cancel an in-flight request.

Sends a cancellation signal to the agent. Note that this is advisory -
the underlying LLM request may still complete.

## Options

- `:reason` - Reason for cancellation (default: :user_cancelled)

## Examples

    {:ok, request} = MyAgent.ask(pid, "What is 2+2?")
    :ok = MyAgent.cancel(pid)

# `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.

# `chat`

```elixir
@spec chat(pid(), String.t(), keyword()) :: {:ok, String.t()} | {:error, term()}
```

Process a chat message and return a response.

This is the main entry point called by the AgentRunner wrapper.

# `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.Messaging.Demo.ChatAgent.cmd(agent, MyAction)
    {agent, directives} = Jido.Messaging.Demo.ChatAgent.cmd(agent, {MyAction, %{value: 42}})
    {agent, directives} = Jido.Messaging.Demo.ChatAgent.cmd(agent, [Action1, Action2])

    # With per-call options (merged into all instructions)
    {agent, directives} = Jido.Messaging.Demo.ChatAgent.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.

# `inject`

```elixir
@spec inject(pid() | atom() | {:via, module(), term()}, String.t(), keyword()) ::
  {:ok, Jido.Agent.t()} | {:error, term()}
```

Inject user-visible input into an active request.

This is intended for programmatic or inter-agent steering and follows the
same queuing rules as `steer/3`.

# `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.Messaging.Demo.ChatAgent.new()
    agent = Jido.Messaging.Demo.ChatAgent.new(id: "custom-id")
    agent = Jido.Messaging.Demo.ChatAgent.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_specs`

```elixir
@spec plugin_specs() :: [Jido.Plugin.Spec.t()]
@spec plugin_specs() :: [map()]
```

Returns the list of plugin specs attached to this agent.

# `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]

# `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.Messaging.Demo.ChatAgent.set(agent, %{status: :running})
    {:ok, agent} = Jido.Messaging.Demo.ChatAgent.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"]

# `steer`

```elixir
@spec steer(pid() | atom() | {:via, module(), term()}, String.t(), keyword()) ::
  {:ok, Jido.Agent.t()} | {:error, term()}
```

Steer an active request with additional user-visible input.

Returns `{:ok, agent}` when the input is queued for the current ReAct run
or `{:error, {:rejected, reason}}` when no eligible run is active.

Queued input is best-effort. If the run terminates before the runtime
drains the queue into conversation state, the queued input is dropped.

# `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.Messaging.Demo.ChatAgent.validate(agent)
    {:ok, agent} = Jido.Messaging.Demo.ChatAgent.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*
