| 1 | import type { HistoryPreparationWait } from "./historyPreparation"; |
| 2 | import type { Item } from "./useController"; |
| 3 | import type { TranscriptRecord } from "./transcriptRecordProjection"; |
| 4 | import type { TranscriptWindowPage } from "./transcriptLiveWindow"; |
| 5 | import type { HistoryContentChunk, HistoryContentRef, HistorySlice, HistorySliceRequest } from "./types"; |
| 6 | |
| 7 | export interface TranscriptBackend { |
| 8 | HistorySliceForTab(tabID: string, req: HistorySliceRequest): Promise<HistorySlice>; |
| 9 | HistoryContentForTab(tabID: string, ref: HistoryContentRef, chunkIndex: number): Promise<HistoryContentChunk>; |
| 10 | } |
| 11 | |
| 12 | export interface TranscriptStoreOptions { |
| 13 | /** Injectable preparation scheduler for deterministic lifecycle tests. */ |
| 14 | preparationWait?: HistoryPreparationWait; |
| 15 | /** Resident sessions with records (unpinned). Default 3. */ |
| 16 | maxResidentSessions?: number; |
| 17 | /** Total inline history body bytes across resident sessions. Default 32MiB. */ |
| 18 | historyBodyBudgetBytes?: number; |
| 19 | /** Parsed-markdown cache budget. Default 16MiB. */ |
| 20 | markdownBudgetBytes?: number; |
| 21 | /** Adjacent history pages retained per session, newest-side included. */ |
| 22 | windowMaxPages?: number; |
| 23 | /** Entries grouped into one live-tail page before it becomes reclaimable. */ |
| 24 | windowPageEntries?: number; |
| 25 | } |
| 26 | |
| 27 | export type HistoryReadOptions = { turns?: number; entries?: number; bytes?: number; current?: () => boolean }; |
| 28 | |
| 29 | export interface TranscriptProjection { |
| 30 | items: Item[]; |
| 31 | startTurn: number; |
| 32 | endTurn: number; |
| 33 | totalTurns: number; |
| 34 | hasOlder: boolean; |
| 35 | /** More history exists past the newer edge of the resident window. */ |
| 36 | hasNewer: boolean; |
| 37 | revision: number; |
| 38 | revisionKnown: boolean; |
| 39 | digest: string; |
| 40 | } |
| 41 | |
| 42 | export interface PreparedTranscriptInstall { |
| 43 | projection: TranscriptProjection; |
| 44 | commit(): void; |
| 45 | } |
| 46 | |
| 47 | export interface LoadOlderResult extends TranscriptProjection { |
| 48 | /** "prepend": page older items; "reload": cursor went stale, full latest replace. */ |
| 49 | kind: "prepend" | "reload"; |
| 50 | /** Items contributed by the older page (kind === "prepend"). */ |
| 51 | prependItems: Item[]; |
| 52 | /** |
| 53 | * Ids the caller must drop: items superseded by cross-page tool merges, plus |
| 54 | * every item on a page reclaimed to keep the window at its page budget. |
| 55 | */ |
| 56 | removeIds: string[]; |
| 57 | } |
| 58 | |
| 59 | export interface LoadNewerResult extends TranscriptProjection { |
| 60 | /** "append": page newer items; "stale": the window predates a rebuild. */ |
| 61 | kind: "append" | "stale"; |
| 62 | /** Items contributed by the newer page (kind === "append"). */ |
| 63 | appendItems: Item[]; |
| 64 | /** Ids reclaimed from the older edge to keep the window bounded. */ |
| 65 | removeIds: string[]; |
| 66 | } |
| 67 | |
| 68 | export interface AppendEntriesResult extends TranscriptProjection { |
| 69 | /** Ids reclaimed from the caller's mounted projection. */ |
| 70 | removeIds: string[]; |
| 71 | } |
| 72 | |
| 73 | export interface TranscriptContentChange { |
| 74 | tabId: string; |
| 75 | /** Re-converted items keyed by their stable item id. */ |
| 76 | patches: Record<string, Item>; |
| 77 | expected?: Record<string, Item>; |
| 78 | } |
| 79 | |
| 80 | export interface SessionTranscript { |
| 81 | bindingKey?: string; |
| 82 | canonicalV2?: boolean; |
| 83 | latestSequence?: number; |
| 84 | key: string; |
| 85 | tabId: string; |
| 86 | sessionPath: string; |
| 87 | records: TranscriptRecord[]; |
| 88 | byId: Map<string, TranscriptRecord>; |
| 89 | /** toolCallId -> result record entryId (first record wins, like resultByID). */ |
| 90 | toolResultOwners: Map<string, string>; |
| 91 | /** entryId -> projected items of that record ([] when consumed). */ |
| 92 | contributions: Map<string, Item[]>; |
| 93 | /** Result record entryIds folded into a call's tool item. */ |
| 94 | consumed: Set<string>; |
| 95 | /** result entryId -> claimer (assistant) entryId. */ |
| 96 | consumedBy: Map<string, string>; |
| 97 | /** toolCallId -> assistant record entryId whose call still lacks a result. */ |
| 98 | unresolvedCalls: Map<string, string>; |
| 99 | /** assistant entryId -> unmatched positional call indexes. */ |
| 100 | pendingPositional: Map<string, number[]>; |
| 101 | /** assistant entryId -> callIndex -> result entryId (for re-conversion). */ |
| 102 | matchTables: Map<string, Map<number, string>>; |
| 103 | itemsCache: Item[] | null; |
| 104 | nextCursor: string; |
| 105 | hasOlder: boolean; |
| 106 | /** Resident window pages, oldest first. Empty until a page is loaded. */ |
| 107 | pages: TranscriptWindowPage[]; |
| 108 | /** Cursor fetching the page immediately newer than the resident window. */ |
| 109 | newerCursor: string; |
| 110 | hasNewer: boolean; |
| 111 | /** Pages reclaimed from each end; diagnostics only. */ |
| 112 | reclaimedOlder: number; |
| 113 | reclaimedNewer: number; |
| 114 | totalTurns: number; |
| 115 | startTurn: number; |
| 116 | endTurn: number; |
| 117 | revision: number; |
| 118 | revisionKnown: boolean; |
| 119 | digest: string; |
| 120 | generation: number; |
| 121 | /** Settles when the current fresh-page generation has installed or failed. */ |
| 122 | generationSettlement?: { generation: number; promise: Promise<void> }; |
| 123 | bodyBytes: number; |
| 124 | olderInFlight: boolean; |
| 125 | newerInFlight: boolean; |
| 126 | pendingContent: Map<string, { generation: number; promise: Promise<string | undefined> }>; |
| 127 | } |
| 128 |