core

package
v0.23.1 Latest Latest
Warning

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

Go to latest
Published: Apr 24, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package core implements the agent loop, streaming, and message types.

Core is deliberately minimal and imports nothing from piglet — all capabilities (tools, commands, prompt sections) are provided by extensions through the [ext] package. The agent loop sends messages to a StreamProvider, executes tool calls, and repeats until the model is done.

Package core defines the domain types for piglet: messages, content, events, tools.

Index

Constants

View Source
const (
	EventBufferSize  = 100
	EmitTimeout      = 250 * time.Millisecond
	ToolConcurrency  = 10
	MaxRetryAttempts = 3
	RetryBaseDelay   = 500 * time.Millisecond
	RetryMaxDelay    = 5 * time.Second
)

Agent buffer and concurrency constants.

View Source
const (
	StreamTextDelta     = "text_delta"
	StreamThinkingDelta = "thinking_delta"
	StreamToolCallDelta = "toolcall_delta"
	StreamToolCallEnd   = "toolcall_end"
	StreamDone          = "done"
	StreamError         = "error"
)

Stream event type constants.

Variables

This section is empty.

Functions

This section is empty.

Types

type API

type API string

API identifies the wire protocol for a model.

const (
	APIOpenAI    API = "openai"
	APIAnthropic API = "anthropic"
	APIGoogle    API = "google"
)

type Agent

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

Agent manages the agent loop: streaming, tool execution, steering, events.

func NewAgent

func NewAgent(cfg AgentConfig) *Agent

NewAgent creates an agent with the given configuration. Panics with a descriptive message if required fields are missing.

func (*Agent) AppendMessage

func (a *Agent) AppendMessage(msg Message)

AppendMessage adds a message to the conversation history.

func (*Agent) Cancel added in v0.20.0

func (a *Agent) Cancel()

Cancel signals the agent to stop without blocking. The agent goroutine will finish asynchronously and close its event channel.

func (*Agent) FollowUp

func (a *Agent) FollowUp(msg Message)

FollowUp queues a message for after the agent finishes its current run.

func (*Agent) IsRunning

func (a *Agent) IsRunning() bool

IsRunning returns whether the agent loop is active.

func (*Agent) Messages

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

Messages returns a snapshot of the conversation history.

func (*Agent) Provider added in v0.4.0

func (a *Agent) Provider() StreamProvider

Provider returns the current streaming provider.

func (*Agent) SetMessages

func (a *Agent) SetMessages(msgs []Message)

SetMessages replaces the conversation history (used after compaction).

func (*Agent) SetModel

func (a *Agent) SetModel(m Model)

SetModel updates the model for future LLM calls.

func (*Agent) SetProvider added in v0.3.0

func (a *Agent) SetProvider(p StreamProvider)

SetProvider swaps the streaming provider for future LLM calls.

func (*Agent) SetStepMode

func (a *Agent) SetStepMode(on bool)

SetStepMode enables or disables step-by-step tool approval.

func (*Agent) SetSystem

func (a *Agent) SetSystem(s string)

SetSystem updates the system prompt.

func (*Agent) SetTools

func (a *Agent) SetTools(tools []Tool)

SetTools updates the active tool set.

func (*Agent) SetTurnContext added in v0.5.0

func (a *Agent) SetTurnContext(ctx []string)

SetTurnContext sets ephemeral context strings that are injected as system messages for the next turn only. Cleared after use by streamOnce.

func (*Agent) Start

func (a *Agent) Start(ctx context.Context, prompt string) <-chan Event

Start begins the agent loop with the given user prompt. Returns a channel of events. The channel is closed when the agent finishes. If the agent is already running, Start waits for it to finish before launching a new run. If the context is cancelled while waiting, a closed empty channel is returned.

func (*Agent) Steer

func (a *Agent) Steer(msg Message)

Steer injects a message that interrupts the current turn. Remaining tool calls are cancelled and the message is processed next.

func (*Agent) StepMode

func (a *Agent) StepMode() bool

StepMode returns whether step mode is enabled.

func (*Agent) StepRespond

func (a *Agent) StepRespond(action StepAction)

StepRespond sends an approval action to the waiting tool.

func (*Agent) Stop

func (a *Agent) Stop()

Stop cancels the agent and waits for it to finish.

func (*Agent) System added in v0.4.0

func (a *Agent) System() string

System returns the current system prompt.

type AgentConfig

type AgentConfig struct {
	System   string
	Model    Model
	Provider StreamProvider
	Tools    []Tool
	Options  StreamOptions

	MaxTurns        int // 0 = unlimited
	MaxMessages     int // hard cap on message count; 0 = unlimited
	MaxRetries      int // retry attempts on error; 0 = use default (3)
	ToolConcurrency int // max parallel tool calls; 0 = use default (10)

	MaxRetryDelay time.Duration // cap on retry backoff; 0 = use default (5s)

	// OnCompact is called when token usage exceeds CompactAt.
	// It receives the context and current messages, and returns the compacted message set.
	// If nil, compaction is disabled.
	OnCompact func(ctx context.Context, messages []Message) ([]Message, error)
	CompactAt int // token threshold; 0 = disabled
}

