Documentation
¶
Overview ¶
Package loop implements the ReAct (Reasoning + Acting) agent loop.
Index ¶
- func IngestRecorderFrom(ctx context.Context) func(source, content string)
- func WithIngestRecorder(ctx context.Context, fn func(source, content string)) context.Context
- type Engine
- func (e *Engine) Run(ctx context.Context, task string) (string, error)
- func (e *Engine) RunWithMessages(ctx context.Context, messages []llm.Message) (string, []llm.Message, error)
- func (e *Engine) SetApprover(a danger.Approver)
- func (e *Engine) SetDangerousConfig(cfg *danger.DangerousConfig)
- func (e *Engine) SetEpisodeContextFunc(ef EpisodeContextFunc)
- func (e *Engine) SetInteractionMode(mode string)
- func (e *Engine) SetIterationCallback(cb IterationCallback)
- func (e *Engine) SetMaxToolParallel(n int)
- func (e *Engine) SetMemoryPromptFunc(fn func() string)
- func (e *Engine) SetModel(model string)
- func (e *Engine) SetNarrator(n *narrate.Narrator)
- func (e *Engine) SetSignalHandler(cb SignalHandler)
- func (e *Engine) SetSkillLoader(sl SkillLoader)
- func (e *Engine) SetSkillVerbose(verbose bool)
- func (e *Engine) SetThinking(thinking string)
- func (e *Engine) SetToolEventHandler(cb ToolEventHandler)
- func (e *Engine) SetUntrustedWrapper(fn func(source, content string) string)
- type EpisodeContextFunc
- type IterationCallback
- type IterationInfo
- type SignalEvent
- type SignalHandler
- type SkillLoader
- type ToolEventHandler
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IngestRecorderFrom ¶ added in v1.10.0
IngestRecorderFrom extracts the ingest recorder from ctx, if any.
func WithIngestRecorder ¶ added in v1.10.0
WithIngestRecorder returns a context that carries fn as the active ingest recorder. Callers such as cmd/odek wrapUntrusted use IngestRecorderFrom to read it back. Using a context value removes the package-global recorder that previously caused cross-session races in the WebUI.
Types ¶
type Engine ¶
type Engine struct {
// PromptCaching enables Anthropic/OpenAI/DeepSeek prompt caching markers.
// When enabled, the system prompt and first user message are annotated
// with cache_control markers, and the system prompt is moved to the
// dedicated "system" field for Anthropic compatibility.
PromptCaching bool
// MaxToolParallel controls how many tool calls run concurrently per
// iteration. 0 = use default (4). Models that support parallel tool
// calling (Claude 3.5+, GPT-4o, DeepSeek V4) can emit multiple tool
// calls in one response — this setting bounds concurrency so tools
// like read_file, search_files, and web_search run in parallel while
// avoiding resource exhaustion.
MaxToolParallel int
// Token accounting — accumulated across all iterations of the most recent run.
// Reset on each Run/RunWithMessages call and read by callers (e.g. WebUI).
TotalInputTokens int
TotalOutputTokens int
// Cache metrics accumulated across all iterations.
TotalCacheCreationTokens int // Anthropic: tokens written to cache
TotalCacheReadTokens int // Anthropic: tokens read from cache
TotalCachedTokens int // OpenAI: cached prompt tokens
// contains filtered or unexported fields
}
Engine runs the agent loop: observe → think → act → repeat.
func New ¶
func New(client *llm.Client, registry *tool.Registry, maxIterations int, systemMessage string, renderer *render.Renderer, maxContext int) *Engine
New creates a new loop Engine. maxContext is the model's maximum context window in tokens. Pass 0 for no limit enforcement.
func (*Engine) RunWithMessages ¶
func (e *Engine) RunWithMessages(ctx context.Context, messages []llm.Message) (string, []llm.Message, error)
RunWithMessages executes the agent loop starting from a pre-built message history. The messages must include the system prompt (if any), all prior conversation turns, and the new user message as the last entry. Returns the final answer plus the full updated message history so callers can persist it (e.g. to a session file).
Use this for multi-turn conversations: load the session, append the new user message, call RunWithMessages, then save the returned messages.
func (*Engine) SetApprover ¶
SetApprover sets the approval gate for dangerous operations. When set and the LLM returns multiple tool calls in one iteration, a single batch approval prompt is shown. Individual tool-level approval is bypassed when the batch is approved (if the approver supports SetTrustAll).
func (*Engine) SetDangerousConfig ¶
func (e *Engine) SetDangerousConfig(cfg *danger.DangerousConfig)
SetDangerousConfig provides the DangerousConfig for batch gate pre-classification. Without it, the batch gate cannot know which risk classes require approval and would skip pre-checking.
func (*Engine) SetEpisodeContextFunc ¶
func (e *Engine) SetEpisodeContextFunc(ef EpisodeContextFunc)
SetEpisodeContextFunc sets the optional per-turn episode search callback. When set, it is called once per new user message to search for relevant past session episodes. The returned context is injected as a system message before the LLM invocation.
func (*Engine) SetInteractionMode ¶
SetInteractionMode sets how progress is surfaced. "off" suppresses all per-iteration render output except the final answer.
func (*Engine) SetIterationCallback ¶
func (e *Engine) SetIterationCallback(cb IterationCallback)
SetIterationCallback sets the iteration progress callback. If nil, no callback is fired.
func (*Engine) SetMaxToolParallel ¶
SetMaxToolParallel sets the maximum concurrency for tool execution per iteration. 0 or negative = use default (4).
func (*Engine) SetMemoryPromptFunc ¶
SetMemoryPromptFunc sets the optional memory prompt callback. When set, it is called before each LLM invocation to get fresh memory content. This ensures the agent sees the latest facts even if it modifies memory during a session.
func (*Engine) SetModel ¶
SetModel updates the LLM model used by this engine at runtime. The model string must be a valid OpenAI-compatible model identifier.
func (*Engine) SetNarrator ¶
SetNarrator sets the optional narrator for engaging mode. When nil (the default), tools render in verbose mode via the Renderer.
func (*Engine) SetSignalHandler ¶ added in v1.2.0
func (e *Engine) SetSignalHandler(cb SignalHandler)
SetSignalHandler sets the optional agent-loop signal callback. Passing nil disables signal emission.
func (*Engine) SetSkillLoader ¶
func (e *Engine) SetSkillLoader(sl SkillLoader)
SetSkillLoader sets the optional skill loader callback.
func (*Engine) SetSkillVerbose ¶
SetSkillVerbose controls whether skill loading shows full banners (true) or condensed markers (false, default). Condensed saves context window space.
func (*Engine) SetThinking ¶ added in v1.0.0
SetThinking updates the thinking/reasoning mode used by this engine at runtime. Accepts the same values as Config.Thinking: "enabled", "disabled", "low", "medium", "high", or "" (provider default). Safe to call between RunWithMessages calls.
func (*Engine) SetToolEventHandler ¶
func (e *Engine) SetToolEventHandler(cb ToolEventHandler)
SetToolEventHandler sets the optional tool event callback for live streaming.
func (*Engine) SetUntrustedWrapper ¶ added in v1.8.0
SetUntrustedWrapper sets a function that wraps externally-sourced content (skill context, episode context) with a nonce'd boundary before injecting it into the model's system context. When nil, that content is injected directly.
type EpisodeContextFunc ¶
EpisodeContextFunc is an optional callback that the loop engine calls before each LLM invocation to discover relevant past session episodes. The callback receives the latest user input as a search query and returns formatted episode context to inject, or empty string if nothing matches.
type IterationCallback ¶
type IterationCallback func(info IterationInfo)
IterationCallback is an optional callback invoked after each iteration of the agent loop. Used by Telegram/WebUI for progress reporting.
type IterationInfo ¶
type IterationInfo struct {
Turn int // current iteration (1-indexed)
MaxTurns int // max iterations configured
ToolNames []string // tools called this turn (duplicates possible)
InputTokens int // cumulative input tokens
OutputTokens int // cumulative output tokens
CacheCreationTokens int // cumulative cache creation tokens
CacheReadTokens int // cumulative cache read tokens
CachedTokens int // cumulative cached tokens (OpenAI)
TotalLatency time.Duration // cumulative wall time
HasFinalAnswer bool // true when the agent reached a final answer
ReasoningContent string // LLM reasoning before tool calls (empty if none)
IsPreTool bool // true when fired BEFORE tool execution (shows reasoning + tools)
}
IterationInfo holds data about a single agent loop iteration, passed to the IterationCallback after each turn. Used for progress reporting.
type SignalEvent ¶ added in v1.2.0
type SignalEvent struct {
// Type is the signal kind. One of:
// "context_trimmed" — prior message groups were dropped to fit the token
// budget (Count = groups dropped, Detail = "proactive"
// for the pre-call budget trim or "survival" for the
// post-error nuclear trim)
// "tool_recovery" — a tool failed repeatedly and the engine injected a
// corrective hint so the model changes approach
// (Tool = failing tool, Detail = the correction)
Type string
Detail string // human-readable detail (mode, correction text, etc.)
Tool string // tool name for tool_recovery
Count int // groups dropped (context_trimmed)
Timestamp time.Time // when the signal fired (UTC)
}
SignalEvent represents an internal agent-loop signal that was previously invisible to the operator — moments where the engine silently intervened to keep the session alive or productive. Surfacing these closes observability gaps around context management and tool-failure recovery.
Not every field is set for every Type; the zero value means "not applicable".
type SignalHandler ¶ added in v1.2.0
type SignalHandler func(event SignalEvent)
SignalHandler receives agent-loop signal events. Implementations must be non-blocking — signals fire inside the hot loop.
type SkillLoader ¶
SkillLoader is an optional callback that the loop engine calls before each LLM invocation to discover contextually relevant skills. The callback receives the latest user input and returns additional system context (formatted skill content) to inject, or empty string if no skills match.
type ToolEventHandler ¶
ToolEventHandler is an optional callback invoked for each tool execution during the agent loop — fires before (tool_call) and after (tool_result) each tool invocation. Used by the WebUI for live streaming of tool events.