web

package
v0.5.6 Latest Latest
Warning

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

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

Documentation

Overview

Package web holds akari's server-rendered UI: templ templates and the small view-model helpers they use. Handlers in the httpapi package resolve auth, query the store, and render these templates, so all rendering lives here.

Package web holds akari's server-rendered UI: templ templates and the small view-model helpers they use. Handlers in the httpapi package resolve auth, query the store, and render these templates, so all rendering lives here.

Package web holds akari's server-rendered UI: templ templates and the small view-model helpers they use. Handlers in the httpapi package resolve auth, query the store, and render these templates, so all rendering lives here.

Package web holds akari's server-rendered UI: templ templates and the small view-model helpers they use. Handlers in the httpapi package resolve auth, query the store, and render these templates, so all rendering lives here.

Package web holds akari's server-rendered UI: templ templates and the small view-model helpers they use. Handlers in the httpapi package resolve auth, query the store, and render these templates, so all rendering lives here.

Package web holds akari's server-rendered UI: templ templates and the small view-model helpers they use. Handlers in the httpapi package resolve auth, query the store, and render these templates, so all rendering lives here.

Package web holds akari's server-rendered UI: templ templates and the small view-model helpers they use. Handlers in the httpapi package resolve auth, query the store, and render these templates, so all rendering lives here.

Package web holds akari's server-rendered UI: templ templates and the small view-model helpers they use. Handlers in the httpapi package resolve auth, query the store, and render these templates, so all rendering lives here.

Index

Constants

View Source
const DefaultRange = "year"

DefaultRange is the window the overview opens on: a trailing year, wide enough to read seasonality and longer trends on the activity grid without jumping to all of history.

View Source
const DefaultSessionLimit = 100

DefaultSessionLimit is the global feed's page size, the fixed slice each request reads. "Show more" no longer grows this: it passes a keyset cursor and appends the next page of the same size (see ShowMorePath), so depth is unbounded and the page cost stays flat.

View Source
const OtherModelLabel = "Other"

OtherModelLabel is the bucket name for the model breakdown's long tail: every model without a pricing entry folds into this one row.

View Source
const SessionsBasePath = "/sessions"

SessionsBasePath is the global (cross-project) session list.

View Source
const SubagentCollapseThreshold = 8

SubagentCollapseThreshold is the subagent count past which the session detail collapses the subagents table behind a summary line. Below it the short list reads fine inline; above it the table pushes the transcript below the fold on exactly the fan-out-heavy sessions a lead most wants to audit, so it folds away by default and the summary carries the count and spend at a glance. The value is a comfortable ceiling: a handful of subagents is context, a few dozen is a wall.

View Source
const UnscoredKey = "unscored"

UnscoredKey is the sentinel a drill-through link and the Grade filter carry for the unscored grade bucket, since the empty string reads as "no grade filter". The Grades panel's unscored bar links with this value.

Variables

View Source
var DateRanges = []DateRange{
	{Key: "7d", Label: "7 days", Days: 7},
	{Key: "30d", Label: "30 days", Days: 30},
	{Key: "90d", Label: "90 days", Days: 90},
	{Key: "year", Label: "Year", Days: 365},
	{Key: "all", Label: "All", Days: 0},
}

DateRanges are the windows the overview offers, narrowest first. The selector renders them in this order, and ParseRange validates against their keys.

View Source
var Static embed.FS

Static holds the embedded static assets (htmx, stylesheet) served under /static/.

Functions

func AgentFacetHref

func AgentFacetHref(f store.SessionFilter, value string) templ.SafeURL

AgentFacetHref and friends return the toggle href for a facet option, holding the rest of the current selection.

func AnalyticsJSON

func AnalyticsJSON(a store.Analytics) string

AnalyticsJSON marshals a session's daily series for the inline chart script.

func AnyFilterActive

func AnyFilterActive(f store.SessionFilter) bool

AnyFilterActive reports whether the global session list is currently narrowed, so the view can show a "clear all" affordance only when it would do something. The content search counts: it is a removable narrowing like the facets, and its chip clears alongside them.

func AttachmentAlt

func AttachmentAlt(a store.AttachmentView) string

AttachmentAlt is the alt text for a rendered image: its filename when one was recovered, else a generic label so the element is never unlabelled.

func AttachmentsByOrdinal

func AttachmentsByOrdinal(atts []store.AttachmentView) map[int][]store.AttachmentView

AttachmentsByOrdinal groups attachments by the message ordinal they belong to, so the session view can render a message's images beneath it.

func BaseName

func BaseName(p string) string

BaseName returns the last path segment of a file path (handling both / and \ separators), for a compact label in the outline. It returns the input unchanged when there is no separator.

func BlobURL

func BlobURL(base, sha string) string

BlobURL builds a tool body's fetch URL from a session blob base and a hash.

func BodyPath

func BodyPath(id int64) string

func CSRFToken added in v0.5.5

func CSRFToken(ctx context.Context) string

CSRFToken returns the token for the current rendered request.

func ChipLabel

func ChipLabel(mediaType string, bytes int64) string

ChipLabel renders a tool body's media type and size, for example "36.0 KB json".

func ChurnSessions

func ChurnSessions(sessions int) string

ChurnSessions labels how many sessions edited a file, so a path churned across the fleet reads apart from one a single session kept rewriting.

func ContextLabel added in v0.2.4

func ContextLabel(content string) string

ContextLabel names what an injected-context turn carries, from the marker its content opens with (see parser.isCodexContext). It is a short, fixed label for the outline row and the transcript disclosure summary, never the raw framing text.

func ContextResetsLabel

func ContextResetsLabel(s store.SessionSignals) string

ContextResetsLabel renders how many inferred context resets (compactions or clears) the session went through, for the Tokens tooltip. An unmeasured session reads a dash; a measured session with none reads "0", a real "it never shed context".

func DetailLabel added in v0.2.2

func DetailLabel(s string) string

DetailLabel renders a tool call's Detail (a command, pattern, URL, or other bounded input summary, up to 2048 bytes and possibly multi-line) as a single scannable line for a chip or outline step: every run of whitespace collapses to one space, and the result is capped at 80 runes with a trailing ellipsis. The cap keeps a chip from growing to the size of its input; the full text still reaches the reader through the element's title attribute, so nothing is lost, only deferred to hover. The truncation counts runes, not bytes, so it never splits a multi-byte UTF-8 sequence.

func DiffTool

func DiffTool(name string) bool

DiffTool reports whether a tool's input body is worth rendering as an inline diff rather than raw JSON (the file-editing tools across the three agents). The client reads this off the chip to decide how to expand the body.

func DuplicateIDsLabel

func DuplicateIDsLabel(n int) string

DuplicateIDsLabel is the chip text for a session that repeats tool-call ids, pluralized for the count. The count itself is a bounded scalar from the store (DuplicateCallUIDCount), not computed over the in-memory tool calls.

func EarlierCountLabel added in v0.4.0

func EarlierCountLabel(n int) string

EarlierCountLabel is the "Show earlier" bar's second half, naming how much of the transcript stays unrendered above the window.

func EmptyToggleHref added in v0.2.2

func EmptyToggleHref(f store.SessionFilter) templ.SafeURL

EmptyToggleHref flips the include-empty state for the footer's toggle, holding every other facet, search, and sort. Like every filter link it carries no keyset cursor, so flipping the empty state reopens the feed at the first page rather than resuming mid-walk under the other visibility, which the changed row set would make meaningless.

func FallbackBadgeLabel added in v0.2.5

func FallbackBadgeLabel(count int) string

FallbackBadgeLabel is the feed row's compact tag text: "fallback" for one, "fallback xN" for more (with the multiplication sign, not the letter). The badge is a quiet count; the fuller sentence lives in its title.

func FallbackBadgeTitle added in v0.2.5

func FallbackBadgeTitle(count int) string

FallbackBadgeTitle is the feed badge's hover sentence, naming what the count means in plain terms. It states the fact ("fell back from Fable 5 to a lower model") without naming the served model, which the feed row does not carry; the session page names it.

func FallbackCategoryLabel added in v0.2.5

func FallbackCategoryLabel(f store.ModelFallback) string

FallbackCategoryLabel renders one fallback's refusal category for a tooltip row. The category is empty until the system entry of the fallback merged in, so an unset value reads "uncategorized" rather than blank.

func FallbackDeclinedObserved added in v0.2.5

func FallbackDeclinedObserved(f store.ModelFallback) bool

FallbackDeclinedObserved reports whether the declined attempt's spend was fully measured: all four token classes merged in from the assistant source line. The classes arrive together, so a single nil means the spend was never observed and the tooltip shows no declined figures rather than a partial, misleading breakdown. This matches the MCP DTO, which likewise reports the declined tokens only when every class is present.

func FallbackModelsLabel added in v0.2.5

func FallbackModelsLabel(f store.ModelFallback) string

FallbackModelsLabel renders one fallback's model pair for a tooltip row, using a real arrow glyph between the from-model and the served model. Either side may be unset when only one transcript line of the fallback was seen, so a missing model reads "unknown" rather than an empty run.

func FallbackNoticeLabel added in v0.2.5

