agentcore

package module
v1.6.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 24, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

README

AgentCore

AgentCore is a minimal, composable Go library for building AI agent applications.

English | 中文

Install

go get github.com/voocel/agentcore

Design Philosophy

A restrained core with open extensibility tends to be more reliable than a complex all-in-one solution. Fewer built-ins, more possibilities.

Stability

  • Keep Agent, AgentLoop, Event, Tool, and Message stable first
  • Behavioral changes should come with tests first; examples/ and internal implementation details are not stable API

Architecture

agentcore/            Agent core (types, loop, agent, events, subagent)
agentcore/llm/        LLM adapters (OpenAI, Anthropic, Gemini via litellm)
agentcore/tools/      Built-in tools: read, write, edit, bash
agentcore/context/    Context runtime — projection, rewrite, overflow recovery

Core design:

  • Standalone dual-loop core (loop.go) — free function, all dependencies injected via parameters. Double loop: inner processes tool calls + steering, outer handles follow-up
  • Stateful Agent (agent.go) — sole consumer of loop events, updates internal state then dispatches to external listeners
  • Event stream — single <-chan Event output drives any UI (TUI, Web, Slack, logging)
  • Two-stage pipelineTransformContext (prune/inject) → ConvertToLLM (filter to LLM messages)
  • SubAgent tool (subagent.go) — multi-agent via tool invocation, four modes: single, parallel, chain, background
  • Context runtime (context/) — projection, committed rewrite, and overflow recovery near the context window limit

Quick Start

Single Agent
package main

import (
    "fmt"
    "os"

    "github.com/voocel/agentcore"
    "github.com/voocel/agentcore/llm"
    "github.com/voocel/agentcore/permission"
    "github.com/voocel/agentcore/tools"
)

func main() {
    model, err := llm.NewOpenAIModel("gpt-5-mini", os.Getenv("OPENAI_API_KEY"))
    if err != nil {
        panic(err)
    }

    agent := agentcore.NewAgent(
        agentcore.WithModel(model),
        agentcore.WithSystemPrompt("You are a helpful coding assistant."),
        agentcore.WithTools(
            tools.NewRead("."),
            tools.NewWrite("."),
            tools.NewEdit("."),
            tools.NewBash("."),
        ),
        agentcore.WithPermissionEngine(permission.NewEngine(permission.EngineConfig{
            Workspace: ".",
            Mode:      permission.ModeBalanced,
        })),
    )

    agent.Subscribe(func(ev agentcore.Event) {
        if ev.Type == agentcore.EventMessageEnd {
            if msg, ok := ev.Message.(agentcore.Message); ok && msg.Role == agentcore.RoleAssistant {
                fmt.Println(msg.Content)
            }
        }
    })

    agent.Prompt("List the files in the current directory.")
    agent.WaitForIdle()
}

For stricter control, pass a custom decision engine with agentcore.WithPermissionEngine(...).

engine := permission.NewEngine(permission.EngineConfig{
    Workspace: ".",
    Mode:      permission.ModeStrict,
    Roots: permission.FilesystemRoots{
        ReadRoots:  []string{"."},
        WriteRoots: []string{"."},
    },
})
Multi-Agent (SubAgent Tool)

Sub-agents are invoked as regular tools with isolated contexts:

model, _ := llm.NewOpenAIModel("gpt-5-mini", apiKey)

scout := agentcore.SubAgentConfig{
    Name:         "scout",
    Description:  "Fast codebase reconnaissance",
    Model:        model,
    SystemPrompt: "Quickly explore and report findings. Be concise.",
    Tools:        []agentcore.Tool{tools.NewRead("."), tools.NewBash(".")},
    MaxTurns:     5,
}

worker := agentcore.SubAgentConfig{
    Name:         "worker",
    Description:  "General-purpose executor",
    Model:        model,
    SystemPrompt: "Implement tasks given to you.",
    Tools:        []agentcore.Tool{tools.NewRead("."), tools.NewWrite("."), tools.NewEdit("."), tools.NewBash(".")},
}

agent := agentcore.NewAgent(
    agentcore.WithModel(model),
    agentcore.WithTools(agentcore.NewSubAgentTool(scout, worker)),
)

Four execution modes via tool call:

// Single: one agent, one task
{"agent": "scout", "task": "Find all API endpoints"}

// Parallel: concurrent execution
{"tasks": [{"agent": "scout", "task": "Find auth code"}, {"agent": "scout", "task": "Find DB schema"}]}

// Chain: sequential with {previous} context passing
{"chain": [{"agent": "scout", "task": "Find auth code"}, {"agent": "worker", "task": "Refactor based on: {previous}"}]}

// Background: async execution, returns immediately, notifies on completion
{"agent": "worker", "task": "Run full test suite", "background": true, "description": "Running tests"}
Steering & Follow-Up
// Interrupt mid-run (delivered after current tool, remaining tools skipped)
agent.Steer(agentcore.UserMsg("Stop and focus on tests instead."))

// Queue for after the agent finishes
agent.FollowUp(agentcore.UserMsg("Now run the tests."))

// Cancel immediately
agent.Abort()
Event Stream

All lifecycle events flow through a single channel — subscribe to drive any UI:

agent.Subscribe(func(ev agentcore.Event) {
    switch ev.Type {
    case agentcore.EventMessageStart:    // assistant starts streaming
    case agentcore.EventMessageUpdate:   // streaming token delta
    case agentcore.EventMessageEnd:      // message complete
    case agentcore.EventToolExecStart:   // tool execution begins
    case agentcore.EventToolExecEnd:     // tool execution ends
    case agentcore.EventError:           // error occurred
    }
})
Structured Tool Progress

Long-running tools can emit structured progress updates instead of ad-hoc JSON:

agentcore.ReportToolProgress(ctx, agentcore.ProgressPayload{
    Kind:    agentcore.ProgressSummary,
    Agent:   "worker",
    Tool:    "bash",
    Summary: "worker → bash",
})

Subscribers should read ev.Progress directly for tool progress updates:

agent.Subscribe(func(ev agentcore.Event) {
    if ev.Type == agentcore.EventToolExecUpdate && ev.Progress != nil {
        fmt.Printf("[%s] %s\n", ev.Progress.Kind, ev.Progress.Summary)
    }
})
Swappable Models

When a model needs to change at runtime, wrap it with SwappableModel. The swap takes effect on the next call. SubAgentConfig.Model is resolved at the start of each sub-agent run, so the same wrapper also works for sub-agents.

defaultModel, _ := llm.NewOpenAIModel("gpt-5-mini", apiKey)
sw := agentcore.NewSwappableModel(defaultModel)

agent := agentcore.NewAgent(agentcore.WithModel(sw))

nextModel, _ := llm.NewOpenAIModel("gpt-5", apiKey)
sw.Swap(nextModel) // next turn uses the new model
Custom LLM (StreamFn)

Swap the LLM call with a proxy, mock, or custom implementation:

agent := agentcore.NewAgent(
    agentcore.WithStreamFn(func(ctx context.Context, req *agentcore.LLMRequest) (*agentcore.LLMResponse, error) {
        // Route to your own proxy/gateway
        return callMyProxy(ctx, req)
    }),
)
Context Compaction

Auto-summarize conversation history when approaching the context window limit. Use the built-in context manager:

import (
    "github.com/voocel/agentcore"
    agentctx "github.com/voocel/agentcore/context"
)

engine := agentctx.NewDefaultEngine(model, 128000)

agent := agentcore.NewAgent(
    agentcore.WithModel(model),
    agentcore.WithContextManager(engine),
)

NewAgent auto-wires ConvertToLLM, token estimation, and context window from the context manager when available.

On each LLM call, the context manager first builds a projected prompt view for the next model request. When a rewrite should become the new runtime baseline, it can return ShouldCommit=true with CommitMessages, and the loop will replace the in-memory baseline before continuing.

When usage exceeds ContextWindow - ReserveTokens (default 16384), compaction:

  1. Keeps recent messages (default 20000 tokens)
  2. Summarizes older messages via LLM into a structured checkpoint (Goal / Progress / Key Decisions / Next Steps)
  3. Tracks file operations (read/write/edit paths) across compacted messages
  4. Supports incremental updates — subsequent compactions update the existing summary rather than re-summarizing
Context Pipeline

For simpler transform-only pipelines, WithContextPipeline / WithTransformContext still work:

agent := agentcore.NewAgent(
    // Stage 1: prune old messages, inject external context
    agentcore.WithTransformContext(func(ctx context.Context, msgs []agentcore.AgentMessage) ([]agentcore.AgentMessage, error) {
        if len(msgs) > 100 {
            msgs = msgs[len(msgs)-50:]
        }
        return msgs, nil
    }),
    // Stage 2: filter to LLM-compatible messages
    agentcore.WithConvertToLLM(func(msgs []agentcore.AgentMessage) []agentcore.Message {
        var out []agentcore.Message
        for _, m := range msgs {
            if msg, ok := m.(agentcore.Message); ok {
                out = append(out, msg)
            }
        }
        return out
    }),
)

Built-in Tools

Tool Description
read Read file contents with head truncation (2000 lines / 50KB)
write Write file with auto-mkdir
edit Exact text replacement with fuzzy match, BOM/line-ending normalization, unified diff output
bash Execute shell commands with tail truncation (2000 lines / 50KB)

Runtime Injection

Use Inject(msg) when the caller's intent is "deliver this as soon as the current agent state allows" without manually branching on running vs idle state.

result, err := agent.Inject(agentcore.UserMsg("Re-check unfinished tasks before stopping."))
if err != nil {
    panic(err)
}
fmt.Println(result.Disposition)

Inject has three outcomes:

  • steered_current_run: the agent is running, so the message was queued into the current run's steering path
  • resumed_idle_run: the agent was idle with an assistant-tail conversation, so the message was queued and Continue() was started immediately
  • queued: the message was queued, but no run was started

