executor

package
v0.5.4 Latest Latest
Warning

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

Go to latest
Published: Mar 28, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package executor provides the core autonomous agent execution loop.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EstimateTokens

func EstimateTokens(messages []provider.Message) int

EstimateTokens estimates the number of tokens in a message slice. Uses a rough heuristic of 4 characters per token (standard for English text).

Types

type ApprovalRecord

type ApprovalRecord struct {
	ID              string
	Status          ApprovalStatus
	ReviewerComment string
}

ApprovalRecord is a resolved approval request.

type ApprovalStatus

type ApprovalStatus string

ApprovalStatus represents the resolution state of an approval.

const (
	ApprovalPending  ApprovalStatus = "pending"
	ApprovalApproved ApprovalStatus = "approved"
	ApprovalRejected ApprovalStatus = "rejected"
	ApprovalTimeout  ApprovalStatus = "timeout"
)

type Approver

type Approver interface {
	// WaitForResolution blocks until the approval with the given ID is resolved
	// or the timeout elapses.
	WaitForResolution(ctx context.Context, approvalID string, timeout time.Duration) (*ApprovalRecord, error)
}

Approver manages approval gate blocking.

type Config

type Config struct {
	// Provider is the AI backend. Required.
	Provider provider.Provider

	// ToolRegistry provides tool definitions and execution. Optional.
	ToolRegistry *tools.Registry

	// Approver handles approval gates. Defaults to NullApprover.
	Approver Approver

	// HumanRequester handles blocking human-request gates. Defaults to NullHumanRequester.
	HumanRequester HumanRequester

	// SecretRedactor redacts secrets from messages. Defaults to NullSecretRedactor.
	SecretRedactor SecretRedactor

	// Transcript records conversation entries. Defaults to NullTranscript.
	Transcript TranscriptRecorder

	// Memory provides persistent agent memory. Defaults to NullMemoryStore.
	Memory MemoryStore

	// MaxIterations caps the agent loop. Default: 10.
	MaxIterations int

	// ApprovalTimeout is how long to wait for human approval. Default: 30m.
	ApprovalTimeout time.Duration

	// RequestTimeout is how long to wait for human request response. Default: 60m.
	RequestTimeout time.Duration

	// LoopDetector config. Zero values use defaults.
	LoopDetection LoopDetectorConfig

	// CompactionThreshold is the fraction of context limit at which compaction triggers. Default: 0.80.
	CompactionThreshold float64

	// TaskID and ProjectID are used for transcript recording.
	TaskID    string
	ProjectID string
}

Config holds all dependencies for the executor. Nil interface fields are replaced with their Null* implementations.

type ContextManager

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

ContextManager tracks token usage across a message array and compacts the conversation when it approaches the model's context limit.

func NewContextManager

func NewContextManager(providerName string, compactionThreshold float64) *ContextManager

NewContextManager creates a ContextManager for the given provider. The model name is used to look up the context window size. compactionThreshold sets the fraction of the context limit that triggers compaction; pass 0 to use the default (0.80).

func (*ContextManager) Compact

func (cm *ContextManager) Compact(
	ctx context.Context,
	messages []provider.Message,
	aiProvider provider.Provider,
) []provider.Message

Compact compresses the conversation history by:

  1. Keeping the system message (index 0) and the most recent 2 exchanges.
  2. Summarising the middle portion using the LLM provider.
  3. Injecting the summary as a system-level context note.

If summarisation fails, the middle messages are replaced with a placeholder rather than aborting. Returns the compacted message slice.

func (*ContextManager) Compactions

func (cm *ContextManager) Compactions() int

Compactions returns how many times compaction has been applied.

func (*ContextManager) ContextLimitTokens

func (cm *ContextManager) ContextLimitTokens() int

ContextLimitTokens returns the model's context window size in tokens.

func (*ContextManager) NeedsCompaction

func (cm *ContextManager) NeedsCompaction(messages []provider.Message) bool

NeedsCompaction returns true if the estimated token count exceeds the threshold.

func (*ContextManager) SetModelLimit

func (cm *ContextManager) SetModelLimit(model string, limit int)

SetModelLimit overrides the context token limit for a specific model name pattern. This allows module config to adjust limits without modifying the built-in defaults.

func (*ContextManager) TokenUsage

func (cm *ContextManager) TokenUsage(messages []provider.Message) (estimated, limit int)

TokenUsage returns the current estimated tokens and the context limit.

type HumanRequest

type HumanRequest struct {
	ID              string
	RequestType     RequestType
	Status          RequestStatus
	ResponseData    string
	ResponseComment string
	Metadata        string // JSON
}

HumanRequest is a resolved human request record.

type HumanRequester

type HumanRequester interface {
	// WaitForResolution blocks until the request with the given ID is resolved
	// or the timeout elapses.
	WaitForResolution(ctx context.Context, requestID string, timeout time.Duration) (*HumanRequest, error)
}

HumanRequester manages blocking human-request gates.

type LoopDetector

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

LoopDetector detects agent execution loops using multiple heuristics.

func NewLoopDetector

func NewLoopDetector(cfg LoopDetectorConfig) *LoopDetector

NewLoopDetector creates a LoopDetector with the given config. Zero values in cfg are replaced with defaults (MaxConsecutive=3, MaxErrors=2, MaxAlternating=3, MaxNoProgress=3).

func (*LoopDetector) Check

func (ld *LoopDetector) Check() (LoopStatus, string)

Check evaluates the recorded history for loop patterns and returns the current status along with a human-readable explanation. Checks are evaluated in priority order: hard breaks take precedence over warnings.