func FallbackNoticeLabel(f store.ModelFallback) string

FallbackNoticeLabel is the inline transcript notice above the turn a fallback landed on: a plain sentence naming the model pair, with the refusal category (or trigger) in parentheses when either is known. Models fall back to "unknown" the same way the tile does, so the notice never reads a blank model.

func FallbackTimeLabel added in v0.2.5

func FallbackTimeLabel(ctx context.Context, f store.ModelFallback) string

FallbackTimeLabel renders when a fallback occurred for a tooltip row, in the viewer's timezone, or a dash when the source lines carried no timestamp.

func FallbacksByOrdinal added in v0.2.5

func FallbacksByOrdinal(fbs []store.ModelFallback) map[int]store.ModelFallback

FallbacksByOrdinal indexes a session's fallbacks by the transcript message ordinal they landed on, for the inline transcript notice to look up a turn in O(1) while the walker renders messages. A fallback whose source lines never named a message ordinal is left out: it has no turn to mark, so it appears only in the header tile's tooltip. When two fallbacks share one ordinal (a turn declined twice), the first in occurrence order wins the slot, since the slice arrives already ordered by occurrence.

func FallbacksOverflow added in v0.2.5

func FallbacksOverflow(count, shown int) int

FallbacksOverflow reports how many fallbacks the count claims beyond the shown rows, so a tooltip that renders only a leading window can name the remainder in a "plus N more" line. It is never negative: the count is the session-wide total and shown is bounded by it.

func FanoutLabel added in v0.4.0

func FanoutLabel(tr store.TreeRollup) string

FanoutLabel is the fan-out chip's text: the subtree's subagent count and its whole-work-item cost, joined so a reader sees at a glance both how wide a prompt fanned out and what the whole thing cost. The count is singular at one ("1 subagent"), and the cost carries the "+" lower-bound marker when any session in the subtree could not be fully priced. It is only ever rendered when the count is positive, so it never reads "0 subagents".

func FanoutTitle added in v0.4.0

func FanoutTitle(tr store.TreeRollup) string

FanoutTitle is the fan-out chip's hover text, spelling out that the chip's cost is the whole work item's, not the root turn's. The row's own token cell shows the root session's own cost; a prompt that delegated to subagents spent far more than that root turn, and this line names that gap so the two cost figures do not read as a contradiction.

func FeedDayKey added in v0.4.0

func FeedDayKey(ctx context.Context, t *time.Time) string

FeedDayKey is the day-bucket key of a timestamp in the viewer's zone, the same key buildSessionFeed groups on. The keyset "Show more" carries the last rendered row's key so the appended page can suppress a repeated day heading when it continues the same day (a page boundary must not print "Today" twice). It is empty for a missing timestamp, matching the undated bucket.

func FeedIsGrouped

func FeedIsGrouped(f store.SessionFilter) bool

FeedIsGrouped reports whether the feed for this filter is split into day headings, which it is only in the default most-recent order.

func FeedMaxTokens added in v0.4.0

func FeedMaxTokens(rows []store.SessionRow) int64

FeedMaxTokens is the token-bar denominator for a page of feed rows: the largest session's total token volume across the page. The first page computes it and the keyset "Show more" carries it forward (SessionFooter.MaxTok) so every appended page scales its bars against the same reference the reader already sees. Recomputing it per page would make a bar's width incomparable across a "Show more" boundary: a page of small sessions would render them full-width against their own small maximum. A later page holding a session larger than this denominator clamps to a full bar (tokenPct caps at 100), which reads as "the biggest so far" rather than misleading.

func FeedTime

func FeedTime(ctx context.Context, t *time.Time) string

FeedTime is the clock time a feed row shows, in the viewer's timezone. The day already rides the group heading, so the row needs only the time of day; the exact stamp is the cell's title on hover.

func FlowRibbonVisible added in v0.4.0

func FlowRibbonVisible(msgs []store.Message) bool

FlowRibbonVisible reports whether the session is long enough for its ribbon to carry information.

func FlowTickClass added in v0.4.0

func FlowTickClass(m store.Message, steps []store.ToolCallView) string

FlowTickClass maps one turn to its tick's tone. Failure outranks everything (a turn that both edited and failed reads as a failure); then edits, then runs, so the ribbon reads "where work landed and where it broke". A user turn reads as its own segment mark, so the ribbon's rhythm shows the prompt cadence; context injections and plain assistant turns stay faint.

func FlowTickTitle added in v0.4.0

func FlowTickTitle(m store.Message, steps []store.ToolCallView) string

FlowTickTitle is a tick's hover label: the turn number and role, its outline title when one reads, and its tool tally with failures broken out, so hovering the ribbon scrubs through the session without leaving it.

func FmtBytes

func FmtBytes(n int64) string

FmtBytes renders a byte count compactly (the tool-body metadata chips).

func FmtContextStamp added in v0.2.2

func FmtContextStamp(u store.TurnUsage) string

FmtContextStamp renders a turn's context occupancy as the compact "ctx 82k" stamp the transcript shows inline; the full per-class split and cost ride the breakdown card the stamp hosts (see turnCard in session.templ), not a hover title.

func FmtCost

func FmtCost(usd float64, incomplete bool) string

FmtCost renders a USD cost. Sub-cent costs still show enough precision to be meaningful.

func FmtDuration

func FmtDuration(start, end *time.Time) string

FmtDuration renders the span between start and end, or a dash. It delegates to durationfmt so the session page's Duration tile and the session OG card, which both show this figure, format it through one definition and cannot drift apart.

func FmtErrorRate

func FmtErrorRate(v float64) string

FmtErrorRate renders a failure share (a 0..1 fraction) as a whole-percent figure, with a "<1%" floor so a small but real error rate never rounds down to a reassuring "0%".

func FmtLatency

func FmtLatency(d time.Duration) string

FmtLatency renders a turn-cycle latency at the coarsest unit that still reads honestly: seconds under a minute, minutes and seconds under an hour, hours and minutes beyond. A zero or negative duration (no measured turn) shows a dash rather than "0s", so an absent figure never reads as an instantaneous reply. The value rounds to whole seconds before the unit split, so 59.6s reads as "1m 0s" rather than a misleading "60s".

func FmtPercent

func FmtPercent(f float64) string

FmtPercent renders a 0..1 fraction as a whole-number percent, for the cache hit rate. A real but tiny rate (under 1%) rounds up to 1% rather than 0%, so a scope that did hit the cache never reads as a total miss; a true zero stays 0%.

func FmtRate

func FmtRate(v float64) string

FmtRate renders a per-minute throughput to one decimal, so the velocity figures read at a granularity that reads as a rate without implying false precision.

func FmtRelTime

func FmtRelTime(ctx context.Context, t *time.Time) string

FmtRelTime renders a timestamp as a coarse "time ago" for the recent past (today, 1 day ago, ...), falling back to an absolute stamp once it is a week or more old, where a relative phrasing stops being useful. It reads "now" from the wall clock; relTime holds the testable core. It backs the "Updated" column on both the projects index and the per-project session table, so the two read alike (the global feed groups by day instead and uses FeedTime).

func FmtSavings

func FmtSavings(usd float64, incomplete bool) string

FmtSavings renders a cache saving for the Cache tile. A non-negative saving reads as "saved $X"; the rare negative, where cache was written but never re-read enough to repay the creation premium, reads as "cost $X" on its magnitude, so the figure stays honest without printing a minus sign into a "saved" label.

An incomplete saving reads "... partial", NOT the "$X+" lower-bound marker the cost figures use. A saving omitted for an unpriced model can be negative (a Claude cache write is priced above input), so the true figure could be lower OR higher than shown: "partial" says it is incomplete without implying a direction the data cannot support.

func FmtSnapshotAge added in v0.5.4

func FmtSnapshotAge(at time.Time) string

FmtSnapshotAge renders how long ago a precomputed snapshot was taken, minute-grain: the Insights page serves from a snapshot recomputed on a cadence rather than live data, and this is the provenance note beside its controls. It is deliberately finer than FmtRelTime's day-grain ladder: an hour-scale cadence needs minutes to read as anything but "today". It reads the wall clock; snapshotAge holds the testable core.

func FmtTime

func FmtTime(ctx context.Context, t *time.Time) string

FmtTime renders a timestamp in the viewer's timezone (UTC when none is set), or a dash when absent. It keeps the bare "2006-01-02 15:04" form for a visible cell; FmtTimeLong adds the zone abbreviation for a hover title, where naming the zone earns its width.

func FmtTimeAt

func FmtTimeAt(ctx context.Context, t time.Time) string

FmtTimeAt renders a non-pointer timestamp in the viewer's timezone, or a dash when zero.

func FmtTimeLong added in v0.2.2

func FmtTimeLong(ctx context.Context, t *time.Time) string

FmtTimeLong is FmtTime with the zone abbreviation appended, for the hover title on a stamp shown short elsewhere. Naming the zone (PST, UTC, ...) lets a reader tell which zone a full stamp is in without cluttering every visible cell with it.

func FmtTokens

func FmtTokens(n int64) string

FmtTokens renders a token count with thousands separators.

func FmtTokensCompact

