@@ -39,7 +39,7 @@ import { CloudService, ExtensionBridgeService } from "@roo-code/cloud"
39
39
40
40
// api
41
41
import { ApiHandler , ApiHandlerCreateMessageMetadata , buildApiHandler } from "../../api"
42
- import { ApiStream } from "../../api/transform/stream"
42
+ import { ApiStream , GroundingSource } from "../../api/transform/stream"
43
43
44
44
// shared
45
45
import { findLastIndex } from "../../shared/array"
@@ -1746,7 +1746,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
1746
1746
this . didFinishAbortingStream = true
1747
1747
}
1748
1748
1749
- // Reset streaming state.
1749
+ // Reset streaming state for each new API request
1750
1750
this . currentStreamingContentIndex = 0
1751
1751
this . currentStreamingDidCheckpoint = false
1752
1752
this . assistantMessageContent = [ ]
@@ -1767,6 +1767,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
1767
1767
const stream = this . attemptApiRequest ( )
1768
1768
let assistantMessage = ""
1769
1769
let reasoningMessage = ""
1770
+ let pendingGroundingSources : GroundingSource [ ] = [ ]
1770
1771
this . isStreaming = true
1771
1772
1772
1773
try {
@@ -1793,6 +1794,13 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
1793
1794
cacheReadTokens += chunk . cacheReadTokens ?? 0
1794
1795
totalCost = chunk . totalCost
1795
1796
break
1797
+ case "grounding" :
1798
+ // Handle grounding sources separately from regular content
1799
+ // to prevent state persistence issues - store them separately
1800
+ if ( chunk . sources && chunk . sources . length > 0 ) {
1801
+ pendingGroundingSources . push ( ...chunk . sources )
1802
+ }
1803
+ break
1796
1804
case "text" : {
1797
1805
assistantMessage += chunk . text
1798
1806
@@ -2086,9 +2094,30 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
2086
2094
let didEndLoop = false
2087
2095
2088
2096
if ( assistantMessage . length > 0 ) {
2097
+ // Display grounding sources to the user if they exist
2098
+ if ( pendingGroundingSources . length > 0 ) {
2099
+ const citationLinks = pendingGroundingSources . map ( ( source , i ) => `[${ i + 1 } ](${ source . url } )` )
2100
+ const sourcesText = `Sources: ${ citationLinks . join ( ", " ) } `
2101
+
2102
+ await this . say ( "text" , sourcesText , undefined , false , undefined , undefined , {
2103
+ isNonInteractive : true ,
2104
+ } )
2105
+ }
2106
+
2107
+ // Strip grounding sources from assistant message before persisting to API history
2108
+ // This prevents state persistence issues while maintaining user experience
2109
+ let cleanAssistantMessage = assistantMessage
2110
+ if ( pendingGroundingSources . length > 0 ) {
2111
+ // Remove any grounding source references that might have been integrated into the message
2112
+ cleanAssistantMessage = assistantMessage
2113
+ . replace ( / \[ \d + \] \s + [ ^ : \n ] + : \s + h t t p s ? : \/ \/ [ ^ \s \n ] + / g, "" )
2114
+ . replace ( / S o u r c e s ? : \s * [ \s \S ] * ?(? = \n \n | \n $ | $ ) / g, "" )
2115
+ . trim ( )
2116
+ }
2117
+
2089
2118
await this . addToApiConversationHistory ( {
2090
2119
role : "assistant" ,
2091
- content : [ { type : "text" , text : assistantMessage } ] ,
2120
+ content : [ { type : "text" , text : cleanAssistantMessage } ] ,
2092
2121
} )
2093
2122
2094
2123
TelemetryService . instance . captureConversationMessage ( this . taskId , "assistant" )
0 commit comments