Use the lower-level APIs when you need stricter control:

  • Steer(msg): queue for the steering path without any idle auto-resume logic
  • FollowUp(msg): queue for after the current run stops
  • prompt-side injection: keep this in the application layer if the message must be merged into the next explicit user prompt rather than the agent queues

API Reference

Agent
Method Description
NewAgent(opts...) Create agent with options
Prompt(input) Start new conversation turn
PromptMessages(msgs...) Start turn with arbitrary AgentMessages
Continue() Resume from current context
Inject(msg) Deliver message via steer / idle resume / queue, depending on current state
Steer(msg) Inject steering message mid-run
FollowUp(msg) Queue message for after completion
Abort() Cancel current execution
AbortSilent() Cancel without emitting abort marker
WaitForIdle() Block until agent finishes
Subscribe(fn) Register event listener
State() Snapshot of current state
ExportMessages() Export messages for serialization
ImportMessages(msgs) Import deserialized messages

License

Apache License 2.0

Documentation

Index

Constants

View Source
const BackgroundTaskCompletedTag = "background-task-completed"

Variables

This section is empty.

Functions

func AgentLoop

func AgentLoop(ctx context.Context, prompts []AgentMessage, agentCtx AgentContext, config LoopConfig) <-chan Event

AgentLoop starts an agent loop with new prompt messages. Prompts are added to context and events are emitted for them.

func AgentLoopContinue

func AgentLoopContinue(ctx context.Context, agentCtx AgentContext, config LoopConfig) <-chan Event

AgentLoopContinue continues from existing context without adding new messages. The last message in context must convert to user or tool role via ConvertToLLM.

func AssertMessageSequence added in v1.6.0

func AssertMessageSequence(msgs []Message) error

AssertMessageSequence returns an error when the transcript would require synthetic repair before being sent to an LLM provider.

func IsContextOverflow

func IsContextOverflow(err error) bool

IsContextOverflow reports whether the error indicates a context window overflow.

func ReactivateDeferred added in v1.5.2

func ReactivateDeferred(tools []Tool, msgs []AgentMessage)

ReactivateDeferred scans restored messages for tool_reference blocks and pre-activates them via the DeferActivator found in tools. This must be called after restoring a session to avoid "Tool reference not found" errors.

func ReportToolProgress

func ReportToolProgress(ctx context.Context, progress ProgressPayload)

ReportToolProgress reports structured progress during tool execution. Silently ignored if no callback is registered in the context.

func WithToolProgress

func WithToolProgress(ctx context.Context, fn ToolProgressFunc) context.Context

WithToolProgress injects a progress callback into the context.

Types

type ActivityDescriber added in v1.6.0

type ActivityDescriber interface {
	ActivityDescription(args json.RawMessage) string
}

ActivityDescriber is an optional interface for tools that provide a human-readable activity description for UI display.

type Agent

type Agent struct {
	// contains filtered or unexported fields
}

Agent is a stateful wrapper around the agent loop. It consumes loop events to update internal state, just like any external listener.

func NewAgent

func NewAgent(opts ...AgentOption) *Agent

NewAgent creates a new Agent with the given options.

When a ContextManager is set, the agent automatically wires ConvertToLLM and ContextEstimate from the manager if the manager implements the optional ContextLLMConverter and/or ContextEstimator interfaces — no need to set them manually.

func (*Agent) Abort

func (a *Agent) Abort()

Abort cancels the current execution and emits an abort marker message so the LLM knows the user interrupted.

func (*Agent) AbortSilent added in v1.5.1

func (a *Agent) AbortSilent()

AbortSilent cancels the current execution without emitting an abort marker. Use for programmatic cancellation (e.g. plan mode transitions) where the cancellation is not a user interruption.

func (*Agent) BaselineContextUsage added in v1.6.1

func (a *Agent) BaselineContextUsage() *ContextUsage

BaselineContextUsage returns the current runtime baseline occupancy. Unlike ContextUsage, this never reports a transient projected view.

func (*Agent) BuildLLMMessages added in v1.5.6

func (a *Agent) BuildLLMMessages() ([]Message, error)

BuildLLMMessages constructs the message list exactly as the agent loop would for an LLM call: system blocks/prompt → converted conversation messages. This enables external callers (e.g., prompt suggestion) to make background LLM calls that share the same message prefix for prompt cache hits. Strict message-sequence mode is honored here just like in the main loop.

func (*Agent) ClearAllQueues

func (a *Agent) ClearAllQueues()

ClearAllQueues removes all queued steering and follow-up messages.

func (*Agent) ClearFollowUpQueue

func (a *Agent) ClearFollowUpQueue()

ClearFollowUpQueue removes all queued follow-up messages.

func (*Agent) ClearMessages

func (a *Agent) ClearMessages()

ClearMessages resets the message history.

func (*Agent) ClearSteeringQueue

func (a *Agent) ClearSteeringQueue()

ClearSteeringQueue removes all queued steering messages.

func (*Agent) ContextSnapshot added in v1.6.1

func (a *Agent) ContextSnapshot() *ContextSnapshot

ContextSnapshot returns the latest context-manager snapshot for observability. Returns nil when no ContextManager is configured or no snapshot is available.

func (*Agent) ContextUsage

func (a *Agent) ContextUsage() *ContextUsage

ContextUsage returns an estimate of the current context window occupancy. Returns nil if contextWindow or contextEstimateFn is not configured.

func (*Agent) Continue

func (a *Agent) Continue() error

Continue resumes from the current context without adding new messages. If the last message is from assistant, it dequeues steering/follow-up

func (*Agent) ExportMessages

func (a *Agent) ExportMessages() []Message

ExportMessages returns concrete Messages for serialization.

func (*Agent) FollowUp

func (a *Agent) FollowUp(msg AgentMessage)

FollowUp queues a message to be processed after the agent finishes.

func (*Agent) HasQueuedMessages

func (a *Agent) HasQueuedMessages() bool

HasQueuedMessages reports whether any steering or follow-up messages are queued.

func (*Agent) ImportMessages

func (a *Agent) ImportMessages(msgs []Message) error

ImportMessages replaces message history from deserialized Messages.

func (*Agent) Inject added in v1.5.7

func (a *Agent) Inject(msg AgentMessage) (InjectResult, error)

Inject delivers a message as soon as the current agent state allows.

Outcomes:

  • running → steer into current run
  • idle + assistant tail → enqueue and Continue()
  • idle + no assistant tail → enqueue for next run

Returns an error if idle resume was attempted but Continue() failed. In that case the message remains in the steering queue and will be delivered on the next run.

func (*Agent) Messages

func (a *Agent) Messages() []AgentMessage

Messages returns the current message history.

func (*Agent) Prompt

func (a *Agent) Prompt(input string) error

Prompt starts a new conversation turn with the given input.

func (*Agent) PromptMessages

func (a *Agent) PromptMessages(msgs ...AgentMessage) error

PromptMessages starts a new conversation turn with arbitrary AgentMessages.

func (*Agent) Reset

func (a *Agent) Reset()

Reset clears all state and queues. If the agent is running, it cancels and waits first.

func (*Agent) SetContextWindow added in v1.5.2

func (a *Agent) SetContextWindow(n int)

SetContextWindow updates the context window size (in tokens).

func (*Agent) SetMessages

func (a *Agent) SetMessages(msgs []AgentMessage) error

SetMessages replaces the message history (e.g. to restore a previous conversation). The agent must not be running.

func (*Agent) SetModel

func (a *Agent) SetModel(m ChatModel)

SetModel changes the LLM provider. Takes effect on the next turn.

func (*Agent) SetSystemBlocks added in v1.5.2

func (a *Agent) SetSystemBlocks(blocks []SystemBlock)

SetSystemBlocks sets a multi-block system prompt with per-block cache control. Takes precedence over SetSystemPrompt. Clears the single-string prompt.

func (*Agent) SetSystemPrompt

func (a *Agent) SetSystemPrompt(s string)

SetSystemPrompt changes the system prompt (single-string mode). Clears any multi-block system prompt set via SetSystemBlocks.

func (*Agent) SetThinkingLevel

func (a *Agent) SetThinkingLevel(level ThinkingLevel)

SetThinkingLevel changes the reasoning depth. Takes effect on the next turn.

func (*Agent) SetTools

func (a *Agent) SetTools(tools ...Tool)

SetTools replaces the tool set. Takes effect on the next turn.

func (*Agent) State

func (a *Agent) State() AgentState

State returns a snapshot of the agent's current state.

func (*Agent) Steer

func (a *Agent) Steer(msg AgentMessage)

Steer queues a steering message to interrupt the agent mid-run. Delivered after the current tool execution; remaining tools are skipped.

func (*Agent) StopAllTasks added in v1.6.0

func (a *Agent) StopAllTasks() int

StopAllTasks cancels all running background tasks.

func (*Agent) StopTask added in v1.6.0

func (a *Agent) StopTask(id string) bool

StopTask cancels a running background task by ID.

func (*Agent) Subscribe

func (a *Agent) Subscribe(fn func(Event)) func()

Subscribe registers a listener for agent events. Returns an unsubscribe function.

func (*Agent) TaskRuntime added in v1.6.0

func (a *Agent) TaskRuntime() *TaskRuntime

TaskRuntime returns the shared TaskRuntime, or nil if not configured.

func (*Agent) Tasks added in v1.6.0

func (a *Agent) Tasks() []BackgroundTaskEntry

Tasks returns snapshots of all background tasks. Returns nil if no TaskRuntime is configured.

func (*Agent) TotalUsage

func (a *Agent) TotalUsage() Usage

TotalUsage returns the cumulative token usage across all turns.

func (*Agent) WaitForIdle

func (a *Agent) WaitForIdle()

WaitForIdle blocks until the agent finishes the current run.

type AgentContext

type AgentContext struct {
	SystemPrompt string        // single-string system prompt (legacy)
	SystemBlocks []SystemBlock // multi-block system prompt with cache control (takes precedence)
	Messages     []AgentMessage
	Tools        []Tool
}