func FmtTokensCompact(n int64) string

FmtTokensCompact renders a token count to a short magnitude (2.1B, 1.7M, 63.0k, 412), for the feed's inline figure where the exact value lives in the hover card. The thousands-separated FmtTokens stays the form for places that show the full number. The buckets mirror fmtTok in static/charts.js, its client-side counterpart, so a figure reads the same on either surface.

func FmtTurnLatency added in v0.2.2

func FmtTurnLatency(d time.Duration) string

FmtTurnLatency renders a turn's reply latency as the inline "+6s" stamp: the leading plus reads it as an elapsed gap from the prompt rather than an absolute time. It reuses FmtLatency for the unit split.

func FoldUnknownModels

func FoldUnknownModels(bs []store.Breakdown) []store.Breakdown

FoldUnknownModels collapses every model without a pricing entry into a single "Other" row, leaving the priced (well-known) models untouched and in their incoming order. Only models we have rates for surface by name on the overview; the rest contribute their totals to "Other" but never their IDs, so a model still under a codename can be exercised without leaking its name.

The input is taken in its store order (cost descending); "Other" is appended last regardless of its totals, the usual place for a catch-all bucket. Summing the per-model session counts can overcount a session that spanned several unpriced models, the same approximation the by-model split already makes across its rows.

func GradeChipLabel added in v0.2.2

func GradeChipLabel(grade string) string

GradeChipLabel and OutcomeChipLabel render the active-filter chip value for a grade or outcome, terse to match the agent/user chips ("grade A", "outcome abandoned").

func GradeClearHref added in v0.2.2

func GradeClearHref(f store.SessionFilter) templ.SafeURL

GradeClearHref, OutcomeClearHref, and RangeClearHref are the removal links for the grade, outcome, and range chips: each drops just its own param while holding every other facet, search, sort, and window, matching the agent/user chip behavior.

func GradeFilterKey added in v0.2.2

func GradeFilterKey(distKey string) string

GradeFilterKey maps a Grades-distribution key to the ?grade= value that drills into the matching sessions: the empty (unscored) bucket becomes the sentinel, a letter stays itself. It is the inverse of gradeLabel for URL building.

func GradedNote added in v0.2.2

func GradedNote(q store.QualityDistribution) string

GradedNote is the coverage caption for a quality distribution panel: the share of in-scope sessions that carry a usable grade, so a reader can weigh a mostly ungraded window's bars for what they are. It reads "" when the window is empty (the panel shows its own empty state), and rounds to whole percent, with a "<1% graded" floor so a nonzero-but-tiny coverage does not round away to "0% graded".

func InsightsData added in v0.3.0

func InsightsData(ins store.Insights) (string, error)

InsightsData serializes the trend grid into the single JSON blob the insights chart engine reads from #insights-data as window.AK_DATA. It is the one bridge between the Go store types and static/js/insights.js: every field name here is a contract the JS depends on, so a rename on either side must move together. It returns the marshaled JSON; the template embeds it raw in a <script type="application/json"> (json.Marshal escapes <, >, and & to \uXXXX, so the payload can never break out of the script element).

It reads the whole Insights value, not just Trends, because a few headline figures the charts annotate live outside the grid: the concurrency peak/average and the window's context percentile. When there is no trend grid the caller renders an empty state instead of calling this.

func IsGrade added in v0.2.2

func IsGrade(v string) bool

IsGrade reports whether v is a grade the session list can filter by: a letter A..F or the unscored sentinel. The handler uses it to reject a tampered ?grade= value.

func IsImageMedia

func IsImageMedia(mediaType string) bool

IsImageMedia reports whether a media type is an image the transcript can show inline, so a non-image attachment falls back to a download link instead.

func IsLocalKind

func IsLocalKind(kind string) bool

IsLocalKind reports whether a project kind is one of the non-remote kinds (standalone or orphaned), which are grouped and labeled apart from git-remote projects in the UI.

func IsOutcome added in v0.2.2

func IsOutcome(v string) bool

IsOutcome reports whether v is a filterable outcome, so the handler can reject a tampered ?outcome= value.

func Loc added in v0.2.2

func Loc(ctx context.Context) *time.Location

Loc is the viewer's timezone for the current render, or UTC when none was set. The formatting helpers localize every stamp and day heading through it, so a reader sees times in their own zone; a page rendered outside a request (or before the cookie is set) reads UTC. templ exposes the render ctx implicitly, so a template calls FmtTime(ctx, t) and this reads the zone off that ctx.

func LocalPath

func LocalPath(p store.ProjectSummary) string

LocalPath recovers the working-directory path from a local project's synthetic key ("local:machine:path"), for display beside the folder name. It returns "" for a remote project.

func LocalPathDir added in v0.5.1

func LocalPathDir(path string) string

LocalPathDir is the dimmable lead of a local working-directory path: everything through the last separator (either slash flavor, since paths arrive from any client OS). The ledger renders it faint so the folder name carries the weight.

func LocalPathLeaf added in v0.5.1

func LocalPathLeaf(path string) string

LocalPathLeaf is the final segment of a local path, the counterpart of LocalPathDir.

func MachineFacetHref

func MachineFacetHref(f store.SessionFilter, value string) templ.SafeURL

func MessageThinkingBand added in v0.3.0

func MessageThinkingBand(agent string, m store.Message) (quality.ThinkingBucket, bool)

MessageThinkingBand is the in-transcript per-message band: the absolute thinking band for one assistant turn, rendered as a chip before the message so the reader sees how hard the model deliberated on that turn without opening the (often redacted) trace. ok is false for a turn that carried no reasoning block, so the caller shows no chip. The turn's tokens are its exact reasoning count where the agent reports one (Codex, in the turn usage) else its reasoning-trace bytes over the agent's calibrated factor.

The estimate is rounded to whole tokens BEFORE banding, the same rule the settle pass applies in gatherObservedThinking (math.Round into the stored int scalar) so a one-turn session bands identically in the chip and in the header readout. Banding the raw float here would let a turn whose estimate lands just over an edge (thinking_bytes=1374 for Claude is 128.4 tokens) read one band in the chip and another off the rounded scalar (128 -> low).

func Notice added in v0.2.2

func Notice(ctx context.Context) string

Notice is the current render's one-shot notice banner text, or "" when none was set. The authed layout renders it once at the top of main when non-empty.

func OutcomeChipLabel added in v0.2.2

func OutcomeChipLabel(outcome string) string

func OutcomeClearHref added in v0.2.2

func OutcomeClearHref(f store.SessionFilter) templ.SafeURL

func OutcomeLabel

func OutcomeLabel(outcome string) string

OutcomeLabel renders a stored outcome string title-cased for display. An empty or unrecognized value reads "Unknown", so the tile never shows a blank cell.

func OutlineStepClass

func OutlineStepClass(t store.ToolCallView) string

OutlineStepClass maps a tool step to its CSS modifier, flagging an errored step in rose.

func OutlineStepHasBody

func OutlineStepHasBody(t store.ToolCallView) bool

OutlineStepHasBody reports whether a tool step has a stored input or result body, so the outline can wire only those steps to the inspector.

func OutlineTitle

func OutlineTitle(m store.Message) string

OutlineTitle is a compact one-line label for an outline turn, drawn from the start of the message content. It collapses runs of whitespace and emits at most 48 runes, and it never scans more than scanCap runes of input, so even a whitespace-heavy message costs a fixed amount, independent of message size.

func OutlineTurnClass

func OutlineTurnClass(role string, steps []store.ToolCallView) string

OutlineTurnClass maps a turn (its role and its tool steps) to its CSS modifier: role tone, with an error override so a turn with a failed tool reads in rose.

func OverviewPath

func OverviewPath(rng string, userIDs []int64) string

OverviewPath builds the overview URL for a range key and a set of selected user ids: the shared target the range buttons link to and the user filter submits, so the two controls always round-trip the full window-and-users state together rather than each clobbering the other's selection. It is rooted at /overview (the app home), not "/" (the public homepage).

func ParseRange

func ParseRange(key string) string

ParseRange normalizes a range query value to a known key, falling back to the default for anything empty or unrecognized.

func PeakContextLabel

func PeakContextLabel(s store.SessionSignals) string

PeakContextLabel renders the heaviest single-turn context the session reached, in full tokens, for the Tokens tooltip. It is a window-independent measure of how loaded the session got. An unmeasured session (no usage) reads a dash rather than a misleading zero.

func ProjectFacetHref

func ProjectFacetHref(f store.SessionFilter, id int64) templ.SafeURL

ProjectFacetHref toggles the project selection for a facet row, holding the rest of the current selection.

func ProjectFacetLabel

func ProjectFacetLabel(pf store.ProjectFacet) string

ProjectFacetLabel is the label for a project option in the session filter rail, friendly for a local project and the remote key otherwise.

func ProjectHref

func ProjectHref(id int64) templ.SafeURL

ProjectHref and friends return sanitized internal URLs for href attributes.

func ProjectLabel added in v0.3.0

func ProjectLabel(kind, name, key string) string