AgentConfig configures the agent loop.

type AssistantContent

type AssistantContent interface {
	// contains filtered or unexported methods
}

AssistantContent is content in assistant messages. Implementations: TextContent, ThinkingContent, ToolCall.

type AssistantMessage

type AssistantMessage struct {
	Content    []AssistantContent `json:"content"`
	Model      string             `json:"model"`
	Provider   string             `json:"provider"`
	Usage      Usage              `json:"usage"`
	StopReason StopReason         `json:"stopReason"`
	Error      string             `json:"error,omitempty"`
	Timestamp  time.Time          `json:"timestamp"`
}

AssistantMessage is a response from the LLM.

func (*AssistantMessage) UnmarshalJSON

func (m *AssistantMessage) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom unmarshaling for AssistantMessage because Content is an interface slice ([]AssistantContent).

type ContentBlock

type ContentBlock interface {
	// contains filtered or unexported methods
}

ContentBlock is content in user messages and tool results. Implementations: TextContent, ImageContent.

type Event

type Event interface {
	// contains filtered or unexported methods
}

Event is emitted by the agent on a buffered channel. Use a type switch on the concrete type.

type EventAgentEnd

type EventAgentEnd struct {
	Messages []Message
}

EventAgentEnd signals the agent loop has finished.

type EventAgentInit added in v0.16.8

type EventAgentInit struct {
	ToolCount int
}

EventAgentInit signals the agent is fully configured and about to process. Emitted after session load check, before the first user message is appended.

type EventAgentStart

type EventAgentStart struct{}

EventAgentStart signals the agent loop has begun.

type EventCompact added in v0.4.0

type EventCompact struct {
	Before          int
	After           int
	TokensAtCompact int
}

EventCompact signals that auto-compaction occurred.

type EventMaxTurns

type EventMaxTurns struct {
	Count int
	Max   int
}

EventMaxTurns signals the agent stopped because MaxTurns was reached.

type EventMessagePre added in v0.16.8

type EventMessagePre struct {
	Content string
}

EventMessagePre signals a user message is about to be appended to history. Emitted before the message enters the conversation, allowing observers to react.

type EventPromptBuild added in v0.16.8

type EventPromptBuild struct {
	System string
}

EventPromptBuild signals the final assembled system prompt. Extensions can observe it for debugging or logging.

type EventRetry

type EventRetry struct {
	Attempt int
	Max     int
	DelayMs int
	Error   string
}

EventRetry signals the agent is retrying after a transient error.

type EventSessionLoad added in v0.16.8

type EventSessionLoad struct {
	MessageCount int
}

EventSessionLoad signals that the agent has pre-loaded conversation history. Emitted at the start of a run when messages were restored from a prior session.

type EventStepWait

type EventStepWait struct {
	ToolCallID string
	ToolName   string
	Args       map[string]any
}

EventStepWait signals the agent is paused, waiting for step approval.

type EventStreamDelta

type EventStreamDelta struct {
	Kind  string // "text", "thinking", "toolcall"
	Index int
	Delta string
}

EventStreamDelta carries an incremental streaming update.

type EventStreamDone

type EventStreamDone struct {
	Message *AssistantMessage
}

EventStreamDone signals the LLM finished streaming. Message is complete.

type EventToolEnd

type EventToolEnd struct {
	ToolCallID string
	ToolName   string
	Result     any
	IsError    bool
}

EventToolEnd signals a tool execution has finished.

type EventToolStart

type EventToolStart struct {
	ToolCallID string
	ToolName   string
	Args       map[string]any
}

EventToolStart signals a tool execution is beginning.

type EventToolUpdate

type EventToolUpdate struct {
	ToolCallID string
	ToolName   string
	Partial    any
}

EventToolUpdate carries a partial tool result for live display.

type EventTurnEnd

type EventTurnEnd struct {
	Assistant   *AssistantMessage
	ToolResults []*ToolResultMessage
}

EventTurnEnd signals a turn has completed.

type EventTurnStart

type EventTurnStart struct{}

EventTurnStart signals a new turn (LLM call + tool execution).

type ImageContent

type ImageContent struct {
	Data     string `json:"data"`
	MimeType string `json:"mimeType"`
}

ImageContent is a base64-encoded image.

type Message

type Message interface {
	// contains filtered or unexported methods
}

Message is the sealed union of conversation messages. Use a type switch: *UserMessage, *AssistantMessage, *ToolResultMessage.

type Model

type Model struct {
	ID            string            `json:"id"`
	Name          string            `json:"name"`
	API           API               `json:"api"`
	Provider      string            `json:"provider"`
	BaseURL       string            `json:"baseUrl,omitempty"`
	Reasoning     bool              `json:"reasoning"`
	ContextWindow int               `json:"contextWindow"`
	MaxTokens     int               `json:"maxTokens"`
	Cost          ModelCost         `json:"cost"`
	Headers       map[string]string `json:"headers,omitempty"`
}

Model describes an LLM endpoint.

func (Model) DisplayName added in v0.3.0

func (m Model) DisplayName() string

DisplayName returns "provider/name" for UI display.

type ModelCost

