Nous.Plugin behaviour (nous v0.13.3)
View SourceBehaviour for composable agent extensions.
Plugins allow you to extend agent capabilities without modifying the core agent or creating monolithic behaviour modules. Multiple plugins can be composed together.
Example
defmodule MyApp.Plugins.Logging do
@behaviour Nous.Plugin
@impl true
def init(_agent, ctx) do
ctx
end
@impl true
def before_request(_agent, ctx, _tools) do
IO.puts("Making LLM request with #{length(ctx.messages)} messages")
{ctx, []}
end
@impl true
def after_response(_agent, response, ctx) do
IO.puts("Got response: #{inspect(response.content)}")
ctx
end
endUsage
agent = Agent.new("openai:gpt-4",
plugins: [MyApp.Plugins.Logging, Nous.Plugins.TodoTracking]
)Callback Execution Order
Plugins are executed in list order. The context flows through each plugin sequentially for all hooks:
init/2— once at run startsystem_prompt/2— once, fragments joined into system messagetools/2— once per iteration, tools collectedbefore_request/3— before each LLM callafter_response/3— after each LLM responseafter_run/3— once after the entire run completes (post-loop)
Built-in Plugins
Nous.Plugins.TodoTracking- Automatic todo/task managementNous.Plugins.HumanInTheLoop- Human approval for tool callsNous.Plugins.Summarization- Context window management
Summary
Callbacks
Post-process after each LLM response.
Post-process after the entire agent run completes.
Pre-process before each LLM call.
Initialize the plugin when the agent run starts.
Contribute system prompt fragments.
Contribute additional tools for this agent run.
Functions
Collect system prompt fragments from all plugins.
Collect tools from all plugins.
Run after_response/3 across all plugins, threading context.
Run after_run/3 across all plugins, threading context.
Run before_request/3 across all plugins, threading context and tools.
Run init/2 across all plugins, threading context through each.
Callbacks
@callback after_response( agent :: Nous.Agent.t(), response :: Nous.Message.t(), ctx :: Nous.Agent.Context.t() ) :: Nous.Agent.Context.t()
Post-process after each LLM response.
Receives the LLM response message and current context. Return the updated context.
@callback after_run( agent :: Nous.Agent.t(), result :: map(), ctx :: Nous.Agent.Context.t() ) :: Nous.Agent.Context.t()
Post-process after the entire agent run completes.
Receives the agent, the final result map, and the final context. Return the updated context. Use this for end-of-run housekeeping like auto-updating memory.
@callback before_request( agent :: Nous.Agent.t(), ctx :: Nous.Agent.Context.t(), tools :: [Nous.Tool.t()] ) :: {Nous.Agent.Context.t(), [Nous.Tool.t()]}
Pre-process before each LLM call.
Receives the current context and tools list. Return the updated context and the updated tools list.
@callback init(agent :: Nous.Agent.t(), ctx :: Nous.Agent.Context.t()) :: Nous.Agent.Context.t()
Initialize the plugin when the agent run starts.
Use this to set up initial state in ctx.deps, register callbacks, etc.
Called once at the start of each Nous.Agent.run/3.
@callback system_prompt(agent :: Nous.Agent.t(), ctx :: Nous.Agent.Context.t()) :: String.t() | nil
Contribute system prompt fragments.
Return a string to append to the system prompt, or nil for no contribution. Fragments from all plugins are joined with newlines.
@callback tools(agent :: Nous.Agent.t(), ctx :: Nous.Agent.Context.t()) :: [Nous.Tool.t()]
Contribute additional tools for this agent run.
Return a list of Nous.Tool structs to add to the agent's tool set.
Called once per iteration before the LLM request.
Functions
@spec collect_system_prompts([module()], Nous.Agent.t(), Nous.Agent.Context.t()) :: String.t() | nil
Collect system prompt fragments from all plugins.
@spec collect_tools([module()], Nous.Agent.t(), Nous.Agent.Context.t()) :: [ Nous.Tool.t() ]
Collect tools from all plugins.
@spec run_after_response( [module()], Nous.Agent.t(), Nous.Message.t(), Nous.Agent.Context.t() ) :: Nous.Agent.Context.t()
Run after_response/3 across all plugins, threading context.
@spec run_after_run([module()], Nous.Agent.t(), map(), Nous.Agent.Context.t()) :: Nous.Agent.Context.t()
Run after_run/3 across all plugins, threading context.
@spec run_before_request([module()], Nous.Agent.t(), Nous.Agent.Context.t(), [ Nous.Tool.t() ]) :: {Nous.Agent.Context.t(), [Nous.Tool.t()]}
Run before_request/3 across all plugins, threading context and tools.
Each plugin receives the current tools and returns the updated tools list.
@spec run_init([module()], Nous.Agent.t(), Nous.Agent.Context.t()) :: Nous.Agent.Context.t()
Run init/2 across all plugins, threading context through each.