ProjectLabel is the folder-name-or-remote-key choice SessionProjectLabel makes, taking the three fields directly so the session OG card (which reads a store.SessionCard, not a full SessionDetail) resolves its heading through the same rule the page's <h1> uses.

func ProjectPath

func ProjectPath(id int64) string

ProjectPath returns the plain string path, used for htmx attributes (which are not URL-sanitized like href).

func ProjectPublishPath added in v0.2.5

func ProjectPublishPath(id int64) string

ProjectPublishPath and ProjectUnpublishPath are the POST targets for the project page's publicity control, mirroring the account overview toggles. They are plain strings the templ form actions wrap in templ.SafeURL.

func ProjectTitle

func ProjectTitle(p store.ProjectSummary) string

ProjectTitle is the heading shown for a project. A remote project shows its canonical remote key; a standalone or orphaned project shows its folder name, since its synthetic key ("local:machine:path") is an internal detail.

func ProjectUnpublishPath added in v0.2.5

func ProjectUnpublishPath(id int64) string

func PublicBlobBase

func PublicBlobBase(publicID string) string

func PublicHref

func PublicHref(publicID string) templ.SafeURL

func PublicOverviewHref

func PublicOverviewHref(username string) templ.SafeURL

PublicOverviewHref is the sanitized href form of PublicOverviewPath, for the account page's link and the signed-in overview badge.

func PublicOverviewOGPath added in v0.3.0

func PublicOverviewOGPath(username string) string

PublicOverviewOGPath is the path of the Open Graph preview card for a user's published overview, the /u/<username>/og.png the page advertises as og:image and the route serves the rendered PNG from. It is PublicOverviewPath with the card suffix, so the page tag and the route stay one definition rather than two string literals that could drift.

func PublicOverviewPath

func PublicOverviewPath(username string) string

PublicOverviewPath is the plain-string path of a user's public usage overview, rooted at /u/<username>. The username is path-escaped so an unusual character cannot break the URL or escape the segment. The range selector on the public page builds its buttons from this base (via RangeOptions), so switching the window refetches the public path rather than the authed overview, and the account page shows it as the shareable link.

func PublicPath

func PublicPath(publicID string) string

PublicPath is the plain-string public URL, shown to the owner as the shareable link to copy.

func PublicProjectHref added in v0.2.5

func PublicProjectHref(id int64) templ.SafeURL

PublicProjectHref is the sanitized href form of PublicProjectPath, for the project page's share link and public badge.

func PublicProjectOGPath added in v0.3.0

func PublicProjectOGPath(id int64) string

PublicProjectOGPath is the path of the Open Graph preview card for a project's published overview, the /p/<id>/og.png the page advertises as og:image and the route serves the rendered PNG from. Built off PublicProjectPath so the tag and the route share one definition.

func PublicProjectPath added in v0.2.5

func PublicProjectPath(id int64) string

PublicProjectPath is the plain-string path of a project's public usage overview, rooted at /p/<id>. The range selector on the public page builds its buttons from this base (via RangeOptions), so switching the window refetches the public path rather than the authed project page, and the signed-in project page shows it as the shareable link.

func PublicSessionBodyPath added in v0.5.5

func PublicSessionBodyPath(publicID string) string

PublicSessionBodyPath is the revocable HTMX transcript fragment endpoint. It stays under the public capability URL and never exposes the numeric session id.

func PublicSessionOGPath added in v0.3.0

func PublicSessionOGPath(publicID string) string

PublicSessionOGPath is the path of the Open Graph preview card for a published session, the /s/<public_id>/og.png the page advertises as og:image and the route serves the rendered PNG from. Built off PublicPath so the tag and the route share one definition.

func QualityGrade

func QualityGrade(s store.SessionSignals) string

QualityGrade is the headline of the session Quality tile: the letter grade for a scored session, or a plain dash for an unscored one (an unknown outcome with no tool signal, where a letter would invent a verdict the transcript does not support).

func QualityGradeClass

func QualityGradeClass(s store.SessionSignals) string

QualityGradeClass is the CSS modifier for the Quality tile. The good/watch/poor tiering itself lives in quality.GradeBand; this only maps the band onto the status palette already in the sheet (sage, peach, rose) rather than introducing new hues, keeping to the One Voice Rule.

func QualityScoreLabel

func QualityScoreLabel(s store.SessionSignals) string

QualityScoreLabel renders the numeric score for the Quality tooltip: "n / 100" for a scored session, "not scored" otherwise, so an unscored session reads as a deliberate abstention rather than a zero.

func RangeBounds added in v0.2.2

func RangeBounds(key string) bool

RangeBounds reports whether a range key names a bounded trailing window (a known key with a positive day span). It is false for "all", the empty string, and any unknown value, which the sessions feed treats as all-history: those add no ?range param, keeping the bare feed unbounded. It is the whitelist the feed's range param passes through (like IsOutcome / IsGrade for their params), so a stale or hand-edited ?range never bounds the list to a made-up window.

func RangeChipLabel added in v0.2.2

func RangeChipLabel(key string) string

RangeChipLabel is the active-filter chip value for the window, reusing the range selector's own option wording ("30 days", "Year") so the chip reads the same as the button that could have set it. It falls back to the raw key for an unknown value, though the handler validates the key before it reaches here.

func RangeClearHref added in v0.2.2

func RangeClearHref(f store.SessionFilter) templ.SafeURL

func RangeLabel added in v0.2.2

func RangeLabel(key string) string

RangeLabel returns a range key's display label ("30 days", "Year"), for the sessions feed's active-range chip. An unknown key returns the key itself, so a stale value still reads rather than rendering blank.

func RangeSince

func RangeSince(key string, now time.Time) time.Time

RangeSince converts a range key to the lower time bound to pass to the store, measured back from now. The "all" window (zero Days) returns the zero time, which the store reads as "no bound".

func RemoteKeyHost added in v0.5.1

func RemoteKeyHost(key string) string

RemoteKeyHost is the dimmable lead of a remote key: the host segment including its trailing slash ("github.com/" from "github.com/hopper/akari"). The projects ledger renders it faint so the owner/repo part carries the visual weight. A key with fewer than two slashes has no host to dim (it is already just owner/repo, or a bare name), so this returns "" and the whole key reads at full weight.

func RemoteKeyName added in v0.5.1

func RemoteKeyName(key string) string

RemoteKeyName is the remainder of a remote key after RemoteKeyHost: the part a reader recognizes the project by.

func ReparsePercent

func ReparsePercent(done, total int) int

ReparsePercent is the completed fraction of a reparse as an integer percent, for the progress bar's fill width. It is 0 before the total is known and is clamped to 100, so a late count revision can never overflow the track.

func RoleClass

func RoleClass(role string) string

RoleClass maps a message role to a CSS class for styling.

func RowGradeClass added in v0.4.0

func RowGradeClass(grade *string) string

RowGradeClass is the CSS band for a feed row's grade chip, matching the session Quality tile's report-card palette. The tiering lives in quality.GradeBand so the feed chip cannot drift from the Quality tile and Insights bars; this only maps the band onto the q-* class. An absent grade returns "" so the caller renders no chip.

func RowOutcomeNote added in v0.4.0

func RowOutcomeNote(outcome string) string

RowOutcomeNote returns a short outcome word to flag on a feed row, but only for the outcomes worth a glance: abandoned and errored. A completed or unknown outcome returns "" so the common, healthy row stays quiet and the failures stand out.

func RowTokens

func RowTokens(s store.SessionSummary) int64

RowTokens is a session's total token volume across all four classes (input, output, cache read, cache write), matching the overview heatmap's notion of a day's "total tokens" so the figure and its breakdown agree across views.

func SSEPath

func SSEPath(id int64) string

SSEPath and BodyPath are the live-update endpoints for a session, carried on data attributes for the static app.js to wire up.

func ScoreBreakdownItems added in v0.2.2

func ScoreBreakdownItems(s store.SessionSignals) []quality.ScoreBreakdownItem

ScoreBreakdownItems returns the penalty lines behind a scored session's grade (label plus the points it subtracted), for the "score arithmetic" group in the quality tooltip. It is empty when the session is unscored (there is no arithmetic) OR scored with no penalties (a clean 100): the caller distinguishes the two through the session's Scored() flag and shows a single "no penalties" row for the clean-scored case.

func SearchClearHref added in v0.2.2

func SearchClearHref(f store.SessionFilter) templ.SafeURL

SearchClearHref is the toggle link for the active search chip: it drops the query while holding every other facet, sort, and the empty toggle, so removing a search leaves the rest of the narrowing in place. It returns the feed to its first page implicitly: the base path carries no keyset cursor (only "Show more" appends one), so a cleared-search link always reopens at the top.

func SelectedUserIDs

func SelectedUserIDs(raw []string, users []store.User) []int64

SelectedUserIDs parses the overview's repeated ?user= ids against the known accounts, keeping only ids that name a real user and returning them in the users-list order. A tampered, stale, or non-numeric id silently drops out, and the stable order keeps the collapsed chips from reshuffling between requests.

func SessionBlobBase

func SessionBlobBase(id int64) string

SessionBlobBase and PublicBlobBase are the per-session prefixes under which CAS blobs are served, for the authenticated and logged-out views respectively. A blob URL is the base plus "/blob/{sha256}"; serving is gated on the session referencing the hash.

