import type { Message, MessageProvenance } from "@kenkaiiii/gg-ai"; import type { CompactionAnchorRemap } from "./compaction/compactor.js"; import type { AutopilotMarkerPayload, AppMarkerPayload, KenTurnPayload } from "./session-manager.js"; export type HistoryMessageVisibility = "transcript" | "hidden" | "summary"; /** Metadata-first transcript visibility with prefix fallback for legacy JSONL. */ export declare function getHistoryMessageVisibility(message: Message): HistoryMessageVisibility; export interface HistoryCheckpoint { header: { id: string; parentSessionId?: string; retainedMessageCount?: number; }; messages: readonly Message[]; } /** * Rebuild a display transcript from a contiguous checkpoint chain. * * Compaction writes the retained tail into the child with fresh session-entry * ids. The largest ordered suffix/prefix overlap therefore compares normalized * message role, content, and provenance rather than persistence ids. A child's * summary is omitted only when its direct parent is readable; the oldest loaded * checkpoint keeps its summary as the fallback for a broken chain. */ export declare function reconstructCheckpointHistory(checkpoints: readonly HistoryCheckpoint[]): Message[]; /** Replay every non-system message and flush anchor work after each one. */ export declare function replayMessagesInOrder(messages: readonly Message[], visitMessage: (message: Message, count: number) => void | Promise, afterMessage: (count: number) => void | Promise): Promise; /** * Move a transcript anchor (`afterMessageCount`) from the pre-compaction * message list onto the compacted one. * * Compaction folds the leading `summarizedCount` non-system messages into a * `prefixCount`-message summary block and keeps the rest verbatim. Anchors * inside the collapsed region land right after the summary (their surrounding * conversation no longer exists); anchors in the retained tail shift by the * difference. Without this, re-persisted markers keep indices from a much * longer transcript — they then replay far too late, or past the end, which is * what bunches old Ken bubbles and error rows at the bottom on resume. */ export declare function remapAnchorForCompaction(anchor: number, remap: CompactionAnchorRemap): number; /** * Drop the read-only file-order position before writing a marker back to disk. * It describes where a marker sat in the file it was READ from, so persisting * it into a rewritten file would bake in a position that no longer applies — * the next load recomputes it anyway. */ export declare function stripRecordedPosition(payload: T): Omit; export interface HistoryAutopilotMarker extends AutopilotMarkerPayload { /** Stable seed derived from persisted marker data for deterministic UI copy. */ copySeed: string; } export declare function autopilotMarkerCopySeed(marker: AutopilotMarkerPayload): string; /** * Normalize persisted autopilot markers for transcript replay. * * Stale anchors are pulled back to where the marker was actually written (see * {@link resolveAnchor}); anything still outside the restored transcript is * dropped rather than replayed at EOF, which is what bunched old Ken all-clear * bubbles at the bottom. Exact duplicate payloads from old rewrite/re-persist * paths are deduped. */ export declare function normalizeAutopilotMarkersForHistory(markers: readonly AutopilotMarkerPayload[], maxAfterMessageCount: number): HistoryAutopilotMarker[]; /** * Normalize persisted app transcript markers for replay: drop markers whose * anchor points beyond the restored message list (stale after compaction) and * dedupe exact payloads (old rewrite paths could re-append). Mirrors * {@link normalizeAutopilotMarkersForHistory}. */ export declare function normalizeAppMarkersForHistory(markers: readonly AppMarkerPayload[], maxAfterMessageCount: number): AppMarkerPayload[]; /** * Normalize persisted Ken turns for replay. Unlike autopilot/app markers, Ken * turns carry real conversation — an out-of-range anchor (stale after * compaction) is CLAMPED to the last message instead of dropped, so the * exchange still renders (at the end, in order) rather than vanishing. Exact * duplicate payloads (old rewrite/re-persist paths) are deduped. */ export declare function normalizeKenTurnsForHistory(turns: readonly KenTurnPayload[], maxAfterMessageCount: number): KenTurnPayload[]; export interface RestoredUserRow { /** The typed text as the live bubble showed it. */ text: string; /** Attached image data URLs. */ images: string[]; /** True when the message carried a video the model could NOT watch natively * (live showed an info row after the bubble). */ videoWarning: boolean; /** True when autopilot injected this turn (the message carried the * situational-awareness preamble). No human typed it, and the live * transcript showed NO user bubble for it — only the Ken-tinted autopilot * marker. Resume must skip the row, or the injected body renders twice: * once styled as Ken's marker, once raw as a user message. */ autopilotInjected: boolean; /** True when this "user" message is a pushed background-work status update * (a spawned child finished, a background process logged or exited) rather * than anything a human sent. * * The live transcript shows NO bubble for these — the loop yields * `steering_message`, which no host renders. They are persisted only because * they are real context the model saw. Resume must skip them too, or a * reopened session is full of machine-facing status lines the user never saw * while working. */ notification: boolean; } /** Rebuild the live user bubble from a persisted user message's content. */ export declare function restoreUserRow(content: Message["content"], provenance?: MessageProvenance): RestoredUserRow; /** * Reverse a prompt-template command's expansion by matching the restored body * against the known templates. * * Best-effort only: it works while a template is byte-identical to the one that * produced the message, and templates drift (edited `.gg/commands/*.md`, * reworded built-ins, app-vs-CLI phrasing). Prefer the invocation recorded at * send time — see {@link resolveRestoredCommand}. Returns null when the text * isn't a known command body (an ordinary user message). */ export declare function detectPromptCommand(text: string, candidates: ReadonlyArray<{ name: string; prompt: string; }>): string | null; /** * The `/name [args]` chip a restored user row should show, or null for an * ordinary message. * * The invocation persisted with the prompt wins: it's exactly what the user * typed and survives any later template edit. Sessions recorded before that was * persisted fall back to matching the expanded body, which is why an edited * command used to resume as its raw multi-KB template. */ export declare function resolveRestoredCommand(persistedCommand: string | null | undefined, text: string, candidates: ReadonlyArray<{ name: string; prompt: string; }>): string | null; /** * Split a persisted assistant message into per-bubble texts. Live streaming * ends the assistant bubble at every server_tool_call (see useAgentEvents' * server_tool_call case), so pre- and post-tool text render as separate rows. * Persisted content keeps that structure as separate text blocks — emit one * text per block instead of gluing them into a single row on resume. */ export declare function restoreAssistantTexts(content: Message["content"]): string[]; //# sourceMappingURL=session-history.d.ts.map