| 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 | /** All resident windows; only unprotected owners can be evicted. 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 | /** Structural publication kind used by the controller's anchor policy. */ |
| 41 | mutation?: "replace" | "prepend" | "append" | "patch"; |
| 42 | } |
| 43 | |
| 44 | export interface PreparedTranscriptInstall { |
| 45 | projection: TranscriptProjection; |
| 46 | commit(): void; |
| 47 | } |
| 48 | |
| 49 | export interface LoadOlderResult extends TranscriptProjection { |
| 50 | /** "prepend": page older items; "reload": cursor went stale, full latest replace. */ |
| 51 | kind: "prepend" | "reload"; |
| 52 | /** Items contributed by the older page (kind === "prepend"). */ |
| 53 | prependItems: Item[]; |
| 54 | /** |
| 55 | * Ids the caller must drop: items superseded by cross-page tool merges, plus |
| 56 | * every item on a page reclaimed to keep the window at its page budget. |
| 57 | */ |
| 58 | removeIds: string[]; |
| 59 | } |
| 60 | |
| 61 | export interface LoadNewerResult extends TranscriptProjection { |
| 62 | /** "append": page newer items; "stale": the window predates a rebuild. */ |
| 63 | kind: "append" | "stale"; |
| 64 | /** Items contributed by the newer page (kind === "append"). */ |
| 65 | appendItems: Item[]; |
| 66 | /** Ids reclaimed from the older edge to keep the window bounded. */ |
| 67 | removeIds: string[]; |
| 68 | } |
| 69 | |
| 70 | export interface AppendEntriesResult extends TranscriptProjection { |
| 71 | /** Ids reclaimed from the caller's mounted projection. */ |
| 72 | removeIds: string[]; |
| 73 | } |
| 74 | |
| 75 | export interface TranscriptContentChange { |
| 76 | tabId: string; |
| 77 | evictedPath?: string; |
| 78 | /** Re-converted items keyed by their stable item id. */ |
| 79 | patches: Record<string, Item>; |
| 80 | expected?: Record<string, Item>; |
| 81 | /** Present when resolving content changed ownership or record structure. */ |
| 82 | projection?: AppendEntriesResult; |
| 83 | } |
| 84 | |
| 85 | export interface SessionTranscript { |
| 86 | bindingKey?: string; |
| 87 | canonicalV2?: boolean; |
| 88 | latestSequence?: number; |
| 89 | key: string; |
| 90 | tabId: string; |
| 91 | sessionPath: string; |
| 92 | records: TranscriptRecord[]; |
| 93 | byId: Map<string, TranscriptRecord>; |
| 94 | /** toolCallId -> result record entryId when the resident match is unique. */ |
| 95 | toolResultOwners: Map<string, string>; |
| 96 | /** assistant entryId + call index -> the uniquely associated result row. */ |
| 97 | toolCallOwners: Map<string, string>; |
| 98 | /** assistant entryId + call index -> stable display node id. */ |
| 99 | toolCallDisplayIds: Map<string, string>; |
| 100 | /** Result record entryId -> stable display node id. */ |
| 101 | toolDisplayIds: Map<string, string>; |
| 102 | /** Calls and result rows whose identity is ambiguous. */ |
| 103 | toolIdentityConflicts: Set<string>; |
| 104 | /** entryId -> projected items of that record ([] when consumed). */ |
| 105 | contributions: Map<string, Item[]>; |
| 106 | /** Result record entryIds folded into a call's tool item. */ |
| 107 | consumed: Set<string>; |
| 108 | /** result entryId -> claimer (assistant) entryId. */ |
| 109 | consumedBy: Map<string, string>; |
| 110 | /** toolCallId -> assistant record entryId whose call still lacks a result. */ |
| 111 | unresolvedCalls: Map<string, string>; |
| 112 | /** assistant entryId -> unmatched positional call indexes. */ |
| 113 | pendingPositional: Map<string, number[]>; |
| 114 | /** assistant entryId -> callIndex -> result entryId (for re-conversion). */ |
| 115 | matchTables: Map<string, Map<number, string>>; |
| 116 | itemsCache: Item[] | null; |
| 117 | nextCursor: string; |
| 118 | hasOlder: boolean; |
| 119 | /** Resident window pages, oldest first. Empty until a page is loaded. */ |
| 120 | pages: TranscriptWindowPage[]; |
| 121 | /** Cursor fetching the page immediately newer than the resident window. */ |
| 122 | newerCursor: string; |
| 123 | hasNewer: boolean; |
| 124 | /** Pages reclaimed from each end; diagnostics only. */ |
| 125 | reclaimedOlder: number; |
| 126 | reclaimedNewer: number; |
| 127 | totalTurns: number; |
| 128 | startTurn: number; |
| 129 | endTurn: number; |
| 130 | revision: number; |
| 131 | revisionKnown: boolean; |
| 132 | digest: string; |
| 133 | generation: number; |
| 134 | /** Settles when the current fresh-page generation has installed or failed. */ |
| 135 | generationSettlement?: { generation: number; promise: Promise<void> }; |
| 136 | bodyBytes: number; |
| 137 | olderInFlight: boolean; |
| 138 | newerInFlight: boolean; |
| 139 | pendingContent: Map<string, { generation: number; promise: Promise<string | undefined> }>; |
| 140 | } |
| 141 |