Documentation
¶
Overview ¶
Package view does result-shaping: the bookends+window anchored view, org-wide discovery (lineage-deduped, RRF-fused when an embedder is wired), scroll (keep-reading), and browse (no-query recent sessions).
Ordering within a session is by message id (insertion order), NOT ts — ts can be non-monotonic, so id is the reliable ordering key.
Index ¶
- func FilterDisplayable(msgs []store.Msg, want int, includeTools bool) []store.Msg
- func FilterDisplayableWith(msgs []store.Msg, want int, includeTools, includeThinking bool) []store.Msg
- func IsDisplayable(content string) bool
- func IsDisplayableWith(content string, includeTools, includeThinking bool) bool
- func IsInterruptionMarker(content string) bool
- func Reversed(msgs []store.Msg) []store.Msg
- func SessionLastActivity(con *sql.DB, sessionID string) string
- func SessionPreview(con *sql.DB, sessionID string, cap int) string
- type AnchoredView
- type AnchoredViewOpts
- type BrowseAllRow
- type BrowseRow
- type Scope
- type ViewMsg
- func RenderMsgs(msgs []store.Msg, includeTools bool, cap int) []ViewMsg
- func RenderMsgsWith(msgs []store.Msg, includeTools, includeThinking bool, cap int) []ViewMsg
- func TakeDisplayable(msgs []store.Msg, want int, includeTools bool, cap int) []ViewMsg
- func TakeDisplayableTail(msgs []store.Msg, want int, includeTools bool, cap int) []ViewMsg
- func TakeDisplayableTailWith(msgs []store.Msg, want int, includeTools, includeThinking bool, cap int) []ViewMsg
- func TakeDisplayableWith(msgs []store.Msg, want int, includeTools, includeThinking bool, cap int) []ViewMsg
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FilterDisplayable ¶ added in v0.9.0
FilterDisplayable keeps the first want displayable records of msgs, in the order given. Callers that want the records nearest the END of a session pass them newest-first and reverse the result. With includeTools set nothing is dropped and this is a plain take-want.
func FilterDisplayableWith ¶ added in v0.9.0
func FilterDisplayableWith(msgs []store.Msg, want int, includeTools, includeThinking bool) []store.Msg
FilterDisplayableWith keeps the first want displayable records of msgs with granular tool and thinking inclusion.
func IsDisplayable ¶ added in v0.9.0
IsDisplayable reports whether a record still says something after everything a runtime generated is removed. It is the display-side twin of the rule search already applies to its haystack, and it is the single place that rule lives for rendering: strip tool runs and injected envelopes, then reject what is left if it is empty, a bare block label (the ~99.5% redacted-thinking case), or the runtime's interruption note.
Nothing is deleted or hidden from the store by this — `--include-tools` puts every dropped row back, exactly as it does for search.
func IsDisplayableWith ¶ added in v0.9.0
IsDisplayableWith reports whether a record still says something according to the requested tool and thinking inclusions.
func IsInterruptionMarker ¶ added in v0.9.0
IsInterruptionMarker reports whether a record is the runtime's "the operator stopped me" note rather than anything either party said. It survives StripGenerated (it carries no tool marker and no envelope tag) but captioning a session with it says nothing about what that session is doing.
Measured across the live corpus by sampling the last three records of every session: 51 tails ended on this marker. [THINKING] (470) and [SYSTEM] (53) are deliberately NOT filtered here — reasoning that carries text is often the truest statement of what a session is working on right now, and a [SYSTEM] note is real injected content.
Corrected 2026-08-05: that reasoning holds only for blocks that carry text, and on this corpus almost none do — about 99.5% of thinking records are the bare label with an empty body (redacted reasoning). Those are skipped by isBareBlockMarker, which filters on emptiness rather than on block type, so the rule above is unchanged for any block that actually says something.
Exported alongside SessionLastActivity because every reader that walks a session tail looking for something a PERSON said has to step over it — including the one that finds where the caller's live turn began (agentproto.currentTurnStart).
func SessionLastActivity ¶ added in v0.9.0
SessionLastActivity returns the session's most recent REAL activity: the newest message that still has content once tool runs and injected envelopes are stripped (parse.StripGenerated). Walking newest-first and skipping generated rows is OpenClaw's selectBoundedActiveTailRecords in miniature.
Returns "" when the whole scanned tail is machinery — honest silence beats captioning a session with a tool result. The row still renders; it just has no "now" line, and Preview still says what the session was for.
Exported because a browse row is not the only place the question "and then what?" gets asked: a search hit is a point in the middle of a conversation, so the same tail read answers where that conversation ended up (agentproto.attachLastActivity). One definition of "real activity" for both, or the two surfaces drift.
func SessionPreview ¶ added in v0.9.0
SessionPreview returns the first SUBSTANTIVE user message's display text for a session — the ask that started it (low-signal openers like 'hi' or '/clear' are skipped via parse.IsSubstantive). The session is never dropped — if no early message is substantive, the first non-empty user message is shown as a fallback so the row still previews something.
browse renders it as the row preview; search uses it as the header-line title when a session was never tagged, which is most of them. Both want the same thing — "what was this about, in the user's own words" — so both read it here. cap is the caller's line budget: a browse row affords more width than a search header line that already carries a stamp, an id and a project.
Types ¶
type AnchoredView ¶
type AnchoredView struct {
BookendStart []ViewMsg `json:"bookend_start"`
Window []ViewMsg `json:"window"`
BookendEnd []ViewMsg `json:"bookend_end"`
MessagesBefore int `json:"messages_before"`
MessagesAfter int `json:"messages_after"`
}
AnchoredView is the goal→match→resolution shape around one anchor message.
func BuildAnchoredView ¶
func BuildAnchoredView(con *sql.DB, sessionID string, anchorID int, opts AnchoredViewOpts) *AnchoredView
BuildAnchoredView builds the ±window + bookends shape around anchorID in session. Returns nil if the window is empty. (Named BuildAnchoredView, not AnchoredView, to avoid colliding with the AnchoredView result type.)
type AnchoredViewOpts ¶
AnchoredViewOpts groups the optional tuning of AnchoredView (window radius, bookend size, tool inclusion) to keep the signature small. Defaults: Window=5, Bookend=3, IncludeTools=false.
type BrowseAllRow ¶ added in v0.5.0
BrowseAllRow is one recent-session row of the cross-project (--all) browse: a BrowseRow tagged with the project it came from.
func BrowseScoped ¶ added in v0.10.0
func BrowseScoped(con *sql.DB, limit int, since, before, sourceTool string, projects []string) ([]BrowseAllRow, error)
BrowseScoped queries recent sessions from an open connection (draining rows first) and populates preview and last activity using the same connection.
type BrowseRow ¶
type BrowseRow struct {
SessionID string `json:"session_id"`
LastTS float64 `json:"last_ts"`
N int `json:"n"`
Preview string `json:"preview"`
Last string `json:"last,omitempty"`
}
BrowseRow is one recent-session row.
Preview and Last answer two different questions and neither substitutes for the other. Preview is the session's OPENING — what it was set up to do, which is its identity and stays true forever. Last is its most recent real activity — what it is doing NOW, which is the whole point of a recency-ordered list.
Keeping both is OpenClaw's split: its session store carries `firstUserMessage` and `lastMessagePreview` as separate fields and its session-list tool exposes them as `derivedTitle` and `lastMessagePreview` (src/gateway/session-utils.fs.ts, src/agents/tools/sessions-list-tool.ts). Showing only the opening — which is what this did, and what Hermes' `sessions list` still does — answers "what is this desk saying right now" with the prompt it was given a thousand messages ago.
type Scope ¶
type Scope struct {
Project string
TDir string // Claude transcript dir; "" for a pre-resolved (DBP) scope
DBP string // pre-ensured db path; "" means resolve lazily from TDir
CWD string // working dir for path filtering; "" means derive from TDir
Source string // "claude" | "codex"
Origin string // owning machine id for a replicated scope; "" = local
OriginName string // owning machine display name; "" = local
Stale bool // replica may lag its origin — report, still serve
}
Scope is one searchable unit discovery/scroll iterate over. A Claude scope is a (project label, transcript dir) pair whose db is resolved lazily from TDir. A non-directory source (e.g. Codex) instead sets DBP (a pre-ensured db) and CWD (for path filtering), leaving TDir empty. Source names the runtime ("claude"/"codex") for the --source filter and display. Resolve/CWD in the scopes package pick the right field, so consumers stay source-agnostic.
A scope replicated from ANOTHER machine (a transcript archive dir) also carries its origin: Origin is the owning machine's stable id (what its rows stamp as origin_machine) and OriginName its human-readable machine dir name. Both empty = a local scope. Stale marks a replica whose last sync is old — the search layer reports it through the stale-fallback posture while still serving its results.
type ViewMsg ¶
type ViewMsg struct {
ID int `json:"id"`
Role string `json:"role"`
Text string `json:"text"`
Anchor bool `json:"anchor,omitempty"`
}
ViewMsg is one message in a window or bookend. The Anchor field is true only for the window's anchor message.
func RenderMsgs ¶ added in v0.9.0
RenderMsgs renders store rows for display at the given cap.
func RenderMsgsWith ¶ added in v0.9.0
RenderMsgsWith renders store rows for display with granular tool/thinking inclusion.
func TakeDisplayable ¶ added in v0.9.0
TakeDisplayable renders the FIRST want displayable records of msgs.
func TakeDisplayableTail ¶ added in v0.9.0
TakeDisplayableTail renders the LAST want displayable records of msgs, still in chronological order. Used for a closing bookend, where the interesting records are the ones nearest the end.