func SessionHref

func SessionHref(id int64) templ.SafeURL

func SessionPageTitle added in v0.2.6

func SessionPageTitle(d store.SessionDetail) string

SessionPageTitle is the browser-tab title for a session view: the session's own summary when it has one (the same line the page's <h1> shows), else a stable "<project> session" label. Both the signed-in and the public session page use it, so a shared link and the in-app tab read the same rather than one saying "Session #42" and the other the project name.

func SessionPath

func SessionPath(id int64) string

SessionPath is the plain-string session path, used for the row-navigation data attribute that makes a whole table row a click target.

func SessionProjectLabel

func SessionProjectLabel(d store.SessionDetail) string

SessionProjectLabel is the project name shown in a session header: the folder name for a local session, the remote key otherwise. It keeps the synthetic "local:machine:path" key out of the heading.

func SessionRowProject

func SessionRowProject(r store.SessionRow) string

SessionRowProject is the project label shown beside a session in the global session list: the folder name for a local project, the remote key otherwise.

func SessionsHref

func SessionsHref(f store.SessionFilter) templ.SafeURL

SessionsHref is the sanitized href form of SessionsPath, for anchor tags.

func SessionsPath

func SessionsPath(f store.SessionFilter) string

SessionsPath is the full global session-list path for the current selection, used as the htmx swap target so a facet click updates the URL coherently.

func ShedLabel added in v0.2.2

func ShedLabel(m ShedMark) string

ShedLabel renders a shed divider's centered label, "context shed: 145k -> 12k", with a real arrow between the before and after occupancy figures.

func ShowMorePath added in v0.2.2

func ShowMorePath(f store.SessionFilter, afterID int64, afterVal, afterDay string, count int, maxTok int64) string