AgentContext holds the immutable context for a single agent loop invocation.

type AgentMessage

type AgentMessage interface {
	GetRole() Role
	GetTimestamp() time.Time
	TextContent() string
	ThinkingContent() string
	HasToolCalls() bool
}

AgentMessage is the app-layer message abstraction. Message implements this interface. Users can define custom types (e.g. status notifications, UI hints) that flow through the context pipeline but get filtered out by ConvertToLLM.

func Collect added in v1.5.1

func Collect(events <-chan Event) ([]AgentMessage, error)

Collect consumes all events from the channel and returns the final messages. Blocks until the channel is closed. Returns any error from EventError events.

func ToAgentMessages

func ToAgentMessages(msgs []Message) []AgentMessage

ToAgentMessages converts a Message slice to AgentMessage slice. Use this to restore conversation history from deserialized Messages.

type AgentOption

type AgentOption func(*Agent)

AgentOption configures an Agent.

func WithContextEstimate

func WithContextEstimate(fn ContextEstimateFn) AgentOption

WithContextEstimate sets the context token estimation function. Use context.ContextEstimateAdapter for the default hybrid estimation.

func WithContextManager added in v1.6.0

func WithContextManager(mgr ContextManager) AgentOption

WithContextManager sets the context lifecycle manager. When configured, it takes precedence over TransformContext for prompt projection, overflow recovery, and usage reporting.

func WithContextPipeline

func WithContextPipeline(
	transform func(ctx context.Context, msgs []AgentMessage) ([]AgentMessage, error),
	convert func([]AgentMessage) []Message,
) AgentOption

WithContextPipeline sets both TransformContext and ConvertToLLM in one call. Prefer WithContextManager for the full context lifecycle; use this helper for simpler transform-based pipelines.

func WithContextWindow

func WithContextWindow(n int) AgentOption

WithContextWindow sets the model's context window size in tokens. Used by ContextUsage() to calculate context occupancy percentage.

func WithConvertToLLM

func WithConvertToLLM(fn func([]AgentMessage) []Message) AgentOption

WithConvertToLLM sets the message conversion function.

func WithDefaultToolChoice added in v1.6.2

func WithDefaultToolChoice(choice any) AgentOption

WithDefaultToolChoice sets the default tool_choice for every LLM call in this agent's loop. Accepted values: "auto" (default), "required" (must call a tool), "none" (no tools). "required" is useful for agents that should never produce plain-text responses.

func WithFollowUpMode

func WithFollowUpMode(mode QueueMode) AgentOption

WithFollowUpMode sets the follow-up queue drain mode. QueueModeAll (default) delivers all queued follow-up messages at once. QueueModeOneAtATime delivers one per turn.

func WithGetApiKey

func WithGetApiKey(fn func(provider string) (string, error)) AgentOption

WithGetApiKey sets a dynamic API key resolver called before each LLM call. The provider parameter identifies which provider is being called (e.g. "openai", "anthropic"). Enables per-provider key resolution, key rotation, OAuth short-lived tokens, and multi-tenant scenarios.

func WithMaxRetries

func WithMaxRetries(n int) AgentOption

WithMaxRetries sets the LLM call retry limit for retryable errors.

func WithMaxRetryDelay added in v1.5.1

func WithMaxRetryDelay(d time.Duration) AgentOption

WithMaxRetryDelay caps the wait time between LLM retries. Applies to both exponential backoff and server-requested Retry-After delays. Default: 60s.

func WithMaxToolConcurrency added in v1.5.1

func WithMaxToolConcurrency(n int) AgentOption

WithMaxToolConcurrency sets the maximum number of tools executed in parallel. 0 or 1 = sequential (default). >1 enables concurrent tool execution.

func WithMaxToolErrors

func WithMaxToolErrors(n int) AgentOption

WithMaxToolErrors sets the consecutive failure threshold per tool. After reaching this limit, the tool is disabled for the rest of the loop. 0 means unlimited (no circuit breaker).

func WithMaxTurns

func WithMaxTurns(n int) AgentOption

WithMaxTurns sets the max turns safety limit.

func WithMiddlewares added in v1.5.1

func WithMiddlewares(mw ...ToolMiddleware) AgentOption

WithMiddlewares sets tool execution middlewares. Each middleware wraps the tool.Execute call. First middleware is outermost.

func WithModel

func WithModel(model ChatModel) AgentOption

WithModel sets the LLM model.

func WithOnMaxTurns added in v1.6.4

func WithOnMaxTurns(action MaxTurnsAction) AgentOption

WithOnMaxTurns configures what happens when the MaxTurns safety limit is reached. The default is MaxTurnsTerminate.

func WithOnMessage added in v1.6.3

func WithOnMessage(fn func(AgentMessage)) AgentOption

WithOnMessage registers a callback invoked after each message is appended to the agent's context. Use for session logging / message persistence.

func WithPermissionEngine added in v1.6.0

func WithPermissionEngine(engine permission.DecisionEngine) AgentOption

WithPermissionEngine sets the runtime permission engine called before tool execution.

func WithReminderGenerator added in v1.6.4

func WithReminderGenerator(gen ReminderGenerator) AgentOption

WithReminderGenerator registers a per-turn reminder generator. Multiple calls stack: every generator is invoked in registration order before each LLM call, and their combined reminders are injected as one-turn system messages. Reminders do not enter the persistent message history.

func WithSessionID

func WithSessionID(id string) AgentOption

WithSessionID sets a session identifier for provider-level caching. Forwarded to providers that support session-based prompt caching.

func WithSteeringMode

func WithSteeringMode(mode QueueMode) AgentOption

WithSteeringMode sets the steering queue drain mode. QueueModeAll (default) delivers all queued steering messages at once. QueueModeOneAtATime delivers one per turn, letting the agent respond to each individually.

func WithStopGuard added in v1.6.4

func WithStopGuard(guard StopGuard) AgentOption

WithStopGuard installs a guard that decides whether the agent may stop when the LLM emits end_turn without tool calls. Nil guard (default) means every stop is allowed — legacy behavior.

func WithStreamFn

func WithStreamFn(fn StreamFn) AgentOption

WithStreamFn sets a custom LLM call function (for proxy/mock).

func WithStrictMessageSequence added in v1.6.0

func WithStrictMessageSequence(enabled bool) AgentOption

WithStrictMessageSequence makes malformed tool call / result transcripts fail fast instead of being repaired before the next LLM call.

func WithSystemBlocks added in v1.5.2

func WithSystemBlocks(blocks []SystemBlock) AgentOption

WithSystemBlocks sets a multi-block system prompt with per-block cache control. Takes precedence over WithSystemPrompt.

func WithSystemPrompt

func WithSystemPrompt(prompt string) AgentOption

WithSystemPrompt sets the system prompt (single-string mode).

func WithTaskRuntime added in v1.6.0

func WithTaskRuntime(rt *TaskRuntime) AgentOption

WithTaskRuntime sets a shared TaskRuntime for background task management. Tools that support background execution (Bash, SubAgent) register their tasks here, enabling a unified Tasks()/StopTask()/StopAllTasks() API on Agent.

func WithThinkingBudgets

func WithThinkingBudgets(budgets map[ThinkingLevel]int) AgentOption

WithThinkingBudgets sets per-level thinking token budgets. Each ThinkingLevel maps to a max thinking token count.

func WithThinkingLevel

func WithThinkingLevel(level ThinkingLevel) AgentOption

WithThinkingLevel sets the reasoning depth for models that support it.

func WithTools

func WithTools(tools ...Tool) AgentOption

WithTools sets the tool list.

func WithTransformContext

func WithTransformContext(fn func(ctx context.Context, msgs []AgentMessage) ([]AgentMessage, error)) AgentOption

WithTransformContext sets the context transform function.

type AgentState

type AgentState struct {
	SystemPrompt     string
	Messages         []AgentMessage
	Tools            []Tool
	IsRunning        bool
	StreamMessage    AgentMessage        // partial message being streamed, nil when idle
	PendingToolCalls map[string]struct{} // tool call IDs currently executing
	TotalUsage       Usage               // cumulative token usage across all turns
	Error            string
}

AgentState is a snapshot of the agent's current state.

type BackgroundTaskEntry added in v1.6.0

type BackgroundTaskEntry struct {
	ID          string
	Type        TaskType
	Description string
	Status      TaskStatus
	StartedAt   time.Time
	EndedAt     time.Time
	OutputFile  string // path to output file on disk
	Error       string
	ExitCode    int // shell: process exit code
	ToolCount   int // number of tool calls executed

	// Shell-specific
	PID     int
	Command string

	// SubAgent-specific
	Agent     string
	Prompt    string // original task prompt
	TokensIn  int
	TokensOut int
	// contains filtered or unexported fields
}

BackgroundTaskEntry is the unified representation of any background task. Both BashTool (shell commands) and SubAgentTool (background agents) register tasks here through a shared TaskRuntime.

func (*BackgroundTaskEntry) SetCancel added in v1.6.0

func (e *BackgroundTaskEntry) SetCancel(fn func())

SetCancel sets the cancellation function for this task entry. Called during registration; only Stop()/StopAll() invoke it.

type CallConfig

type CallConfig struct {
	ThinkingLevel  ThinkingLevel
	ThinkingBudget int    // max thinking tokens, 0 = use provider default
	APIKey         string // per-call API key override, empty = use model default
	SessionID      string // provider session caching identifier
	MaxTokens      int    // per-call max tokens override, 0 = use model default
	ToolChoice     any    // "auto" / "required" / "none" / {"type":"tool","name":"xxx"}, nil = provider default
}

CallConfig holds per-call configuration resolved from CallOptions.

func ResolveCallConfig

func ResolveCallConfig(opts []CallOption) CallConfig

ResolveCallConfig applies options and returns the resolved config.

type CallOption

type CallOption func(*CallConfig)

