@@ -69,6 +69,8 @@ import {
6969 ChatResultWithMetadata as AgenticChatResultWithMetadata ,
7070} from './agenticChatEventParser'
7171import { ChatSessionService } from '../chat/chatSessionService'
72+ import { AgenticChatResultStream } from './agenticChatResultStream'
73+ import { executeToolMessage , toolErrorMessage , toolResultMessage } from './textFormatting'
7274
7375type ChatHandlers = Omit <
7476 LspHandlers < Chat > ,
@@ -122,10 +124,21 @@ export class AgenticChatController implements ChatHandlers {
122124 return this . #tabBarController. onConversationClick ( params )
123125 }
124126
127+ async #sendProgressToClient( chunk : ChatResult | string , partialResultToken ?: string | number ) {
128+ if ( ! isNullish ( partialResultToken ) ) {
129+ await this . #features. lsp . sendProgress ( chatRequestType , partialResultToken , chunk )
130+ }
131+ }
132+
133+ #getChatResultStream( partialResultToken ?: string | number ) : AgenticChatResultStream {
134+ return new AgenticChatResultStream ( async ( chunk : ChatResult | string ) =>
135+ this . #sendProgressToClient( chunk , partialResultToken )
136+ )
137+ }
138+
125139 async onChatPrompt ( params : ChatParams , token : CancellationToken ) : Promise < ChatResult | ResponseError < ChatResult > > {
126140 // Phase 1: Initial Setup - This happens only once
127141 const maybeDefaultResponse = getDefaultChatResponse ( params . prompt . prompt )
128-
129142 if ( maybeDefaultResponse ) {
130143 return maybeDefaultResponse
131144 }
@@ -151,7 +164,7 @@ export class AgenticChatController implements ChatHandlers {
151164 } )
152165
153166 const conversationIdentifier = session ?. conversationId ?? 'New conversation'
154-
167+ const chatResultStream = this . #getChatResultStream ( params . partialResultToken )
155168 try {
156169 // Get the initial request input
157170 const initialRequestInput = await this . #prepareRequestInput( params , session , triggerContext )
@@ -161,7 +174,7 @@ export class AgenticChatController implements ChatHandlers {
161174 initialRequestInput ,
162175 session ,
163176 metric ,
164- params . partialResultToken ,
177+ chatResultStream ,
165178 conversationIdentifier ,
166179 token
167180 )
@@ -173,7 +186,8 @@ export class AgenticChatController implements ChatHandlers {
173186 params ,
174187 metric ,
175188 triggerContext ,
176- isNewConversation
189+ isNewConversation ,
190+ chatResultStream
177191 )
178192 } catch ( err ) {
179193 return this . #handleRequestError( err , params . tabId , metric )
@@ -214,15 +228,14 @@ export class AgenticChatController implements ChatHandlers {
214228 initialRequestInput : GenerateAssistantResponseCommandInput ,
215229 session : ChatSessionService ,
216230 metric : Metric < CombinedConversationEvent > ,
217- partialResultToken ?: string | number ,
231+ chatResultStream : AgenticChatResultStream ,
218232 conversationIdentifier ?: string ,
219233 token ?: CancellationToken
220234 ) : Promise < Result < AgenticChatResultWithMetadata , string > > {
221235 let currentRequestInput = { ...initialRequestInput }
222236 let finalResult : Result < AgenticChatResultWithMetadata , string > | null = null
223237 let iterationCount = 0
224238 const maxIterations = 10 // Safety limit to prevent infinite loops
225-
226239 metric . recordStart ( )
227240
228241 while ( iterationCount < maxIterations ) {
@@ -247,7 +260,7 @@ export class AgenticChatController implements ChatHandlers {
247260 cwsprChatResponseCode : response . $metadata . httpStatusCode ,
248261 cwsprChatMessageId : response . $metadata . requestId ,
249262 } ) ,
250- partialResultToken
263+ chatResultStream
251264 )
252265
253266 // Store the conversation ID from the first response
@@ -267,7 +280,7 @@ export class AgenticChatController implements ChatHandlers {
267280 const currentMessage = currentRequestInput . conversationState ?. currentMessage
268281
269282 // Process tool uses and update the request input for the next iteration
270- const toolResults = await this . #processToolUses( pendingToolUses )
283+ const toolResults = await this . #processToolUses( pendingToolUses , chatResultStream )
271284 currentRequestInput = this . #updateRequestInputWithToolResults( currentRequestInput , toolResults )
272285
273286 if ( ! currentRequestInput . conversationState ! . history ) {
@@ -318,14 +331,17 @@ export class AgenticChatController implements ChatHandlers {
318331 /**
319332 * Processes tool uses by running the tools and collecting results
320333 */
321- async #processToolUses( toolUses : Array < ToolUse & { stop : boolean } > ) : Promise < ToolResult [ ] > {
334+ async #processToolUses(
335+ toolUses : Array < ToolUse & { stop : boolean } > ,
336+ chatResultStream : AgenticChatResultStream
337+ ) : Promise < ToolResult [ ] > {
322338 const results : ToolResult [ ] = [ ]
323339
324340 for ( const toolUse of toolUses ) {
325341 if ( ! toolUse . name || ! toolUse . toolUseId ) continue
326342
327343 try {
328- this . #debug ( `Running tool ${ toolUse . name } with input:` , JSON . stringify ( toolUse . input ) )
344+ await chatResultStream . writeResultBlock ( { body : ` ${ executeToolMessage ( toolUse ) } ` } )
329345
330346 const result = await this . #features. agent . runTool ( toolUse . name , toolUse . input )
331347 let toolResultContent : ToolResultContentBlock
@@ -343,10 +359,13 @@ export class AgenticChatController implements ChatHandlers {
343359 status : 'success' ,
344360 content : [ toolResultContent ] ,
345361 } )
346-
347- this . #debug( `Tool ${ toolUse . name } completed with result:` , JSON . stringify ( result ) )
362+ await chatResultStream . writeResultBlock ( { body : toolResultMessage ( toolUse , result ) } )
348363 } catch ( err ) {
349- this . #log( `Error running tool ${ toolUse . name } :` , err instanceof Error ? err . message : 'unknown error' )
364+ const errMsg = err instanceof Error ? err . message : 'unknown error'
365+ await chatResultStream . writeResultBlock ( {
366+ body : toolErrorMessage ( toolUse , errMsg ) ,
367+ } )
368+ this . #log( `Error running tool ${ toolUse . name } :` , errMsg )
350369 results . push ( {
351370 toolUseId : toolUse . toolUseId ,
352371 status : 'error' ,
@@ -394,12 +413,12 @@ export class AgenticChatController implements ChatHandlers {
394413 params : ChatParams ,
395414 metric : Metric < CombinedConversationEvent > ,
396415 triggerContext : TriggerContext ,
397- isNewConversation : boolean
416+ isNewConversation : boolean ,
417+ chatResultStream : AgenticChatResultStream
398418 ) : Promise < ChatResult | ResponseError < ChatResult > > {
399419 if ( ! result . success ) {
400420 return new ResponseError < ChatResult > ( LSPErrorCodes . RequestFailed , result . error )
401421 }
402-
403422 const conversationId = session . conversationId
404423 this . #debug( 'Final session conversation id:' , conversationId || '' )
405424
@@ -452,7 +471,7 @@ export class AgenticChatController implements ChatHandlers {
452471 } )
453472 }
454473
455- return result . data . chatResult
474+ return chatResultStream . getResult ( )
456475 }
457476
458477 /**
@@ -792,11 +811,11 @@ export class AgenticChatController implements ChatHandlers {
792811 async #processGenerateAssistantResponseResponse(
793812 response : GenerateAssistantResponseCommandOutput ,
794813 metric : Metric < AddMessageEvent > ,
795- partialResultToken ?: string | number
814+ chatResultStream : AgenticChatResultStream
796815 ) : Promise < Result < AgenticChatResultWithMetadata , string > > {
797816 const requestId = response . $metadata . requestId !
798817 const chatEventParser = new AgenticChatEventParser ( requestId , metric )
799-
818+ const streamWriter = chatResultStream . getResultStreamWriter ( )
800819 for await ( const chatEvent of response . generateAssistantResponseResponse ! ) {
801820 const result = chatEventParser . processPartialEvent ( chatEvent )
802821
@@ -805,10 +824,9 @@ export class AgenticChatController implements ChatHandlers {
805824 return result
806825 }
807826
808- if ( ! isNullish ( partialResultToken ) ) {
809- await this . #features. lsp . sendProgress ( chatRequestType , partialResultToken , result . data . chatResult )
810- }
827+ await streamWriter . write ( result . data . chatResult )
811828 }
829+ await streamWriter . close ( )
812830
813831 metric . mergeWith ( {
814832 cwsprChatFullResponseLatency : metric . getTimeElapsed ( ) ,
@@ -837,9 +855,7 @@ export class AgenticChatController implements ChatHandlers {
837855 return result
838856 }
839857
840- if ( ! isNullish ( partialResultToken ) ) {
841- await this . #features. lsp . sendProgress ( chatRequestType , partialResultToken , result . data . chatResult )
842- }
858+ await this . #sendProgressToClient( result . data . chatResult , partialResultToken )
843859 }
844860
845861 return chatEventParser . getResult ( )
0 commit comments