timeline

package
v1.34.0 Latest Latest
Warning

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

Go to latest
Published: Sep 18, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package timeline folds an ordered stream of session events into the nodes the connect TUI renders. It mirrors the fold of the web session viewer that --web serves, so both views agree on turns, tool previews, bodies and truncation caps. Pure: no I/O, no styling.

Files:

  • timeline.go: the fold's output types (Node, Block, ToolCall, Status).
  • fold.go: Fold, the reducer that builds and refines those nodes.
  • tools.go: one-line previews and expanded bodies for tool calls.
  • eventtext.go: the readable text of any event.
  • sanitize.go: stripping terminal control sequences from event text.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EventText

func EventText(ev Event) string

EventText is an event's readable text: joined text blocks for messages and tool results, the message for errors, explanation/description for outcomes. "" if none.

func Sanitize

func Sanitize(s string) string

Sanitize strips what a terminal would act on rather than print: escape sequences (CSI, OSC, DCS/PM/APC, or a lone ESC and the byte after it), C0 controls other than \n and \t, DEL, and C1 controls. Event text is authored by models, tools and peers; rendered raw it could clear the screen, move the cursor or retitle the window. Everything else, valid UTF-8 or not, passes through untouched.

func ToolDisplayName

func ToolDisplayName(ev Event) string

ToolDisplayName is the name to show for a tool use, qualified by its MCP server when it has one.

func ToolKind

func ToolKind(name string) string

ToolKind maps a tool name to the built-in whose body renderer applies; "" is unknown.

func ToolPayloadPreview

func ToolPayloadPreview(ev Event) string

ToolPayloadPreview prefers what will actually execute over the model's own description of it, for places where the user is asked to approve it.

func ToolPreview

func ToolPreview(ev Event) string

ToolPreview is the call's one identifying argument on a single line: the first string-valued key in a fixed precedence, whitespace collapsed, capped at previewMaxRunes.

Types

type Block

type Block struct {
	Kind  BlockKind
	Event Event      // every kind but BlockTools
	Calls []ToolCall // BlockTools
}

Block is one thing a model request produced, in arrival order. Consecutive tool uses share one BlockTools; anything else between them starts another.

func (Block) Streaming

func (b Block) Streaming() bool

Streaming reports an agent block whose event has not settled (no processed_at).

type BlockKind

type BlockKind string

BlockKind says what a Block holds.

const (
	BlockThinking   BlockKind = "thinking"
	BlockText       BlockKind = "text"
	BlockTools      BlockKind = "tools"
	BlockThreadSent BlockKind = "thread_sent"
	BlockError      BlockKind = "error"
	BlockRequestEnd BlockKind = "request_end"
)

type Event

Event is one session event as the API returns it.

type Fold

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

Fold is the reducer that builds and refines the nodes: Upsert files an event and Reset refolds a whole log. Queued user nodes (sent, not yet ingested) wait at the tail and everything else files ahead of them, where the server will order it once it ingests them. The accepting turn is always the last node before that tail; only queued nodes ever shift, and each owns just its own id, so indices held in `owner` stay cheap to keep valid.

func NewFold

func NewFold() *Fold

NewFold returns an empty fold.

func (*Fold) Nodes

func (f *Fold) Nodes() []Node

Nodes aliases internal storage: valid until the next Upsert/Reset.

func (*Fold) Reset

func (f *Fold) Reset(events []Event)

Reset discards the fold and refolds events from scratch.

func (*Fold) Status

func (f *Fold) Status() Status

Status digests the latest status event seen; the zero Status before any.

func (*Fold) TakeDirty

func (f *Fold) TakeDirty() int

TakeDirty reports the lowest index whose node changed (or was popped) since the last call, so a renderer can reuse what it drew for the nodes before it.

func (*Fold) TotalUsage

func (f *Fold) TotalUsage() Usage

TotalUsage sums every request_end seen.

func (*Fold) Upsert

func (f *Fold) Upsert(ev Event)

Upsert files an event. An unseen id is appended, so those must arrive in display order; a known id refines in place (a streaming agent.message filling in, then its final) and only the owning node is touched.

type Lifecycle

type Lifecycle string