CallOption configures per-call LLM parameters.

func WithAPIKey

func WithAPIKey(key string) CallOption

WithAPIKey overrides the API key for a single LLM call. Enables key rotation, OAuth short-lived tokens, and multi-tenant scenarios.

func WithCallSessionID

func WithCallSessionID(id string) CallOption

WithCallSessionID sets a session identifier for a single LLM call.

func WithMaxTokens added in v1.5.1

func WithMaxTokens(tokens int) CallOption

WithMaxTokens overrides the max output tokens for a single LLM call.

func WithThinking

func WithThinking(level ThinkingLevel) CallOption

WithThinking sets the thinking level for a single LLM call.

func WithThinkingBudget

func WithThinkingBudget(tokens int) CallOption

WithThinkingBudget sets the max thinking tokens for a single LLM call.

func WithToolChoice added in v1.6.2

func WithToolChoice(choice any) CallOption

WithToolChoice controls whether the model must call a tool. Accepted values: "auto" (default), "required" (must call a tool), "none" (no tools).

type ChatModel

type ChatModel interface {
	Generate(ctx context.Context, messages []Message, tools []ToolSpec, opts ...CallOption) (*LLMResponse, error)
	GenerateStream(ctx context.Context, messages []Message, tools []ToolSpec, opts ...CallOption) (<-chan StreamEvent, error)
	SupportsTools() bool
}

ChatModel is the LLM provider interface.

type CompactReason added in v1.6.0

type CompactReason string

CompactReason identifies why a committed context rewrite was requested. It is attached to explicit commits such as manual /compact or overflow recovery, not to transient per-request projections.

const (
	CompactReasonManual    CompactReason = "manual"
	CompactReasonOverflow  CompactReason = "overflow"
	CompactReasonThreshold CompactReason = "threshold"
)

type ConcurrencySafer added in v1.6.0

type ConcurrencySafer interface {
	ConcurrencySafe(args json.RawMessage) bool
}

ConcurrencySafer is an optional interface for tools that declare whether they can safely execute concurrently with other tools. Takes precedence over ReadOnlyer for concurrency scheduling.

type ContentBlock

type ContentBlock struct {
	Type     ContentType `json:"type"`
	Text     string      `json:"text,omitempty"`
	Thinking string      `json:"thinking,omitempty"`
	ToolCall *ToolCall   `json:"tool_call,omitempty"`
	Image    *ImageData  `json:"image,omitempty"`
	ToolName string      `json:"tool_name,omitempty"` // tool_reference: referenced tool name
}

ContentBlock is a tagged union for message content. Exactly one payload field is populated, matching the Type value.

func ImageBlock

func ImageBlock(data, mimeType string) ContentBlock

func ImageURLBlock added in v1.5.1

func ImageURLBlock(url string) ContentBlock

func TextBlock

func TextBlock(text string) ContentBlock

func ThinkingBlock

func ThinkingBlock(thinking string) ContentBlock

func ToolCallBlock

func ToolCallBlock(tc ToolCall) ContentBlock

func ToolRefBlock added in v1.5.2

func ToolRefBlock(toolName string) ContentBlock

type ContentTool added in v1.5.1

type ContentTool interface {
	ExecuteContent(ctx context.Context, args json.RawMessage) ([]ContentBlock, error)
}

ContentTool is an optional interface for tools that return rich content (e.g., images). When a tool implements ContentTool, the agent loop calls ExecuteContent instead of Execute, enabling multi-block responses with text + image content blocks.

type ContentType

type ContentType string

ContentType identifies the kind of content in a ContentBlock.

const (
	ContentText     ContentType = "text"
	ContentThinking ContentType = "thinking"
	ContentToolCall ContentType = "toolCall"
	ContentImage    ContentType = "image"
	ContentToolRef  ContentType = "tool_reference"
)

type ContextCommitResult added in v1.6.0

type ContextCommitResult struct {
	Messages       []AgentMessage
	Usage          *ContextUsage
	Changed        bool
	Strategy       string
	CompactedCount int
	KeptCount      int
	SplitTurn      bool
}

ContextCommitResult is the result of an explicit committed rewrite. The returned Messages should replace the runtime baseline when Changed is true, for example after a manual /compact command.

type ContextEstimateFn

type ContextEstimateFn func(msgs []AgentMessage) (tokens, usageTokens, trailingTokens int)

ContextEstimateFn estimates the current context token consumption from messages. Returns total tokens, tokens from LLM Usage, and estimated trailing tokens.

type ContextEstimator added in v1.6.0

type ContextEstimator interface {
	EstimateContext([]AgentMessage) (tokens, usageTokens, trailingTokens int)
}

ContextEstimator is an optional interface a ContextManager can implement to provide token estimation. When implemented, NewAgent auto-wires it.

type ContextLLMConverter added in v1.6.0

type ContextLLMConverter interface {
	ConvertToLLM([]AgentMessage) []Message
}

ContextLLMConverter is an optional interface a ContextManager can implement to provide its own AgentMessage → Message conversion (e.g. to handle summary message types). When implemented, NewAgent auto-wires it.

type ContextManager added in v1.6.0

type ContextManager interface {
	// Project builds the prompt view for a single model call without mutating
	// the caller's runtime baseline.
	Project(ctx context.Context, msgs []AgentMessage) (ContextProjection, error)

	// Compact performs an explicit committed rewrite of msgs. The caller is
	// responsible for replacing its runtime baseline with the returned Messages
	// when Changed is true.
	Compact(ctx context.Context, msgs []AgentMessage, reason CompactReason) (ContextCommitResult, error)

	// RecoverOverflow produces a retryable view after a provider reports
	// context overflow. When ShouldCommit is true, CommitMessages should replace
	// the runtime baseline before continuing.
	RecoverOverflow(ctx context.Context, msgs []AgentMessage, cause error) (ContextRecoveryResult, error)

	// Sync tells the manager what the current runtime baseline is after restore,
	// clear, import, or any other external replacement of messages.
	Sync(msgs []AgentMessage)

	// Usage returns the latest effective context usage remembered by the
	// manager. It may reflect a projected or recovered view rather than the raw
	// runtime baseline.
	Usage() *ContextUsage

	// Snapshot returns the latest active view snapshot remembered by the
	// manager. It is intended for observability and may be nil before the
	// manager has seen any messages.
	Snapshot() *ContextSnapshot
}

ContextManager owns prompt projection, committed rewrites, overflow recovery, and usage reporting for long-running agent sessions.

The manager deliberately distinguishes between transient prompt projection and explicit baseline rewrites:

  • Project builds a prompt view for one LLM call without committing it.
  • Compact performs an explicit committed rewrite such as /compact.
  • RecoverOverflow produces a retryable prompt view after context overflow and may optionally return a new committed baseline.
  • Sync updates the manager with the current runtime baseline after external message replacement, session restore, or clear.
  • Usage reports the latest effective usage remembered by the manager.
  • Snapshot reports the current active view and recent rewrite details for debugging and UI surfaces.

type ContextProjection added in v1.6.0

type ContextProjection struct {
	Messages       []AgentMessage
	Usage          *ContextUsage
	CommitMessages []AgentMessage
	ShouldCommit   bool
}

ContextProjection is the prompt view projected for a single LLM call. By default the projection does not modify the runtime message baseline. When ShouldCommit is true, CommitMessages should replace the runtime baseline before continuing the current call.

type ContextRecoveryResult added in v1.6.0

type ContextRecoveryResult struct {
	View           []AgentMessage
	CommitMessages []AgentMessage
	Usage          *ContextUsage
	Changed        bool
	ShouldCommit   bool
	Strategy       string
	CompactedCount int
	KeptCount      int
	SplitTurn      bool
}

ContextRecoveryResult is the result of overflow recovery.

View is always the retryable prompt view. CommitMessages is optional and, when ShouldCommit is true, should replace the runtime message baseline so future usage reporting and turns start from the recovered state.

type ContextSnapshot added in v1.6.0

type ContextSnapshot struct {
	BaselineUsage      *ContextUsage
	Usage              *ContextUsage
	Scope              string
	TranscriptMessages int
	ActiveMessages     int
	SummaryMessages    int
	ToolMessages       int
	ClearedToolResults int
	TrimmedTextBlocks  int
	LastStrategy       string
	LastChanged        bool
	LastCompactedCount int
	LastKeptCount      int
	LastSplitTurn      bool
}

ContextSnapshot describes both the runtime baseline and the current active context view, plus the most recent rewrite details remembered by the manager.

Snapshot is meant for debugging, observability, and UI surfaces such as /context. BaselineUsage always reflects the caller's current runtime message baseline. Usage reports the active view currently remembered by the manager, which may be the baseline runtime messages, a projected prompt view, or a recovered/committed view depending on the most recent operation.

type ContextUsage

type ContextUsage struct {
	Tokens         int     `json:"tokens"`          // estimated total tokens in context
	ContextWindow  int     `json:"context_window"`  // model's context window size
	Percent        float64 `json:"percent"`         // tokens / contextWindow * 100
	UsageTokens    int     `json:"usage_tokens"`    // from last LLM-reported Usage
	TrailingTokens int     `json:"trailing_tokens"` // chars/4 estimate for trailing messages
}

ContextUsage represents the current context window occupancy estimate.

type ContextWindower added in v1.6.0

type ContextWindower interface {
	ContextWindow() int
}

ContextWindower is an optional interface a ContextManager can implement to report its configured context window size.

type Cost added in v1.5.1

type Cost struct {
	Input      float64 `json:"input"`
	Output     float64 `json:"output"`
	CacheRead  float64 `json:"cache_read"`
	CacheWrite float64 `json:"cache_write"`
	Total      float64 `json:"total"`
}

Cost tracks monetary cost for a single LLM call in USD.

func (*Cost) Add added in v1.5.1

func (c *Cost) Add(other *Cost)

Add accumulates another Cost into this one (nil-safe).

