Documentation
¶
Overview ¶
Package sessions provides the shared types and logic for building a per-session summary from a chain of merkle nodes. It is consumed by both the API server (for /v1/sessions/summary) and the deck TUI (for rendering).
All functions in this package operate on *merkle.Node, not on any specific storage driver type. Callers are responsible for fetching and walking the ancestry chain; this package computes derived metadata over that chain.
Index ¶
- Constants
- func BlocksHaveGitActivity(blocks []llm.ContentBlock) bool
- func BlocksHaveToolError(blocks []llm.ContentBlock) bool
- func BuildLabel(nodes []*merkle.Node) string
- func CopyModelCosts(costs map[string]ModelCost) map[string]ModelCost
- func CostForTokens(pricing Pricing, inputTokens, outputTokens int64) (float64, float64, float64)
- func CostForTokensWithCache(pricing Pricing, inputTokens, outputTokens, cacheCreation, cacheRead int64) (float64, float64, float64)
- func CountToolCalls(blocks []llm.ContentBlock) int
- func DetermineStatus(leaf *merkle.Node, hasToolError, hasGitActivity bool) string
- func DominantModel(costs map[string]ModelCost) string
- func ExtractLabelText(blocks []llm.ContentBlock) string
- func ExtractText(blocks []llm.ContentBlock) string
- func ExtractToolCalls(blocks []llm.ContentBlock) []string
- func FirstModel(nodes []*merkle.Node) string
- func MergeModelCosts(target map[string]ModelCost, costs map[string]ModelCost)
- func NormalizeModel(model string) string
- func StripTaggedSection(text, tag string) string
- func SumModelCosts(costs map[string]ModelCost) (float64, float64, float64)
- type ModelCost
- type NodeTokens
- type Pricing
- type PricingTable
- type SessionSummary
Constants ¶
const ( StatusCompleted = "completed" StatusFailed = "failed" StatusAbandoned = "abandoned" StatusUnknown = "unknown" )
Status values returned by DetermineStatus.
Variables ¶
This section is empty.
Functions ¶
func BlocksHaveGitActivity ¶
func BlocksHaveGitActivity(blocks []llm.ContentBlock) bool
BlocksHaveGitActivity reports whether the blocks contain a Bash tool call whose command invokes `git commit` or `git push`.
func BlocksHaveToolError ¶
func BlocksHaveToolError(blocks []llm.ContentBlock) bool
BlocksHaveToolError reports whether any tool_result block is marked as an error.
func BuildLabel ¶
BuildLabel derives a short human-readable label for the session from the most recent user-role prompts in the chain. Falls back to a truncated form of the leaf hash if no usable prompts are found.
func CopyModelCosts ¶
CopyModelCosts returns a shallow copy of the map, or an empty map if nil.
func CostForTokens ¶
CostForTokens calculates cost using base input/output pricing. For cache-aware cost calculation, use CostForTokensWithCache.
func CostForTokensWithCache ¶
func CostForTokensWithCache(pricing Pricing, inputTokens, outputTokens, cacheCreation, cacheRead int64) (float64, float64, float64)
CostForTokensWithCache calculates cost accounting for prompt caching. When cache token counts are available, base input tokens are:
baseInput = totalInput - cacheCreation - cacheRead
Each token type is priced at its respective rate.
func CountToolCalls ¶
func CountToolCalls(blocks []llm.ContentBlock) int
CountToolCalls returns how many tool_use blocks are in the slice.
func DetermineStatus ¶
DetermineStatus classifies a session based on its terminal (leaf) node and a pair of flags derived from scanning the full ancestry.
Precedence:
- Any tool_result error in the chain → StatusFailed
- Any git commit/push in the chain → StatusCompleted (strong done signal)
- Non-assistant leaf → StatusAbandoned
- Assistant leaf with a known-terminal stop_reason → StatusCompleted
- Assistant leaf with a known-failing stop_reason → StatusFailed
- Empty or otherwise unrecognised stop_reason → StatusUnknown
func DominantModel ¶
DominantModel returns the model with the highest total cost in the map, or the empty string if none.
func ExtractLabelText ¶
func ExtractLabelText(blocks []llm.ContentBlock) string
ExtractLabelText concatenates human-visible text from content blocks for label-building purposes, stripping tagged meta sections like <system-reminder>...</system-reminder>.
func ExtractText ¶
func ExtractText(blocks []llm.ContentBlock) string
ExtractText concatenates visible text across text, tool_output, and tool_use blocks, joined by newlines.
func ExtractToolCalls ¶
func ExtractToolCalls(blocks []llm.ContentBlock) []string
ExtractToolCalls returns the names of all tool_use blocks.
func FirstModel ¶
FirstModel returns the normalized model of the first node in the chain that has a non-empty Model field, or the empty string.
func MergeModelCosts ¶
MergeModelCosts adds the per-model values in costs into target in place. Does nothing if target is nil.
func NormalizeModel ¶
NormalizeModel canonicalizes a model name: lowercased, trimmed, date suffixes stripped, and vendor-specific version markers rewritten so the result can be used as a key into PricingTable.
func StripTaggedSection ¶
StripTaggedSection removes all occurrences of a given XML-like tagged section (e.g. <system-reminder>…</system-reminder>) from text.
Types ¶
type ModelCost ¶
type ModelCost struct {
Model string `json:"model"`
InputTokens int64 `json:"input_tokens"`
OutputTokens int64 `json:"output_tokens"`
InputCost float64 `json:"input_cost"`
OutputCost float64 `json:"output_cost"`
TotalCost float64 `json:"total_cost"`
SessionCount int `json:"session_count"`
}
ModelCost is a per-model aggregate of cost and token usage within a session or a collection of sessions.
type NodeTokens ¶
NodeTokens holds all token counts for a node, including cache breakdown.
func TokensForNode ¶
func TokensForNode(n *merkle.Node) NodeTokens
TokensForNode extracts token counts from a merkle node's Usage metadata. Returns a zero-valued NodeTokens when Usage is nil.
type Pricing ¶
type Pricing struct {
Input float64 `json:"input"`
Output float64 `json:"output"`
CacheRead float64 `json:"cache_read"`
CacheWrite float64 `json:"cache_write"`
}
Pricing is the per-million-tokens price for a single model.
func PricingForModel ¶
func PricingForModel(pricing PricingTable, model string) (Pricing, bool)
PricingForModel looks up pricing for a model name, trying the normalized form first and falling back to the raw string.
type PricingTable ¶
PricingTable maps model names (after normalization) to their Pricing.
func DefaultPricing ¶
func DefaultPricing() PricingTable
DefaultPricing returns hardcoded pricing per million tokens for supported models.
Last verified: 2026-04-16 Sources:
- Anthropic: https://platform.claude.com/docs/en/about-claude/pricing
- OpenAI: https://platform.openai.com/docs/pricing
- DeepSeek: https://api-docs.deepseek.com/quick_start/pricing
Anthropic cache multipliers: CacheWrite = 1.25x input, CacheRead = 0.10x input. OpenAI cache: CacheWrite = 1x input (no surcharge), CacheRead = 0.50x input (except o3-mini).
To override at runtime, pass a JSON file path to LoadPricing.
func LoadPricing ¶
func LoadPricing(path string) (PricingTable, error)
LoadPricing loads a pricing table, applying JSON overrides from path if set. An empty path returns DefaultPricing unchanged.
type SessionSummary ¶
type SessionSummary struct {
ID string `json:"id"`
Label string `json:"label"`
Model string `json:"model"`
Project string `json:"project"`
AgentName string `json:"agent_name,omitempty"`
Status string `json:"status"`
StartTime time.Time `json:"start_time"`
EndTime time.Time `json:"end_time"`
Duration time.Duration `json:"duration_ns"`
InputTokens int64 `json:"input_tokens"`
OutputTokens int64 `json:"output_tokens"`
InputCost float64 `json:"input_cost"`
OutputCost float64 `json:"output_cost"`
TotalCost float64 `json:"total_cost"`
ToolCalls int `json:"tool_calls"`
MessageCount int `json:"message_count"`
SessionCount int `json:"session_count,omitempty"`
// Truncated is true when this summary was built from a partial chain
// because an ancestor's parent_hash could not be resolved in the
// current store. MissingParent names the hash that would have
// continued the walk if the referenced node existed. Both fields are
// informational — they signal that higher ancestors may live outside
// this store (trimmed history, foreign chain, offloaded data) rather
// than an error.
Truncated bool `json:"truncated,omitempty"`
MissingParent string `json:"missing_parent,omitempty"`
}
SessionSummary is the aggregate view of a single session (a root-to-leaf chain). It is produced by BuildSummary and consumed by both the API's /v1/sessions/summary response and the deck TUI overview.
func BuildSummary ¶
func BuildSummary(nodes []*merkle.Node, pricing PricingTable) (SessionSummary, map[string]ModelCost, string, error)
BuildSummary computes a SessionSummary from a chain of nodes in chronological order (root first, leaf last). It also returns the per-model cost breakdown used for rollups, and the derived status (duplicated on the returned summary for convenience).
Returns an error if the input chain is empty.