2025-07-11 09:29:08 -07:00
/ * *
* @license
* Copyright 2025 Google LLC
* SPDX - License - Identifier : Apache - 2.0
* /
2025-08-26 00:04:53 +02:00
import type { ToolResult } from '../tools/tools.js' ;
2025-11-11 08:10:50 -08:00
import type { Content } from '@google/genai' ;
2025-08-26 00:04:53 +02:00
import type { GeminiClient } from '../core/client.js' ;
2025-07-23 08:57:06 +09:00
import { getResponseText , partToString } from './partUtils.js' ;
2025-10-22 16:09:10 -04:00
import { debugLogger } from './debugLogger.js' ;
2025-11-11 08:10:50 -08:00
import type { ModelConfigKey } from '../services/modelConfigService.js' ;
import type { Config } from '../config/config.js' ;
2025-07-11 09:29:08 -07:00
/ * *
* A function that summarizes the result of a tool execution .
*
* @param result The result of the tool execution .
* @returns The summary of the result .
* /
export type Summarizer = (
2025-11-11 08:10:50 -08:00
config : Config ,
2025-07-11 09:29:08 -07:00
result : ToolResult ,
geminiClient : GeminiClient ,
abortSignal : AbortSignal ,
) = > Promise < string > ;
/ * *
* The default summarizer for tool results .
*
* @param result The result of the tool execution .
* @param geminiClient The Gemini client to use for summarization .
* @param abortSignal The abort signal to use for summarization .
* @returns The summary of the result .
* /
export const defaultSummarizer : Summarizer = (
2025-11-11 08:10:50 -08:00
_config : Config ,
2025-07-11 09:29:08 -07:00
result : ToolResult ,
_geminiClient : GeminiClient ,
_abortSignal : AbortSignal ,
) = > Promise . resolve ( JSON . stringify ( result . llmContent ) ) ;
2025-07-15 10:22:31 -07:00
const SUMMARIZE_TOOL_OUTPUT_PROMPT = ` Summarize the following tool output to be a maximum of {maxOutputTokens} tokens. The summary should be concise and capture the main points of the tool output.
2025-07-11 09:29:08 -07:00
The summarization should be done based on the content that is provided . Here are the basic rules to follow :
1 . If the text is a directory listing or any output that is structural , use the history of the conversation to understand the context . Using this context try to understand what information we need from the tool output and return that as a response .
2 . If the text is text content and there is nothing structural that we need , summarize the text .
3 . If the text is the output of a shell command , use the history of the conversation to understand the context . Using this context try to understand what information we need from the tool output and return a summarization along with the stack trace of any error within the < error > < / error > tags . The stack trace should be complete and not truncated . If there are warnings , you should include them in the summary within < warning > < / warning > tags .
Text to summarize :
"{textToSummarize}"
Return the summary string which should first contain an overall summarization of text followed by the full stack trace of errors and warnings in the tool output .
` ;
2025-11-11 08:10:50 -08:00
export const llmSummarizer : Summarizer = async (
config ,
result ,
geminiClient ,
abortSignal ,
) = >
2025-07-11 09:29:08 -07:00
summarizeToolOutput (
2025-11-11 08:10:50 -08:00
config ,
{ model : 'summarizer-default' } ,
2025-07-11 09:29:08 -07:00
partToString ( result . llmContent ) ,
geminiClient ,
abortSignal ,
) ;
export async function summarizeToolOutput (
2025-11-11 08:10:50 -08:00
config : Config ,
modelConfigKey : ModelConfigKey ,
2025-07-11 09:29:08 -07:00
textToSummarize : string ,
geminiClient : GeminiClient ,
abortSignal : AbortSignal ,
) : Promise < string > {
2025-11-11 08:10:50 -08:00
const maxOutputTokens =
config . modelConfigService . getResolvedConfig ( modelConfigKey )
. generateContentConfig . maxOutputTokens ? ? 2000 ;
2025-07-15 10:22:31 -07:00
// There is going to be a slight difference here since we are comparing length of string with maxOutputTokens.
// This is meant to be a ballpark estimation of if we need to summarize the tool output.
if ( ! textToSummarize || textToSummarize . length < maxOutputTokens ) {
2025-07-11 09:29:08 -07:00
return textToSummarize ;
}
const prompt = SUMMARIZE_TOOL_OUTPUT_PROMPT . replace (
2025-07-15 10:22:31 -07:00
'{maxOutputTokens}' ,
String ( maxOutputTokens ) ,
2025-07-11 09:29:08 -07:00
) . replace ( '{textToSummarize}' , textToSummarize ) ;
const contents : Content [ ] = [ { role : 'user' , parts : [ { text : prompt } ] } ] ;
try {
2025-11-11 08:10:50 -08:00
const parsedResponse = await geminiClient . generateContent (
modelConfigKey ,
2025-07-11 09:29:08 -07:00
contents ,
abortSignal ,
2025-11-11 08:10:50 -08:00
) ;
2025-07-11 09:29:08 -07:00
return getResponseText ( parsedResponse ) || textToSummarize ;
} catch ( error ) {
2025-10-22 16:09:10 -04:00
debugLogger . warn ( 'Failed to summarize tool output.' , error ) ;
2025-07-11 09:29:08 -07:00
return textToSummarize ;
}
}