type DeferActivator added in v1.5.2

type DeferActivator interface {
	DeferFilter
	Activate(names ...string)
}

DeferActivator is an optional extension of DeferFilter that supports pre-activating deferred tools (e.g. when restoring a session whose history contains tool_reference blocks for previously activated tools).

type DeferFilter added in v1.5.2

type DeferFilter interface {
	// IsDeferred reports whether the tool is deferred and not yet activated.
	// Unactivated deferred tools are excluded from the API request entirely.
	IsDeferred(toolName string) bool
	// WasDeferred reports whether the tool was originally in the deferred set
	// (regardless of activation). Activated deferred tools are sent with
	// defer_loading: true.
	WasDeferred(toolName string) bool
}

DeferFilter controls deferred tool loading for the LLM. When a tool in the agent's tool list implements DeferFilter:

  • IsDeferred returns true → tool schema is excluded from the API request
  • WasDeferred returns true → tool schema is sent with defer_loading: true

Unactivated deferred tools are excluded entirely. Once activated via tool_reference, they are sent with defer_loading: true so the API server manages their context loading. Tools remain registered for execution regardless — only their API visibility changes.

IsDeferred is also used by the system prompt builder to exclude unactivated tools from the tool description section (they appear in <available-deferred-tools> by name only).

type DeltaKind added in v1.6.3

type DeltaKind string

DeltaKind identifies what kind of content a message_update delta carries.

const (
	DeltaText     DeltaKind = ""         // default: regular text
	DeltaThinking DeltaKind = "thinking" // model reasoning/thinking
	DeltaToolCall DeltaKind = "toolcall" // tool call argument JSON
)

type EndReason added in v1.5.7

type EndReason string

EndReason describes why a single agent run stopped.

const (
	EndReasonStop     EndReason = "stop"
	EndReasonMaxTurns EndReason = "max_turns"
	EndReasonAborted  EndReason = "aborted"
	EndReasonError    EndReason = "error"
)

type Event

type Event struct {
	Type               EventType
	Message            AgentMessage    // for message_start/update/end, turn_end
	Delta              string          // text delta for message_update
	DeltaKind          DeltaKind       // for message_update: what kind of delta
	ToolID             string          // for tool_exec_*
	Tool               string          // tool name for tool_exec_*
	ToolLabel          string          // human-readable tool label (from ToolLabeler)
	Args               json.RawMessage // tool args for tool_exec_start/tool_exec_update
	Result             json.RawMessage // tool result for tool_exec_end and preview updates
	Progress           *ProgressPayload
	UpdateKind         ToolExecUpdateKind
	IsError            bool // tool error flag for tool_exec_end
	Preview            json.RawMessage
	PermissionRequest  *permission.Request
	PermissionDecision *permission.Decision
	ToolResults        []ToolResult   // for turn_end: all tool results from this turn
	Err                error          // for error events
	NewMessages        []AgentMessage // for agent_end: messages added during this loop
	RetryInfo          *RetryInfo     // for retry events
	Summary            *RunSummary    // for agent_end: factual run summary
}

Event is a lifecycle event emitted by the agent loop. This is the single output channel for all lifecycle information.

type EventStream added in v1.5.1

type EventStream struct {
	// contains filtered or unexported fields
}

EventStream wraps an event channel to provide both real-time iteration and deferred result collection.

Usage:

stream := agentcore.NewEventStream(AgentLoop(...))
for ev := range stream.Events() {
    // handle real-time events
}
msgs, err := stream.Result()

func NewEventStream added in v1.5.1

func NewEventStream(source <-chan Event) *EventStream

NewEventStream creates an EventStream that reads from the source channel. Events are forwarded to an internal channel for iteration. The final result is captured from EventAgentEnd.

func (*EventStream) Done added in v1.5.1

func (s *EventStream) Done() <-chan struct{}

Done returns a channel that is closed when the stream finishes.

func (*EventStream) Events added in v1.5.1

func (s *EventStream) Events() <-chan Event

Events returns the event channel for real-time iteration. The channel is closed when the source is exhausted.

func (*EventStream) Result added in v1.5.1

func (s *EventStream) Result() ([]AgentMessage, error)

Result blocks until the stream is done and returns the final messages. Returns the error from the last EventError, if any.

type EventType

type EventType string

EventType identifies agent lifecycle event types.

const (
	EventAgentStart           EventType = "agent_start"
	EventAgentEnd             EventType = "agent_end"
	EventTurnStart            EventType = "turn_start"
	EventTurnEnd              EventType = "turn_end"
	EventMessageStart         EventType = "message_start"
	EventMessageUpdate        EventType = "message_update"
	EventMessageEnd           EventType = "message_end"
	EventToolExecStart        EventType = "tool_exec_start"
	EventToolExecUpdate       EventType = "tool_exec_update"
	EventToolExecEnd          EventType = "tool_exec_end"
	EventToolApprovalRequest  EventType = "tool_approval_request"
	EventToolApprovalResolved EventType = "tool_approval_resolved"
	EventRetry                EventType = "retry"
	EventError                EventType = "error"
)

type FuncTool

type FuncTool struct {
	// contains filtered or unexported fields
}

FuncTool wraps a function as a Tool (convenience helper).

func NewFuncTool

func NewFuncTool(name, description string, schema map[string]any, fn func(ctx context.Context, args json.RawMessage) (json.RawMessage, error)) *FuncTool

func (*FuncTool) Description

func (t *FuncTool) Description() string

func (*FuncTool) Execute

func (t *FuncTool) Execute(ctx context.Context, args json.RawMessage) (json.RawMessage, error)

func (*FuncTool) Name

func (t *FuncTool) Name() string

func (*FuncTool) Schema

func (t *FuncTool) Schema() map[string]any

type ImageData

type ImageData struct {
	Data     string `json:"data,omitempty"`
	URL      string `json:"url,omitempty"`
	MimeType string `json:"mime_type,omitempty"`
}

ImageData holds image content as base64 data or a URL. When URL is set, providers pass it directly (no download/encoding needed). When Data is set, it is sent as a base64 data URL with MimeType. MimeType is required for base64 mode, optional for URL mode (provider infers it).

type InjectDisposition added in v1.5.7

type InjectDisposition string

InjectDisposition describes how an injected message was delivered.

const (
	InjectSteeredCurrentRun InjectDisposition = "steered_current_run"
	InjectResumedIdleRun    InjectDisposition = "resumed_idle_run"
	InjectQueued            InjectDisposition = "queued"
)

type InjectResult added in v1.5.7

type InjectResult struct {
	Disposition InjectDisposition
}

InjectResult reports the delivery outcome of Agent.Inject.

type InterruptBehavior added in v1.6.0

type InterruptBehavior string

InterruptBehavior controls what happens when a queued user message arrives while a tool is still running.

const (
	InterruptBehaviorBlock  InterruptBehavior = "block"
	InterruptBehaviorCancel InterruptBehavior = "cancel"
)

type InterruptBehaviorer added in v1.6.0

type InterruptBehaviorer interface {
	InterruptBehavior(args json.RawMessage) InterruptBehavior
}

InterruptBehaviorer is an optional interface for tools that declare whether they should be cancelled or allowed to finish when a steering message arrives. Defaults to InterruptBehaviorBlock when not implemented.

type LLMRequest

type LLMRequest struct {
	Messages []Message
	Tools    []ToolSpec
}

LLMRequest is the request passed to StreamFn.

type LLMResponse

type LLMResponse struct {
	Message Message
}

LLMResponse is the response from StreamFn.

type LoopConfig

type LoopConfig struct {
	Model                 ChatModel
	StreamFn              StreamFn      // nil = use Model directly
	MaxTurns              int           // safety limit, default 10
	MaxRetries            int           // LLM call retry limit for retryable errors, default 3
	MaxToolErrors         int           // consecutive tool failure threshold per tool, 0 = unlimited
	StrictMessageSequence bool          // fail fast instead of repairing malformed tool call / result history
	ThinkingLevel         ThinkingLevel // reasoning depth

	// Two-stage pipeline: TransformContext -> ConvertToLLM
	// ContextManager takes precedence when configured.
	ContextManager   ContextManager
	TransformContext func(ctx context.Context, msgs []AgentMessage) ([]AgentMessage, error)
	ConvertToLLM     func(msgs []AgentMessage) []Message

	// CommitContext replaces the runtime message baseline after an explicit
	// committed compaction, a committed projection rewrite, or committed
	// overflow recovery.
	CommitContext func(msgs []AgentMessage, usage *ContextUsage) error

	// PermissionEngine is called after validation/preview and before execution.
	// Returning nil means no extra approval step was required.
	PermissionEngine permission.DecisionEngine

	// GetApiKey resolves the API key before each LLM call.
	// The provider parameter identifies which provider is being called (e.g. "openai", "anthropic").
	// Enables per-provider key resolution, key rotation, OAuth tokens, and multi-tenant scenarios.
	// When nil or returns empty string, the model's default key is used.
	GetApiKey func(provider string) (string, error)

	// ThinkingBudgets maps each ThinkingLevel to a max thinking token count.
	// When set, the resolved budget is passed to the model alongside the level.
	ThinkingBudgets map[ThinkingLevel]int

	// SessionID enables provider-level session caching (e.g. Anthropic prompt cache).
	SessionID string

	// Steering: called after each tool execution to check for user interruptions.
	GetSteeringMessages func() []AgentMessage

	// FollowUp: called when the agent would otherwise stop.
	GetFollowUpMessages func() []AgentMessage

	// MaxRetryDelay caps the wait time between retries (including server-requested Retry-After).
	// Default: 60s. Set to prevent excessively long waits from overloaded providers.
	MaxRetryDelay time.Duration

	// Middlewares are applied around each tool execution (outermost first).
	// Use for logging, timing, argument/result modification, etc.
	Middlewares []ToolMiddleware

	// MaxToolConcurrency limits parallel tool execution.
	// 0 or 1 = sequential (default, backward compatible).
	// >1 = up to N tools execute concurrently within a single turn.
	MaxToolConcurrency int

	// ShouldEmitAbortMarker reports whether an abort marker message should be
	// emitted when the context is cancelled. When nil or returns false, the
	// cancellation is silent (legacy behavior). Set by Agent.Abort().
	ShouldEmitAbortMarker func() bool

	// ToolChoice sets the default tool_choice for every LLM call in this loop.
	// "auto" (default), "required" (must call a tool), "none" (no tools).
	// nil means use provider default.
	ToolChoice any

	// StopAfterTool, if non-nil, is called after each successful (non-error)
	// tool execution. If it returns true, the loop exits immediately with
	// EndReasonStop — even when ToolChoice is "required". Use this to let a
	// terminal tool (e.g. commit_chapter) end the loop without wasting turns.
	StopAfterTool func(toolName string) bool

	// OnMessage, if non-nil, is called after each message is appended to
	// context (assistant, tool result, steering). Use for session logging.
	OnMessage func(msg AgentMessage)

	// ReminderGens are invoked once per turn, just before the LLM request
	// is built. Their output is injected as one-turn system messages between
	// the static system prompt and the conversation history. Reminders are
	// NOT persisted to the agent message history.
	ReminderGens []ReminderGenerator

	// StopGuard is consulted when the LLM would end a run without tool calls.
	// Nil (default) means every stop is allowed.
	StopGuard StopGuard

	// OnMaxTurns selects the behavior when MaxTurns is exhausted.
	// Default (MaxTurnsTerminate) emits an error and ends the run.
	// MaxTurnsSoftRestart resets the turn counter and continues the loop.
	OnMaxTurns MaxTurnsAction
}

