Packages

Luagents is a library for building agents that can use Lua code to reason and act.

Current section

Files

Jump to
luagents lib luagents.ex
Raw

lib/luagents.ex

defmodule Luagents do
@moduledoc """
ReAct Agent implementation that thinks using Lua.
Inspired by smolagents but uses Lua for reasoning.
This module provides a high-level interface for creating and running ReAct agents
that use Lua code for step-by-step reasoning and tool execution.
## Quick Start
# Run a simple task with default configuration
{:ok, answer} = Luagents.run("What is 15 + 25?")
# Create a custom agent with specific LLM provider
agent = Luagents.create_agent(
name: "MathBot",
llm: Luagents.create_llm(:ollama, model: "mistral"),
max_iterations: 5
)
{:ok, result} = Luagents.run_with_agent(agent, "Calculate the area of a circle with radius 10")
## LLM Providers
Supports multiple LLM providers:
- `:anthropic` - Claude models (default)
- `:ollama` - Local Ollama models
## Built-in Tools
Comes with several built-in tools:
- `add(a, b)` - Add two numbers
- `multiply(a, b)` - Multiply two numbers
- `concat(strings)` - Concatenate strings
- `search(query)` - Search for information (mock)
"""
alias Luagents.{Agent, LLM, Memory, Tool}
## Public API
@doc """
Run a task with the default agent configuration.
Uses Anthropic Claude by default with all built-in tools.
## Options
- `:tools` - Map of tools to provide to the agent
- `:llm` - LLM instance to use (defaults to Ollama)
- `:max_iterations` - Maximum reasoning iterations (default: 10)
- `:name` - Agent name for identification
## Examples
# Simple calculation
{:ok, answer} = Luagents.run("What is 10 + 20?")
# With custom tools
custom_tools = Map.merge(Luagents.builtin_tools(), %{
"greet" => Luagents.create_tool("greet", "Say hello", [], fn _ -> {:ok, "Hello!"} end)
})
{:ok, response} = Luagents.run("Greet me", tools: custom_tools)
"""
@spec run(String.t(), Keyword.t()) :: {:ok, String.t()} | {:error, String.t()}
def run(task, opts \\ []) do
agent = create_agent(opts)
run_with_agent(agent, task)
end
@doc """
Create a new agent with custom configuration.
## Options
- `:name` - Agent name (default: "Luagent")
- `:llm` - LLM instance (default: Anthropic Claude)
- `:tools` - Map of available tools (default: builtin tools)
- `:max_iterations` - Maximum reasoning iterations (default: 10)
- `:memory` - Initial memory state (default: empty)
## Examples
# Basic agent
agent = Luagents.create_agent()
# Custom agent with Ollama
agent = Luagents.create_agent(
name: "LocalAgent",
llm: Luagents.create_llm(:ollama, model: "mistral"),
max_iterations: 15
)
# Agent with custom tools
agent = Luagents.create_agent(tools: %{
"custom" => Luagents.create_tool("custom", "Custom tool", [], fn _ -> "Custom tool" end)
})
"""
@spec create_agent(Keyword.t()) :: Agent.t()
def create_agent(opts \\ []) do
Agent.new(opts)
end
@doc """
Run a task with a specific agent instance.
This allows you to reuse an agent across multiple tasks, maintaining
any stateful configuration while getting fresh memory for each task.
## Examples
agent = Luagents.create_agent(name: "MathBot")
{:ok, result1} = Luagents.run_with_agent(agent, "What is 5 + 3?")
{:ok, result2} = Luagents.run_with_agent(agent, "What is 10 * 4?")
"""
@spec run_with_agent(Agent.t(), String.t()) :: {:ok, String.t()} | {:error, String.t()}
def run_with_agent(agent, task) do
Agent.run(agent, task)
end
## LLM Management
@doc """
Create an LLM instance for use with agents.
## Providers
- `:anthropic` - Claude models (requires ANTHROPIC_API_KEY)
- `:ollama` - Local Ollama models (requires Ollama server running)
## Examples
# Anthropic Claude model
llm = Luagents.create_llm(:anthropic, model: "claude-3-haiku-20240307")
# Ollama with local model
llm = Luagents.create_llm(:ollama, model: "mistral")
# Custom Ollama host
llm = Luagents.create_llm(:ollama, model: "mistral", host: "http://192.168.1.100:11434")
"""
@spec create_llm(LLM.provider(), Keyword.t()) :: LLM.t()
def create_llm(provider, opts \\ []) do
LLM.new([provider: provider] ++ opts)
end
@doc """
Create a custom tool for use with agents.
## Parameters
- `name` - Tool name (used in Lua code)
- `description` - Human-readable description
- `parameters` - List of parameter specifications
- `function_or_api` - Function that executes the tool or a module that implements the deflua API
## Examples
# Simple tool with no parameters
greet_tool = Luagents.create_tool(
"greet",
"Say hello",
[],
fn _ -> "Hello, World!" end
)
# Tool with parameters
power_tool = Luagents.create_tool(
"power",
"Raise a number to a power",
[
%{name: "base", type: :number, description: "Base number", required: true},
%{name: "exponent", type: :number, description: "Exponent", required: true}
],
fn [base, exp] -> :math.pow(base, exp) end
)
# Tool with deflua macro API
defmodule WebSearch do
use Lua.API
deflua search(query) do
# Implement search logic here
end
end
tool = Luagents.create_tool(
"search",
"Search the web",
[%{name: "query", type: :string, description: "Search query", required: true}],
WebSearch
)
"""
@spec create_tool(String.t(), String.t(), [Tool.parameter()], Tool.func() | Tool.api()) :: Tool.t()
def create_tool(name, description, parameters, function_or_api) do
Tool.new(name, description, parameters, function_or_api)
end
@doc """
Get the current memory state of an agent.
Returns the conversation history as a list of messages.
## Examples
agent = Luagents.create_agent()
# ... run some tasks ...
messages = Luagents.get_agent_memory(agent)
"""
@spec get_agent_memory(Agent.t()) :: [Memory.message()]
def get_agent_memory(%Agent{memory: memory}) do
Memory.get_messages(memory)
end
@doc """
Get agent configuration details.
## Examples
agent = Luagents.create_agent(name: "TestBot", max_iterations: 5)
info = Luagents.get_agent_info(agent)
# => %{name: "TestBot", max_iterations: 5, tool_count: 4, memory_size: 0}
"""
@spec get_agent_info(Agent.t()) :: map()
def get_agent_info(%Agent{} = agent) do
%{
name: agent.name,
max_iterations: agent.max_iterations,
tool_count: map_size(agent.tools),
memory_size: length(Memory.get_messages(agent.memory))
}
end
@doc """
Create an agent with cleared memory but same configuration.
Useful for starting fresh conversations with the same agent setup.
## Examples
agent = Luagents.create_agent(name: "Bot")
# ... run some tasks ...
fresh_agent = Luagents.reset_agent_memory(agent)
"""
@spec reset_agent_memory(Agent.t()) :: Agent.t()
def reset_agent_memory(%Agent{} = agent) do
%{agent | memory: Memory.new()}
end
end