Documentation
¶
Overview ¶
Package transcript renders a session's event log as text a model reads. Two renderers live here over the same log: Render, the outcome grader's role-labelled plain text (plan 21 slice 3), and RenderDream, the streamed, redacted, capped markdown a dream's stages read (plan 41 §3.2). It sits outside internal/brain because both the brain and the controlplane's dream runner import it, and it depends on internal/domain and internal/events alone — nothing here may reach for a provider, a store or an HTTP layer.
Index ¶
Constants ¶
const ( // GraderTranscriptBudget caps the rendered transcript handed to the // grader; the head is kept and a truncation note marks the cut (ours). GraderTranscriptBudget = 200_000 // GraderItemBudget caps any single transcript item (a tool result can be // 100 KiB on its own; the grader needs the shape, not every byte). GraderItemBudget = 4_000 )
const ( // DreamPageSize is the keyset page the renderer pulls. Large enough that a // long session is not a thousand round trips, small enough that one page // of tool results is not itself the memory bound the cap exists to hold. DreamPageSize = 200 )
Variables ¶
var DreamTranscriptCap = 24 << 10
DreamTranscriptCap bounds one rendered transcript, so a hundred of them are at most 2.4 MiB — the per-dream bound (§3.2). The head kept and the rolling tail are each half of it, which is what makes it a memory bound and not just an output length: a test that lowers the cap sees both buffers shrink with it. A var, not a const, for that test (memoryPruneInterval's idiom); nothing in production writes it.
Functions ¶
func ContentText ¶
ContentText flattens an event body's content — a string or a block array — into plain text for the transcript.
func FlattenBlocks ¶
func FlattenBlocks(raw json.RawMessage) (string, bool)
FlattenBlocks renders a content-block array as plain text. Most blocks carry their text at the top level; a search_result block carries its evidence as title + source + nested text blocks, so those flatten too — web_search answers would otherwise vanish from the transcript.
func IndexLine ¶
IndexLine is one INDEX.md row (§3.1): seq · session_id · created_at · turns · rendered_bytes · the first user message. What the cap elided is named in the bytes column rather than appended, so the one free-text field stays last and a "·" inside a user's message cannot look like another column.
func Redact ¶
Redact replaces the four secret shapes with "[REDACTED_SECRET]": an sk- key, an AKIA access key id, a Bearer token, and an api_key/token/secret/password assignment with either separator. Fixed in code, not configurable — a knob here is a way to leak a credential into a memory store (§3.2).
It is best-effort by construction: a shape pattern cannot know a private key, a cookie, a connection string or an opaque token from prose, which is why internal/provider/redact.go redacts by known value instead — that redactor holds the credential it is removing, and a dream's renderer holds none. What backs this is the clone by default and the completion scan, not the pattern list.
func Render ¶
Render renders the session's conversation-bearing events as the role-labeled plain text the grader reads (shape ours, INFERRED). Long items truncate at GraderItemBudget; the whole transcript at GraderTranscriptBudget.
The events render in consumption order (events.ConsumptionOrderer, #793): a message posted while one of its thread's requests was in flight renders where that thread's next request consumed it, after the reply and the results that never saw it. Windows are per thread, so on a whole-session history a child's request never holds a primary row. history itself is left in seq order, since the grader reads its watermark and outcome start off it.
The agent-to-agent message pair (plan 35) is deliberately not rendered. The grader reads the whole session rather than one thread, so a child's report is already here as that child's own submit_result call, and rendering the coordinator's copy of it would put the same text in twice. RenderDream keeps the received half, because it reads the session view alone (§3.2).
Types ¶
type Dream ¶
type Dream struct {
SessionID string
Text []byte // the rendered markdown: redacted, per-event truncated, capped
Turns int // user.message events kept (the INDEX.md "turns" column)
ElidedBytes int // bytes the per-transcript cap removed; 0 when the cap was not hit
FirstUser string // the first user message's text, redacted, one line, ≤ 200 runes
}
Dream is one input session rendered for a dream.
func RenderDream ¶
RenderDream streams the session's log in pages of DreamPageSize through log.List with Scope events.ScopeSession and the AfterSeq keyset, renders and redacts each event as it arrives, and keeps only a head and a rolling tail of half DreamTranscriptCap each — peak memory is the cap whatever the log's length.
The scope is the coordinator's view: its primary thread's rows plus the ones a child cross-posted. Per-thread logs are not expanded, so a delegated task reads as the report that came back (§3.2).