LoopConfig configures the agent loop.

type MaxTurnsAction added in v1.6.4

type MaxTurnsAction int

MaxTurnsAction selects the behavior when MaxTurns is reached.

const (
	// MaxTurnsTerminate (default) emits an error event and ends the run.
	MaxTurnsTerminate MaxTurnsAction = iota
	// MaxTurnsSoftRestart resets the internal turn counter to 0 and continues
	// the loop. Useful for very long runs where MaxTurns is a soft upper bound.
	MaxTurnsSoftRestart
)

type Message

type Message struct {
	Role       Role           `json:"role"`
	Content    []ContentBlock `json:"content"`
	StopReason StopReason     `json:"stop_reason,omitempty"`
	Usage      *Usage         `json:"usage,omitempty"`
	Metadata   map[string]any `json:"metadata,omitempty"`
	Timestamp  time.Time      `json:"timestamp"`
}

Message is an LLM-level message with structured content blocks.

func AbortMsg added in v1.5.1

func AbortMsg(text, phase string) Message

AbortMsg creates an assistant abort marker message. phase is "inference" or "tool_execution".

func CollectMessages

func CollectMessages(msgs []AgentMessage) []Message

CollectMessages extracts concrete Messages from an AgentMessage slice, dropping custom types. Use this to serialize conversation history.

func DefaultConvertToLLM

func DefaultConvertToLLM(msgs []AgentMessage) []Message

DefaultConvertToLLM filters AgentMessages to LLM-compatible Messages. Custom message types are dropped; only user/assistant/system/tool messages pass through.

func RepairMessageSequence

func RepairMessageSequence(msgs []Message) []Message

RepairMessageSequence ensures tool call / tool result pairs are complete. Orphaned tool calls (no matching result) get a synthetic error result inserted. Orphaned tool results (no matching call) are removed. This prevents LLM providers from rejecting malformed message sequences.

func SystemMsg

func SystemMsg(text string) Message

SystemMsg creates a system message.

func ToolResultMsg

func ToolResultMsg(toolCallID string, content json.RawMessage, isError bool) Message

ToolResultMsg creates a tool result message.

func UserMsg

func UserMsg(text string) Message

UserMsg creates a user message from plain text.

func (Message) GetRole

func (m Message) GetRole() Role

func (Message) GetTimestamp

func (m Message) GetTimestamp() time.Time

func (Message) HasToolCalls

func (m Message) HasToolCalls() bool

HasToolCalls reports whether any tool call blocks exist.

func (Message) IsEmpty

func (m Message) IsEmpty() bool

IsEmpty reports whether the message has no meaningful content.

func (Message) TextContent

func (m Message) TextContent() string

TextContent returns the concatenated text from all text blocks.

func (Message) ThinkingContent

func (m Message) ThinkingContent() string

ThinkingContent returns the concatenated thinking text.

func (Message) ToolCalls

func (m Message) ToolCalls() []ToolCall

ToolCalls returns all tool call blocks.

type MessageSequenceIssue added in v1.6.0

type MessageSequenceIssue struct {
	Kind           MessageSequenceIssueKind
	MessageIndex   int
	AssistantIndex int
	ToolCallID     string
	ToolName       string
}

MessageSequenceIssue describes a structural problem in a tool call / tool result transcript. The current validator intentionally stays narrow and focuses on the two invariants the loop already repairs today:

  • every tool call should have a following tool result
  • every tool result should reference a known tool call

func ValidateMessageSequence added in v1.6.0

func ValidateMessageSequence(msgs []Message) []MessageSequenceIssue

ValidateMessageSequence reports message-sequence issues that could cause provider rejections or inconsistent replay.

type MessageSequenceIssueKind added in v1.6.0

type MessageSequenceIssueKind string
const (
	MessageSequenceIssueMissingToolResult MessageSequenceIssueKind = "missing_tool_result"
	MessageSequenceIssueOrphanToolResult  MessageSequenceIssueKind = "orphan_tool_result"
)

type PermissionChecker added in v1.6.0

type PermissionChecker interface {
	CheckPermission(ctx context.Context, req permission.Request) (*permission.Decision, error)
}

PermissionChecker lets a tool perform tool-specific permission checks before the shared decision engine runs. Returning nil means "fall through".

type PermissionMetadataProvider added in v1.6.0

type PermissionMetadataProvider interface {
	PermissionMetadata() permission.Metadata
}

PermissionMetadataProvider lets a tool override the default permission classification used by the decision engine.

type Previewer added in v1.5.1

type Previewer interface {
	Preview(ctx context.Context, args json.RawMessage) (json.RawMessage, error)
}

Previewer is an optional interface for tools that can compute a preview (e.g., diff) before execution. The agent loop calls Preview and emits the result as EventToolExecUpdate so the UI can display it before the tool runs.

type ProgressPayload added in v1.5.7

type ProgressPayload struct {
	Kind       ProgressPayloadKind `json:"kind"`
	Agent      string              `json:"agent,omitempty"`
	Tool       string              `json:"tool,omitempty"`
	Summary    string              `json:"summary,omitempty"`
	Delta      string              `json:"delta,omitempty"`
	Thinking   string              `json:"thinking,omitempty"`
	Message    string              `json:"message,omitempty"`
	Turn       int                 `json:"turn,omitempty"`
	Attempt    int                 `json:"attempt,omitempty"`
	MaxRetries int                 `json:"max_retries,omitempty"`
	IsError    bool                `json:"is_error,omitempty"`
	Args       json.RawMessage     `json:"args,omitempty"`
	Meta       json.RawMessage     `json:"meta,omitempty"`
	// DeltaKind distinguishes what kind of content Delta carries when Kind is
	// ProgressToolDelta. Consumers can use this to filter/render text vs
	// tool-call argument JSON differently.
	DeltaKind DeltaKind `json:"delta_kind,omitempty"`
}

ProgressPayload is the structured progress envelope emitted by tools.

type ProgressPayloadKind added in v1.5.7

type ProgressPayloadKind string

ProgressPayloadKind distinguishes structured progress update semantics.

const (
	ProgressToolStart   ProgressPayloadKind = "tool_start"
	ProgressToolEnd     ProgressPayloadKind = "tool_end"
	ProgressToolDelta   ProgressPayloadKind = "tool_delta"
	ProgressThinking    ProgressPayloadKind = "thinking"
	ProgressSummary     ProgressPayloadKind = "summary"
	ProgressToolError   ProgressPayloadKind = "tool_error"
	ProgressTurnCounter ProgressPayloadKind = "turn_counter"
	ProgressRetry       ProgressPayloadKind = "retry"
	ProgressContext     ProgressPayloadKind = "context"
)

type ProviderNamer

type ProviderNamer interface {
	ProviderName() string
}

ProviderNamer is an optional interface for ChatModel implementations to expose their provider name (e.g. "openai", "anthropic", "gemini"). Used by the agent loop to pass provider context to GetApiKey callbacks.

type ProxyEvent

type ProxyEvent struct {
	Type       ProxyEventType `json:"type"`
	Delta      string         `json:"delta,omitempty"`
	ToolCallID string         `json:"tool_call_id,omitempty"`
	ToolName   string         `json:"tool_name,omitempty"`
	StopReason StopReason     `json:"stop_reason,omitempty"`
	Usage      *Usage         `json:"usage,omitempty"`
	Err        error          `json:"-"`
}

ProxyEvent is a bandwidth-optimized event from a remote proxy server. The client reconstructs the full message incrementally from these deltas.

type ProxyEventType

type ProxyEventType string

ProxyEventType identifies proxy streaming event types. Proxy events are bandwidth-optimized: they carry only deltas, not the full partial message on each event.

const (
	ProxyEventTextDelta     ProxyEventType = "text_delta"
	ProxyEventThinkingDelta ProxyEventType = "thinking_delta"
	ProxyEventToolCallStart ProxyEventType = "toolcall_start"
	ProxyEventToolCallDelta ProxyEventType = "toolcall_delta"
	ProxyEventDone          ProxyEventType = "done"
	ProxyEventError         ProxyEventType = "error"
)

type ProxyModel

type ProxyModel struct {
	// contains filtered or unexported fields
}

ProxyModel implements ChatModel by forwarding to a remote proxy server. It reconstructs streaming events from bandwidth-optimized ProxyEvents.

