Documentation
¶
Index ¶
- Constants
- Variables
- func ResolveChannelByName(channels map[string]*Channel, name string) (conversationID, adapterName, externalID string, wildcard bool, err error)
- type ActiveChannelStore
- type AdapterBinding
- type AgentCostSummary
- type Binding
- type Channel
- func (ch *Channel) ConversationID() string
- func (ch *Channel) EphemeralConversationID() string
- func (ch *Channel) IsBroadcast() bool
- func (ch *Channel) IsEphemeral() bool
- func (ch *Channel) ResolveAllBindings() []AdapterBinding
- func (ch *Channel) ResolveBinding() (adapterName, externalID string, wildcard, ok bool)
- type ChatEvent
- type ChatEventFunc
- type ConversationInfo
- type ConversationInfoWithStats
- type ConversationStatsRow
- type Dispatcher
- func (d *Dispatcher) ActiveChannelsForChannel(channelName string) []string
- func (d *Dispatcher) AddAgent(name string, engine *Engine) error
- func (d *Dispatcher) AddChannel(ch *Channel) error
- func (d *Dispatcher) Agent(name string) *Engine
- func (d *Dispatcher) Agents() []string
- func (d *Dispatcher) Channels() map[string]*Channel
- func (d *Dispatcher) ClearActiveChannelByKey(ctx context.Context, adapterKey, channelName string) error
- func (d *Dispatcher) Dispatch(ctx context.Context, agentName string, msg adapter.IncomingMessage) error
- func (d *Dispatcher) FallbackAgent() *Engine
- func (d *Dispatcher) IsPanicked() bool
- func (d *Dispatcher) ListModelDetails(ctx context.Context, providerFilter string) []llm.ModelInfo
- func (d *Dispatcher) ListModels(ctx context.Context) []string
- func (d *Dispatcher) LoadActiveChannels(ctx context.Context) error
- func (d *Dispatcher) Panic()
- func (d *Dispatcher) PanicTime() time.Time
- func (d *Dispatcher) RemoveAgent(name string) error
- func (d *Dispatcher) RemoveChannel(ctx context.Context, name string) error
- func (d *Dispatcher) RenameAgent(oldName, newName string) error
- func (d *Dispatcher) Resume()
- func (d *Dispatcher) Run(ctx context.Context) error
- func (d *Dispatcher) SendFor(adapterName string) SendFunc
- func (d *Dispatcher) SendVia(ctx context.Context, adapterName string, msg adapter.OutgoingMessage) error
- func (d *Dispatcher) SetActiveChannelByKey(ctx context.Context, adapterKey, channelName string) error
- func (d *Dispatcher) StopChat(adapterName, externalID string) error
- func (d *Dispatcher) UpdateChannel(name string, ch *Channel) error
- type DispatcherOption
- type Engine
- func (e *Engine) AdapterContext() (adapterName, externalID, conversationID string)
- func (e *Engine) AppendMemoryEntry(entry string) error
- func (e *Engine) AppendSkill(s skill.Skill)
- func (e *Engine) Chat(ctx context.Context, msg adapter.IncomingMessage) (string, error)
- func (e *Engine) ChatWithEvents(ctx context.Context, msg adapter.IncomingMessage, onEvent ChatEventFunc) (string, error)
- func (e *Engine) ClearSession(ctx context.Context, convID string) error
- func (e *Engine) CompactSession(ctx context.Context, convID string) (string, error)
- func (e *Engine) DisplayName() string
- func (e *Engine) DryRun(ctx context.Context, msg adapter.IncomingMessage, policy ExecPolicy) (*TurnResult, error)
- func (e *Engine) GetSkill(name string) (skill.Skill, bool)
- func (e *Engine) HandleMessage(ctx context.Context, msg adapter.IncomingMessage) error
- func (e *Engine) HandleMessageWithEvents(ctx context.Context, msg adapter.IncomingMessage, onEvent ChatEventFunc) error
- func (e *Engine) HasTools() bool
- func (e *Engine) LLMRouter() *llm.Router
- func (e *Engine) ListModelDetails(ctx context.Context, providerFilter string) []llm.ModelInfo
- func (e *Engine) ListModels(ctx context.Context) []string
- func (e *Engine) Location() *time.Location
- func (e *Engine) MaxToolRounds() int
- func (e *Engine) ModelName() string
- func (e *Engine) Name() string
- func (e *Engine) NudgeResetExternal(convID, kind string)
- func (e *Engine) PermissionTier() string
- func (e *Engine) PersonaDir() string
- func (e *Engine) PersonaSection(section string) (content string, editable bool, agentMutable bool, ok bool)
- func (e *Engine) PersonaSections() map[string]bool
- func (e *Engine) ProviderName() string
- func (e *Engine) RemoveMemoryEntry(heading string) error
- func (e *Engine) RemoveSkill(name string) bool
- func (e *Engine) ReplyGuardConfig() ReplyGuard
- func (e *Engine) RequestStop()
- func (e *Engine) SavePersonaSection(section, content string) error
- func (e *Engine) SetApprovalConfig(timeout time.Duration, retries int)
- func (e *Engine) SetAuditor(a audit.Emitter)
- func (e *Engine) SetLocation(loc *time.Location)
- func (e *Engine) SetMaxContextMessages(n int)
- func (e *Engine) SetMaxToolRounds(n int)
- func (e *Engine) SetModel(model string)
- func (e *Engine) SetName(name string)
- func (e *Engine) SetNudgeConfig(memoryInterval, skillInterval int)
- func (e *Engine) SetPermissionTier(tier string) error
- func (e *Engine) SetProvider(provider string) error
- func (e *Engine) SetReplyGuard(g ReplyGuard)
- func (e *Engine) SetReviewer(r *Engine)
- func (e *Engine) SetReviewerConfig(maxIter int, timeout time.Duration)
- func (e *Engine) SetScheduler(sched *scheduler.Scheduler)
- func (e *Engine) SetSkillDirs(agentSkillsDir, globalSkillsDir string)
- func (e *Engine) SetSupervisor(s *Engine)
- func (e *Engine) SetSupervisorConfig(timeout time.Duration, contextMessages int)
- func (e *Engine) SetSupervisorExcerptConfig(bodyExcerptLen, toolDescLen int)
- func (e *Engine) SetTraceCapture(enabled bool, maxBytes int)
- func (e *Engine) SetTraceSink(s TraceSink)
- func (e *Engine) Skills() []skill.Skill
- func (e *Engine) SkillsDir() string
- func (e *Engine) StopGeneration() uint64
- func (e *Engine) Supervisor() *Engine
- func (e *Engine) ToolNames() []string
- func (e *Engine) TraceCaptureEnabled() bool
- func (e *Engine) UpdateSkill(name string, updated skill.Skill) bool
- type ExecKind
- type ExecPolicy
- type InterestingTurn
- type InterestingTurnStore
- type MemoryStore
- type MessageSearchHit
- type ModelCostSummary
- type ProviderCostSummary
- type ReplyGuard
- type ReplyGuardVerdict
- type SQLiteMemoryStore
- func (s *SQLiteMemoryStore) AddMessage(ctx context.Context, convID string, msg StoredMessage) (int64, error)
- func (s *SQLiteMemoryStore) AddSkillUsages(ctx context.Context, convID string, messageID int64, skills []SkillUsageRecord) error
- func (s *SQLiteMemoryStore) AddToolCalls(ctx context.Context, convID string, messageID int64, calls []ToolCallRecord) error
- func (s *SQLiteMemoryStore) AppendSkillRevision(ctx context.Context, r SkillRevision) (int64, error)
- func (s *SQLiteMemoryStore) BumpSkillPatch(ctx context.Context, agent, skill string) error
- func (s *SQLiteMemoryStore) BumpSkillUse(ctx context.Context, agent, skill string) error
- func (s *SQLiteMemoryStore) BumpSkillView(ctx context.Context, agent, skill string) error
- func (s *SQLiteMemoryStore) ClearActiveChannel(ctx context.Context, adapterKey string) error
- func (s *SQLiteMemoryStore) ClearMessages(ctx context.Context, convID string) error
- func (s *SQLiteMemoryStore) Close() error
- func (s *SQLiteMemoryStore) ConversationCost(ctx context.Context, convID string) (float64, error)
- func (s *SQLiteMemoryStore) CountConversationsBefore(ctx context.Context, before time.Time) (int, error)
- func (s *SQLiteMemoryStore) DeleteConversation(ctx context.Context, convID string) error
- func (s *SQLiteMemoryStore) GetActiveChannel(ctx context.Context, adapterKey string) (string, error)
- func (s *SQLiteMemoryStore) GetConversationStats(ctx context.Context, convID string) (*ConversationStatsRow, error)
- func (s *SQLiteMemoryStore) GetCostsByAgent(ctx context.Context) ([]AgentCostSummary, error)
- func (s *SQLiteMemoryStore) GetCostsByProvider(ctx context.Context) ([]ProviderCostSummary, error)
- func (s *SQLiteMemoryStore) GetMessages(ctx context.Context, convID string, limit int) ([]StoredMessage, error)
- func (s *SQLiteMemoryStore) GetOrCreateConversation(ctx context.Context, adapterName, externalID string) (string, error)
- func (s *SQLiteMemoryStore) GetOrCreateConversationByID(ctx context.Context, convID, adapter, externalID string) error
- func (s *SQLiteMemoryStore) GetSkillRevision(ctx context.Context, id int64) (*SkillRevision, error)
- func (s *SQLiteMemoryStore) GetSkillUsage(ctx context.Context, agent, skill string) (*SkillUsageStats, error)
- func (s *SQLiteMemoryStore) GetSkillUsages(ctx context.Context, convID string) ([]SkillUsageRecord, error)
- func (s *SQLiteMemoryStore) GetTelemetrySummary(ctx context.Context, since, until *time.Time) (*TelemetrySummary, error)
- func (s *SQLiteMemoryStore) GetToolCalls(ctx context.Context, convID string) ([]ToolCallRecord, error)
- func (s *SQLiteMemoryStore) LatestSkillRevision(ctx context.Context, agent, skillName string) (*SkillRevision, error)
- func (s *SQLiteMemoryStore) ListActiveChannels(ctx context.Context) (map[string]string, error)
- func (s *SQLiteMemoryStore) ListConversations(ctx context.Context, opts SessionListOpts) ([]ConversationInfo, int, error)
- func (s *SQLiteMemoryStore) ListConversationsWithStats(ctx context.Context, opts SessionListOpts) ([]ConversationInfoWithStats, int, error)
- func (s *SQLiteMemoryStore) ListInterestingTurns(ctx context.Context, agent string, since time.Time, limit int) ([]InterestingTurn, error)
- func (s *SQLiteMemoryStore) ListSkillUsage(ctx context.Context, agent string) ([]SkillUsageStats, error)
- func (s *SQLiteMemoryStore) MarkSkillRevisionReverted(ctx context.Context, id int64) (bool, error)
- func (s *SQLiteMemoryStore) PruneByCount(ctx context.Context, maxConversations int) (int, error)
- func (s *SQLiteMemoryStore) PruneConversations(ctx context.Context, before time.Time) (int, error)
- func (s *SQLiteMemoryStore) ReplaceMessages(ctx context.Context, convID string, replacement StoredMessage) error
- func (s *SQLiteMemoryStore) SearchMessages(ctx context.Context, query string, limit int, agentFilter string) ([]MessageSearchHit, error)
- func (s *SQLiteMemoryStore) SetActiveChannel(ctx context.Context, adapterKey, channelName string) error
- func (s *SQLiteMemoryStore) SetSkillOrigin(ctx context.Context, agent, skill, origin string) error
- func (s *SQLiteMemoryStore) SetSkillPinned(ctx context.Context, agent, skill string, pinned bool) error
- func (s *SQLiteMemoryStore) SetSkillState(ctx context.Context, agent, skill, state string) error
- func (s *SQLiteMemoryStore) TransitionSkillRevisions(ctx context.Context, agent, transitionID string) ([]SkillRevision, error)
- func (s *SQLiteMemoryStore) UpdateConversationStats(ctx context.Context, convID, agent string, msg StoredMessage, ...) error
- type SendFunc
- type SessionListOpts
- type SkillRevision
- type SkillUsageRecord
- type SkillUsageStats
- type SkillUsageSummary
- type StoredMessage
- type TelemetryStore
- type TelemetrySummary
- type ToolCallRecord
- type ToolSkillUsageSummary
- type ToolUsageSummary
- type TraceMessage
- type TracePayload
- type TraceRound
- type TraceSink
- type TraceToolCall
- type TraceTruncation
- type TurnMessage
- type TurnResult
- type TurnTrace
Constants ¶
const ( // AuditFull emits full live-turn semantics — the record genuinely // represents what happened. This is the default. AuditFull = "full" // AuditSummary emits lifecycle events and errors only. AuditSummary = "summary" )
Audit emission modes for a policy turn.
const ( SkillOpCreate = "create" SkillOpUpdate = "update" SkillOpRename = "rename" SkillOpDelete = "delete" )
Skill mutation kinds recorded in skill_revisions.op. The name always describes the mutation that happened, never its inverse.
const ( SkillActorSelf = "self" // the agent editing its own skills (config MCP) SkillActorUser = "user" // an operator via REST or external MCP SkillActorCurator = "curator" // an automated maintenance pass SkillActorRevert = "revert" // the inverse of an earlier revision )
Actors recorded in skill_revisions.actor — who caused the mutation. SkillActorRevert marks a row written by an undo, which is what makes a revert itself revertible (and what a future auto-revert curator must refuse to auto-undo, or it would oscillate).
const ( // GuardOff disables a signal: it is not evaluated at all. GuardOff = "off" // GuardWarn audits the trip and delivers the reply unchanged. GuardWarn = "warn" // GuardWithhold audits the trip and replaces the wire text with a notice. GuardWithhold = "withhold" )
Reply-guard actions. Each signal carries one.
const ( TraceSourceLive = "live" TraceSourceEval = string(ExecEval) )
Trace sources. They mirror ExecKind, with "live" standing in for the zero value so a stored row never carries an empty discriminator. A dry-run turn's trace carries string(ExecDryRun) but gets no named constant: that trace only ever rides out on its TurnResult, so nothing stores it or filters on it.
const DefaultMaxTraceBytes = 256 * 1024
DefaultMaxTraceBytes is the per-trace payload cap when none is configured. Oldest rounds are dropped first when a trace exceeds it.
Variables ¶
var ErrAdapterKeyNotActive = errors.New("adapter key not active on this channel")
ErrAdapterKeyNotActive is returned when attempting to deactivate an adapter key that is not active on the specified channel.
var ErrChannelNotFound = errors.New("channel not found")
ErrChannelNotFound is returned when the specified channel does not exist.
var ErrChannelsNotConfigured = errors.New("channels not configured")
ErrChannelsNotConfigured is returned when channel operations are attempted but no channels are configured.
var ErrNotEnoughMessages = errors.New("not enough messages to compact")
ErrNotEnoughMessages is returned when a compact operation is attempted on a session with fewer than 2 messages.
Functions ¶
func ResolveChannelByName ¶ added in v0.28.0
func ResolveChannelByName(channels map[string]*Channel, name string) (conversationID, adapterName, externalID string, wildcard bool, err error)
ResolveChannelByName looks up a named channel in a channel registry and returns the conversation ID, adapter name, and external ID. When the channel has only wildcard adapter bindings (no specific externalID), wildcard is true. Returns an error if the channel is not found.
Types ¶
type ActiveChannelStore ¶ added in v0.26.0
type ActiveChannelStore interface {
// GetActiveChannel returns the active channel name for the given adapter
// key ("adapter:externalID"). Returns ("", nil) when no override is set.
GetActiveChannel(ctx context.Context, adapterKey string) (string, error)
// SetActiveChannel persists the active channel override for the given
// adapter key.
SetActiveChannel(ctx context.Context, adapterKey, channelName string) error
// ClearActiveChannel removes the active channel override, reverting the
// adapter key to config-based routing.
ClearActiveChannel(ctx context.Context, adapterKey string) error
// ListActiveChannels returns all active channel overrides. Used on startup
// to populate the dispatcher's in-memory cache.
ListActiveChannels(ctx context.Context) (map[string]string, error)
}
ActiveChannelStore persists the user's active channel selection per adapter chat. This state survives restarts so users don't lose their /session choice.
type AdapterBinding ¶ added in v0.28.0
AdapterBinding is a parsed adapter:externalID pair.
type AgentCostSummary ¶ added in v0.30.1
type AgentCostSummary struct {
Agent string `db:"agent" json:"agent"`
Cost float64 `db:"total_cost" json:"cost"`
InputTokens int `db:"total_prompt" json:"input_tokens"`
OutputTokens int `db:"total_completion" json:"output_tokens"`
Messages int `db:"total_messages" json:"messages"`
Sessions int `db:"sessions" json:"sessions"`
}
AgentCostSummary aggregates cost/token data per agent from persistent storage.
type Binding ¶
Binding maps an adapter pattern to an agent name. Pattern is either a wildcard ("telegram") or specific ("telegram:12345").
type Channel ¶ added in v0.26.0
type Channel struct {
// Name is the unique identifier for this channel (e.g. "work", "personal").
Name string
// AgentName is the agent that handles messages routed through this channel.
AgentName string
// Adapters lists the adapter bindings from the config, using the same
// "adapter" (wildcard) or "adapter:externalID" (specific) format.
Adapters []string
// Delivery controls how scheduled messages are delivered through this
// channel's adapter bindings. "broadcast" delivers through all specific
// bindings; any other value (including empty) uses the first specific
// binding only.
Delivery string
// Implicit is true when the channel was auto-synthesized from an agent's
// adapter bindings (backward compatibility). Implicit channels are not
// shown in /session listings unless the user explicitly opts in.
Implicit bool
// SessionMode is "persistent" (default) or "ephemeral". Ephemeral
// channels create a unique conversation for each interaction.
SessionMode string
}
Channel is a named routing endpoint that binds adapter chats to an agent with explicit session identity. Channels decouple conversations from the rigid 1:1 agent-adapter binding, enabling session switching (/session) and cross-adapter session sharing.
func (*Channel) ConversationID ¶ added in v0.26.0
ConversationID returns the persistent conversation ID for this channel. Channel-based conversations use the format "chan:{name}".
func (*Channel) EphemeralConversationID ¶ added in v0.29.1
EphemeralConversationID returns a unique conversation ID for a single ephemeral interaction. Format: "chan:{name}:{unix_nano}_{seq}".
func (*Channel) IsBroadcast ¶ added in v0.28.0
IsBroadcast returns true when the channel is configured for broadcast delivery.
func (*Channel) IsEphemeral ¶ added in v0.29.1
IsEphemeral returns true when the channel uses ephemeral session mode.
func (*Channel) ResolveAllBindings ¶ added in v0.28.0
func (ch *Channel) ResolveAllBindings() []AdapterBinding
ResolveAllBindings returns all specific adapter:externalID bindings from the channel's adapter list. Wildcard-only bindings are skipped. Used for broadcast delivery where a message should be sent through every specific binding.
func (*Channel) ResolveBinding ¶ added in v0.28.0
ResolveBinding returns the first specific adapter binding (adapter:externalID) from the channel's adapter list. If only wildcard bindings exist, returns the wildcard adapter name with an empty externalID and wildcard=true. Returns ok=false if the channel has no adapter bindings at all.
type ChatEvent ¶ added in v0.14.0
type ChatEvent struct {
Type string `json:"type"` // "tool_start", "tool_end", "thinking", "usage", "tool_approval", "content_delta", "thinking_delta"
Tool string `json:"tool,omitempty"` // tool name
ToolID string `json:"tool_id,omitempty"` // unique tool call ID (from LLM response)
Round int `json:"round,omitempty"` // 1-based tool round
Duration int64 `json:"duration_ms,omitempty"` // tool execution time
Error string `json:"error,omitempty"` // tool error (if any)
Text string `json:"text,omitempty"` // human-readable status message / content delta
Tokens int `json:"tokens,omitempty"` // total tokens used (usage event)
TokensCached int `json:"tokens_cached,omitempty"` // cached prompt tokens (usage event)
CostUSD float64 `json:"cost_usd,omitempty"` // estimated cost in USD (usage event)
// ApprovalID and ApprovalCallback are set on "tool_approval" events so
// the adapter can render inline approve/deny buttons.
ApprovalID string `json:"approval_id,omitempty"`
ApprovalCallback string `json:"approval_callback,omitempty"` // "appr:{id}" prefix
// ApprovalStatus distinguishes pending approvals from auto-approved ones.
// Values: "" (pending, needs user action), "auto_approved" (rule matched),
// "auto_denied" (identical call was denied earlier this turn),
// "supervisor_approved", "supervisor_denied", "supervisor_escalated",
// "supervisor_error" (supervisor LLM call failed; falls through to human).
ApprovalStatus string `json:"approval_status,omitempty"`
// ApprovalScope names which auto-approve rule matched, machine-readable
// alongside the human-readable Text. Set only when ApprovalStatus is
// "auto_approved"; values are "config" (TOML-declared), "session" or
// "permanent". Consumers that only key on ApprovalStatus are unaffected.
ApprovalScope string `json:"approval_scope,omitempty"`
}
ChatEvent describes an intermediate pipeline event streamed to SSE clients.
type ChatEventFunc ¶ added in v0.14.0
type ChatEventFunc func(ChatEvent)
ChatEventFunc is called for each intermediate pipeline event.
type ConversationInfo ¶
type ConversationInfo struct {
ID string `db:"id" json:"id"`
Adapter string `db:"adapter" json:"adapter"`
ExternalID string `db:"external_id" json:"external_id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
MessageCount int `db:"message_count" json:"message_count"`
}
ConversationInfo provides metadata about a conversation.
type ConversationInfoWithStats ¶ added in v0.23.0
type ConversationInfoWithStats struct {
ConversationInfo
TotalCost float64 `db:"total_cost" json:"total_cost"`
TotalPrompt int `db:"total_tokens_prompt" json:"total_tokens_prompt"`
TotalCompl int `db:"total_tokens_completion" json:"total_tokens_completion"`
LastModel string `db:"last_model" json:"last_model"`
LastProvider string `db:"last_provider" json:"last_provider"`
UpdatedAt *time.Time `db:"updated_at" json:"updated_at,omitempty"`
}
ConversationInfoWithStats combines conversation metadata with telemetry stats.
type ConversationStatsRow ¶ added in v0.23.0
type ConversationStatsRow struct {
ConversationID string `db:"conversation_id" json:"conversation_id"`
Agent string `db:"agent" json:"agent"`
TotalMessages int `db:"total_messages" json:"total_messages"`
TotalCost float64 `db:"total_cost" json:"total_cost"`
TotalPrompt int `db:"total_tokens_prompt" json:"total_tokens_prompt"`
TotalCompletion int `db:"total_tokens_completion" json:"total_tokens_completion"`
TotalCached int `db:"total_tokens_cached" json:"total_tokens_cached"`
TotalToolCalls int `db:"total_tool_calls" json:"total_tool_calls"`
TotalToolErrors int `db:"total_tool_errors" json:"total_tool_errors"`
LastModel string `db:"last_model" json:"last_model"`
LastProvider string `db:"last_provider" json:"last_provider"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
}
ConversationStatsRow holds aggregated telemetry for a conversation.
type Dispatcher ¶
type Dispatcher struct {
// OnBroadcast, when set, is called after an adapter message (Telegram,
// Discord, etc.) is successfully processed. The server uses this to
// notify WebSocket clients of conversation activity from other adapters.
OnBroadcast func(agentName, convID, adapterName, channelName, summary string)
// OnPanic is called when a /panic command is processed. The server uses
// this to pause the scheduler and broadcast a panic status frame.
OnPanic func()
// OnResume is called when a /resume command is processed.
OnResume func()
// Auditor emits audit events for routing/session decisions.
Auditor audit.Emitter
// contains filtered or unexported fields
}
Dispatcher routes incoming messages to the correct agent Engine based on channel bindings (or legacy adapter bindings). It owns the adapter lifecycle and the shared incoming channel.
func NewDispatcher ¶
func NewDispatcher( agents map[string]*Engine, bindings []Binding, adapters []adapter.Adapter, logger *slog.Logger, opts ...DispatcherOption, ) *Dispatcher
NewDispatcher creates a Dispatcher from a set of named engines, bindings, and adapters. Bindings are processed in order; specific bindings ("telegram:12345") take priority over wildcard bindings ("telegram").
func (*Dispatcher) ActiveChannelsForChannel ¶ added in v0.28.0
func (d *Dispatcher) ActiveChannelsForChannel(channelName string) []string
ActiveChannelsForChannel returns all adapter keys that currently have the given channel as their active override. Always returns a non-nil slice.
func (*Dispatcher) AddAgent ¶ added in v0.29.8
func (d *Dispatcher) AddAgent(name string, engine *Engine) error
AddAgent registers a new engine in the dispatcher's runtime map. Returns an error if the name is already taken.
func (*Dispatcher) AddChannel ¶ added in v0.29.7
func (d *Dispatcher) AddChannel(ch *Channel) error
AddChannel registers a new channel in the dispatcher's runtime registry and updates binding maps. Returns an error if channels are not configured, the name is already taken, or the referenced agent does not exist.
func (*Dispatcher) Agent ¶
func (d *Dispatcher) Agent(name string) *Engine
Agent returns the Engine for the named agent, or nil if not found.
func (*Dispatcher) Agents ¶
func (d *Dispatcher) Agents() []string
Agents returns the names of all registered agents.
func (*Dispatcher) Channels ¶ added in v0.26.0
func (d *Dispatcher) Channels() map[string]*Channel
Channels returns the channel registry. Returns nil when channels are not configured.
func (*Dispatcher) ClearActiveChannelByKey ¶ added in v0.28.0
func (d *Dispatcher) ClearActiveChannelByKey(ctx context.Context, adapterKey, channelName string) error
ClearActiveChannelByKey removes the active channel override for the given adapter key, but only if the key is currently active on the specified channel. Returns ErrAdapterKeyNotActive if the key is not active on channelName.
func (*Dispatcher) Dispatch ¶
func (d *Dispatcher) Dispatch(ctx context.Context, agentName string, msg adapter.IncomingMessage) error
Dispatch sends a message to a specific agent by name. Used by the scheduler.
func (*Dispatcher) FallbackAgent ¶ added in v0.33.0
func (d *Dispatcher) FallbackAgent() *Engine
FallbackAgent returns the "default" agent if it exists, otherwise the first available agent, or nil if no agents are registered.
func (*Dispatcher) IsPanicked ¶ added in v0.27.1
func (d *Dispatcher) IsPanicked() bool
IsPanicked returns true if the dispatcher is in panic mode.
func (*Dispatcher) ListModelDetails ¶ added in v0.16.11
ListModelDetails returns enriched model metadata by querying the fallback agent's router. When providerFilter is non-empty only the named provider is queried.
func (*Dispatcher) ListModels ¶ added in v0.15.1
func (d *Dispatcher) ListModels(ctx context.Context) []string
ListModels returns available LLM models by querying the fallback agent's router.
func (*Dispatcher) LoadActiveChannels ¶ added in v0.26.0
func (d *Dispatcher) LoadActiveChannels(ctx context.Context) error
LoadActiveChannels reads persisted /session selections from the store and populates the in-memory cache. Call once at startup after WithChannels.
func (*Dispatcher) Panic ¶ added in v0.27.1
func (d *Dispatcher) Panic()
Panic triggers an emergency stop via the API. Cancels all in-flight requests and calls the OnPanic hook.
func (*Dispatcher) PanicTime ¶ added in v0.27.1
func (d *Dispatcher) PanicTime() time.Time
PanicTime returns the time when panic was triggered. Returns zero time if not panicked.
func (*Dispatcher) RemoveAgent ¶ added in v0.29.8
func (d *Dispatcher) RemoveAgent(name string) error
RemoveAgent removes an engine from the dispatcher's runtime map. Returns an error if the agent does not exist or is the last registered agent. Callers must check for channel/schedule references before calling.
func (*Dispatcher) RemoveChannel ¶ added in v0.29.7
func (d *Dispatcher) RemoveChannel(ctx context.Context, name string) error
RemoveChannel removes a channel from the dispatcher's runtime registry, clears its adapter bindings, and removes any active channel overrides that reference it. Returns an error if the channel does not exist or is implicit.
func (*Dispatcher) RenameAgent ¶ added in v0.16.9
func (d *Dispatcher) RenameAgent(oldName, newName string) error
RenameAgent atomically renames an agent, updating all routing maps.
func (*Dispatcher) Resume ¶ added in v0.27.1
func (d *Dispatcher) Resume()
Resume clears the panic state and calls the OnResume hook.
func (*Dispatcher) Run ¶
func (d *Dispatcher) Run(ctx context.Context) error
Run starts all adapters and processes incoming messages until ctx is cancelled. Each message is handled in its own goroutine so slow LLM calls do not block the dispatch loop.
func (*Dispatcher) SendFor ¶
func (d *Dispatcher) SendFor(adapterName string) SendFunc
SendFor returns a SendFunc that routes outgoing messages through the adapter matching the incoming message's adapter name.
func (*Dispatcher) SendVia ¶
func (d *Dispatcher) SendVia(ctx context.Context, adapterName string, msg adapter.OutgoingMessage) error
SendVia sends a message through the adapter registered under adapterName. Returns an error if no adapter with that name is registered.
func (*Dispatcher) SetActiveChannelByKey ¶ added in v0.28.0
func (d *Dispatcher) SetActiveChannelByKey(ctx context.Context, adapterKey, channelName string) error
SetActiveChannelByKey sets the active channel override for the given adapter key (e.g. "telegram:12345"). Returns an error if the channel name is not in the registry or channels are not configured.
func (*Dispatcher) StopChat ¶ added in v0.27.1
func (d *Dispatcher) StopChat(adapterName, externalID string) error
StopChat cancels the in-flight request for the given adapter and external ID. Returns an error if no request is in progress. Used by REST API and WebSocket.
func (*Dispatcher) UpdateChannel ¶ added in v0.29.7
func (d *Dispatcher) UpdateChannel(name string, ch *Channel) error
UpdateChannel replaces an existing channel in the dispatcher's runtime registry, re-indexing its adapter bindings. Returns an error if the channel does not exist or is implicit.
type DispatcherOption ¶ added in v0.26.0
type DispatcherOption func(*Dispatcher)
DispatcherOption configures optional Dispatcher behavior.
func WithChannels ¶ added in v0.26.0
func WithChannels(channels []*Channel, activeStore ActiveChannelStore) DispatcherOption
WithChannels configures channel-based routing. When set, the dispatcher routes messages through the channel registry instead of the legacy specific/wildcard binding maps. The activeStore persists /session selections across restarts.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine is the core agent orchestrator. Each named agent gets its own Engine instance with its own persona, skills, permissions, and LLM router.
func (*Engine) AdapterContext ¶ added in v0.24.0
AdapterContext returns the adapter routing info for the current in-flight message. Designed to be wired into configmcp.Deps.AdapterContext so that in-process MCP servers can populate approval requests with routing info.
func (*Engine) AppendMemoryEntry ¶ added in v0.18.0
AppendMemoryEntry adds a new entry to the persona's MEMORY.md. Returns an error if no persona is configured.
func (*Engine) AppendSkill ¶
AppendSkill appends a new skill to the engine's in-memory skill list.
func (*Engine) Chat ¶
Chat processes a single incoming message through the full pipeline and returns the response text. It does not call the sendFunc — use this when the caller wants to receive the reply directly (e.g. the REST API). Any pending approval request is accessible via GET /api/v1/approvals.
func (*Engine) ChatWithEvents ¶ added in v0.14.0
func (e *Engine) ChatWithEvents(ctx context.Context, msg adapter.IncomingMessage, onEvent ChatEventFunc) (string, error)
ChatWithEvents is like Chat but calls onEvent for intermediate status events (tool calls, etc.) that can be streamed to the client in real time.
func (*Engine) ClearSession ¶ added in v0.29.0
ClearSession removes all messages from the session but keeps the conversation row so the session identity is preserved.
func (*Engine) CompactSession ¶ added in v0.29.0
CompactSession summarises the conversation into a single message, replacing the full history. Returns the summary text.
func (*Engine) DisplayName ¶ added in v0.16.9
DisplayName returns a human-friendly name derived from the agent's identity persona (if available), falling back to the agent ID.
func (*Engine) DryRun ¶ added in v0.43.0
func (e *Engine) DryRun(ctx context.Context, msg adapter.IncomingMessage, policy ExecPolicy) (*TurnResult, error)
DryRun executes one turn under an execution policy and returns the full transcript. Nothing is persisted, nothing is sent, and every non-idempotent tool call is suppressed — the caller gets the response and the tool trace to store (or show) wherever it wants.
This is the entry point behind the "Test now" preview surfaces and, later, the eval runner's per-sample execution.
func (*Engine) GetSkill ¶ added in v0.9.0
GetSkill returns a skill by name and true, or a zero value and false if not found.
func (*Engine) HandleMessage ¶
HandleMessage processes a single incoming message and sends the response back via the adapter's SendFunc. It delegates to HandleMessageWithEvents with a nil event callback.
func (*Engine) HandleMessageWithEvents ¶ added in v0.15.0
func (e *Engine) HandleMessageWithEvents(ctx context.Context, msg adapter.IncomingMessage, onEvent ChatEventFunc) error
HandleMessageWithEvents is like HandleMessage but calls onEvent for intermediate pipeline events (thinking, tool calls, usage). The Dispatcher uses this to refresh adapter typing indicators during processing.
func (*Engine) LLMRouter ¶ added in v0.17.0
LLMRouter returns the engine's LLM router for runtime configuration updates.
func (*Engine) ListModelDetails ¶ added in v0.16.11
ListModelDetails returns enriched model metadata from all registered providers.
func (*Engine) ListModels ¶ added in v0.15.1
ListModels returns available LLM models from all registered providers.
func (*Engine) Location ¶ added in v0.40.10
Location returns the engine's effective timezone for date metadata.
func (*Engine) MaxToolRounds ¶ added in v0.29.4
MaxToolRounds returns the current tool round limit.
func (*Engine) NudgeResetExternal ¶ added in v0.36.0
NudgeResetExternal resets nudge counters from external events (e.g. agent self-writes to memory or skills). kind is "memory" or "skill".
func (*Engine) PermissionTier ¶
PermissionTier returns the agent's default permission tier.
func (*Engine) PersonaDir ¶
PersonaDir returns the directory the agent's persona was loaded from. Returns an empty string if no persona is configured.
func (*Engine) PersonaSection ¶ added in v0.10.0
func (e *Engine) PersonaSection(section string) (content string, editable bool, agentMutable bool, ok bool)
PersonaSection returns the content, editability, and agent-mutability of a persona section. Returns ("", false, false, false) if no persona is configured or section is unknown.
func (*Engine) PersonaSections ¶
PersonaSections returns which persona sections are loaded (soul/user/memory). Returns nil if no persona is configured.
func (*Engine) ProviderName ¶ added in v0.17.2
ProviderName returns the agent's default LLM provider.
func (*Engine) RemoveMemoryEntry ¶ added in v0.18.0
RemoveMemoryEntry removes a memory entry by heading from the persona's MEMORY.md. Returns an error if no persona is configured.
func (*Engine) RemoveSkill ¶ added in v0.9.0
RemoveSkill removes a skill by name from the engine's in-memory skill list. Returns false if the skill was not found.
func (*Engine) ReplyGuardConfig ¶ added in v0.43.5
func (e *Engine) ReplyGuardConfig() ReplyGuard
ReplyGuardConfig returns the current reply sanity guard settings.
func (*Engine) RequestStop ¶ added in v0.43.4
func (e *Engine) RequestStop()
RequestStop asks every turn currently running on this engine to end at its next step boundary — the top of a tool round, or the gap before the next tool call in a round. The call in flight is never killed: it completes (bounded by toolExecTimeout) and is recorded with its real outcome, the remaining calls are not started, and the turn leaves through the normal wrap-up and persistence path instead of the error path.
It is a signal, not a barrier: RequestStop returns immediately and a turn with no tool rounds left to run (or none at all) is unaffected. Turns that start after this call capture the new generation and run normally, so there is nothing to reset — the dispatcher's panic state is what refuses new work.
Why a boundary and not a kill: this is the temporal-composability half of "A Programming Paradigm for Spatiotemporal Composability" (Shi, Zhang & Cui): https://github.com/cordiverse/paper/blob/main/paper.pdf — applied to a turn. A tool call is an effect; the runtime can only revert — or even truthfully report — a set of effects it knows the exact extent of. A context kill lands mid-step and destroys that: the call in flight is abandoned client-side while the server may still commit, and the calls after it are recorded as failures though nothing was attempted. Stopping at a boundary keeps the recorded effect set equal to the applied one, which is the precondition the revertible-effect machinery in internal/skilleffect needs to mean anything at turn granularity (see stage 7 of the plan below).
Stage 1 of design/plans/6-step-boundary-stop.md, and deliberately only that: the signal is engine-wide and wired from Dispatcher.executePanic alone, so /stop, POST /sessions/{id}/stop and the WS cancel frame still work by context cancellation until stop scoping (stage 3) lands. Approval abort (stage 4) and the scheduler fixes (stage 5) are likewise not here.
func (*Engine) SavePersonaSection ¶ added in v0.10.0
SavePersonaSection writes content to the named persona section. Returns an error if no persona is configured.
func (*Engine) SetApprovalConfig ¶ added in v0.21.2
SetApprovalConfig configures the approval timeout and retry count. Call this after NewEngine, before the engine starts handling messages.
func (*Engine) SetAuditor ¶ added in v0.26.0
SetAuditor sets the audit emitter for this engine.
func (*Engine) SetLocation ¶ added in v0.40.10
SetLocation sets the timezone used for the system-prompt date line. Nil is ignored (location stays at its current value; default UTC). Call after NewEngine; also re-applied on config hot-reload.
func (*Engine) SetMaxContextMessages ¶ added in v0.22.0
SetMaxContextMessages overrides the default context message limit. Call this after NewEngine, before the engine starts handling messages.
func (*Engine) SetMaxToolRounds ¶ added in v0.27.1
SetMaxToolRounds overrides the default tool round limit. Call this after NewEngine, before the engine starts handling messages.
func (*Engine) SetNudgeConfig ¶ added in v0.36.0
func (*Engine) SetPermissionTier ¶ added in v0.11.0
SetPermissionTier replaces the engine's permission engine with one for the new tier.
func (*Engine) SetProvider ¶ added in v0.20.0
SetProvider changes the engine's default LLM provider.
func (*Engine) SetReplyGuard ¶ added in v0.43.5
func (e *Engine) SetReplyGuard(g ReplyGuard)
SetReplyGuard replaces the reply sanity guard settings. Called at wiring time and again on every config reload, so a narrowed policy narrows the effective guard.
func (*Engine) SetReviewer ¶ added in v0.36.0
func (*Engine) SetReviewerConfig ¶ added in v0.36.0
func (*Engine) SetScheduler ¶
SetScheduler provides a Scheduler reference so the engine can register new schedules at runtime via SCHEDULE_ADD directives. Call this after the Scheduler is initialized.
func (*Engine) SetSkillDirs ¶
SetSkillDirs configures the directories used for skill creation and hot-reload. agentSkillsDir is where new skill files are written; globalSkillsDir is the shared skills directory merged on top of agent-specific skills. Call this after NewEngine, before the engine starts handling messages.
func (*Engine) SetSupervisor ¶ added in v0.30.0
SetSupervisor configures a supervisor engine that reviews tool calls before they reach the human approval flow. Call this after all engines are constructed.
func (*Engine) SetSupervisorConfig ¶ added in v0.30.0
SetSupervisorConfig configures supervisor review parameters. Zero values are ignored (the existing default is kept): pass 0 for timeout to keep the default 15s, pass 0 for contextMessages to keep the default 5. Call this after NewEngine, before the engine starts handling messages.
func (*Engine) SetSupervisorExcerptConfig ¶ added in v0.36.2
SetSupervisorExcerptConfig configures the maximum excerpt lengths included in the supervisor review prompt. Zero values keep the defaults (500 for skill body, 200 for tool description).
func (*Engine) SetTraceCapture ¶ added in v0.47.0
SetTraceCapture applies the [eval] capture switch and the per-trace byte cap. Called at wiring time and again on every config reload, so turning capture off in TOML stops recording without a restart.
func (*Engine) SetTraceSink ¶ added in v0.47.0
SetTraceSink wires where captured live traces are written. A nil sink disables live capture whatever [eval] capture says — the switch and the storage are separate concerns and both have to be present.
func (*Engine) SkillsDir ¶ added in v0.9.0
SkillsDir returns the directory where agent-specific skill files are stored.
func (*Engine) StopGeneration ¶ added in v0.43.4
StopGeneration returns the engine's current stop generation. A turn that started at generation g must end at its next step boundary once this differs from g.
func (*Engine) Supervisor ¶ added in v0.30.0
Supervisor returns the supervisor engine, if any.
func (*Engine) ToolNames ¶
ToolNames returns the names of all registered MCP tools for this agent. Returns nil if the agent has no tools configured.
func (*Engine) TraceCaptureEnabled ¶ added in v0.47.0
TraceCaptureEnabled reports whether live turns on this engine are recorded.
type ExecKind ¶ added in v0.43.0
type ExecKind string
ExecKind labels why a turn is running under an ExecPolicy. The zero value is an ordinary live turn; any other value doubles as the audit source.
type ExecPolicy ¶ added in v0.43.0
type ExecPolicy struct {
// Kind selects the policy flavour and becomes the audit source.
Kind ExecKind
// Variant names the eval variant this sample belongs to (e.g. "candidate").
// Empty for dry-runs and for the conventional incumbent.
Variant string
// Model overrides the agent's model for this turn only. Empty runs the
// agent's live model. The override is applied by cloning the router
// (llm.Router.WithModel) rather than mutating it, so a preview of a
// candidate model cannot retarget a live turn already in flight.
Model string
// Provider overrides the agent's provider for this turn only, composed
// with Model by the same clone (llm.Router.WithProvider). Empty runs the
// agent's live provider. Safe to override freely because every agent
// router registers every configured provider, so the clone is a pointer
// swap rather than a rebuild.
Provider string
// ConvID is the in-flight conversation identity — "dryrun:{uuid}" or
// "eval:{run}:{task}:{k}". It is used for cost tracking, audit grouping and
// log correlation, and is never written to the conversations table.
ConvID string
// AsOf pins the clock for both date-injection points (the scheduled-message
// header and the "## Current Date" prompt section), so a replay is
// date-deterministic. Zero means "now".
AsOf time.Time
// HistoryFrom names a conversation whose recent messages are loaded
// read-only as the context *preceding* this turn. Empty means a fresh turn
// with no history. The message being answered is always appended after it,
// so a caller replaying a stored conversation points here at the messages
// before the one it re-runs, not at the whole thing.
HistoryFrom string
// History is context pinned by the caller and replayed verbatim as the
// messages preceding this turn. It takes precedence over HistoryFrom.
//
// The two differ in *when* the context is chosen. HistoryFrom names a live
// conversation and reads its most recent window at turn time, which is
// right for "preview this against whatever the session looks like now".
// History carries a snippet captured earlier, which is what a saved eval
// task needs: the source conversation drifts (ClearMessages empties it,
// retention prunes it) and its latest window is not the window that
// preceded the saved message. A test case that silently re-scopes itself
// between runs is not a test case.
//
// Only Role and Content are read; the remaining StoredMessage fields are
// ignored by assembleMessages and may be left zero.
History []StoredMessage
// AuditMode is AuditFull (default) or AuditSummary.
AuditMode string
}
ExecPolicy is the per-request execution policy for a turn that must not touch the world: no writes, no persistence, no approvals, no adapters. It is resolved once by the caller and threaded through the turn alongside the tool-round budget — there is no engine-level mutable state, so a policy turn and a live turn can run concurrently on the same Engine.
Tool execution is split by the *existing* idempotency signal (tool.Manager.IsIdempotent, built for within-turn memoization): idempotent tools run for real so the model sees a truthful world; everything else returns a suppression marker.
type InterestingTurn ¶ added in v0.44.0
type InterestingTurn struct {
MessageID int64 `db:"message_id"`
ConversationID string `db:"conversation_id"`
Content string `db:"content"`
CreatedAt time.Time `db:"created_at"`
// Agent is the agent that handled the conversation, empty when its stats
// row was pruned.
Agent string `db:"agent"`
// ToolCalls, MaxRound, Faults, ReplyCost and ReplyContent describe the
// assistant reply to this turn: the next assistant message in the
// conversation. ReplyContent is capped at replyPreviewMax runes.
ToolCalls int `db:"tool_calls"`
MaxRound int `db:"max_round"`
Faults int `db:"faults"`
ReplyCost float64 `db:"reply_cost"`
ReplyContent string `db:"reply_content"`
// CommandMatches counts skills that matched this turn via a command
// trigger (match_type 'command'), as opposed to ambient or scheduled.
CommandMatches int `db:"command_matches"`
// Preceding holds up to precedingTurns messages immediately before this
// one, oldest first, each capped at precedingContentMax runes.
Preceding []TurnMessage `db:"-"`
}
InterestingTurn is one past user turn with the facts that decide whether it is worth offering as an eval test case. The facts are raw — which signals count, and how they rank, is the caller's policy (internal/eval decides both, since the cost decile is relative to the pool it asked for).
type InterestingTurnStore ¶ added in v0.44.0
type InterestingTurnStore interface {
ListInterestingTurns(ctx context.Context, agent string, since time.Time, limit int) ([]InterestingTurn, error)
}
InterestingTurnStore is the narrow telemetry surface behind the eval "suggest test cases from history" endpoint. It is deliberately not folded into MemoryStore or TelemetryStore: obtain one by type-asserting a MemoryStore, the same way the API layer reaches TelemetryStore.
type MemoryStore ¶
type MemoryStore interface {
GetOrCreateConversation(ctx context.Context, adapter, externalID string) (string, error)
// GetOrCreateConversationByID ensures a conversation row exists for the
// given convID. The adapter and externalID are stored as metadata so that
// ListConversations can report the correct source (e.g. "ws", "api",
// "sched"). If the row already exists (INSERT OR IGNORE) the stored
// adapter/externalID are left unchanged.
GetOrCreateConversationByID(ctx context.Context, convID, adapter, externalID string) error
AddMessage(ctx context.Context, convID string, msg StoredMessage) (int64, error)
GetMessages(ctx context.Context, convID string, limit int) ([]StoredMessage, error)
ListConversations(ctx context.Context, opts SessionListOpts) ([]ConversationInfo, int, error)
// DeleteConversation removes a conversation and all its messages by ID.
// Returns nil if the conversation does not exist (idempotent).
DeleteConversation(ctx context.Context, convID string) error
// ClearMessages removes all messages, tool calls, skill usages, and stats
// for a conversation but keeps the conversation row itself. This allows
// the session identity to be preserved while starting fresh.
ClearMessages(ctx context.Context, convID string) error
// ReplaceMessages atomically clears all messages and telemetry for a
// conversation and inserts a single replacement message in one transaction.
ReplaceMessages(ctx context.Context, convID string, replacement StoredMessage) error
Close() error
}
MemoryStore defines the interface for conversation persistence.
type MessageSearchHit ¶ added in v0.36.1
type MessageSearchHit struct {
ID int64 `db:"id" json:"id"`
ConversationID string `db:"conversation_id" json:"conversation_id"`
Role string `db:"role" json:"role"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
Snippet string `db:"snippet" json:"snippet"`
}
MessageSearchHit represents a single FTS5 search result.
type ModelCostSummary ¶ added in v0.23.0
type ModelCostSummary struct {
Model string `db:"model" json:"model"`
Provider string `db:"provider" json:"provider"`
TotalCost float64 `db:"total_cost" json:"total_cost"`
MessageCount int `db:"message_count" json:"message_count"`
TotalPrompt int `db:"total_prompt" json:"total_tokens_prompt"`
TotalCompl int `db:"total_completion" json:"total_tokens_completion"`
TotalCached int `db:"total_cached" json:"total_tokens_cached"`
}
ModelCostSummary aggregates cost/token data per model.
type ProviderCostSummary ¶ added in v0.34.0
type ProviderCostSummary struct {
Provider string `db:"provider" json:"provider"`
Cost float64 `db:"total_cost" json:"cost"`
InputTokens int `db:"total_prompt" json:"input_tokens"`
OutputTokens int `db:"total_completion" json:"output_tokens"`
CachedTokens int `db:"total_cached" json:"cached_tokens"`
Messages int `db:"messages" json:"messages"`
}
ProviderCostSummary aggregates cost/token data per provider from message-level records.
type ReplyGuard ¶ added in v0.43.5
type ReplyGuard struct {
Enabled bool
// OnRoleMarkup, OnOversized and OnNoToolCalls are GuardOff/GuardWarn/
// GuardWithhold. An unset action reads as GuardOff.
OnRoleMarkup string
OnOversized string
OnNoToolCalls string
// MaxReplyBytes is the largest final reply, in bytes. Non-positive
// disables the byte measure.
MaxReplyBytes int
// MaxCompletionTokens bounds provider-reported completion tokens.
// Non-positive disables the token measure, which is the default: it
// measures the same thing as bytes and doubles the false-positive surface.
MaxCompletionTokens int
// ExcerptBytes is how much of the raw reply reaches the audit detail.
ExcerptBytes int
}
ReplyGuard holds the resolved reply sanity guard settings for one engine. It is the agent-side mirror of config.ReplyGuardConfig; the agent package deliberately does not import config, so main.go translates.
The zero value is a disabled guard, which is what every engine built without explicit wiring (tests, the reviewer engine) gets.
type ReplyGuardVerdict ¶ added in v0.43.5
type ReplyGuardVerdict struct {
// Signals lists every signal that tripped, in evaluation order.
Signals []string `json:"signals"`
// Action is the strongest action any tripped signal asked for
// ("warn" or "withhold").
Action string `json:"action"`
// Notice is the operator notice a live turn would have delivered in place
// of the reply. Empty when the action is only "warn".
Notice string `json:"notice,omitempty"`
}
ReplyGuardVerdict is the externally visible form of a guard trip, carried on TurnResult so a preview can show what the guard would have done.
type SQLiteMemoryStore ¶
type SQLiteMemoryStore struct {
// contains filtered or unexported fields
}
SQLiteMemoryStore implements MemoryStore and TelemetryStore using SQLite.
func NewInMemoryStore ¶
func NewInMemoryStore() (*SQLiteMemoryStore, error)
NewInMemoryStore creates an in-memory SQLite store (for testing).
func NewSQLiteMemoryStore ¶
func NewSQLiteMemoryStore(dbPath string) (*SQLiteMemoryStore, error)
NewSQLiteMemoryStore opens or creates a SQLite database at the given path.
func (*SQLiteMemoryStore) AddMessage ¶
func (s *SQLiteMemoryStore) AddMessage(ctx context.Context, convID string, msg StoredMessage) (int64, error)
func (*SQLiteMemoryStore) AddSkillUsages ¶ added in v0.23.0
func (s *SQLiteMemoryStore) AddSkillUsages(ctx context.Context, convID string, messageID int64, skills []SkillUsageRecord) error
AddSkillUsages persists skill usage records linked to a user message.
func (*SQLiteMemoryStore) AddToolCalls ¶ added in v0.23.0
func (s *SQLiteMemoryStore) AddToolCalls(ctx context.Context, convID string, messageID int64, calls []ToolCallRecord) error
AddToolCalls persists tool call records linked to an assistant message.
func (*SQLiteMemoryStore) AppendSkillRevision ¶ added in v0.43.4
func (s *SQLiteMemoryStore) AppendSkillRevision(ctx context.Context, r SkillRevision) (int64, error)
AppendSkillRevision records a skill mutation and returns the new revision id. seq is assigned here as the next value within (agent, transition_id), so a caller only has to supply the transition id.
func (*SQLiteMemoryStore) BumpSkillPatch ¶ added in v0.36.0
func (s *SQLiteMemoryStore) BumpSkillPatch(ctx context.Context, agent, skill string) error
func (*SQLiteMemoryStore) BumpSkillUse ¶ added in v0.36.0
func (s *SQLiteMemoryStore) BumpSkillUse(ctx context.Context, agent, skill string) error
func (*SQLiteMemoryStore) BumpSkillView ¶ added in v0.36.0
func (s *SQLiteMemoryStore) BumpSkillView(ctx context.Context, agent, skill string) error
func (*SQLiteMemoryStore) ClearActiveChannel ¶ added in v0.26.0
func (s *SQLiteMemoryStore) ClearActiveChannel(ctx context.Context, adapterKey string) error
func (*SQLiteMemoryStore) ClearMessages ¶ added in v0.29.0
func (s *SQLiteMemoryStore) ClearMessages(ctx context.Context, convID string) error
ClearMessages removes all messages, tool calls, skill usages, and stats for a conversation but keeps the conversation row itself.
func (*SQLiteMemoryStore) Close ¶
func (s *SQLiteMemoryStore) Close() error
func (*SQLiteMemoryStore) ConversationCost ¶ added in v0.7.0
ConversationCost returns the total cost of all messages in a conversation.
func (*SQLiteMemoryStore) CountConversationsBefore ¶ added in v0.7.0
func (s *SQLiteMemoryStore) CountConversationsBefore(ctx context.Context, before time.Time) (int, error)
CountConversationsBefore returns the number of conversations created before the given time.
func (*SQLiteMemoryStore) DeleteConversation ¶
func (s *SQLiteMemoryStore) DeleteConversation(ctx context.Context, convID string) error
func (*SQLiteMemoryStore) GetActiveChannel ¶ added in v0.26.0
func (*SQLiteMemoryStore) GetConversationStats ¶ added in v0.23.0
func (s *SQLiteMemoryStore) GetConversationStats(ctx context.Context, convID string) (*ConversationStatsRow, error)
GetConversationStats returns the aggregated telemetry for a conversation.
func (*SQLiteMemoryStore) GetCostsByAgent ¶ added in v0.30.1
func (s *SQLiteMemoryStore) GetCostsByAgent(ctx context.Context) ([]AgentCostSummary, error)
GetCostsByAgent returns per-agent aggregated cost data from persistent storage.
func (*SQLiteMemoryStore) GetCostsByProvider ¶ added in v0.34.0
func (s *SQLiteMemoryStore) GetCostsByProvider(ctx context.Context) ([]ProviderCostSummary, error)
GetCostsByProvider returns per-provider aggregated cost data from message-level records.
func (*SQLiteMemoryStore) GetMessages ¶
func (s *SQLiteMemoryStore) GetMessages(ctx context.Context, convID string, limit int) ([]StoredMessage, error)
func (*SQLiteMemoryStore) GetOrCreateConversation ¶
func (*SQLiteMemoryStore) GetOrCreateConversationByID ¶
func (s *SQLiteMemoryStore) GetOrCreateConversationByID(ctx context.Context, convID, adapter, externalID string) error
func (*SQLiteMemoryStore) GetSkillRevision ¶ added in v0.43.4
func (s *SQLiteMemoryStore) GetSkillRevision(ctx context.Context, id int64) (*SkillRevision, error)
GetSkillRevision returns a revision by id regardless of whether it is still armed. Returns (nil, nil) when no such revision exists.
func (*SQLiteMemoryStore) GetSkillUsage ¶ added in v0.36.0
func (s *SQLiteMemoryStore) GetSkillUsage(ctx context.Context, agent, skill string) (*SkillUsageStats, error)
func (*SQLiteMemoryStore) GetSkillUsages ¶ added in v0.23.0
func (s *SQLiteMemoryStore) GetSkillUsages(ctx context.Context, convID string) ([]SkillUsageRecord, error)
GetSkillUsages returns all skill usage records for a conversation.
func (*SQLiteMemoryStore) GetTelemetrySummary ¶ added in v0.23.0
func (s *SQLiteMemoryStore) GetTelemetrySummary(ctx context.Context, since, until *time.Time) (*TelemetrySummary, error)
GetTelemetrySummary returns aggregated telemetry data, optionally filtered by time range.
func (*SQLiteMemoryStore) GetToolCalls ¶ added in v0.23.0
func (s *SQLiteMemoryStore) GetToolCalls(ctx context.Context, convID string) ([]ToolCallRecord, error)
GetToolCalls returns all tool call records for a conversation.
func (*SQLiteMemoryStore) LatestSkillRevision ¶ added in v0.43.4
func (s *SQLiteMemoryStore) LatestSkillRevision(ctx context.Context, agent, skillName string) (*SkillRevision, error)
LatestSkillRevision returns the newest still-armed revision for a skill, or for the whole agent when skillName is empty. Returns (nil, nil) when there is nothing left to revert.
func (*SQLiteMemoryStore) ListActiveChannels ¶ added in v0.26.0
func (*SQLiteMemoryStore) ListConversations ¶
func (s *SQLiteMemoryStore) ListConversations(ctx context.Context, opts SessionListOpts) ([]ConversationInfo, int, error)
func (*SQLiteMemoryStore) ListConversationsWithStats ¶ added in v0.23.0
func (s *SQLiteMemoryStore) ListConversationsWithStats(ctx context.Context, opts SessionListOpts) ([]ConversationInfoWithStats, int, error)
ListConversationsWithStats returns conversations joined with their telemetry stats.
func (*SQLiteMemoryStore) ListInterestingTurns ¶ added in v0.44.0
func (s *SQLiteMemoryStore) ListInterestingTurns(ctx context.Context, agent string, since time.Time, limit int) ([]InterestingTurn, error)
ListInterestingTurns returns the most recent answered user turns since the given time, newest first, with the reply telemetry a suggestion ranker needs. An empty agent means every agent. The limit bounds the candidate pool, not the number of suggestions.
func (*SQLiteMemoryStore) ListSkillUsage ¶ added in v0.36.0
func (s *SQLiteMemoryStore) ListSkillUsage(ctx context.Context, agent string) ([]SkillUsageStats, error)
func (*SQLiteMemoryStore) MarkSkillRevisionReverted ¶ added in v0.43.4
MarkSkillRevisionReverted claims a revision for undoing and reports whether this caller won the claim. The conditional UPDATE is the whole at-most-once mechanism: two concurrent reverts of the same revision both run the statement, exactly one affects a row, and the loser is told the revision was already disposed of. Because the flag lives in SQLite rather than memory, the guarantee also survives a restart.
func (*SQLiteMemoryStore) PruneByCount ¶ added in v0.23.0
PruneByCount deletes the oldest conversations when the total exceeds maxConversations. Returns the number of conversations deleted.
func (*SQLiteMemoryStore) PruneConversations ¶ added in v0.7.0
PruneConversations deletes all conversations (and their messages, tool calls, skill usages, and stats) created before the given time. Returns the number of conversations deleted.
func (*SQLiteMemoryStore) ReplaceMessages ¶ added in v0.29.0
func (s *SQLiteMemoryStore) ReplaceMessages(ctx context.Context, convID string, replacement StoredMessage) error
ReplaceMessages atomically clears all messages and telemetry for a conversation and inserts a single replacement message in one transaction.
func (*SQLiteMemoryStore) SearchMessages ¶ added in v0.36.1
func (s *SQLiteMemoryStore) SearchMessages(ctx context.Context, query string, limit int, agentFilter string) ([]MessageSearchHit, error)
SearchMessages performs a full-text search across messages, optionally filtered by agent name via the conversation_stats join.
func (*SQLiteMemoryStore) SetActiveChannel ¶ added in v0.26.0
func (s *SQLiteMemoryStore) SetActiveChannel(ctx context.Context, adapterKey, channelName string) error
func (*SQLiteMemoryStore) SetSkillOrigin ¶ added in v0.36.0
func (s *SQLiteMemoryStore) SetSkillOrigin(ctx context.Context, agent, skill, origin string) error
func (*SQLiteMemoryStore) SetSkillPinned ¶ added in v0.36.0
func (*SQLiteMemoryStore) SetSkillState ¶ added in v0.36.0
func (s *SQLiteMemoryStore) SetSkillState(ctx context.Context, agent, skill, state string) error
func (*SQLiteMemoryStore) TransitionSkillRevisions ¶ added in v0.43.4
func (s *SQLiteMemoryStore) TransitionSkillRevisions(ctx context.Context, agent, transitionID string) ([]SkillRevision, error)
TransitionSkillRevisions returns the still-armed revisions of one transition in LIFO order (newest first) — the order they must be undone in.
func (*SQLiteMemoryStore) UpdateConversationStats ¶ added in v0.23.0
func (s *SQLiteMemoryStore) UpdateConversationStats(ctx context.Context, convID, agent string, msg StoredMessage, toolCallCount, toolErrorCount int) error
UpdateConversationStats incrementally updates the conversation_stats row.
type SendFunc ¶
type SendFunc func(ctx context.Context, msg adapter.OutgoingMessage) error
SendFunc is a callback for sending a response back to the originating adapter. The Dispatcher sets this when constructing each Engine.
type SessionListOpts ¶ added in v0.29.6
type SessionListOpts struct {
Limit int // 0 = no limit (return all)
Offset int
Agent string // filter by agent prefix in conversation ID
}
SessionListOpts controls pagination and filtering for session listing.
type SkillRevision ¶ added in v0.43.4
type SkillRevision struct {
ID int64 `db:"id" json:"id"`
Agent string `db:"agent" json:"agent"`
TransitionID string `db:"transition_id" json:"transition_id"`
// Seq orders revisions within one transition. It is assigned by
// AppendSkillRevision; whatever a caller sets here is ignored.
Seq int `db:"seq" json:"seq"`
Op string `db:"op" json:"op"`
SkillName string `db:"skill_name" json:"skill_name"`
// PriorName is the name before a rename; nil for every other op.
PriorName *string `db:"prior_name" json:"prior_name,omitempty"`
// PriorPayload is the raw file content before the mutation; nil when no
// file existed (always so for SkillOpCreate).
PriorPayload *string `db:"prior_payload" json:"prior_payload,omitempty"`
// NewVersion and PriorVersion are the frontmatter versions after and
// before the mutation. They are the join key against tool_calls
// (skill_name/skill_version), i.e. by_tool_skill in GetTelemetrySummary —
// not skill_usage, which is version-less. Empty means unknown (e.g. the
// prior bytes did not parse).
NewVersion string `db:"new_version" json:"new_version,omitempty"`
PriorVersion string `db:"prior_version" json:"prior_version,omitempty"`
Actor string `db:"actor" json:"actor"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
// RevertedAt is nil while the revision is armed (revertible) and set once
// it has been disposed of by a revert.
RevertedAt *time.Time `db:"reverted_at" json:"reverted_at,omitempty"`
}
SkillRevision is one row of the skill mutation undo journal. It records the on-disk state that existed *before* a mutation, so the mutation can be undone exactly once.
PriorName and PriorPayload are pointers because NULL is load-bearing: a NULL PriorPayload means the skill file did not exist before the mutation (the prior state is "absent"), which is a different instruction to the reverter than an empty file.
type SkillUsageRecord ¶ added in v0.23.0
type SkillUsageRecord struct {
ID int64 `db:"id" json:"id"`
MessageID int64 `db:"message_id" json:"message_id"`
ConversationID string `db:"conversation_id" json:"conversation_id"`
SkillName string `db:"skill_name" json:"skill_name"`
MatchType string `db:"match_type" json:"match_type"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
}
SkillUsageRecord represents a skill matched for a user message.
type SkillUsageStats ¶ added in v0.36.0
type SkillUsageStats struct {
SkillName string `db:"skill_name" json:"skill_name"`
AgentName string `db:"agent_name" json:"agent_name"`
ViewCount int `db:"view_count" json:"view_count"`
UseCount int `db:"use_count" json:"use_count"`
PatchCount int `db:"patch_count" json:"patch_count"`
LastViewedAt *time.Time `db:"last_viewed_at" json:"last_viewed_at,omitempty"`
LastUsedAt *time.Time `db:"last_used_at" json:"last_used_at,omitempty"`
LastPatchedAt *time.Time `db:"last_patched_at" json:"last_patched_at,omitempty"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
State string `db:"state" json:"state"`
Pinned bool `db:"pinned" json:"pinned"`
ArchivedAt *time.Time `db:"archived_at" json:"archived_at,omitempty"`
Origin string `db:"origin" json:"origin"`
}
SkillUsageStats holds per-skill telemetry counters and metadata.
type SkillUsageSummary ¶ added in v0.23.0
type SkillUsageSummary struct {
SkillName string `db:"skill_name" json:"skill_name"`
MatchCount int `db:"match_count" json:"match_count"`
MatchTypes string `db:"match_types" json:"match_types"`
}
SkillUsageSummary aggregates skill usage data per skill.
type StoredMessage ¶
type StoredMessage struct {
ID int64 `db:"id"`
ConversationID string `db:"conversation_id"`
Role string `db:"role"`
Content string `db:"content"`
ReasoningContent string `db:"reasoning_content"`
TokensUsed int `db:"tokens_used"`
Cost float64 `db:"cost"`
Model string `db:"model"`
Provider string `db:"provider"`
TokensPrompt int `db:"tokens_prompt"`
TokensCompletion int `db:"tokens_completion"`
TokensCached int `db:"tokens_cached"`
CreatedAt time.Time `db:"created_at"`
}
StoredMessage represents a message persisted in the memory store.
type TelemetryStore ¶ added in v0.23.0
type TelemetryStore interface {
AddToolCalls(ctx context.Context, convID string, messageID int64, calls []ToolCallRecord) error
AddSkillUsages(ctx context.Context, convID string, messageID int64, skills []SkillUsageRecord) error
UpdateConversationStats(ctx context.Context, convID, agent string, msg StoredMessage, toolCallCount, toolErrorCount int) error
GetConversationStats(ctx context.Context, convID string) (*ConversationStatsRow, error)
ListConversationsWithStats(ctx context.Context, opts SessionListOpts) ([]ConversationInfoWithStats, int, error)
GetToolCalls(ctx context.Context, convID string) ([]ToolCallRecord, error)
GetSkillUsages(ctx context.Context, convID string) ([]SkillUsageRecord, error)
GetTelemetrySummary(ctx context.Context, since, until *time.Time) (*TelemetrySummary, error)
GetCostsByAgent(ctx context.Context) ([]AgentCostSummary, error)
GetCostsByProvider(ctx context.Context) ([]ProviderCostSummary, error)
PruneByCount(ctx context.Context, maxConversations int) (int, error)
BumpSkillView(ctx context.Context, agent, skill string) error
BumpSkillUse(ctx context.Context, agent, skill string) error
BumpSkillPatch(ctx context.Context, agent, skill string) error
GetSkillUsage(ctx context.Context, agent, skill string) (*SkillUsageStats, error)
ListSkillUsage(ctx context.Context, agent string) ([]SkillUsageStats, error)
SetSkillState(ctx context.Context, agent, skill, state string) error
SetSkillPinned(ctx context.Context, agent, skill string, pinned bool) error
SetSkillOrigin(ctx context.Context, agent, skill, origin string) error
SearchMessages(ctx context.Context, query string, limit int, agentFilter string) ([]MessageSearchHit, error)
}
TelemetryStore extends MemoryStore with telemetry persistence methods. Implementations can be obtained by type-asserting a MemoryStore.
type TelemetrySummary ¶ added in v0.23.0
type TelemetrySummary struct {
ByModel []ModelCostSummary `json:"by_model"`
ByTool []ToolUsageSummary `json:"by_tool"`
BySkill []SkillUsageSummary `json:"by_skill"`
// ByToolSkill breaks tool reliability down per owning (skill, version) so
// callers can compare a skill's tool behaviour across versions (e.g. did an
// edit reduce failures?). Only attributed tool calls appear here.
ByToolSkill []ToolSkillUsageSummary `json:"by_tool_skill"`
}
TelemetrySummary holds aggregated telemetry for the summary endpoint.
type ToolCallRecord ¶ added in v0.23.0
type ToolCallRecord struct {
ID int64 `db:"id" json:"id"`
MessageID int64 `db:"message_id" json:"message_id"`
ConversationID string `db:"conversation_id" json:"conversation_id"`
ToolName string `db:"tool_name" json:"tool_name"`
ServerName string `db:"server_name" json:"server_name"`
Round int `db:"round" json:"round"`
DurationMs int64 `db:"duration_ms" json:"duration_ms"`
Success bool `db:"success" json:"success"`
// Outcome refines Success: "ok", "rejected" (healthy tool, bad args),
// "failed" (transport/exec failure), "denied" (approval denied),
// "cached" (identical idempotent call served from the within-turn cache;
// Success true, DurationMs 0, nothing executed), or "suppressed" (a write
// refused by a dry-run/eval execution policy; Success true, nothing ran).
Outcome string `db:"outcome" json:"outcome"`
// Arguments and Result are in-memory only — AddToolCalls inserts an
// explicit column list, so these never reach the database. They exist so a
// caller holding the returned records (the dry-run transcript, an eval
// sample) can show what the call actually did; live turns still persist
// name/server/round/outcome only.
Arguments string `db:"-" json:"arguments,omitempty"`
Result string `db:"-" json:"result,omitempty"`
// SkillName / SkillVersion identify the skill that owned the turn this
// call ran under, when ownership is unambiguous (single-skill/scheduled
// turns). Blank for interactive multi-match or unmatched turns.
SkillName string `db:"skill_name" json:"skill_name,omitempty"`
SkillVersion string `db:"skill_version" json:"skill_version,omitempty"`
ErrorMsg string `db:"error_msg" json:"error_msg,omitempty"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
}
ToolCallRecord represents a persisted tool call linked to an assistant message.
type ToolSkillUsageSummary ¶ added in v0.40.3
type ToolSkillUsageSummary struct {
SkillName string `db:"skill_name" json:"skill_name"`
SkillVersion string `db:"skill_version" json:"skill_version"`
ToolName string `db:"tool_name" json:"tool_name"`
ServerName string `db:"server_name" json:"server_name"`
CallCount int `db:"call_count" json:"call_count"`
RejectionCount int `db:"rejection_count" json:"rejection_count"`
FailureCount int `db:"failure_count" json:"failure_count"`
DenialCount int `db:"denial_count" json:"denial_count"`
CachedCount int `db:"cached_count" json:"cached_count"`
AvgDuration float64 `db:"avg_duration" json:"avg_duration_ms"`
}
ToolSkillUsageSummary aggregates tool call data per owning (skill, version). The outcome split mirrors ToolUsageSummary; the legacy combined error_count field was removed from the payload (issue #215) — prefer FailureCount for a "broken tool" signal and read DenialCount separately (approval denials aren't faults).
type ToolUsageSummary ¶ added in v0.23.0
type ToolUsageSummary struct {
ToolName string `db:"tool_name" json:"tool_name"`
ServerName string `db:"server_name" json:"server_name"`
CallCount int `db:"call_count" json:"call_count"`
// The non-ok outcomes are split into RejectionCount (healthy tool, bad
// args), FailureCount (transport/exec failures), and DenialCount (approval
// denials), so a "healthy but argued-with" or denied tool isn't reported as
// broken. The legacy combined error_count field (rejected + failed + denied)
// was removed from the payload — it conflated denials with real failures and
// was misread as a "broken tool" signal (see issue #215). Reconstruct the old
// total as RejectionCount + FailureCount + DenialCount if needed.
RejectionCount int `db:"rejection_count" json:"rejection_count"`
FailureCount int `db:"failure_count" json:"failure_count"`
DenialCount int `db:"denial_count" json:"denial_count"`
// CachedCount counts calls served from the within-turn idempotent-result
// cache. Included in CallCount (the model did make the call) but excluded
// from AvgDuration (0ms hits would make a slow tool look fast).
CachedCount int `db:"cached_count" json:"cached_count"`
AvgDuration float64 `db:"avg_duration" json:"avg_duration_ms"`
}
ToolUsageSummary aggregates tool call data per tool.
type TraceMessage ¶ added in v0.47.0
TraceMessage is one message of the history window exactly as it went on the wire (the truncation notice included — it is part of what the model read).
type TracePayload ¶ added in v0.47.0
type TracePayload struct {
SystemPrompt string `json:"system_prompt"`
History []TraceMessage `json:"history"`
Prompt string `json:"prompt"`
Response string `json:"response"`
Rounds []TraceRound `json:"rounds"`
Truncation *TraceTruncation `json:"truncation,omitempty"`
}
TracePayload is the JSON blob half of a trace: everything too big or too shapeless for a column.
func DecodeTracePayload ¶ added in v0.47.0
func DecodeTracePayload(raw string) (TracePayload, error)
DecodeTracePayload parses a stored payload blob.
type TraceRound ¶ added in v0.47.0
type TraceRound struct {
Round int `json:"round"`
ToolCalls []TraceToolCall `json:"tool_calls"`
}
TraceRound groups a turn's calls by the tool-call round they ran in, which is the unit truncation drops.
type TraceSink ¶ added in v0.47.0
TraceSink persists captured turn traces. The eval store implements it; nil means capture is wired to nothing and the engine records nothing.
type TraceToolCall ¶ added in v0.47.0
type TraceToolCall struct {
Tool string `json:"tool"`
Server string `json:"server,omitempty"`
Outcome string `json:"outcome"`
DurationMs int64 `json:"duration_ms"`
Arguments string `json:"arguments,omitempty"`
Result string `json:"result,omitempty"`
Error string `json:"error,omitempty"`
}
TraceToolCall is one tool call with the payloads a stored ToolCallRecord deliberately drops: arguments and result are db:"-" on the record, and this is where they are finally written down.
type TraceTruncation ¶ added in v0.47.0
type TraceTruncation struct {
DroppedRounds int `json:"dropped_rounds,omitempty"`
DroppedHistory int `json:"dropped_history,omitempty"`
ClampedText bool `json:"clamped_text,omitempty"`
Note string `json:"note"`
}
TraceTruncation records what the byte cap removed, so a reader never mistakes a trimmed trace for a short turn.
type TurnMessage ¶ added in v0.44.0
type TurnMessage struct {
Role string `db:"role" json:"role"`
Content string `db:"content" json:"content"`
}
TurnMessage is one {role, content} pair of context preceding a turn. It is the shape eval task pinned history is stored in.
type TurnResult ¶ added in v0.43.0
type TurnResult struct {
// ConversationID is the in-flight identity the turn ran under.
ConversationID string `json:"conversation_id"`
// Prompt is the message text that was sent, after any header injection.
Prompt string `json:"prompt"`
// Response is the final assistant text.
Response string `json:"response"`
// ToolCalls are the calls this turn made, in execution order, carrying
// arguments and results (in-memory only — nothing was written).
ToolCalls []ToolCallRecord `json:"tool_calls"`
// Rounds is the number of tool-call rounds the turn used.
Rounds int `json:"rounds"`
// StopReason is why the tool loop ended, as a machine-readable slug
// ("repeated_calls", "max_rounds", "stop_requested"). Empty means the model
// finished on its own — the ordinary case. It is the only non-textual
// signal that a turn was cut short: the alternative is scraping the
// "[engine: turn ended early — …]" marker out of the response body.
StopReason string `json:"stop_reason,omitempty"`
// Tokens and Cost cover the whole turn, accumulated across rounds.
Tokens llm.TokenUsage `json:"tokens"`
CostUSD float64 `json:"cost_usd"`
// Model and Provider identify what actually answered — read back from the
// response, so an override that the provider silently redirected shows the
// model that really ran rather than the one that was asked for.
Model string `json:"model"`
Provider string `json:"provider"`
// Upstream is the provider-reported serving upstream (OpenRouter's routed
// provider), empty when the provider has no such concept.
Upstream string `json:"upstream,omitempty"`
// RequestedModel is the override the caller asked for, empty when the turn
// ran the agent's live model. The pair is what lets a transcript say "this
// is not your live model" without the UI having to know the agent config.
RequestedModel string `json:"requested_model,omitempty"`
// ReplyGuard is the reply sanity guard verdict, omitted when nothing
// tripped. A preview evaluates the guard but never substitutes the text,
// so this is the only place a previewed trip is visible — Response still
// holds what the model actually produced.
ReplyGuard *ReplyGuardVerdict `json:"reply_guard,omitempty"`
// AsOf is the clock the turn ran under.
AsOf time.Time `json:"as_of"`
// DurationMs is wall-clock time for the whole turn.
DurationMs int64 `json:"duration_ms"`
// Trace is the full L1 turn trace — the built system prompt, the history
// window as sent, and the per-round tool calls with their payloads. A
// policy turn always builds one and never persists it: isolation is
// structural, so the caller decides where it goes (the eval runner stores
// it; a dry-run preview renders it and drops it).
Trace *TurnTrace `json:"trace,omitempty"`
}
TurnResult is everything a caller needs from one turn executed outside the normal chat pipeline. The eval runner and the dry-run handlers store it where they want; nothing here has been persisted.
type TurnTrace ¶ added in v0.47.0
type TurnTrace struct {
ID int64 `json:"id"`
Agent string `json:"agent"`
ConversationID string `json:"conversation_id"`
Source string `json:"source"`
Model string `json:"model,omitempty"`
Provider string `json:"provider,omitempty"`
// RequestedModel is the override the turn asked for, empty when it ran the
// agent's live model.
RequestedModel string `json:"requested_model,omitempty"`
// Upstream is the provider-reported serving upstream, empty for providers
// without the concept.
Upstream string `json:"upstream,omitempty"`
Rounds int `json:"rounds"`
StopReason string `json:"stop_reason,omitempty"`
Tokens llm.TokenUsage `json:"tokens"`
CostUSD float64 `json:"cost_usd"`
LatencyMs int64 `json:"latency_ms"`
StartedAt time.Time `json:"started_at"`
CreatedAt time.Time `json:"created_at"`
// Truncated reports that the byte cap removed something; the detail is in
// Payload.Truncation.
Truncated bool `json:"truncated"`
// Bytes is the encoded payload size after truncation.
Bytes int `json:"bytes"`
Payload TracePayload `json:"payload"`
// contains filtered or unexported fields
}
TurnTrace is one recorded turn: metadata columns plus the payload blob.
func (*TurnTrace) EncodePayload ¶ added in v0.47.0
EncodePayload serialises the payload blob for storage. buildTurnTrace has already encoded the payload once to size it against the cap, so the result is reused rather than marshalled a second time on the way to the store. Any code that mutates Payload after the trace is built must clear encoded.