Lifecycle is where a ToolCall stands, derived from its parts.

const (
	Running          Lifecycle = "running"
	AwaitingApproval Lifecycle = "awaiting_approval"
	Denied           Lifecycle = "denied"
	Failed           Lifecycle = "failed"
	Completed        Lifecycle = "completed"
)

type Line

type Line struct {
	Kind LineKind
	Text string
}

Line is one styled line of a tool body.

func ToolBody

func ToolBody(call ToolCall) []Line

ToolBody is the expanded view of a call: the user's verdict if any, the input in the tool's own idiom, then the result. Write and edit results are one-line acks, so they only surface on error.

func TruncateDense

func TruncateDense(lines []Line) []Line

TruncateDense keeps the head of a body within the dense caps and appends a note saying what it dropped. denseMaxChars counts runes, newlines included; the line that crosses it is cut to the remaining budget on a rune boundary.

type LineKind

type LineKind int

LineKind says how a renderer should style a Line of a tool body.

const (
	LineMeta LineKind = iota // dim header: a path, or "@@" between edits
	LineCmd                  // the call's one-line input: "$ cmd", "pattern  in path", url
	LineOut                  // payload: result text, written content, diff context, input JSON
	LineAdd
	LineDel
	LineErr   // result text of a failed call
	LineNote  // "(non-text content)", "… N more lines"
	LineAllow // the user's verdict: "Allowed"
	LineDeny  // "Denied — msg"
)

type Node

type Node struct {
	Kind             NodeKind
	Event            Event   // the node's event; NodeTurn / NodeOutcome: the span start, if seen
	Blocks           []Block // NodeTurn
	Open             bool    // NodeTurn: no span.model_request_end yet
	Brief            *Event  // NodeThreadReceived: our last thread_message_sent to that peer
	OutcomeEnd       *Event  // NodeOutcome: the verdict (Result, Explanation); nil while grading
	IdleFrom, IdleTo time.Time
}

Node is one row group of the transcript, in render order.

func (Node) Queued

func (n Node) Queued() bool

Queued reports a user message sent but not yet ingested by the server.

type NodeKind

type NodeKind string

NodeKind says what a Node represents and which of its fields are set.

const (
	NodeTurn           NodeKind = "turn"
	NodeUser           NodeKind = "user"
	NodeThreadReceived NodeKind = "thread_received"
	NodeOutcome        NodeKind = "outcome"
	NodeError          NodeKind = "error"
	NodeInterrupted    NodeKind = "interrupted"
	NodeRescheduled    NodeKind = "rescheduled"
	NodeTerminated     NodeKind = "terminated"
	NodeOutcomeDefined NodeKind = "outcome_defined"
	NodeIdle           NodeKind = "idle"    // a status_idle→status_running gap >= idleThreshold
	NodeSilent         NodeKind = "silent"  // status machinery between turns; verbose-only
	NodeUnknown        NodeKind = "unknown" // system.message, thread_context_compacted, anything unrecognised
)

type Status

type Status struct {
	State      string     // running | idle | rescheduling | terminated | deleted | ""
	StopReason string     // status_idle only: end_turn | requires_action | retries_exhausted
	Pending    []ToolCall // requires_action calls still AwaitingApproval, oldest first
}

Status is the latest session.status_* (or session.deleted) event, digested. StopReason "requires_action" with no Pending means the session waits on a custom tool result (a worker's job), not on an approval we can give.

type ToolCall

type ToolCall struct {
	Use          Event
	Confirmation *Event
	Result       *Event
}

ToolCall is a tool use with the confirmation and result that name it by id.

func (ToolCall) Lifecycle

func (c ToolCall) Lifecycle() Lifecycle

Lifecycle derives from a call's parts: denial (policy or user) beats a stray result; else the result decides; else an unanswered ask gate is blocked, not running.

type Usage

type Usage struct {
	Input, Output int64
}

Usage is one model request's token counts. Input is everything sent (the ↑ figure): uncached input plus cache reads plus cache writes.

func UsageOf

func UsageOf(ev Event) *Usage

UsageOf is a span.model_request_end's token counts; nil when it carried none.

Jump to

Keyboard shortcuts

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