@@ -17,58 +17,19 @@ import type { AcpNotificationHandler } from "./acpConnection";
1717import {
1818 attachMcpAppPayload ,
1919 extractToolResultText ,
20- findMessageInReplayBuffer ,
2120 findReplayMessageWithToolCall ,
2221} from "./acpToolCallContent" ;
2322import {
24- getLocalSessionId ,
25- subscribeToSessionRegistration ,
26- } from "./acpSessionTracker" ;
23+ clearReplayAssistantMessage ,
24+ clearReplayAssistantTracking ,
25+ ensureReplayAssistantMessage ,
26+ getTrackedReplayAssistantMessageId ,
27+ } from "./acpReplayAssistant" ;
28+ import { getLocalSessionId } from "./acpSessionTracker" ;
2729import { perfLog } from "@/shared/lib/perfLog" ;
2830
2931// Pre-set message ID for the next live stream per goose session
3032const presetMessageIds = new Map < string , string > ( ) ;
31- const pendingUsageUpdates = new Map < string , SessionUpdate [ ] > ( ) ;
32-
33- function shouldBufferPendingUpdate ( update : SessionUpdate ) : boolean {
34- return update . sessionUpdate === "usage_update" ;
35- }
36-
37- function queuePendingUsageUpdate (
38- gooseSessionId : string ,
39- update : SessionUpdate ,
40- ) : void {
41- const pending = pendingUsageUpdates . get ( gooseSessionId ) ;
42- if ( pending ) {
43- pending . push ( update ) ;
44- return ;
45- }
46- pendingUsageUpdates . set ( gooseSessionId , [ update ] ) ;
47- }
48-
49- function flushPendingUsageUpdates (
50- localSessionId : string ,
51- gooseSessionId : string ,
52- ) : void {
53- const pending = pendingUsageUpdates . get ( gooseSessionId ) ;
54- if ( ! pending ?. length ) {
55- return ;
56- }
57-
58- pendingUsageUpdates . delete ( gooseSessionId ) ;
59-
60- for ( const update of pending ) {
61- if ( useChatStore . getState ( ) . loadingSessionIds . has ( localSessionId ) ) {
62- handleReplay ( localSessionId , update ) ;
63- } else {
64- handleLive ( localSessionId , gooseSessionId , update ) ;
65- }
66- }
67- }
68-
69- subscribeToSessionRegistration ( ( localSessionId , gooseSessionId ) => {
70- flushPendingUsageUpdates ( localSessionId , gooseSessionId ) ;
71- } ) ;
7233
7334// Per-session perf counters for replay/live streaming.
7435interface ReplayPerf {
@@ -117,32 +78,22 @@ export async function handleSessionNotification(
11778 notification : SessionNotification ,
11879) : Promise < void > {
11980 const gooseSessionId = notification . sessionId ;
81+ const sessionId = getLocalSessionId ( gooseSessionId ) ?? gooseSessionId ;
12082 const { update } = notification ;
121- const localSessionId = getLocalSessionId ( gooseSessionId ) ;
122-
123- if ( ! localSessionId ) {
124- if ( shouldBufferPendingUpdate ( update ) ) {
125- queuePendingUsageUpdate ( gooseSessionId , update ) ;
126- }
127- return ;
128- }
129-
130- const isReplay = useChatStore
131- . getState ( )
132- . loadingSessionIds . has ( localSessionId ) ;
83+ const isReplay = useChatStore . getState ( ) . loadingSessionIds . has ( sessionId ) ;
13384
13485 if ( isReplay ) {
135- const sid = localSessionId . slice ( 0 , 8 ) ;
136- let perf = replayPerf . get ( localSessionId ) ;
86+ const sid = sessionId . slice ( 0 , 8 ) ;
87+ let perf = replayPerf . get ( sessionId ) ;
13788 const now = performance . now ( ) ;
13889 if ( ! perf ) {
13990 perf = { firstAt : now , lastAt : now , count : 0 } ;
140- replayPerf . set ( localSessionId , perf ) ;
91+ replayPerf . set ( sessionId , perf ) ;
14192 perfLog ( `[perf:replay] ${ sid } first notification received` ) ;
14293 }
14394 perf . lastAt = now ;
14495 perf . count += 1 ;
145- handleReplay ( localSessionId , update ) ;
96+ handleReplay ( sessionId , gooseSessionId , update ) ;
14697 } else {
14798 const perf = livePerf . get ( gooseSessionId ) ;
14899 if ( perf && update . sessionUpdate === "agent_message_chunk" ) {
@@ -155,7 +106,7 @@ export async function handleSessionNotification(
155106 ) ;
156107 }
157108 }
158- handleLive ( localSessionId , gooseSessionId , update ) ;
109+ handleLive ( sessionId , gooseSessionId , update ) ;
159110 }
160111}
161112
@@ -171,25 +122,17 @@ export function clearReplayPerf(sessionId: string): void {
171122 replayPerf . delete ( sessionId ) ;
172123}
173124
174- function handleReplay ( sessionId : string , update : SessionUpdate ) : void {
125+ function handleReplay (
126+ sessionId : string ,
127+ gooseSessionId : string ,
128+ update : SessionUpdate ,
129+ ) : void {
175130 switch ( update . sessionUpdate ) {
176131 case "agent_message_chunk" : {
177- const messageId = update . messageId ?? crypto . randomUUID ( ) ;
178- const buffer = ensureReplayBuffer ( sessionId ) ;
179- if ( ! getBufferedMessage ( sessionId , messageId ) ) {
180- buffer . push ( {
181- id : messageId ,
182- role : "assistant" ,
183- created : Date . now ( ) ,
184- content : [ ] ,
185- metadata : {
186- userVisible : true ,
187- agentVisible : true ,
188- completionStatus : "inProgress" ,
189- } ,
190- } ) ;
191- }
192- const msg = getBufferedMessage ( sessionId , messageId ) ;
132+ const msg = ensureReplayAssistantMessage (
133+ sessionId ,
134+ update . messageId ?? null ,
135+ ) ;
193136 if ( msg && update . content . type === "text" && "text" in update . content ) {
194137 const last = msg . content [ msg . content . length - 1 ] ;
195138 if ( last ?. type === "text" ) {
@@ -202,6 +145,7 @@ function handleReplay(sessionId: string, update: SessionUpdate): void {
202145 }
203146
204147 case "user_message_chunk" : {
148+ clearReplayAssistantMessage ( sessionId ) ;
205149 const messageId = update . messageId ?? crypto . randomUUID ( ) ;
206150 const buffer = ensureReplayBuffer ( sessionId ) ;
207151 const existing = getBufferedMessage ( sessionId , messageId ) ;
@@ -233,22 +177,25 @@ function handleReplay(sessionId: string, update: SessionUpdate): void {
233177 }
234178
235179 case "tool_call" : {
236- const msg = findMessageInReplayBuffer ( sessionId ) ;
237- if ( msg ) {
238- msg . content . push ( {
239- type : "toolRequest" ,
240- id : update . toolCallId ,
241- name : update . title ,
242- arguments : { } ,
243- status : "executing" ,
244- startedAt : Date . now ( ) ,
245- } ) ;
246- }
180+ const msg = ensureReplayAssistantMessage ( sessionId ) ;
181+ msg . content . push ( {
182+ type : "toolRequest" ,
183+ id : update . toolCallId ,
184+ name : update . title ,
185+ arguments : { } ,
186+ status : "executing" ,
187+ startedAt : Date . now ( ) ,
188+ } ) ;
247189 break ;
248190 }
249191
250192 case "tool_call_update" : {
251- const msg = findReplayMessageWithToolCall ( sessionId , update . toolCallId ) ;
193+ const replayMessageId = getTrackedReplayAssistantMessageId ( sessionId ) ;
194+ const msg =
195+ findReplayMessageWithToolCall ( sessionId , update . toolCallId ) ??
196+ ( replayMessageId
197+ ? getBufferedMessage ( sessionId , replayMessageId )
198+ : undefined ) ;
252199 if ( msg ) {
253200 if ( update . title ) {
254201 const tc = msg . content . find (
@@ -286,6 +233,10 @@ function handleReplay(sessionId: string, update: SessionUpdate): void {
286233 ( tc as ToolRequestContent ) ?. name ?? update . title ?? "" ,
287234 update ,
288235 true ,
236+ {
237+ gooseSessionId,
238+ replayMessageId,
239+ } ,
289240 ) ;
290241 }
291242 }
@@ -459,6 +410,7 @@ function handleShared(sessionId: string, update: SessionUpdate): void {
459410 currentModelId ;
460411
461412 const sessionStore = useChatSessionStore . getState ( ) ;
413+ sessionStore . setSessionModels ( sessionId , availableModels ) ;
462414 sessionStore . updateSession (
463415 sessionId ,
464416 { modelId : currentModelId , modelName : currentModelName } ,
@@ -533,6 +485,7 @@ function ensureLiveAssistantMessage(
533485
534486export function clearMessageTracking ( ) : void {
535487 presetMessageIds . clear ( ) ;
488+ clearReplayAssistantTracking ( ) ;
536489}
537490
538491const handler : AcpNotificationHandler = {
0 commit comments