136 lines
4.8 KiB
Go
136 lines
4.8 KiB
Go
// This file implements the telemetry holder that retains per-run telemetry
|
|
// events (US-001, #291) and folds them into a cumulative accumulator for the
|
|
// /status command to display. It was moved verbatim from cmd/pigo
|
|
// (telemetry_state.go, US-013) into the shared cli layer so the status and repl
|
|
// subpackages share one holder type.
|
|
package cli
|
|
|
|
import (
|
|
"github.com/smallnest/pigo/internal/agentcore"
|
|
)
|
|
|
|
// TelemetryHolder holds the most recent run's telemetry event and a cumulative
|
|
// accumulator that sums metrics across all runs in the session.
|
|
type TelemetryHolder struct {
|
|
// last is the telemetry event from the most recent completed run, or nil if
|
|
// no run has completed yet.
|
|
last *agentcore.TelemetryEvent
|
|
// cumulative is the accumulator that sums metrics across all runs.
|
|
cumulative cumulativeTelemetry
|
|
}
|
|
|
|
// cumulativeTelemetry holds the accumulated metrics from all runs in the session.
|
|
type cumulativeTelemetry struct {
|
|
// turns is the total number of turns across all runs.
|
|
turns int
|
|
// toolDurationsMs maps tool name to aggregated count and total milliseconds
|
|
// across all runs.
|
|
toolDurationsMs map[string]agentcore.ToolTiming
|
|
// truncationCount is the total number of truncations across all runs.
|
|
truncationCount int
|
|
// compactionCount is the total number of compactions across all runs.
|
|
compactionCount int
|
|
// contextTokens is the most recent observed context token count.
|
|
contextTokens int
|
|
// contextWindow is the most recent observed context window size.
|
|
contextWindow int
|
|
}
|
|
|
|
// NewTelemetryHolder creates a new, empty TelemetryHolder with no telemetry yet.
|
|
func NewTelemetryHolder() *TelemetryHolder {
|
|
return &TelemetryHolder{
|
|
last: nil,
|
|
cumulative: cumulativeTelemetry{
|
|
toolDurationsMs: make(map[string]agentcore.ToolTiming),
|
|
},
|
|
}
|
|
}
|
|
|
|
// Reset clears the holder to "no telemetry yet", as if the session had just
|
|
// started. It is called when switching sessions (/fork, /clone, /import).
|
|
func (h *TelemetryHolder) Reset() {
|
|
h.last = nil
|
|
h.cumulative = cumulativeTelemetry{
|
|
toolDurationsMs: make(map[string]agentcore.ToolTiming),
|
|
}
|
|
}
|
|
|
|
// Fold incorporates a new TelemetryEvent into the holder: it becomes the new
|
|
// "last run" event, and its metrics are added to the cumulative accumulator.
|
|
func (h *TelemetryHolder) Fold(ev agentcore.TelemetryEvent) {
|
|
// Store the new event as the last run.
|
|
h.last = &ev
|
|
|
|
// Add its metrics to the cumulative accumulator.
|
|
h.cumulative.turns += ev.Turns
|
|
h.cumulative.truncationCount += ev.TruncationCount
|
|
h.cumulative.compactionCount += ev.CompactionCount
|
|
|
|
// Update the latest context tokens and window (always use the most recent).
|
|
h.cumulative.contextTokens = ev.ContextTokens
|
|
h.cumulative.contextWindow = ev.ContextWindow
|
|
|
|
// Sum the per-tool timings.
|
|
for name, timing := range ev.ToolDurationsMs {
|
|
agg := h.cumulative.toolDurationsMs[name]
|
|
agg.Count += timing.Count
|
|
agg.TotalMs += timing.TotalMs
|
|
h.cumulative.toolDurationsMs[name] = agg
|
|
}
|
|
}
|
|
|
|
// HasTelemetry returns true if at least one run has completed and telemetry is
|
|
// available.
|
|
func (h *TelemetryHolder) HasTelemetry() bool {
|
|
return h.last != nil
|
|
}
|
|
|
|
// Last returns the most recent TelemetryEvent, or nil if no run has completed.
|
|
func (h *TelemetryHolder) Last() *agentcore.TelemetryEvent {
|
|
return h.last
|
|
}
|
|
|
|
// CumulativeTurns returns the total number of turns across all runs.
|
|
func (h *TelemetryHolder) CumulativeTurns() int {
|
|
return h.cumulative.turns
|
|
}
|
|
|
|
// CumulativeTruncationCount returns the total number of truncations across all runs.
|
|
func (h *TelemetryHolder) CumulativeTruncationCount() int {
|
|
return h.cumulative.truncationCount
|
|
}
|
|
|
|
// CumulativeCompactionCount returns the total number of compactions across all runs.
|
|
func (h *TelemetryHolder) CumulativeCompactionCount() int {
|
|
return h.cumulative.compactionCount
|
|
}
|
|
|
|
// CumulativeToolDurations returns the aggregated tool timings across all runs.
|
|
func (h *TelemetryHolder) CumulativeToolDurations() map[string]agentcore.ToolTiming {
|
|
// Return a copy to prevent mutation of the internal state.
|
|
result := make(map[string]agentcore.ToolTiming, len(h.cumulative.toolDurationsMs))
|
|
for name, timing := range h.cumulative.toolDurationsMs {
|
|
result[name] = timing
|
|
}
|
|
return result
|
|
}
|
|
|
|
// LatestContextTokens returns the most recent observed context token count.
|
|
func (h *TelemetryHolder) LatestContextTokens() int {
|
|
return h.cumulative.contextTokens
|
|
}
|
|
|
|
// LatestContextWindow returns the most recent observed context window size.
|
|
func (h *TelemetryHolder) LatestContextWindow() int {
|
|
return h.cumulative.contextWindow
|
|
}
|
|
|
|
// CumulativeContextUtilization returns the latest utilization ratio, or 0 if no
|
|
// window is known.
|
|
func (h *TelemetryHolder) CumulativeContextUtilization() float64 {
|
|
if h.cumulative.contextWindow <= 0 {
|
|
return 0
|
|
}
|
|
return float64(h.cumulative.contextTokens) / float64(h.cumulative.contextWindow)
|
|
}
|