@@ -66,9 +66,9 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
6666 const { id : model , info, reasoning : thinkingConfig , maxTokens } = this . getModel ( )
6767
6868 const contents = messages . map ( convertAnthropicMessageToGemini )
69-
7069 const config : GenerateContentConfig = {
7170 systemInstruction,
71+ ...( this . options . geminiEnableGoogleSearch && { tools : [ { googleSearch : { } } ] } ) ,
7272 httpOptions : this . options . googleGeminiBaseUrl ? { baseUrl : this . options . googleGeminiBaseUrl } : undefined ,
7373 thinkingConfig,
7474 maxOutputTokens : this . options . modelMaxTokens ?? maxTokens ?? undefined ,
@@ -144,20 +144,52 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
144144
145145 async completePrompt ( prompt : string ) : Promise < string > {
146146 try {
147- const { id : model } = this . getModel ( )
148-
147+ const { id : model , reasoning : thinkingConfig } = this . getModel ( )
149148 const result = await this . client . models . generateContent ( {
150149 model,
151150 contents : [ { role : "user" , parts : [ { text : prompt } ] } ] ,
152151 config : {
152+ thinkingConfig,
153+ ...( this . options . geminiEnableGoogleSearch && { tools : [ { googleSearch : { } } ] } ) ,
153154 httpOptions : this . options . googleGeminiBaseUrl
154155 ? { baseUrl : this . options . googleGeminiBaseUrl }
155156 : undefined ,
156157 temperature : this . options . modelTemperature ?? 0 ,
157158 } ,
158159 } )
159160
160- return result . text ?? ""
161+ let text = result . text ?? ""
162+ const candidate = result . candidates ?. [ 0 ]
163+ const supports = candidate ?. groundingMetadata ?. groundingSupports
164+ const chunks = candidate ?. groundingMetadata ?. groundingChunks
165+
166+ if ( text && supports && chunks ) {
167+ // Sort supports by end index in descending order to avoid shifting issues when inserting.
168+ const sortedSupports = [ ...supports ] . sort (
169+ ( a , b ) => ( b . segment ?. endIndex ?? 0 ) - ( a . segment ?. endIndex ?? 0 ) ,
170+ )
171+
172+ for ( const support of sortedSupports ) {
173+ const endIndex = support . segment ?. endIndex
174+ if ( endIndex === undefined || ! support . groundingChunkIndices ?. length ) {
175+ continue
176+ }
177+
178+ const citationLinks = support . groundingChunkIndices
179+ . map ( ( i : number ) => {
180+ const uri = chunks [ i ] ?. web ?. uri
181+ return uri ? `[${ i + 1 } ](${ uri } )` : null
182+ } )
183+ . filter ( Boolean )
184+
185+ if ( citationLinks . length > 0 ) {
186+ const citationString = " " + citationLinks . join ( " " )
187+ text = text . slice ( 0 , endIndex ) + citationString + text . slice ( endIndex )
188+ }
189+ }
190+ }
191+
192+ return text
161193 } catch ( error ) {
162194 if ( error instanceof Error ) {
163195 throw new Error ( `Gemini completion error: ${ error . message } ` )
0 commit comments