analytics

package module
v0.2.6 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2026 License: AGPL-3.0 Imports: 6 Imported by: 0

Documentation

Overview

Package analytics provides tools for analyzing the statistics of conversation state, such as per-(kind, source) counts and byte sizes. Source identifies the originating tool for tool_call and tool_result artifacts, allowing callers to attribute context cost to specific tools.

For tool_result artifacts, Source is resolved by joining the result's ToolCallID against the originating tool_call.Name in the same scope (the slice the caller passes to AnalyzeTurns, or the load function's returns to AnalyzeStore). When no matching tool_call exists in the scope (e.g. compaction has dropped the call), the result buckets under the Source "(unknown)" so the gap is visible in the report.

The package depends only on artifact, ledger, and x/llmbytes: it takes plain values from any thread-like container and never imports session, junk, or any storage abstraction. Multi-store aggregation is the caller's responsibility — pass a load function to AnalyzeStore and let it enumerate threads however it likes.

The Render function turns a []Stats into a Markdown table (header, per-bucket rows, bolded totals row) suitable for surfacing in a chat reply or TUI feedback message.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Render added in v0.2.1

func Render(stats []Stats) string

Render formats a slice of Stats as a Markdown table.

The table has columns Kind, Source, Count, Bytes, %. A totals row appears last, with the Kind, Count, and Bytes cells wrapped in **bold** markers. The % cell on the totals row is blank.

Bytes are humanized to B/K/M/G with one decimal place for any unit ≥ 1 K (e.g. "8.2 K", "1.5 M"); integer byte counts are rendered as "{n} B". Counts are rendered as plain integers.

The % column is the integer percent of each row's bytes against the total byte budget (rounded to the nearest integer). When totalBytes is zero (e.g. every artifact is artifact.Usage, which contributes zero bytes), the % column is replaced with "—" for every row.

Input order is preserved. Callers that want a particular ordering must sort the input themselves; the canonical sort is (Kind, Source) lexicographic, returned by Analyze*.

The empty case — len(stats) == 0 — returns the single line "No artifacts in this thread yet." with no trailing newline.

The column widths are derived from the data rows; the bolded totals row can therefore overflow visually (the ** markers push the cell past the column width). This is intentional and mirrors the Markdown convention that totals rows may exceed the column header's width when rendered in monospace.

Types

type Stats added in v0.2.0

type Stats struct {
	Kind   string
	Source string
	Count  int
	Bytes  int64
}

Stats holds per-(Kind, Source) statistics: the artifact kind, the source identifier (the tool name for tool_call and tool_result artifacts; empty for all other kinds), the count of artifacts in the bucket, and their aggregate byte size as seen by the LLM provider.

func AnalyzeStore

func AnalyzeStore(loadFn func() ([]ledger.Turn, error)) ([]Stats, error)

AnalyzeStore aggregates statistics across the turns produced by the given load function. It returns a merged, sorted slice of Stats.

The load function is invoked once. The caller is responsible for any thread-enumeration or filtering (for example, a "last N days" lookback); analytics itself is single-scope. Per-thread tool_call to tool_result attribution is also the caller's responsibility: the load function may either flatten across threads (the common case, where cross-thread attribution is out of scope) or perform its own per-thread join before returning. Callers that need the previous per-thread whole-scope join behavior must compose it inside the load function.

A nil load function returns (nil, nil). A load function that returns an error short-circuits the analysis.

func AnalyzeThread

func AnalyzeThread(t *ledger.Thread) []Stats

AnalyzeThread is a convenience wrapper that aggregates statistics for all turns in the given thread.

func AnalyzeTurns

func AnalyzeTurns(turns []ledger.Turn) []Stats

AnalyzeTurns aggregates per-(Kind, Source) statistics over a slice of turns. It returns a slice of Stats sorted lexicographically by (Kind, Source).

tool_result artifacts are resolved against tool_call artifacts in the same slice via a whole-slice ToolCallID→Name map. A result whose ToolCallID has no matching call anywhere in the slice buckets under orphanToolSource ("(unknown)").

Jump to

Keyboard shortcuts

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