Packages
nous
0.9.0
0.17.0
0.16.6
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.17
0.12.16
0.12.15
0.12.14
0.12.13
0.12.12
0.12.11
0.12.9
0.12.7
0.12.6
0.12.5
0.12.3
0.12.2
0.12.0
0.11.3
0.11.0
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.5.0
AI agent framework for Elixir with multi-provider LLM support
Current section
Files
Jump to
Current section
Files
lib/nous/agents/basic_agent.ex
defmodule Nous.Agents.BasicAgent do
@moduledoc """
Default agent implementation with standard tool-calling behavior.
BasicAgent implements the `Nous.Agent.Behaviour` and provides:
- Standard message building with system prompts
- Simple tool call detection and execution
- Text extraction from assistant responses
This is the default behaviour used when no `behaviour_module` is specified.
## Example
agent = Agent.new("openai:gpt-4",
instructions: "Be helpful",
tools: [&search/2]
)
# Uses BasicAgent by default
{:ok, result} = Agent.run(agent, "Search for Elixir tutorials")
"""
@behaviour Nous.Agent.Behaviour
alias Nous.{Message, Messages}
alias Nous.Agent.Context
@doc """
Build messages to send to the LLM.
Combines system prompt (if any) with conversation messages.
"""
@impl true
def build_messages(_agent, ctx) do
# Start with messages from context
messages = ctx.messages
# If system prompt not already in messages, add it
has_system = Enum.any?(messages, &Message.is_system?/1)
if not has_system and ctx.system_prompt do
[Message.system(ctx.system_prompt) | messages]
else
messages
end
end
@doc """
Process a response from the LLM.
Adds the response to context and updates `needs_response` based on
whether there are tool calls to process.
"""
@impl true
def process_response(_agent, response, ctx) do
# Add message to context - this also updates needs_response
Context.add_message(ctx, response)
end
@doc """
Extract the final output from the context.
Returns the text content of the last assistant message.
"""
@impl true
def extract_output(_agent, ctx) do
case Context.last_message(ctx) do
%Message{role: :assistant} = msg ->
{:ok, Messages.extract_text(msg)}
%Message{role: :tool} ->
# Last message was a tool result, look for preceding assistant message
case find_last_assistant_message(ctx.messages) do
nil -> {:error, :no_output}
msg -> {:ok, Messages.extract_text(msg)}
end
nil ->
{:error, :no_output}
_other ->
{:error, :no_output}
end
end
@doc """
Get tools available for this agent.
Returns the tools configured on the agent.
"""
@impl true
def get_tools(agent) do
agent.tools
end
# Private helpers
defp find_last_assistant_message(messages) do
messages
|> Enum.reverse()
|> Enum.find(&(&1.role == :assistant))
end
end