type ModelCost struct {
	Input      float64 `json:"input" yaml:"input"`
	Output     float64 `json:"output" yaml:"output"`
	CacheRead  float64 `json:"cacheRead" yaml:"cacheRead"`
	CacheWrite float64 `json:"cacheWrite" yaml:"cacheWrite"`
}

ModelCost is per-million-token pricing.

type StepAction

type StepAction int

StepAction is the user's response when step mode pauses before a tool.

const (
	StepApprove StepAction = iota
	StepSkip
	StepAbort
)

type StopReason

type StopReason string

StopReason indicates why the assistant stopped generating.

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

type StreamEvent

type StreamEvent struct {
	Type    string            // "text_delta", "thinking_delta", "toolcall_delta", "toolcall_end", "done", "error"
	Index   int               // content block index
	Delta   string            // incremental text for delta events
	Tool    *ToolCall         // complete tool call on "toolcall_end"
	Message *AssistantMessage // complete message on "done" or "error"
	Error   error             // set on "error"
}

StreamEvent is emitted by providers during streaming. Type discriminates; optional fields carry data for that type.

type StreamOptions

type StreamOptions struct {
	Temperature *float64
	MaxTokens   *int
	Thinking    ThinkingLevel
	APIKeyFunc  func(provider string) string
	Headers     map[string]string
}

StreamOptions configures an LLM streaming call.

type StreamProvider

type StreamProvider interface {
	Stream(ctx context.Context, req StreamRequest) <-chan StreamEvent
}

StreamProvider is the single interface all LLM providers implement. Three implementations: OpenAI-compatible, Anthropic, Google.

Stream returns a channel of StreamEvents. Implementations MUST close the channel when ctx is cancelled or streaming completes. Failure to close the channel leaks the consumer goroutine.

type StreamRequest

type StreamRequest struct {
	System   string
	Messages []Message
	Tools    []ToolSchema
	Options  StreamOptions
}

StreamRequest is the input to a provider's Stream method.

type TextContent

type TextContent struct {
	Text string `json:"text"`
}

TextContent is a text block.

type ThinkingContent

type ThinkingContent struct {
	Thinking string `json:"thinking"`
}

ThinkingContent is a reasoning/thinking block.

type ThinkingLevel

type ThinkingLevel string

ThinkingLevel controls reasoning depth for models that support it.

const (
	ThinkingOff    ThinkingLevel = "off"
	ThinkingLow    ThinkingLevel = "low"
	ThinkingMedium ThinkingLevel = "medium"
	ThinkingHigh   ThinkingLevel = "high"
)

type Tool

type Tool struct {
	ToolSchema
	Execute ToolExecuteFn
}

Tool is a schema plus its execute function.

type ToolCall

type ToolCall struct {
	ID           string         `json:"id"`
	Name         string         `json:"name"`
	Arguments    map[string]any `json:"arguments"`
	ProviderMeta map[string]any `json:"providerMeta,omitempty"` // opaque provider data (e.g. Gemini thought signatures)
}

ToolCall is a request from the assistant to invoke a tool.

type ToolExecuteFn

type ToolExecuteFn func(ctx context.Context, id string, args map[string]any) (*ToolResult, error)

ToolExecuteFn is the function signature for tool execution. ctx carries cancellation (e.g., from steering or abort). id is the tool call ID from the LLM. args are the parsed JSON arguments.

type ToolResult

type ToolResult struct {
	Content []ContentBlock `json:"content"`
	Details any            `json:"details,omitempty"` // opaque, forwarded to UI via events
}

ToolResult is what a tool returns after execution.

type ToolResultMessage

type ToolResultMessage struct {
	ToolCallID string         `json:"toolCallId"`
	ToolName   string         `json:"toolName"`
	Content    []ContentBlock `json:"content"`
	IsError    bool           `json:"isError"`
	Timestamp  time.Time      `json:"timestamp"`
}

ToolResultMessage is the result of a tool execution sent back to the LLM.

func (*ToolResultMessage) UnmarshalJSON

func (m *ToolResultMessage) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom unmarshaling for ToolResultMessage because Content is an interface slice ([]ContentBlock).

type ToolSchema

type ToolSchema struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Parameters  any    `json:"parameters"` // JSON Schema object
}

ToolSchema is the definition sent to the LLM so it knows what tools exist.

type Usage

type Usage struct {
	InputTokens      int     `json:"inputTokens"`
	OutputTokens     int     `json:"outputTokens"`
	CacheReadTokens  int     `json:"cacheReadTokens"`
	CacheWriteTokens int     `json:"cacheWriteTokens"`
	Cost             float64 `json:"cost"`
}

Usage tracks token consumption and cost for an LLM call.

type UserMessage

type UserMessage struct {
	Content   string         `json:"content,omitempty"`
	Blocks    []ContentBlock `json:"blocks,omitempty"`
	Timestamp time.Time      `json:"timestamp"`
}

UserMessage is a message from the user.

func (*UserMessage) UnmarshalJSON

func (m *UserMessage) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom unmarshaling for UserMessage because Blocks is an interface slice ([]ContentBlock).

Jump to

Keyboard shortcuts

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