agent

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: May 6, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package agent provides the session-based streaming agent loop that ties llm, tools, History, and Locker together.

The library never sees a scope parameter. Multi-tenant callers bind scope at VFS-tool registration time via vfs.ScopedStorage.Scope (ADR-013).

Concurrency is bounded at the session granularity by a pluggable Locker (ADR-024). v1 ships LocalLocker for in-process use; v1.1 ships a Redis impl; callers can implement Locker themselves for any other backend.

Index

Constants

View Source
const (
	EndReasonStop      = "stop"
	EndReasonMaxTurns  = "max_turns"
	EndReasonError     = "error"
	EndReasonTimeout   = "timeout"
	EndReasonCancelled = "cancelled"
)

EndReason values emitted on EventEnd.

Variables

This section is empty.

Functions

func Drain

func Drain(events <-chan Event) ([]llm.Message, error)

Drain consumes events from the channel until it closes and returns the assembled assistant message followed by tool-result messages, in the order they were produced this turn. Returns the first error encountered on EventError.

Drain is the recommended way for RunWithMessages callers to obtain the turn's output messages for appending to their own history store. Callers who also need streaming (e.g., to a UI) fan out the channel themselves before passing one branch to Drain.

func RegisterVFSTools

func RegisterVFSTools(reg *tools.Registry, opts *VFSToolOptions) error

RegisterVFSTools registers read_file, list_files into the supplied registry, plus write_file/delete_file when not read-only. If opts.Storage satisfies vfs.Searchable, also registers `search`. Tool handlers capture opts.Storage via closure (ADR-021).

Types

type Event

type Event struct {
	Kind       EventKind
	Text       string
	ToolCall   *llm.ToolCall
	ToolResult *ToolResult
	Image      *llm.ImagePart
	Usage      *llm.Usage
	Err        error
	EndReason  string
}

Event is one streaming event from a session run.

type EventKind

type EventKind string

EventKind identifies the kind of an agent.Event. String-valued so kinds can be added in any order without renumbering callers.

const (
	EventText       EventKind = "text"
	EventThinking   EventKind = "thinking"
	EventToolCall   EventKind = "tool_call"
	EventToolResult EventKind = "tool_result"
	EventImage      EventKind = "image"
	EventUsage      EventKind = "usage"
	EventError      EventKind = "error"
	EventEnd        EventKind = "end"
)

type History

type History interface {
	Append(ctx context.Context, sessionID string, msgs ...llm.Message) error
	Read(ctx context.Context, sessionID string) ([]llm.Message, error)
}

History is the pluggable conversation-history interface (ADR-014).

SessionID is opaque to aikido; implementations use it as a key into whatever store the caller has. v1 ships an in-memory backend under agent/history/memory.

Append is variadic so the agent can flush a turn's worth of messages (user, assistant, tool results) in a single backend round-trip.

type LocalLocker

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

LocalLocker is the in-process implementation of Locker. Suitable for single-replica deployments and tests. Memory grows with the number of distinct session IDs seen; call Forget(id) to drop a key once the session is finished.

func NewLocalLocker

func NewLocalLocker() *LocalLocker

NewLocalLocker returns a fresh in-process Locker.

func (*LocalLocker) Forget

func (l *LocalLocker) Forget(id string)

Forget drops the per-id mutex for the given session id. Safe to call after all Run calls for the session have completed.

func (*LocalLocker) Lock

func (l *LocalLocker) Lock(ctx context.Context, sessionID string) (func(), error)

Lock blocks until the per-id lock is acquired or ctx cancels.

type Locker

type Locker interface {
	Lock(ctx context.Context, sessionID string) (unlock func(), err error)
}

Locker provides mutual exclusion keyed by session ID.

The Session acquires a lock on its ID before each Run begins (covering History.Read at turn start) and releases it after EventEnd. The unlock function returned by Lock must be called exactly once; the agent always calls it via defer.

type Session

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

Session bundles a session ID, a model + system prompt, a tool registry, a History plug-in, and a Locker plug-in. Multiple Run calls share the session's history, serialized by the Locker.

func NewLocalSession

func NewLocalSession(opts *SessionOptions) (*Session, error)

NewLocalSession is a convenience constructor for single-replica deployments and tests. It auto-supplies in-memory implementations for History and Locker if the caller leaves them unset.

For multi-replica deployments, or any setup needing a custom Locker (e.g., Redis) or a persistent History (e.g., Postgres), use NewSession directly and supply your own plug-ins.

History defaults to an in-memory store; conversation is lost when the process restarts.

func NewSession

func NewSession(opts *SessionOptions) (*Session, error)

NewSession constructs a Session. Returns an error if any required field (Client, History, Locker, Model, ID) is empty.

func (*Session) Run

func (s *Session) Run(ctx context.Context, userText string) (<-chan Event, error)

Run executes one agent turn from a single user message.

The user message and the assistant's response (including any tool calls and tool results produced this turn) are accumulated for one variadic History.Append at end of turn. The returned channel closes after EventEnd.

On EndReasonError (including History I/O failure or Lock-acquire timeout) the History is NOT updated for this turn — the caller knows to retry, and the durable transcript stays consistent.

func (*Session) RunWithMessages

func (s *Session) RunWithMessages(ctx context.Context, history []llm.Message) (<-chan Event, error)

RunWithMessages is the lower-level escape hatch for callers that maintain their own history shape (trimming, branched conversations, agent-as-subroutine).

The history slice is the conversation so far, excluding the system prompt (which Run prepends from SessionOptions.SystemPrompt). RunWithMessages does not append to History; the caller owns the message log here and uses Drain to assemble the produced messages.

type SessionOptions

type SessionOptions struct {
	ID           string
	Client       llm.Client
	Tools        *tools.Registry
	History      History
	Locker       Locker
	Model        string
	SystemPrompt string

	MaxTurns       int
	RunTimeout     time.Duration
	LLMCallTimeout time.Duration
	MaxTokens      int
	Temperature    *float32

	Logger *slog.Logger
}

SessionOptions configure a Session.

type ToolResult

type ToolResult struct {
	CallID  string
	Name    string
	OK      bool
	Content any
	Error   string
}

ToolResult is one tool execution result surfaced to the caller.

type VFSToolOptions

type VFSToolOptions struct {
	Storage           vfs.Storage // required; pre-bound to scope if multi-tenant
	HideHiddenPaths   bool        // hide paths beginning with "_" or "." (per segment)
	AllowedExtensions []string    // nil = allow all
	MaxFileBytes      int64       // default 1 MiB; 0 means default

	// ReadOnly disables registration of write_file and delete_file. Use this
	// for fixed-corpus deployments (e.g. an embedded knowledge base over
	// vfs/embedfs). Search and list/read remain registered.
	ReadOnly bool
}

VFSToolOptions configure the built-in VFS tools.

Directories

Path Synopsis
Package history provides a reusable conformance suite for the agent.History interface.
Package history provides a reusable conformance suite for the agent.History interface.
memory
Package memory provides an in-process agent.History backend.
Package memory provides an in-process agent.History backend.

Jump to

Keyboard shortcuts

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