Skip to main content

examples/demo.exs

# Run with: mix run examples/demo.exs
#
# A self-contained demo of the agent loop using the in-process TestModel —
# no API key needed. Shows: instructions, a tool that takes the RunContext
# (dependency injection), and the final structured result.

alias ExAgent.{Tool, RunContext}
alias ExAgent.Message.Part

balance_tool =
  Tool.new(
    name: "get_balance",
    description: "Return the account balance for the current customer.",
    parameters_json_schema: %{type: "object", properties: %{}},
    takes_ctx: true,
    call: fn %RunContext{deps: %{customer_id: id}}, _args ->
      {:ok, 123.45 * id}
    end
  )

# The TestModel is scripted: first it calls the tool, then it writes the final answer.
model = %ExAgent.Models.Test{
  script: [
    {:tool_calls, [%Part.ToolCall{tool_name: "get_balance", args: %{}}]},
    "Your balance is ready. (final answer)"
  ]
}

agent =
  ExAgent.new(
    model: model,
    instructions: "You are a bank assistant.",
    tools: [balance_tool]
  )

{:ok, result} = ExAgent.run(agent, "What's my balance?", deps: %{customer_id: 2})

IO.puts("=== OUTPUT ===")
IO.inspect(result.output, label: "output")

IO.puts("\n=== MESSAGE HISTORY ===")

Enum.each(result.messages, fn msg ->
  case msg do
    %ExAgent.Message.Request{parts: parts} ->
      IO.puts("[Request]")
      Enum.each(parts, &IO.inspect/1)

    %ExAgent.Message.Response{parts: parts} ->
      IO.puts("[Response]")
      Enum.each(parts, &IO.inspect/1)
  end
end)

IO.puts("\n=== USAGE ===")
IO.inspect(result.usage, label: "usage")