ShowMorePath is the plain-string path the "Show more" button fetches: the current feed's filter plus a keyset cursor (afterID, the last visible row's id, and afterVal, that row's sort value as the page saw it) so the store resumes strictly after it rather than re-reading the page under a doubled limit. afterVal fixes the resume boundary to what the reader already saw, so a later change to the cursor row's own column cannot drift the page and duplicate or skip rows; it is empty for an order with no keyset cursor. afterDay is the last row's day-bucket key, carried only for the day-grouped default order so the appended page suppresses a repeated heading; count is the running total already shown, so the appended footer reports the cumulative "Showing N" without counting the corpus; maxTok is the feed's token-bar denominator (the first page's largest session), carried so the appended page scales its bars against the same reference rather than its own page maximum. The cursor rides only this link, never the facet or sort URLs, so any filter change resets to the first page.

func Sparkline

func Sparkline(vals []float64) string

Sparkline renders a tiny inline SVG line of daily cost for a project row in the index. It is purely decorative trend context, so it carries aria-hidden and no axis; the cost column beside it holds the real number. Returns an empty string when there is nothing to draw (the cell stays blank).

func SplitProjectFacets added in v0.4.0

func SplitProjectFacets(projects []store.ProjectFacet) (repos, folders []store.ProjectFacet)

SplitProjectFacets partitions the project filter options into git-remote repositories and local folders, preserving the store's busiest-first order within each group. The session toolbar renders the two as separate option groups so a reader scanning for a repository is not wading through a machine's scratch folders: a repository is the audit unit, a local folder the looser catch-all beneath it. The store already orders remotes ahead of locals (GlobalFacets), so this only routes each option to its bucket.

func StaticURL added in v0.5.6

func StaticURL(path string) templ.SafeURL

StaticURL fingerprints an embedded asset so a newly deployed binary cannot reuse client code cached from an older HTML/data contract. The asset bytes are immutable for the process lifetime, so build the lookup once and keep templates to a map read.

func StatusClass

func StatusClass(status string) string

StatusClass maps a tool result status to a CSS class.

func StripPromptPreamble added in v0.4.0

func StripPromptPreamble(title string) string

StripPromptPreamble reduces a session's first-message title to the part a reader cares about, stripping the machine-generated preamble a coding-agent harness wraps around the human's words. It works on the already-single-spaced title (squashSpaces ran in the store), so every preamble sits on one line.

It only ever clarifies: it returns a slash command as its own name, strips leading harness wrapper blocks, and jumps past an embedded AGENTS.md instruction dump to the task that follows. When it cannot find a cleaner form it returns the original, so a title never gets worse than it was, and it never returns something longer than the input.

func SubagentFailures added in v0.4.0

func SubagentFailures(subs []store.SubagentRow) int

SubagentFailures counts the direct children that ended in an error, for the collapsed fold's "N failed" clause.

func SubagentTitle added in v0.4.0

func SubagentTitle(r store.SubagentRow) string

SubagentTitle is the label a subagents-table row leads with: the child's stripped first prompt (for an Agent-tool child this is the task description the parent gave it), falling back to the bare agent name so a row is never blank.

func SubagentsCollapsed added in v0.4.0

func SubagentsCollapsed(subs []store.SubagentRow) bool

SubagentsCollapsed reports whether a session's subagents table should render collapsed behind its summary (more than SubagentCollapseThreshold children), so the template and a test read the same rule rather than each spelling out the comparison.

func SubagentsSummaryLabel added in v0.4.0

func SubagentsSummaryLabel(subs []store.SubagentRow) string

SubagentsSummaryLabel is the collapsed subagents summary: the direct child count, their summed cost, and how many of them failed ("34 subagents · $6.12 · 2 failed"). It describes the subagents table it heads, which lists a session's direct children (Store.Subagents), so all three figures are over those direct rows, not the feed fan-out chip's whole-subtree rollup (TreeRollup, which also folds in a subagent's own subagents). For a flat fan-out the two read the same; for a nested one they legitimately differ, because this summary answers "what is in the table below" while the feed chip answers "what did the whole work item cost". The cost carries the "+" lower-bound marker when any direct child could not be fully priced. The failed clause appears only when a child errored, so a clean fan-out stays two figures. The count is singular at one, though the collapse only ever engages well above that.

func ThinkingBucketLabel added in v0.3.0

func ThinkingBucketLabel(b quality.ThinkingBucket) string

ThinkingBucketLabel renders a band for the session tooltip and the per-message transcript chip. The xhigh constant reads better spelled out.

func ThinkingTokensLabel added in v0.3.0

func ThinkingTokensLabel(tokens int) string

ThinkingTokensLabel renders an estimated per-turn reasoning-token volume ("~300 tok"). The tilde marks it as an estimate: Codex reasoning tokens are exact, but the Claude and pi figures are inferred from the reasoning-trace bytes, so the readout never implies a precision it does not have. The scale is absolute and agent-independent, so the figure is comparable across models (unlike the first cut's within-model byte proxy). The per-turn framing comes from the surrounding label, so it is left off here.

func ToolFilePath added in v0.2.2

func ToolFilePath(t store.ToolCallView) string

ToolFilePath is the path a tool chip and outline step should DISPLAY: the worktree-relative form when it is known, else the absolute path. The same repo file then reads the same across the worktrees it was edited from.

func ToolFileTitle added in v0.2.2

func ToolFileTitle(t store.ToolCallView) string

ToolFileTitle is the hover title for a tool chip's path: the absolute path when it differs from the displayed (relative) form, so the full location is one hover away without cluttering the chip. It is empty when the two are the same (a path with no relative form), so no redundant title is attached.

func ToolsByOrdinal

func ToolsByOrdinal(tools []store.ToolCallView) map[int][]store.ToolCallView

ToolsByOrdinal groups tool calls by the message ordinal they belong to, so the session view can render a message's tool calls beneath it.

func TrendBucket added in v0.3.0

func TrendBucket(key string) string

TrendBucket picks the time-bucket unit the Insights trend charts aggregate a range into: daily for the short windows (7d/30d) where a day still carries enough sessions to read, weekly for the long windows (90d/year/all) where daily points would be noise. The choice is the same for every chart in a view, so all the trend series share one bucket grid and the range selector windows them together. An unknown key falls back to the default range's unit, so a stale ?range still renders a sane grid.

func TurnCostLabel added in v0.2.2

func TurnCostLabel(u store.TurnUsage) string

TurnCostLabel renders a turn's cost for its breakdown card: the dollar figure when the turn was priced, or "unpriced" when it carries no cost (a turn whose usage never got a rate), so the card never shows a misleading "$0.00" for an unmeasured cost. A priced-but-incomplete turn (some of its token-bearing rows were unpriced) renders the same "$X+" lower-bound marker every other token/cost figure uses, so the card's cost never reads as exact next to unpriced token rows.

func TurnTokenTotal added in v0.2.2

func TurnTokenTotal(u store.TurnUsage) int64

TurnTokenTotal is the four-class spend total for one turn (input + output + cache read + cache write), the headline the turn's breakdown card carries above its per-class split. It is a real all-four-classes total, distinct from the context-occupancy figure the visible "ctx" stamp shows (which excludes output), so the card reconciles with the four rows beneath it.

func UserFacetHref

func UserFacetHref(f store.SessionFilter, value string) templ.SafeURL

func ValidKeysetValue added in v0.4.0

func ValidKeysetValue(sortKey, val string) bool

ValidKeysetValue reports whether val is a well-formed cursor value for the given feed sort key, so the handler can drop a tampered ?av (which would otherwise fail the SQL cast and 500) and fall back to the id-only cursor. It mirrors keysetCursorValue's per-column formats; an empty key reads as the default order, and a non-keyset order accepts no value.

func VerdictOutcomeTone added in v0.4.0

func VerdictOutcomeTone(outcome string) string

VerdictOutcomeTone bands a session outcome onto the status palette for the subagents table's outcome column: completed green, abandoned peach, errored rose, unknown toneless. It is the single-session shape of CompletionTone.

func VizColor

func VizColor(i int) string

VizColor returns the categorical color for index i, wrapping past the eighth.

func WithCSRFToken added in v0.5.5

func WithCSRFToken(ctx context.Context, token string) context.Context

WithCSRFToken attaches the request's double-submit token at the render seam. Forms include it so clients that legitimately lack Origin and Fetch Metadata can still prove they loaded the form from this server.

func WithLoc added in v0.2.2

func WithLoc(ctx context.Context, loc *time.Location) context.Context

WithLoc returns a context carrying the viewer's timezone, for the httpapi render path to attach before a component renders. A nil location is ignored so the accessor's UTC default still applies.

func WithNotice added in v0.2.2

func WithNotice(ctx context.Context, notice string) context.Context

WithNotice returns a context carrying a one-shot notice banner's text, for the httpapi render path to attach before a component renders. An empty string is ignored, so the accessor's no-notice default still applies.

Types

type BreakdownRow

type BreakdownRow struct {
	Label      string
	Cost       string
	CostUSD    float64
	Tokens     int64
	Input      int64
	Output     int64
	CacheRead  int64
	CacheWrite int64
	Reasoning  int64
	Sessions   int
	Pct        float64
	Color      string
	// Incomplete marks a slice whose cost folded in an unpriced usage event, so the
	// row shows the same "$X+" lower-bound marker the per-session figures use.
	Incomplete bool
}

BreakdownRow is one bar in a by-model or by-agent breakdown: the label, its formatted cost, the raw token volume (total plus the four-class split that feeds the hover card), a fill width as a percentage of the largest token volume in the set, and its categorical color. The token fields stay raw int64s so the template runs them through the same FmtTokens the rest of the app uses.

func BuildBreakdown

func BuildBreakdown(bs []store.Breakdown) []BreakdownRow

BuildBreakdown turns store breakdowns into renderable bar rows. Bar width is proportional to token volume so model and agent shares compare on the one figure every slice carries: a model still under a codename (unpriced, so its cost folds to zero) still draws a bar that reflects how much it was used.

type ChurnBar

type ChurnBar struct {
	// Project is the file's project display label, shown as a tag beside the path so the
	// churn list groups the same relative path per project across worktrees.
	Project  string
	Path     string
	Edits    int
	Sessions int
	Pct      float64
}

ChurnBar is one file's bar in the churn list: sized by edit count, labelled with its path, and annotated with how many sessions returned to it.

func ChurnBars

func ChurnBars(c store.FileChurn) []ChurnBar

ChurnBars turns the most-edited files into renderable bars, each width its share of the most-churned file so the worst hotspot reads full and the rest relative.

type DateRange

type DateRange struct {
	Key   string
	Label string
	Days  int
}

DateRange is one option in the trailing-window selector. Days is the width of the window; a zero Days means all of history (no lower bound).

type DistRow

type DistRow struct {
	Label string
	Count int
	Pct   float64
	Color string
	// Href, when set, drills the row into the matching session list (a /sessions link
	// carrying the grade or outcome filter plus the current window). It is empty for a
	// dimension with no session-list filter (archetypes) and for a zero-count row, which
	// stays plain text rather than linking to an empty list.
	Href string
}

DistRow is one bar in an Insights distribution: a display label, the session count, the fill width as a percent of the largest bar in the set, and the bar colour. It reuses the breakdown bars' markup and animation, so a distribution reads with the same instrument styling as the cost breakdowns.

func ArchetypeBars

func ArchetypeBars(counts []store.LabeledCount) []DistRow

ArchetypeBars renders the archetype mix, lightest to heaviest, each in its own categorical hue. Archetypes have no session-list filter, so their rows do not link.

func GradeBars

func GradeBars(counts []store.LabeledCount, base store.SessionFilter, rng string) []DistRow

GradeBars renders the grade distribution: A through F then the unscored bucket, each banded in the report-card tone the session Quality tile uses. Each non-empty bar links into the matching sessions, carrying the current window (rng) so the session list is scoped to the same period the panel counted. base is the drill-down's starting filter: the fleet Insights page passes an empty filter (a fleet-wide drill), while the project page passes a filter already scoped to the project so the drill stays inside it. IncludeEmpty rides along because the panel counts sessions regardless of message_count (a zero-message session can still carry a grade), so the drilled feed must show empties too or its count would fall short of the bar it drilled from.

func GradeBarsPlain added in v0.2.5

func GradeBarsPlain(counts []store.LabeledCount) []DistRow

GradeBarsPlain and OutcomeBarsPlain are the drill-free counterparts to GradeBars and OutcomeBars, for the public project overview. Passing a nil href builder leaves every row's Href empty, so distributionPanel renders plain bars instead of links into the private session feed: the public page shows the quality distribution but keeps the sessions behind it private (they publish one at a time, not through the project's overview).

func OutcomeBars

func OutcomeBars(counts []store.LabeledCount, base store.SessionFilter, rng string) []DistRow

OutcomeBars renders the outcome distribution, reusing OutcomeLabel for the title-cased names and a semantic tone per outcome. Each non-empty bar links into the matching sessions, carrying base (the project scope on the project page, empty on the fleet Insights page), the current window (rng), and IncludeEmpty for the same reason GradeBars does: the panel scope counts zero-message sessions, so the drilled feed must include them to match.

func OutcomeBarsPlain added in v0.2.5

func OutcomeBarsPlain(counts []store.LabeledCount) []DistRow

type Facets

type Facets struct {
	Agents   []string
	Machines []string
	Users    []string
}

Facets are the distinct filter values available for a project's session list.

type FeedRow

type FeedRow struct {
	Row store.SessionRow
	// FadeProject marks a row whose project repeats the row directly above it in
	// the same day group, so the template can mute the repeated label and let a run
	// of same-project sessions read as one burst rather than a stuttering column.
	FadeProject bool
	// TokenPct is the row's total token volume as a percent of the feed's token
	// denominator (the largest session on the first loaded page, held stable across
	// keyset pages), backing a magnitude bar so the big runs stand out without the
	// reader parsing seven-digit figures. It is 0 for a zero-token session.
	TokenPct int
}

FeedRow is one session prepared for the feed: its source row plus the derived bits the template would otherwise have to compute inline.

type FilterOption added in v0.2.2

type FilterOption struct {
	Key   string
	Label string
}

FilterOption is one choice in a toolbar filter select: the canonical key that rides the query string and its display label. Outcome and grade both use it, so the two selects render from one shape.

func GradeFilterOptions added in v0.2.2

func GradeFilterOptions() []FilterOption

GradeFilterOptions are the grade filter's choices: the five letters best to worst, then the "unscored" sentinel that matches a session with no gated grade (the Insights Grades panel's empty bucket). The letter labels are the letters themselves; the sentinel reuses gradeLabel so it reads "Unscored", the same word the grade bar carries.

func OutcomeFilterOptions added in v0.2.2

func OutcomeFilterOptions() []FilterOption

OutcomeFilterOptions are the outcome filter's choices, in the distribution's canonical order (best to worst, unknown last), so the toolbar select reads the same order the Insights outcome bars do. The labels reuse OutcomeLabel, so the select and the session detail's Outcome field name a bucket identically.

type GuideLink struct {
	Label string
	Route string
}

GuideLink is a prev/next navigation target.

type GuideNavItem

type GuideNavItem struct {
	// Num is the zero-padded reading position ("00".."08"), shown in mono beside
	// the label.
	Num    string
	Label  string
	Route  string
	Active bool
}

GuideNavItem is one chapter in the docs sidebar rail.

type GuideTocItem

type GuideTocItem struct {
	ID    string
	Text  string
	Level int
}

GuideTocItem is one heading in the on-this-page table of contents. Level is 2 or 3; an H3 is indented under the H2 it follows.

type GuideView

type GuideView struct {
	Title   string
	Summary string
	// BodyHTML is the chapter rendered to HTML by the guide package's goldmark
	// pipeline over our own trusted Markdown, injected verbatim into the prose
	// column.
	BodyHTML string
	// RawMarkdown is the exact Markdown source, embedded once so "Copy page" can
	// place it on the clipboard without a network round-trip.
	RawMarkdown string
	// RawPath is the chapter's raw-Markdown URL (/guide/<slug>.md), the "View as
	// Markdown" target and the rel=alternate the head advertises.
	RawPath   string
	GithubURL string
	Nav       []GuideNavItem
	Toc       []GuideTocItem
	Prev      *GuideLink
	Next      *GuideLink
	// LoggedIn switches the header's corner action between "Open app" and
	// "Log in", since the guide is reachable in either state.
	LoggedIn bool
}

GuideView is everything the docs page needs to render one chapter.

type HeaderStats

type HeaderStats struct {
	Cache   store.CacheStats
	Signals store.SessionSignals
	// Fallbacks is the session's recorded model fallbacks, loaded only when the
	// session's rollup says it has any (ModelFallbackCount > 0), so the common
	// no-fallback session pays for no extra read. The header tile and the transcript
	// notices both read it, so bundling it here keeps the render seams stable rather
	// than widening every signature the way a bare slice parameter would.
	Fallbacks []store.ModelFallback
	// Thinking is the session's observed-thinking readout: the absolute band and the
	// estimated per-turn token volumes behind it, all read straight from the stored signals
	// row (the band is an absolute cut, not a cohort rank, so no extra read is needed).
	// Bundled here for the same stable-seams reason as Fallbacks.
	Thinking ThinkingReadout
}

HeaderStats bundles the derived stat-tile inputs the session instrument header renders beside the token figures: prompt-cache effectiveness and the session's quality signals. Threading one struct keeps the SessionMain / sessionStats / public render seams stable as the header grows, rather than widening every signature each time a new tile lands.

type MsgMetrics added in v0.2.2

type MsgMetrics struct {
	Latency time.Duration
	Shed    *ShedMark
}

MsgMetrics is the render-only overlay one transcript message carries: its reply latency (a zero duration means the message opens no answered turn) and a shed marker (nil unless this turn shed context relative to the previous measured one). The duplicate-prompt verdict is NOT here: it rides on store.Message.DuplicatePrompt, folded in the message read, so the walker holds no state for it.

type OGMeta

type OGMeta struct {
	Title       string
	Description string
	// Image is the absolute URL of the preview card. Open Graph requires an absolute
	// URL here, so the handler builds it from the request origin; empty omits it.
	Image string
	// URL is the absolute canonical URL of the page; empty omits og:url.
	URL string
}

OGMeta carries the Open Graph and Twitter card metadata a public page emits so a shared link unfurls with a title, description, and preview image. The zero value emits only the basic title tags; Image (an absolute URL) switches the Twitter card to the large-image form and adds og:image. Description and URL are optional.

type Page

type Page struct {
	Title    string
	Username string
	IsAdmin  bool
	LoggedIn bool
	// Active is the sidebar nav key for the current page ("overview",
	// "sessions", "projects", "account"), so the shell can mark the
	// current section. Empty leaves no item active.
	Active string
	// OverviewPublic reports whether the signed-in user has published their own
	// usage overview, which drives the account page's Publicity controls and the
	// "Public" badge on the signed-in overview. The share link is /u/<username>, so
	// Username (already on the page) is all the badge and account section need to
	// build it. This is populated from the same UserByID lookup that fills Username,
	// so reading it costs no extra query.
	OverviewPublic bool
}

Page is the shared layout context for every rendered page.

type RangeOption

type RangeOption struct {
	Label  string
	Href   string
	Active bool
}

RangeOption is one rendered button in the trailing-window selector: the window label, the URL the button refetches the usage panel from, and whether it is the active window. The href is built per panel so the selector can sit on any page (the global overview or one project) and refetch from that page's own path.

func ProjectRangeOptions

func ProjectRangeOptions(projectID int64, sel store.SessionFilter, active string) []RangeOption

ProjectRangeOptions is RangeOptions for a project's usage panel: it roots the selector at the project path and preserves the active session filters, so the window control and the filter rail share the URL without clobbering each other.

func RangeOptions

func RangeOptions(basePath string, preserve url.Values, active string) []RangeOption

RangeOptions builds the selector's buttons for a panel rooted at basePath. Any params in preserve (except range, which each button sets) ride along on every href, so switching the window on a page that also carries other query state (the project page's session filters) does not drop that state from the URL.

