Agent Framework
The agent package provides multi-agent orchestration with automatic tool execution, session management, persistent memory, sub-agents, handoffs, fan-out, team coordination, and context strategies.
Basic Agent
import (
"github.com/joakimcarlsson/ai/agent"
"github.com/joakimcarlsson/ai/session"
)
myAgent := agent.New(llmClient,
agent.WithSystemPrompt("You are a helpful assistant."),
agent.WithTools(&weatherTool{}),
agent.WithSession("user-123", session.FileStore("./sessions")),
)
response, _ := myAgent.Chat(ctx, "What's the weather in Tokyo?")
fmt.Println(response.Content)
How It Works
When you call Chat(), the agent:
- Builds the message history (system prompt + session messages + user message)
- Sends messages to the LLM
- If the LLM requests tool calls, executes them automatically
- Loops back to step 2 with tool results until the LLM responds with text
- Persists the conversation to the session store
Configuration Options
| Option | Description | Default |
|---|---|---|
WithSystemPrompt(prompt) |
Sets the agent's behavior | none |
WithTools(tools...) |
Adds tools the agent can use | none |
WithSession(id, store) |
Enables conversation persistence | none |
WithMemory(id, store, opts...) |
Enables long-term memory | none |
WithMaxIterations(n) |
Max tool execution loops | 10 |
WithAutoExecute(bool) |
Auto-execute tool calls | true |
WithContextStrategy(strategy, maxTokens) |
Context window management | none |
WithSequentialToolExecution() |
Disable parallel tool execution | parallel |
WithMaxParallelTools(n) |
Limit concurrent tool execution | unlimited |
WithState(map) |
Template variables for system prompt | none |
WithInstructionProvider(fn) |
Dynamic system prompt generation | none |
WithHooks(hooks...) |
Add hook interceptors for observation/interception | none |
WithConfirmationProvider(fn) |
Require human approval for sensitive tools | none |
WithSubAgents(configs...) |
Register child agents | none |
WithHandoffs(configs...) |
Register peer agents for transfer | none |
WithFanOut(configs...) |
Register parallel task distribution | none |
WithTeam(config) |
Enable team coordination with peer-to-peer messaging | none |
WithCoordinatorMode() |
Restrict lead agent to team-only tools | disabled |
WithTeammateTemplates(map) |
Pre-configured agent templates for teammates | none |
ChatResponse
type ChatResponse struct {
Content string
ToolCalls []message.ToolCall
ToolResults []ToolExecutionResult
Usage llm.TokenUsage
FinishReason message.FinishReason
AgentName string // Set when a handoff occurred
TotalToolCalls int
TotalDuration time.Duration
TotalTurns int
}
All metrics are aggregated across the full agent loop, not just the final LLM call:
| Field | Description |
|---|---|
TotalTurns |
Number of LLM round-trips (API calls) made |
TotalDuration |
Wall-clock time from Chat() entry to return |
TotalToolCalls |
Total tool invocations across all iterations |
ToolResults |
Results of every tool execution during the conversation |
FinishReason |
Why the agent stopped: FinishReasonStop (natural completion), FinishReasonMaxTokens (hit context limit), FinishReasonToolUse (tool required), or FinishReasonMaxIterations (hit tool loop limit) |
Finish Reasons and Max Iterations
The FinishReason indicates why the agent loop terminated:
- FinishReasonStop: The agent naturally completed its task and produced a final text response.
- FinishReasonMaxTokens: The LLM hit its configured token limit during generation.
- FinishReasonToolUse: The agent returned pending tool calls. This occurs either because WithAutoExecute(false) is set (see Continue/Resume), or because a tool requires human confirmation (see Confirmation).
- FinishReasonMaxIterations: The agent hit the loop limit configured by WithMaxIterations(n) (default 10) before completing its task. When this occurs, the agent can no longer execute tools automatically. You can intercept this behavior by registering a Continuation Provider.
Debug APIs
Inspect the messages that would be sent to the LLM after applying context strategies:
// Non-destructive — does not modify the session
messages, err := myAgent.PeekContextMessages(ctx, "Hello")
// Modifying — adds the user message to the session
messages, err := myAgent.BuildContextMessages(ctx, "Hello")
Use PeekContextMessages to debug context window management without side effects.