Usage:

proxy := agentcore.NewProxyModel(myProxyFn)
agent := agentcore.NewAgent(agentcore.WithModel(proxy))

func NewProxyModel

func NewProxyModel(fn ProxyStreamFn) *ProxyModel

NewProxyModel creates a ChatModel that delegates to a proxy stream function.

func (*ProxyModel) Generate

func (p *ProxyModel) Generate(ctx context.Context, messages []Message, tools []ToolSpec, opts ...CallOption) (*LLMResponse, error)

Generate collects the full streamed response synchronously.

func (*ProxyModel) GenerateStream

func (p *ProxyModel) GenerateStream(ctx context.Context, messages []Message, tools []ToolSpec, opts ...CallOption) (<-chan StreamEvent, error)

GenerateStream converts proxy events into standard StreamEvents.

func (*ProxyModel) SupportsTools

func (p *ProxyModel) SupportsTools() bool

SupportsTools reports that the proxy can handle tool calls.

type ProxyStreamFn

type ProxyStreamFn func(ctx context.Context, req *LLMRequest) (<-chan ProxyEvent, error)

ProxyStreamFn makes an LLM call through a remote proxy and returns a channel of bandwidth-optimized ProxyEvents.

type QueueMode

type QueueMode string

QueueMode controls how steering/follow-up queues are drained.

const (
	QueueModeAll        QueueMode = "all"
	QueueModeOneAtATime QueueMode = "one-at-a-time"
)

type ReadOnlyer added in v1.6.0

type ReadOnlyer interface {
	ReadOnly(args json.RawMessage) bool
}

ReadOnlyer is an optional interface for tools that declare read-only behavior. Read-only tools are eligible for concurrent execution by default. The args parameter allows input-dependent classification (e.g., bash is read-only for "ls" but not for "rm").

type Reminder added in v1.6.4

type Reminder struct {
	// Source is a logical identifier for the generator emitting this reminder.
	// When multiple reminders from the same turn share a Source, the last one
	// wins; earlier duplicates are dropped.
	Source string
	// Content is the reminder body. It will be wrapped in
	// `<system-reminder>...</system-reminder>` before injection.
	Content string
}

Reminder is a one-turn system message injected before the LLM call. Reminders live for exactly one turn — they are NOT persisted to the agent's message history and do not participate in context compaction.

The typical use case is "every-turn steering" — facts that the host needs to re-affirm on every call (current phase, pending work, stop conditions) without polluting the durable conversation.

type ReminderGenerator added in v1.6.4

type ReminderGenerator func(ctx context.Context, turn TurnInfo) []Reminder

ReminderGenerator produces reminders for the upcoming LLM call. It is invoked once per turn, just before the LLM request is built. Returning nil or an empty slice skips injection for that turn.

type RetryInfo

type RetryInfo struct {
	Attempt    int
	MaxRetries int
	Delay      time.Duration
	Err        error
}

RetryInfo carries retry context for EventRetry events.

type Role

type Role string

Role defines message roles.

const (
	RoleUser      Role = "user"
	RoleAssistant Role = "assistant"
	RoleSystem    Role = "system"
	RoleTool      Role = "tool"
)

type RunSummary added in v1.5.7

type RunSummary struct {
	TurnCount  int
	ToolCalls  int
	ToolErrors int
	EndReason  EndReason
}

RunSummary captures loop facts that are known at the end of a run. It intentionally excludes higher-level policy judgments.

type StopDecision added in v1.6.4

type StopDecision struct {
	// Allow=true lets the stop proceed; Allow=false keeps the loop alive.
	Allow bool
	// InjectMessage is delivered as a user message on the next turn when
	// Allow=false && !Escalate. Empty InjectMessage with Allow=false is
	// treated as Allow=true (safe default — never stall silently).
	InjectMessage string
	// Escalate=true ends the run immediately with an error.
	Escalate bool
}

StopDecision is the guard's verdict.

type StopGuard added in v1.6.4

type StopGuard func(ctx context.Context, stop StopInfo) StopDecision

StopGuard is consulted when the LLM would end a run without tool calls (i.e. the assistant produced a final text response and no more tool calls).

Return Allow=true to let the agent stop normally. Return Allow=false with an InjectMessage to keep the agent running for another turn — the message is delivered as a user message on the next LLM call. Set Escalate=true to force the run to end with a guard-escalation error (used when the guard has repeatedly blocked stops and suspects a prompt bug).

Guard state (e.g. consecutive-block counters) is the guard's own responsibility; agentcore passes only the current turn index and the stopping assistant message.

type StopInfo added in v1.6.4

type StopInfo struct {
	// TurnIndex is the index of the turn that just produced the stopping message.
	TurnIndex int
	// Message is the assistant message whose StopReason triggered this check.
	Message Message
}

StopInfo carries the information a StopGuard needs to decide.

type StopReason

type StopReason string

StopReason indicates why the LLM stopped generating.

const (
	StopReasonStop    StopReason = "stop"
	StopReasonLength  StopReason = "length"
	StopReasonToolUse StopReason = "toolUse"
	StopReasonError   StopReason = "error"
	StopReasonAborted StopReason = "aborted"
)

type StreamEvent

type StreamEvent struct {
	Type         StreamEventType
	ContentIndex int     // which content block is being updated
	Delta        string  // text/thinking/toolcall argument delta
	Message      Message // partial (during streaming) or final (done)
	// CompletedToolCall is populated on StreamEventToolCallEnd with the fully
	// reconstructed tool call. It lets the loop start execution immediately
	// without re-parsing the partial assistant message.
	CompletedToolCall *ToolCall
	StopReason        StopReason // finish reason (for done events)
	Err               error      // for error events
}

StreamEvent is a streaming event from the LLM.

type StreamEventType

type StreamEventType string

StreamEventType identifies LLM streaming event types.

const (
	// Text content streaming
	StreamEventTextStart StreamEventType = "text_start"
	StreamEventTextDelta StreamEventType = "text_delta"
	StreamEventTextEnd   StreamEventType = "text_end"

	// Thinking/reasoning streaming
	StreamEventThinkingStart StreamEventType = "thinking_start"
	StreamEventThinkingDelta StreamEventType = "thinking_delta"
	StreamEventThinkingEnd   StreamEventType = "thinking_end"

	// Tool call streaming
	StreamEventToolCallStart StreamEventType = "toolcall_start"
	StreamEventToolCallDelta StreamEventType = "toolcall_delta"
	StreamEventToolCallEnd   StreamEventType = "toolcall_end"

	// Terminal events
	StreamEventDone  StreamEventType = "done"
	StreamEventError StreamEventType = "error"
)

type StreamFn

type StreamFn func(ctx context.Context, req *LLMRequest) (*LLMResponse, error)

StreamFn is an injectable LLM call function. When nil, the loop uses model.Generate / model.GenerateStream directly.

type SubAgentConfig

type SubAgentConfig struct {
	Name        string
	Description string
	// Model is resolved when each sub-agent run starts. Wrappers that swap
	// the underlying model at runtime are supported and take effect on the
	// next sub-agent run.
	Model        ChatModel
	SystemPrompt string
	Tools        []Tool
	StreamFn     StreamFn
	MaxTurns     int

	// ToolChoice sets the default tool_choice for every LLM call in this
	// sub-agent's loop. nil uses the provider default ("auto").
	ToolChoice any

	// StopAfterTools lists tool names that trigger early loop exit after
	// successful execution. Useful with ToolChoice "required" to let a
	// terminal tool (e.g. "commit_chapter") end the loop cleanly.
	StopAfterTools []string

	// OnMessage, if non-nil, is called after each message is appended to
	// context. The agentName and task are provided for session routing.
	OnMessage func(agentName, task string, msg AgentMessage)

	// Optional context lifecycle hooks for long-running sub-agents.
	ContextManager        ContextManager
	ContextManagerFactory func(model ChatModel) ContextManager
	TransformContext      func(ctx context.Context, msgs []AgentMessage) ([]AgentMessage, error)
	ConvertToLLM          func(msgs []AgentMessage) []Message

	// StopGuardFactory, if non-nil, creates a fresh StopGuard for each run.
	// The factory receives the agent name and task, enabling run-scoped state
	// (e.g. baseline progress captured at dispatch time).
	StopGuardFactory func(agentName, task string) StopGuard
}

SubAgentConfig defines a sub-agent's identity and capabilities.

type SubAgentTool

type SubAgentTool struct {
	// contains filtered or unexported fields
}

SubAgentTool implements the Tool interface. The main agent calls this tool to delegate tasks to specialized sub-agents with isolated contexts.

func NewSubAgentTool

func NewSubAgentTool(agents ...SubAgentConfig) *SubAgentTool

NewSubAgentTool creates a subagent tool from a set of agent configs.

func (*SubAgentTool) Description

func (t *SubAgentTool) Description() string

func (*SubAgentTool) Execute

func (t *SubAgentTool) Execute(ctx context.Context, args json.RawMessage) (json.RawMessage, error)

func (*SubAgentTool) Label

func (t *SubAgentTool) Label() string

func (*SubAgentTool) Name

func (t *SubAgentTool) Name() string

func (*SubAgentTool) Schema

func (t *SubAgentTool) Schema() map[string]any

func (*SubAgentTool) SetBgOutputFactory added in v1.5.3

func (t *SubAgentTool) SetBgOutputFactory(fn func(taskID, agentName string) (io.WriteCloser, string, error))

SetBgOutputFactory sets the factory that creates output writers for background tasks. The factory receives the task ID and agent name, returns a writer, file path, and error. If not set, background output is not persisted.

func (*SubAgentTool) SetCreateModel added in v1.5.1

func (t *SubAgentTool) SetCreateModel(fn func(name string) (ChatModel, error))

SetCreateModel sets the factory for resolving model names (e.g. "haiku", "gpt-4o-mini") to ChatModel instances at runtime. Enables LLM to override the default model per call.