type ReparseView

type ReparseView struct {
	InProgress bool
	Done       int
	Total      int
	Failed     int
}

ReparseView is the reparse status the account page renders: whether one is running and how far along. The httpapi layer fills it from the reparse service, so the web package stays free of a dependency on that service.

type SessionDayGroup

type SessionDayGroup struct {
	Label string
	Rows  []FeedRow
}

SessionDayGroup is a run of feed rows under one day heading. Label is empty when the feed is not day-grouped (any order other than most-recent), in which case the template renders the rows without a heading.

func BuildSessionFeed

func BuildSessionFeed(ctx context.Context, rows []store.SessionRow, grouped bool, prevKey string, maxTok int64) []SessionDayGroup

BuildSessionFeed groups session rows for the feed. When grouped is true (the most-recent order) the rows, already sorted newest first, are split under day headings ("Today", "Yesterday", a weekday, then a date); otherwise they form a single unlabeled group in the order the query returned. Within a group a row whose project repeats the previous row's is flagged to mute its label. maxTok is the token-bar denominator every row scales against: the first page establishes it (FeedMaxTokens) and the keyset "Show more" carries it forward, so a bar's width means the same magnitude on page three as on page one rather than re-normalizing to each appended page's own maximum.

type SessionFooter added in v0.2.2

type SessionFooter struct {
	// Shown is how many rows the feed renders cumulatively: on the first page it is
	// len(rows), and on each keyset "Show more" it is the prior total plus the appended
	// page, so the count grows as the reader loads deeper. When HasMore is false it is the
	// exact total (the whole set is loaded); when HasMore is true it reads "Showing N".
	Shown int
	// HasMore reports that at least one more row matches past the loaded pages (from
	// ListAllSessions' limit+1 probe), so the footer offers "Show more" and the count reads
	// "Showing N" rather than the exact "N sessions".
	HasMore bool
	// MoreHref is the "Show more" target: a keyset path carrying the last row's id as the
	// cursor (and, in the day-grouped order, its day key), set only when more rows match.
	// The button appends the next page onto the feed rather than re-rendering it, so depth
	// is unbounded; there is no cap.
	MoreHref string
	// MaxTok is the feed's token-bar denominator, the largest session's token volume on
	// the first loaded page. It rides the "Show more" cursor so each appended page scales
	// its bars against the same reference the first page set, keeping a bar's width
	// comparable across pages rather than re-normalizing to each page's own maximum.
	MaxTok int64
	// HasEmpty reports whether the current scope holds at least one empty (zero-message)
	// session, so the toggle appears only when it would change the feed; IncludeEmpty
	// reports whether those empties are being shown. Together they drive the terse
	// toggle: "empty hidden · show" when hidden, "showing empty · hide" when shown.
	HasEmpty     bool
	IncludeEmpty bool
	EmptyHref    string
}

SessionFooter is the state the feed's footer renders under the list: the session count, whether a "Show more" button applies, and the empty-hidden toggle. It is computed once from the loaded rows and two bounded store probes (hasMore and hasEmpty) so the template stays a dumb renderer and the render cost stays linear in the page rather than the corpus: the old "N of M" carried a count(*) over the whole matching history, which the incremental-efficiency gate flagged.

func BuildSessionFooter added in v0.2.2

func BuildSessionFooter(f store.SessionFilter, rows []store.SessionRow, priorCount int, hasMore, hasEmpty bool, lastDayKey string, maxTok int64) SessionFooter

BuildSessionFooter assembles the footer state from the loaded page and two bounded probes: hasMore (does a further page exist, from the limit+1 read) and hasEmpty (does any empty session sit in scope). priorCount is the running total already shown before this page (0 on the first page, the cumulative count on a keyset append), so Shown reports the whole loaded feed. lastDayKey is the day-bucket key of the page's last row, carried into the "Show more" cursor so the next appended page can continue the same day without reprinting its heading; it is empty for a flat (non-grouped) order, where day headings do not apply. maxTok is the feed's token-bar denominator (FeedMaxTokens of the first page), carried into the "Show more" cursor so appended pages scale their bars against the same reference. The "Show more" link appears only when more rows match, and the empty toggle only when the scope holds an empty session (or already shows them, so the reader can hide them again).

func (SessionFooter) CountLabel added in v0.2.2

func (ft SessionFooter) CountLabel() string

CountLabel is the footer's session-count figure, tabular and terse. When the whole matching set fit in the page (no further page) the shown count IS the exact total, so it reads "N sessions"; when more match beyond the page it reads "Showing N", since the exact total is deliberately not counted.

func (SessionFooter) EmptyToggleLabel added in v0.2.2

func (ft SessionFooter) EmptyToggleLabel() (text, verb string)

EmptyToggleLabel is the terse toggle copy: "empty hidden" and a "show" verb when empties are hidden, or "showing empty" and a "hide" verb when they are shown. It returns the two parts (the state text and the verb) so the template can style the verb as the link affordance. The count is gone with the O(total) aggregate that produced it: the toggle only reports the state, not the magnitude.

func (SessionFooter) HasEmptyToggle added in v0.2.2

func (ft SessionFooter) HasEmptyToggle() bool

HasEmptyToggle reports whether the footer shows the empty-hidden toggle.

type SessionSortOption