func (*LoopDetector) Record

func (ld *LoopDetector) Record(toolName string, args map[string]any, result string, isError bool)

Record appends a tool invocation to the history.

func (*LoopDetector) Reset

func (ld *LoopDetector) Reset()

Reset clears recorded history.

type LoopDetectorConfig

type LoopDetectorConfig struct {
	// MaxConsecutive is the number of identical consecutive tool calls before a loop is detected.
	// Default: 3.
	MaxConsecutive int
	// MaxErrors is the number of times the same tool call can return the same error before a loop is detected.
	// Default: 2.
	MaxErrors int
	// MaxAlternating is the number of A/B alternating cycles before a loop is detected.
	// Default: 3.
	MaxAlternating int
	// MaxNoProgress is the number of identical (same args + same result) non-error calls before a loop is detected.
	// Default: 3.
	MaxNoProgress int
}

LoopDetectorConfig holds configurable thresholds for loop detection.

type LoopStatus

type LoopStatus int

LoopStatus represents the result of a loop check.

const (
	// LoopStatusOK means no loop detected.
	LoopStatusOK LoopStatus = iota
	// LoopStatusWarning means a potential loop pattern is forming.
	LoopStatusWarning
	// LoopStatusBreak means a definitive loop is detected; execution should stop.
	LoopStatusBreak
)

type MemoryEntry

type MemoryEntry struct {
	ID       string
	AgentID  string
	Content  string
	Category string
}

MemoryEntry is a single piece of persistent agent memory.

type MemoryStore

type MemoryStore interface {
	// Search finds relevant memories for agentID using query text.
	Search(ctx context.Context, agentID, query string, limit int) ([]MemoryEntry, error)
	// Save persists a memory entry.
	Save(ctx context.Context, entry MemoryEntry) error
	// ExtractAndSave extracts facts from a transcript and saves them.
	ExtractAndSave(ctx context.Context, agentID, transcript string, embedder provider.Embedder) error
}

MemoryStore provides persistent memory storage and retrieval.

type NullApprover

type NullApprover struct{}

NullApprover is a no-op Approver — always returns "approved".

func (*NullApprover) WaitForResolution

func (n *NullApprover) WaitForResolution(_ context.Context, _ string, _ time.Duration) (*ApprovalRecord, error)

type NullHumanRequester

type NullHumanRequester struct{}

NullHumanRequester is a no-op HumanRequester — always returns expired.

func (*NullHumanRequester) WaitForResolution

func (n *NullHumanRequester) WaitForResolution(_ context.Context, _ string, _ time.Duration) (*HumanRequest, error)

type NullMemoryStore

type NullMemoryStore struct{}

NullMemoryStore is a no-op MemoryStore.

func (*NullMemoryStore) ExtractAndSave

func (n *NullMemoryStore) ExtractAndSave(_ context.Context, _ string, _ string, _ provider.Embedder) error

func (*NullMemoryStore) Save

func (*NullMemoryStore) Search

func (n *NullMemoryStore) Search(_ context.Context, _, _ string, _ int) ([]MemoryEntry, error)

type NullSecretRedactor

type NullSecretRedactor struct{}

NullSecretRedactor is a no-op SecretRedactor.

func (*NullSecretRedactor) CheckAndRedact

func (n *NullSecretRedactor) CheckAndRedact(_ *provider.Message)

func (*NullSecretRedactor) Redact

func (n *NullSecretRedactor) Redact(text string) string

type NullTranscript

type NullTranscript struct{}

NullTranscript is a no-op TranscriptRecorder.

func (*NullTranscript) Record

type RequestStatus

type RequestStatus string

RequestStatus represents the resolution state of a human request.

const (
	RequestPending   RequestStatus = "pending"
	RequestResolved  RequestStatus = "resolved"
	RequestCancelled RequestStatus = "cancelled"
	RequestExpired   RequestStatus = "expired"
)

type RequestType

type RequestType string

RequestType categorizes what the agent needs from the human.

const (
	RequestTypeToken  RequestType = "token"
	RequestTypeBinary RequestType = "binary"
	RequestTypeAccess RequestType = "access"
	RequestTypeInfo   RequestType = "info"
	RequestTypeCustom RequestType = "custom"
)

type Result

type Result struct {
	Content    string
	Thinking   string
	Iterations int
	Status     string // "completed", "failed", "loop_detected", "approval_timeout", "request_expired"
	Error      string
}

Result is the outcome of an Execute call.

func Execute

func Execute(ctx context.Context, cfg Config, systemPrompt, userTask, agentID string) (*Result, error)

Execute runs the autonomous agent loop with the given config. systemPrompt is the agent's system instructions; userTask is the task to complete; agentID is the agent's identifier used for memory and transcript recording.

type SecretRedactor

type SecretRedactor interface {
	// Redact returns the text with known secrets replaced.
	Redact(text string) string
	// CheckAndRedact redacts secrets from a message in place.
	CheckAndRedact(msg *provider.Message)
}

SecretRedactor redacts secrets from text.

type TranscriptEntry

type TranscriptEntry struct {
	ID         string
	AgentID    string
	TaskID     string
	ProjectID  string
	Iteration  int
	Role       provider.Role
	Content    string
	Thinking   string
	ToolCalls  []provider.ToolCall
	ToolCallID string
}

TranscriptEntry is a single recorded message in the agent conversation.

type TranscriptRecorder

type TranscriptRecorder interface {
	Record(ctx context.Context, entry TranscriptEntry) error
}

TranscriptRecorder records agent interactions.

Jump to

Keyboard shortcuts

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