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
- type API
- type Agent
- func (a *Agent) AppendMessage(msg Message)
- func (a *Agent) Cancel()
- func (a *Agent) FollowUp(msg Message)
- func (a *Agent) IsRunning() bool
- func (a *Agent) Messages() []Message
- func (a *Agent) Provider() StreamProvider
- func (a *Agent) SetMessages(msgs []Message)
- func (a *Agent) SetModel(m Model)
- func (a *Agent) SetProvider(p StreamProvider)
- func (a *Agent) SetStepMode(on bool)
- func (a *Agent) SetSystem(s string)
- func (a *Agent) SetTools(tools []Tool)
- func (a *Agent) SetTurnContext(ctx []string)
- func (a *Agent) Start(ctx context.Context, prompt string) <-chan Event
- func (a *Agent) Steer(msg Message)
- func (a *Agent) StepMode() bool
- func (a *Agent) StepRespond(action StepAction)
- func (a *Agent) Stop()
- func (a *Agent) System() string
- type AgentConfig
- type AssistantContent
- type AssistantMessage
- type ContentBlock
- type Event
- type EventAgentEnd
- type EventAgentInit
- type EventAgentStart
- type EventCompact
- type EventMaxTurns
- type EventMessagePre
- type EventPromptBuild
- type EventRetry
- type EventSessionLoad
- type EventStepWait
- type EventStreamDelta
- type EventStreamDone
- type EventToolEnd
- type EventToolStart
- type EventToolUpdate
- type EventTurnEnd
- type EventTurnStart
- type ImageContent
- type Message
- type Model
- type ModelCost
- type StepAction
- type StopReason
- type StreamEvent
- type StreamOptions
- type StreamProvider
- type StreamRequest
- type TextContent
- type ThinkingContent
- type ThinkingLevel
- type Tool
- type ToolCall
- type ToolExecuteFn
- type ToolResult
- type ToolResultMessage
- type ToolSchema
- type Usage
- type UserMessage
Constants ¶
const ( EventBufferSize = 100 EmitTimeout = 250 * time.Millisecond ToolConcurrency = 10 MaxRetryAttempts = 3 RetryBaseDelay = 500 * time.Millisecond RetryMaxDelay = 5 * time.Second )
Agent buffer and concurrency constants.
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 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 ¶
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) Provider ¶ added in v0.4.0
func (a *Agent) Provider() StreamProvider
Provider returns the current streaming provider.
func (*Agent) SetMessages ¶
SetMessages replaces the conversation history (used after compaction).
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 ¶
SetStepMode enables or disables step-by-step tool approval.
func (*Agent) SetTurnContext ¶ added in v0.5.0
SetTurnContext sets ephemeral context strings that are injected as system messages for the next turn only. Cleared after use by streamOnce.
func (*Agent) Start ¶
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 ¶
Steer injects a message that interrupts the current turn. Remaining tool calls are cancelled and the message is processed next.
func (*Agent) StepRespond ¶
func (a *Agent) StepRespond(action StepAction)
StepRespond sends an approval action to the waiting tool.
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
EventCompact signals that auto-compaction occurred.
type EventMaxTurns ¶
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 ¶
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 ¶
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 ¶
EventToolEnd signals a tool execution has finished.
type EventToolStart ¶
EventToolStart signals a tool execution is beginning.
type EventToolUpdate ¶
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 ¶
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
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 ¶
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).