type SessionSortOption struct {
	Key   string
	Label string
}

SessionSortOption is one choice in the feed's sort control. The cross-project feed sorts by recency, volume, or message count; the categorical dimensions (agent, project, machine, user) are served by the filters instead, so the control stays a short list rather than a header per column.

func SessionSortOptions

func SessionSortOptions() []SessionSortOption

SessionSortOptions are the feed's sort choices, in menu order. "updated" (the default) is the only one that day-groups the feed; the others read as a flat, ranked list.

type SessionView added in v0.4.0

type SessionView struct {
	Detail store.SessionDetail
	// Outline is the whole session at bounded columns (store.OutlineMessages): one entry
	// per turn for the outline rail and the flow ribbon, regardless of how much of the
	// transcript the window below actually renders.
	Outline []store.Message
	// Page is the transcript window the body renders: the tail of the session on first
	// load, a windowed continuation on a "Show earlier" or live-append fetch.
	Page store.TranscriptPage
	// Tools is the whole session's tool metadata, for the outline rail and the flow
	// ribbon (which cover every turn regardless of the window below).
	Tools map[int][]store.ToolCallView
	// WindowTools and WindowAttachments are Page's own tool calls and attachments,
	// grouped by ordinal. Transcript rows render from these, never from Tools: they were
	// read in the same transaction as the rows, so a rebuild committing mid-request
	// cannot pair one projection's messages with another's chips or images.
	WindowTools       map[int][]store.ToolCallView
	WindowAttachments map[int][]store.AttachmentView
	Subagents         []store.SubagentRow
	Header            HeaderStats
	DupIDs            int
	// ProjectionRevision is the public pagination snapshot token. Private session
	// pagination reconciles through its live append cursor and leaves this zero.
	ProjectionRevision int64
}

SessionView bundles everything the session page and its live body fragment render, so the SessionPage / SessionMain / fragment seams stay stable as the auditor view grows (the same reasoning as HeaderStats, one level up). The handlers fill it; the templates only read it.

func (*SessionView) SetPage added in v0.4.0

func (v *SessionView) SetPage(page store.TranscriptPage)

SetPage installs a transcript window on the view and groups the page's snapshot-pinned tools and attachments for the row renderer.

type ShedMark added in v0.2.2

type ShedMark struct {
	FromTokens int64
	ToTokens   int64
	// FromUsage and ToUsage carry the full per-turn usage behind the two occupancy figures, so
	// the shed divider's breakdown card can spell out each side's token classes and cost rather
	// than the label's two bare context totals. FromUsage is the prior measured turn's usage,
	// ToUsage this turn's; both are the same *TurnUsage the message carries on Message.Usage
	// (never nil here: a shed is detected only between two turns that both presented a context).
	FromUsage store.TurnUsage
	ToUsage   store.TurnUsage
}

ShedMark records that a message's turn shed context relative to the turn before it (a compaction or a manual clear): FromTokens is the prior turn's context occupancy, ToTokens is this turn's. The transcript draws a divider labelled "context shed: <from> -> <to>" above the marked message. Both figures are context occupancy (input + cache read + cache write), the same three-class sum quality.IsContextReset judges, so the label and the reset decision never disagree.

The shed dividers are derived from Message.Usage, the per-message fold grouped by message_ordinal with NULL-ordinal usage rows dropped (see store.messagesFullQuery). This is deliberately a different fold from the stored session_signals.context_reset_count, which gatherContextHealth derives from the RAW usage_events stream in source order (every row, NULL-ordinal ones included, no ordinal collapse). The two agree whenever each ordinal carries exactly one dated usage row, the shape a real agent produces; they can diverge (a session shows context_reset_count = 1 yet no shed divider, or vice versa) only for a multi-row turn or an unattributed row, which the schema permits but the parser does not emit. This divergence is intentional and does not need to reconcile: the divider attaches to a rendered message, so it can only mark a drop between two turns that each presented a context, while the signal measures the raw turn sequence. It is the same divergence the per-turn usage fold carries, documented on store.messagesFullQuery and pinned by store's TestMessagesTurnUsageDivergesFromContextFold.

type SnippetParts added in v0.2.2

type SnippetParts struct {
	Before string
	Match  string
	After  string
}

SnippetParts splits a search snippet into its before/match/after text runs so the template can render each as an auto-escaped text node and wrap only the middle in <mark>. The <mark> element is thus template structure around plain text: the matched content is never interpolated as markup, so a query or a message that contains "<script>" renders as escaped text inside the highlight rather than injecting an element. Offsets out of range (a malformed snippet) collapse to the whole text as the "before" run with an empty match, so a bad window degrades to plain unhighlighted text rather than a panic.

func SplitSnippet added in v0.2.2

func SplitSnippet(s store.SearchSnippet) SnippetParts

SnippetParts computes the three runs from a store snippet's byte offsets.

type ThinkingReadout added in v0.3.0

type ThinkingReadout struct {
	Measured   bool
	Bucket     quality.ThinkingBucket
	Turns      int     // assistant turns that carried a reasoning block
	TailTokens int     // hardest-decile-mean per-turn reasoning tokens (the band's basis)
	PeakTokens int     // the single hardest turn's reasoning tokens
	Coverage   float64 // share of assistant turns that reasoned, in [0, 1]
}

ThinkingReadout is what the Quality tooltip's Thinking group renders: whether the session was measured at all (it had assistant turns), the absolute band its observed thinking landed in (quality.ThinkingBucketForTokens over the hardest-decile-mean turn; ThinkingOff when no turn carried a reasoning block), and the estimated per-turn token volumes behind it. Tail is the band's basis (the mean of the hardest tenth of the thinking turns), Peak the single hardest turn, and Coverage the share of assistant turns that reasoned.

type ToolBar

type ToolBar struct {
	Name    string
	Calls   int
	Pct     float64
	ErrText string // "" when the tool never failed, else its error rate ("12%")
	Color   string
}

ToolBar is one tool's bar in the mix: sized by call volume, coloured by its error band, and annotated with its error rate when it had any failures. The dual encoding reads mix (bar length) and reliability (colour and the error suffix) in one row.

func ToolBars

func ToolBars(t store.ToolStats) []ToolBar

ToolBars turns the fleet's busiest tools into renderable bars: each width is its share of the most-called tool, so the busiest tool is full and the rest are relative, and each colour bands the tool's reliability. A non-zero bar always shows at least a sliver so a rarely-called tool never reads as absent beside a dominant one.

type TranscriptWalker added in v0.2.2

type TranscriptWalker struct {
	// contains filtered or unexported fields
}

TranscriptWalker derives the two carried per-message instruments (reply latency and context sheds) as the render walks the message slice in order, holding only O(1) state between messages rather than a second session-sized structure. The render path already holds the message slice the page renders; the walker adds nothing that scales with the session beyond that. Instantiate one per transcript render and call Next once per message in order.

The carried state is exactly:

  • anchor: the pending user prompt's timestamp (nil when no turn is open), for latency.
  • prevContext / prevUsage / havePrev: the previous measured turn's context occupancy and its full usage, for shed detection against the current turn.

The two sub-computations keep their own semantics:

  • Latency pairs each answered user prompt with the reply that followed it. The walk holds the time of the most recent timestamped user message; the FIRST following timestamped assistant message closes that turn (latency = its time minus the anchor's), and the anchor is then cleared so a later reply in the same stretch is not double-counted. A new user message resets the anchor, so an interleaved exchange measures each prompt against its own reply. A negative gap (clock skew, or timestamps out of order relative to ordinal order) is dropped rather than shown as a nonsense stamp. A message missing a timestamp is transparent: a user prompt with none sets no anchor, and an assistant with none cannot close one.

  • Shed marks the turns where context dropped (a compaction or a clear). For each message that carries usage (Message.Usage != nil), it compares that turn's context occupancy against the previous message-with-usage's through quality.IsContextReset; messages without usage are skipped, so the comparison is always between two turns that actually presented a context. The shed is attributed to the turn AFTER the drop (the smaller, post-compaction context), where the transcript draws the divider: above the message that first ran on the shed-down context. This reads the ordinal-grouped Message.Usage fold, so it can intentionally diverge from session_signals.context_reset_count (the raw-stream fold); see ShedMark for why the two need not reconcile.

The duplicate-prompt badge is not derived here: it is folded in the message read as store.Message.DuplicatePrompt over the whole session (see store.messagesFullQuery), so the walker needs no digest set and the render reads m.DuplicatePrompt directly.

func SeededWalker added in v0.4.0

func SeededWalker(seed []store.Message) *TranscriptWalker

SeededWalker returns a walker primed with the unrendered rows that precede a transcript window, so the window's first rendered turns still carry their latency and shed stamps. The seed is the store's fixed short lookback (transcriptSeedLookback); a boundary turn whose prompt sits deeper than the lookback simply shows no latency, which the P-2 plan accepts. A whole-transcript render passes nil.

func (*TranscriptWalker) Next added in v0.2.2

Next advances the walker over one message and returns that message's latency and shed marks. Messages must be passed in transcript (ordinal) order, once each; the walker's carried state depends on the order.

Jump to

Keyboard shortcuts

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