218 lines
9.3 KiB
Go
218 lines
9.3 KiB
Go
package agentcore
|
|
|
|
// AgentEvent is the sealed interface implemented by every event the loop emits.
|
|
// Consumers dispatch with a type switch, consistent with Content. pigo covers
|
|
// all 10 of pi's event types (PRD FR-24).
|
|
type AgentEvent interface {
|
|
isAgentEvent()
|
|
// EventType returns the discriminant string, useful for logging and for
|
|
// serialising events to the stream-json/stdio protocol (US-020).
|
|
EventType() string
|
|
}
|
|
|
|
// Event type discriminants.
|
|
const (
|
|
EventAgentStart = "agent_start"
|
|
EventAgentEnd = "agent_end"
|
|
EventTurnStart = "turn_start"
|
|
EventTurnEnd = "turn_end"
|
|
EventMessageStart = "message_start"
|
|
EventMessageUpdate = "message_update"
|
|
EventMessageEnd = "message_end"
|
|
EventToolExecutionStart = "tool_execution_start"
|
|
EventToolExecutionUpdate = "tool_execution_update"
|
|
EventToolExecutionEnd = "tool_execution_end"
|
|
EventCompaction = "compaction"
|
|
EventCompactionStart = "compaction_start"
|
|
EventTelemetry = "telemetry"
|
|
EventSubAgentProgress = "subagent_progress"
|
|
)
|
|
|
|
// AgentStartEvent is emitted once when a loop run begins. SessionID, when set,
|
|
// is the id of the session backing this run; it is carried in the first
|
|
// stream-json event so a caller can associate output with a session and resume
|
|
// it later (mirrors pi/Claude Code, which put a session id in the first event).
|
|
type AgentStartEvent struct {
|
|
SessionID string
|
|
}
|
|
|
|
// AgentEndEvent is emitted once when a loop run ends, carrying the messages
|
|
// newly produced during this run (the EventStream result).
|
|
type AgentEndEvent struct {
|
|
Messages []AgentMessage
|
|
}
|
|
|
|
// TurnStartEvent marks the start of a turn (a single assistant response cycle).
|
|
type TurnStartEvent struct{}
|
|
|
|
// TurnEndEvent marks the end of a turn, with the assistant message and any tool
|
|
// results produced during it.
|
|
type TurnEndEvent struct {
|
|
Message AssistantMessage
|
|
ToolResults []ToolResultMessage
|
|
}
|
|
|
|
// MessageStartEvent is emitted when a message begins streaming.
|
|
type MessageStartEvent struct {
|
|
Message AgentMessage
|
|
}
|
|
|
|
// MessageUpdateEvent is emitted for each streaming delta, carrying the current
|
|
// partial message and the raw provider-level event that produced it.
|
|
type MessageUpdateEvent struct {
|
|
Message AgentMessage
|
|
AssistantMessageEvent any
|
|
}
|
|
|
|
// MessageEndEvent is emitted when a message finishes streaming.
|
|
type MessageEndEvent struct {
|
|
Message AgentMessage
|
|
}
|
|
|
|
// ToolExecutionStartEvent is emitted before a tool runs.
|
|
type ToolExecutionStartEvent struct {
|
|
ToolCallID string
|
|
ToolName string
|
|
Args any
|
|
}
|
|
|
|
// ToolExecutionUpdateEvent carries a partial result during tool execution.
|
|
type ToolExecutionUpdateEvent struct {
|
|
ToolCallID string
|
|
ToolName string
|
|
PartialResult AgentToolResult
|
|
}
|
|
|
|
// ToolExecutionEndEvent is emitted when a tool finishes.
|
|
type ToolExecutionEndEvent struct {
|
|
ToolCallID string
|
|
ToolName string
|
|
Result AgentToolResult
|
|
IsError bool
|
|
}
|
|
|
|
// CompactionEvent is emitted when the loop compacts the context window, either
|
|
// automatically (threshold/overflow) or on an explicit /compact request. It
|
|
// carries before/after token counts and how many messages were summarized vs.
|
|
// retained. When compaction fails it is still emitted with ErrorMessage set and
|
|
// the token/count fields describing the unchanged context, so consumers can
|
|
// surface the failure without the session aborting (US-004).
|
|
type CompactionEvent struct {
|
|
// Reason is why compaction ran: "manual", "threshold", or "overflow".
|
|
Reason string
|
|
// TokensBefore is the estimated context tokens prior to compaction.
|
|
TokensBefore int
|
|
// TokensAfter is the estimated context tokens after compaction (equals
|
|
// TokensBefore when compaction failed or was a no-op).
|
|
TokensAfter int
|
|
// SummarizedCount is the number of messages folded into the summary.
|
|
SummarizedCount int
|
|
// KeptCount is the number of recent messages retained verbatim.
|
|
KeptCount int
|
|
// ErrorMessage is non-empty when compaction failed; the original context is
|
|
// preserved in that case.
|
|
ErrorMessage string
|
|
}
|
|
|
|
// CompactionStartEvent is emitted immediately before the loop runs compaction,
|
|
// so a front-end can show an in-progress "Compacting conversation…" indicator
|
|
// while the summarization request is in flight. The matching CompactionEvent is
|
|
// emitted when it completes (or fails). Reason mirrors CompactionEvent.Reason.
|
|
type CompactionStartEvent struct {
|
|
// Reason is why compaction is running: "manual", "threshold", or "overflow".
|
|
Reason string
|
|
// TokensBefore is the estimated context tokens that triggered compaction.
|
|
TokensBefore int
|
|
}
|
|
|
|
// SubAgentProgressEvent carries structured progress from a running sub-agent
|
|
// (dispatched by the task tool). It is reported at the sub-agent's tool
|
|
// execution / turn boundaries so a TUI (multi-line status panel) or headless
|
|
// mode (stderr line) can display live progress. Elapsed time is intentionally
|
|
// omitted: consumers compute it themselves (TUI from tool-start time, headless
|
|
// from when the id was first seen) to avoid emitting an event per frame.
|
|
type SubAgentProgressEvent struct {
|
|
// ToolCallID is the parent task call's tool-call id, used as the key for
|
|
// the status line.
|
|
ToolCallID string
|
|
// Description is the task call's description, for display (may be empty).
|
|
Description string
|
|
// Activity is the current activity: tool name / phase, e.g. "Editing",
|
|
// "Running bash", "Thinking".
|
|
Activity string
|
|
// Tokens is the estimated sub-agent output token count (0 = unknown).
|
|
Tokens int
|
|
}
|
|
|
|
// ToolTiming records how long one tool invocation took, keyed by tool name in
|
|
// TelemetryEvent.ToolDurationsMs. It aggregates repeated calls of the same tool
|
|
// so a summary stays compact regardless of turn count.
|
|
type ToolTiming struct {
|
|
// Count is how many times the tool was invoked over the run.
|
|
Count int
|
|
// TotalMs is the summed wall-clock duration of every invocation, in
|
|
// milliseconds.
|
|
TotalMs int64
|
|
}
|
|
|
|
// TelemetryEvent is a lightweight, additive observability summary emitted once
|
|
// at run end (just before agent_end) so scripts consuming the stream-json
|
|
// output can read structured metrics without a new dependency (no
|
|
// Prometheus/OTLP). It is purely observational: consumers that ignore it behave
|
|
// exactly as before. Metrics covered (observability — structured telemetry collection):
|
|
// - per-tool wall-clock durations (ToolDurationsMs, aggregated by tool name),
|
|
// - how many turns ran (Turns),
|
|
// - how many assistant responses were truncated by the output cap
|
|
// (TruncationCount),
|
|
// - how many times the context was compacted (CompactionCount),
|
|
// - the latest context-utilization ratio (ContextUtilization = used tokens /
|
|
// ContextWindow) and the raw numbers behind it.
|
|
type TelemetryEvent struct {
|
|
// Turns is the number of turns (turn_start events) the run executed.
|
|
Turns int
|
|
// ToolDurationsMs maps a tool name to its aggregated timing over the run.
|
|
ToolDurationsMs map[string]ToolTiming
|
|
// TruncationCount is how many assistant responses stopped with reason
|
|
// "length" (truncated by the output token cap), each triggering a resend.
|
|
TruncationCount int
|
|
// CompactionCount is how many successful context compactions occurred.
|
|
CompactionCount int
|
|
// ContextUtilization is the latest used/window ratio in [0,1], or 0 when the
|
|
// context window is unknown. Computed as ContextTokens / ContextWindow.
|
|
ContextUtilization float64
|
|
// ContextTokens is the most recently observed estimated context-token usage.
|
|
ContextTokens int
|
|
// ContextWindow is the model's total context-token budget (0 when unknown).
|
|
ContextWindow int
|
|
}
|
|
|
|
func (AgentStartEvent) isAgentEvent() {}
|
|
func (AgentEndEvent) isAgentEvent() {}
|
|
func (TurnStartEvent) isAgentEvent() {}
|
|
func (TurnEndEvent) isAgentEvent() {}
|
|
func (MessageStartEvent) isAgentEvent() {}
|
|
func (MessageUpdateEvent) isAgentEvent() {}
|
|
func (MessageEndEvent) isAgentEvent() {}
|
|
func (ToolExecutionStartEvent) isAgentEvent() {}
|
|
func (ToolExecutionUpdateEvent) isAgentEvent() {}
|
|
func (ToolExecutionEndEvent) isAgentEvent() {}
|
|
func (CompactionEvent) isAgentEvent() {}
|
|
func (CompactionStartEvent) isAgentEvent() {}
|
|
func (TelemetryEvent) isAgentEvent() {}
|
|
func (SubAgentProgressEvent) isAgentEvent() {}
|
|
|
|
func (AgentStartEvent) EventType() string { return EventAgentStart }
|
|
func (AgentEndEvent) EventType() string { return EventAgentEnd }
|
|
func (TurnStartEvent) EventType() string { return EventTurnStart }
|
|
func (TurnEndEvent) EventType() string { return EventTurnEnd }
|
|
func (MessageStartEvent) EventType() string { return EventMessageStart }
|
|
func (MessageUpdateEvent) EventType() string { return EventMessageUpdate }
|
|
func (MessageEndEvent) EventType() string { return EventMessageEnd }
|
|
func (ToolExecutionStartEvent) EventType() string { return EventToolExecutionStart }
|
|
func (ToolExecutionUpdateEvent) EventType() string { return EventToolExecutionUpdate }
|
|
func (ToolExecutionEndEvent) EventType() string { return EventToolExecutionEnd }
|
|
func (CompactionEvent) EventType() string { return EventCompaction }
|
|
func (CompactionStartEvent) EventType() string { return EventCompactionStart }
|
|
func (TelemetryEvent) EventType() string { return EventTelemetry }
|
|
func (SubAgentProgressEvent) EventType() string { return EventSubAgentProgress }
|