@@ -23,20 +23,60 @@ import { skillTagsToSlashCommands } from "../message-editor/skillTags";
2323import { isNotification , POSTHOG_NOTIFICATIONS } from "./acpNotifications" ;
2424import { extractPromptDisplayContent } from "./promptContent" ;
2525
26+ export interface StoredLogEventPosition {
27+ taskRunId : string ;
28+ entryIndex : number ;
29+ }
30+
31+ export interface StoredLogEventPositionOptions {
32+ taskRunId : string ;
33+ startEntryIndex : number ;
34+ firstPositionedEntryIndex ?: number ;
35+ }
36+
37+ // Ordinals are local reconciliation provenance, so keep them out of the ACP
38+ // event shape that crosses host and renderer boundaries.
39+ const storedLogEventPositions = new WeakMap <
40+ AcpMessage ,
41+ StoredLogEventPosition
42+ > ( ) ;
43+
44+ export function getStoredLogEventPosition (
45+ event : AcpMessage ,
46+ ) : StoredLogEventPosition | undefined {
47+ return storedLogEventPositions . get ( event ) ;
48+ }
49+
50+ function recordStoredLogEventPosition (
51+ event : AcpMessage ,
52+ position : StoredLogEventPosition | undefined ,
53+ ) : AcpMessage {
54+ if ( position ) storedLogEventPositions . set ( event , position ) ;
55+ return event ;
56+ }
57+
2658/**
2759 * Convert a stored log entry to an ACP message.
2860 */
29- function storedEntryToAcpMessage ( entry : StoredLogEntry ) : AcpMessage {
61+ function storedEntryToAcpMessage (
62+ entry : StoredLogEntry ,
63+ position ?: StoredLogEventPosition ,
64+ ) : AcpMessage {
3065 const ts = entry . timestamp ? new Date ( entry . timestamp ) . getTime ( ) : Date . now ( ) ;
3166 const promoted = promoteImportedUserPrompt ( entry , ts ) ;
3267 // Freeze at creation: events assigned via setSession bypass the store's
3368 // per-append freeze, so this keeps them read-only once stored.
34- if ( promoted ) return Object . freeze ( promoted ) ;
35- return Object . freeze ( {
36- type : "acp_message" ,
37- ts,
38- message : ( entry . notification ?? { } ) as JsonRpcMessage ,
39- } ) ;
69+ if ( promoted ) {
70+ return recordStoredLogEventPosition ( Object . freeze ( promoted ) , position ) ;
71+ }
72+ return recordStoredLogEventPosition (
73+ Object . freeze ( {
74+ type : "acp_message" ,
75+ ts,
76+ message : ( entry . notification ?? { } ) as JsonRpcMessage ,
77+ } ) ,
78+ position ,
79+ ) ;
4080}
4181
4282/**
@@ -192,13 +232,16 @@ function withToolCallUpdate(
192232 update : Record < string , unknown > ,
193233) : AcpMessage {
194234 const msg = event . message as { params ?: SessionNotification } ;
195- return Object . freeze ( {
196- ...event ,
197- message : {
198- ...msg ,
199- params : { ...msg . params , update } ,
200- } as JsonRpcMessage ,
201- } ) ;
235+ return recordStoredLogEventPosition (
236+ Object . freeze ( {
237+ ...event ,
238+ message : {
239+ ...msg ,
240+ params : { ...msg . params , update } ,
241+ } as JsonRpcMessage ,
242+ } ) ,
243+ getStoredLogEventPosition ( event ) ,
244+ ) ;
202245}
203246
204247/**
@@ -262,6 +305,7 @@ export function collapseSupersededToolCallUpdates(
262305export function convertStoredEntriesToEvents (
263306 entries : StoredLogEntry [ ] ,
264307 taskDescription ?: string ,
308+ positionOptions ?: StoredLogEventPositionOptions ,
265309) : AcpMessage [ ] {
266310 const events : AcpMessage [ ] = [ ] ;
267311
@@ -272,8 +316,20 @@ export function convertStoredEntriesToEvents(
272316 events . push ( createUserMessageEvent ( taskDescription , startTs ) ) ;
273317 }
274318
275- for ( const entry of entries ) {
276- events . push ( storedEntryToAcpMessage ( entry ) ) ;
319+ const firstPositionedEntryIndex =
320+ positionOptions ?. firstPositionedEntryIndex ?? 0 ;
321+ for ( let entryIndex = 0 ; entryIndex < entries . length ; entryIndex += 1 ) {
322+ const position =
323+ positionOptions && entryIndex >= firstPositionedEntryIndex
324+ ? {
325+ taskRunId : positionOptions . taskRunId ,
326+ entryIndex :
327+ positionOptions . startEntryIndex +
328+ entryIndex -
329+ firstPositionedEntryIndex ,
330+ }
331+ : undefined ;
332+ events . push ( storedEntryToAcpMessage ( entries [ entryIndex ] , position ) ) ;
277333 }
278334
279335 return collapseSupersededToolCallUpdates ( events ) ;
0 commit comments