func (*SubAgentTool) SetNotifyFn added in v1.5.1

func (t *SubAgentTool) SetNotifyFn(fn func(AgentMessage))

SetNotifyFn sets the callback invoked when a background task completes. Typically bound to Agent.FollowUp so the main agent receives the result as a follow-up message.

func (*SubAgentTool) SetTaskRuntime added in v1.6.0

func (t *SubAgentTool) SetTaskRuntime(rt *TaskRuntime)

SetTaskRuntime sets the shared task runtime for background task registration. When set, background tasks are registered here instead of managed internally.

type SwappableModel added in v1.5.7

type SwappableModel struct {
	// contains filtered or unexported fields
}

SwappableModel wraps a ChatModel and allows replacing the underlying model at runtime. Swaps take effect on the next call.

func NewSwappableModel added in v1.5.7

func NewSwappableModel(initial ChatModel) *SwappableModel

func (*SwappableModel) Current added in v1.5.7

func (m *SwappableModel) Current() ChatModel

func (*SwappableModel) Generate added in v1.5.7

func (m *SwappableModel) Generate(ctx context.Context, messages []Message, tools []ToolSpec, opts ...CallOption) (*LLMResponse, error)

func (*SwappableModel) GenerateStream added in v1.5.7

func (m *SwappableModel) GenerateStream(ctx context.Context, messages []Message, tools []ToolSpec, opts ...CallOption) (<-chan StreamEvent, error)

func (*SwappableModel) ProviderName added in v1.5.7

func (m *SwappableModel) ProviderName() string

func (*SwappableModel) SupportsTools added in v1.5.7

func (m *SwappableModel) SupportsTools() bool

func (*SwappableModel) Swap added in v1.5.7

func (m *SwappableModel) Swap(next ChatModel)

type SystemBlock added in v1.5.2

type SystemBlock struct {
	Text         string `json:"text"`
	CacheControl string `json:"cache_control,omitempty"` // e.g. "ephemeral"
}

SystemBlock is one segment of a multi-part system prompt. Use with AgentContext.SystemBlocks for per-block cache control.

type TaskNotification added in v1.6.0

type TaskNotification struct {
	TaskID      string     `json:"task_id"`
	Type        TaskType   `json:"type"`
	Status      TaskStatus `json:"status"`
	Description string     `json:"description,omitempty"`
	OutputFile  string     `json:"output_file,omitempty"`
	Error       string     `json:"error,omitempty"`
	ExitCode    *int       `json:"exit_code,omitempty"`
	Command     string     `json:"command,omitempty"`
	Agent       string     `json:"agent,omitempty"`
}

func NotificationFromEntry added in v1.6.0

func NotificationFromEntry(e *BackgroundTaskEntry) TaskNotification

func (TaskNotification) ToAgentMessage added in v1.6.0

func (n TaskNotification) ToAgentMessage() AgentMessage

type TaskRuntime added in v1.6.0

type TaskRuntime struct {
	// contains filtered or unexported fields
}

TaskRuntime is a unified registry for background tasks. Tools register their background work here; the Agent exposes a single Tasks()/StopTask()/StopAllTasks() surface to callers.

func NewTaskRuntime added in v1.6.0

func NewTaskRuntime() *TaskRuntime

NewTaskRuntime creates an empty task runtime.

func (*TaskRuntime) Get added in v1.6.0

Get returns a snapshot of a single task, or nil if not found.

func (*TaskRuntime) List added in v1.6.0

func (r *TaskRuntime) List() []BackgroundTaskEntry

List returns snapshots of all tasks, sorted by creation order (ascending seq ID).

func (*TaskRuntime) NextID added in v1.6.0

func (r *TaskRuntime) NextID(prefix string) string

NextID generates a sequential task ID with the given prefix (e.g. "shell", "bg").

func (*TaskRuntime) Register added in v1.6.0

func (r *TaskRuntime) Register(entry *BackgroundTaskEntry)

Register adds a task entry. The caller is responsible for populating all fields.

func (*TaskRuntime) Stop added in v1.6.0

func (r *TaskRuntime) Stop(id string) bool

Stop cancels a running task by ID. Returns true if a running task was found and its cancel function was invoked. The background goroutine is responsible for writing the terminal status (failed/completed) and EndedAt after it observes the cancellation. This avoids a race where Stop() writes the terminal state and the goroutine then skips its final metadata update.

func (*TaskRuntime) StopAll added in v1.6.0

func (r *TaskRuntime) StopAll() int

StopAll cancels all running tasks. Returns the number cancelled.

func (*TaskRuntime) Update added in v1.6.0

func (r *TaskRuntime) Update(id string, fn func(e *BackgroundTaskEntry)) bool

Update applies a mutation function to a task entry under the lock. Returns false if the task is not found.

type TaskStatus added in v1.6.0

type TaskStatus string

TaskStatus represents the lifecycle state of a background task.

const (
	TaskRunning   TaskStatus = "running"
	TaskCompleted TaskStatus = "completed"
	TaskFailed    TaskStatus = "failed"
)

type TaskType added in v1.6.0

type TaskType string

TaskType distinguishes the origin of a background task.

const (
	TaskTypeShell    TaskType = "shell"
	TaskTypeSubAgent TaskType = "subagent"
)

type ThinkingLevel

type ThinkingLevel string

ThinkingLevel configures the reasoning depth for models that support it.

const (
	ThinkingOff     ThinkingLevel = "off"
	ThinkingMinimal ThinkingLevel = "minimal"
	ThinkingLow     ThinkingLevel = "low"
	ThinkingMedium  ThinkingLevel = "medium"
	ThinkingHigh    ThinkingLevel = "high"
	ThinkingXHigh   ThinkingLevel = "xhigh"
)

type Tool

type Tool interface {
	Name() string
	Description() string
	Schema() map[string]any
	Execute(ctx context.Context, args json.RawMessage) (json.RawMessage, error)
}

Tool defines the minimal tool interface. Timeout control goes through context.Context. Tools can report execution progress via ReportToolProgress(ctx, payload).

type ToolCall

type ToolCall struct {
	ID   string          `json:"id"`
	Name string          `json:"name"`
	Args json.RawMessage `json:"args"`
}

ToolCall represents a tool invocation request from the LLM.

type ToolExecUpdateKind added in v1.5.1

type ToolExecUpdateKind string

ToolExecUpdateKind distinguishes update payload semantics for tool_exec_update events.

const (
	ToolExecUpdatePreview  ToolExecUpdateKind = "preview"
	ToolExecUpdateProgress ToolExecUpdateKind = "progress"
)

type ToolExecuteFunc added in v1.5.1

type ToolExecuteFunc func(ctx context.Context, args json.RawMessage) (json.RawMessage, error)

ToolExecuteFunc is the function signature for tool execution. Used as the "next" parameter in middleware chains.

type ToolLabeler

type ToolLabeler interface {
	Label() string
}

ToolLabeler is an optional interface for tools to provide a human-readable label.

type ToolMiddleware added in v1.5.1

type ToolMiddleware func(ctx context.Context, call ToolCall, next ToolExecuteFunc) (json.RawMessage, error)

ToolMiddleware wraps tool execution with cross-cutting concerns. Call next to continue the chain; skip next to short-circuit execution. Example: logging, timing, argument/result modification, audit.

type ToolProgressFunc

type ToolProgressFunc func(progress ProgressPayload)

ToolProgressFunc is a callback for reporting tool execution progress. Tools call ReportToolProgress to emit partial results during long operations.

type ToolResult

type ToolResult struct {
	ToolCallID    string          `json:"tool_call_id"`
	ToolName      string          `json:"-"` // internal: for toolErrors tracking
	Content       json.RawMessage `json:"content,omitempty"`
	ContentBlocks []ContentBlock  `json:"-"` // rich content (images); not serialized
	IsError       bool            `json:"is_error,omitempty"`
	Details       any             `json:"details,omitempty"` // optional metadata for UI display/logging
}

ToolResult represents a tool execution outcome.

type ToolSpec

type ToolSpec struct {
	Name         string `json:"name"`
	Description  string `json:"description"`
	Parameters   any    `json:"parameters"`
	DeferLoading bool   `json:"defer_loading,omitempty"`
}

ToolSpec describes a tool for the LLM (name + description + JSON schema).

type TurnInfo added in v1.6.4

type TurnInfo struct {
	// TurnIndex is 0 for the first LLM call in this run, 1 for the second, etc.
	TurnIndex int
}

TurnInfo carries per-turn state handed to reminder generators.

type Usage

type Usage struct {
	Input       int   `json:"input"`
	Output      int   `json:"output"`
	CacheRead   int   `json:"cache_read"`
	CacheWrite  int   `json:"cache_write"`
	TotalTokens int   `json:"total_tokens"`
	Cost        *Cost `json:"cost,omitempty"`
}

Usage tracks token consumption for a single LLM call.

Field semantics:

  • Input: prompt tokens sent to the model (includes cached tokens for some providers)
  • Output: completion tokens generated (includes reasoning tokens if applicable)
  • CacheRead: tokens served from prompt cache (Anthropic: cache_read_input_tokens)
  • CacheWrite: tokens written to prompt cache (Anthropic: cache_creation_input_tokens)
  • TotalTokens: provider-reported total, typically Input + Output
  • Cost: monetary cost computed from model pricing (nil if pricing unavailable)

func (*Usage) Add

func (u *Usage) Add(other *Usage)

Add accumulates another Usage into this one (nil-safe).

Directories

Path Synopsis
Package context provides strategy-driven context compression for agentcore: prompt projection, summary checkpoints, overflow recovery, and usage estimation.
Package context provides strategy-driven context compression for agentcore: prompt projection, summary checkpoints, overflow recovery, and usage estimation.
examples
multi command
single command
Package schema provides a fluent builder for JSON Schema objects.
Package schema provides a fluent builder for JSON Schema objects.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL