diff --git a/common/api-review/ai.api.md b/common/api-review/ai.api.md index 199b97b10a9..0e3ead30b63 100644 --- a/common/api-review/ai.api.md +++ b/common/api-review/ai.api.md @@ -208,6 +208,8 @@ export interface EnhancedGenerateContentResponse extends GenerateContentResponse functionCalls: () => FunctionCall[] | undefined; inlineDataParts: () => InlineDataPart[] | undefined; text: () => string; + // (undocumented) + thoughtSummary: () => string | undefined; } // @public @@ -240,6 +242,10 @@ export interface FileDataPart { inlineData?: never; // (undocumented) text?: never; + // (undocumented) + thought?: boolean; + // (undocumented) + thoughtSignature?: string; } // @public @@ -294,6 +300,10 @@ export interface FunctionCallPart { inlineData?: never; // (undocumented) text?: never; + // (undocumented) + thought?: boolean; + // (undocumented) + thoughtSignature?: string; } // @public @@ -326,6 +336,10 @@ export interface FunctionResponsePart { inlineData?: never; // (undocumented) text?: never; + // (undocumented) + thought?: boolean; + // (undocumented) + thoughtSignature?: string; } // @public @@ -691,6 +705,10 @@ export interface InlineDataPart { inlineData: GenerativeContentBlob; // (undocumented) text?: never; + // (undocumented) + thought?: boolean; + // (undocumented) + thoughtSignature?: string; videoMetadata?: VideoMetadata; } @@ -957,10 +975,15 @@ export interface TextPart { inlineData?: never; // (undocumented) text: string; + // (undocumented) + thought?: boolean; + // (undocumented) + thoughtSignature?: string; } // @public export interface ThinkingConfig { + includeThoughts?: boolean; thinkingBudget?: number; } diff --git a/packages/ai/src/requests/response-helpers.ts b/packages/ai/src/requests/response-helpers.ts index 2505b5c9276..1c723137aac 100644 --- a/packages/ai/src/requests/response-helpers.ts +++ b/packages/ai/src/requests/response-helpers.ts @@ -78,7 +78,7 @@ export function addHelpers( } ); } - return getText(response); + return getText(response, false); } else if (response.promptFeedback) { throw new AIError( AIErrorCode.RESPONSE_ERROR, @@ -160,13 +160,22 @@ export function addHelpers( } /** - * Returns all text found in all parts of first candidate. + * Returns all text from the first candidate's parts, filtering by whether they + * are part of the model's 'thought' process. + * + * @param response - The {@link GenerateContentResponse} from which to extract text. + * @param isThought - If `true`, extracts text from `thought` parts of the response, + * which represent the model's internal reasoning. If `false`, extracts text from + * regular response parts. */ -export function getText(response: GenerateContentResponse): string { +export function getText( + response: GenerateContentResponse, + isThought: boolean +): string { const textStrings = []; if (response.candidates?.[0].content?.parts) { for (const part of response.candidates?.[0].content?.parts) { - if (part.text) { + if (part.text && (part.thought ?? false) === isThought) { textStrings.push(part.text); } } diff --git a/packages/ai/src/types/content.ts b/packages/ai/src/types/content.ts index ad2906671e4..dadb700d474 100644 --- a/packages/ai/src/types/content.ts +++ b/packages/ai/src/types/content.ts @@ -47,6 +47,8 @@ export interface TextPart { inlineData?: never; functionCall?: never; functionResponse?: never; + thought?: boolean; + thoughtSignature?: string; } /** @@ -62,6 +64,8 @@ export interface InlineDataPart { * Applicable if `inlineData` is a video. */ videoMetadata?: VideoMetadata; + thought?: boolean; + thoughtSignature?: string; } /** @@ -90,6 +94,8 @@ export interface FunctionCallPart { inlineData?: never; functionCall: FunctionCall; functionResponse?: never; + thought?: boolean; + thoughtSignature?: string; } /** @@ -101,6 +107,8 @@ export interface FunctionResponsePart { inlineData?: never; functionCall?: never; functionResponse: FunctionResponse; + thought?: boolean; + thoughtSignature?: string; } /** @@ -113,6 +121,8 @@ export interface FileDataPart { functionCall?: never; functionResponse?: never; fileData: FileData; + thought?: boolean; + thoughtSignature?: string; } /** diff --git a/packages/ai/src/types/requests.ts b/packages/ai/src/types/requests.ts index e68f3af161d..a9161b2280b 100644 --- a/packages/ai/src/types/requests.ts +++ b/packages/ai/src/types/requests.ts @@ -294,4 +294,13 @@ export interface ThinkingConfig { * feature or if the specified budget is not within the model's supported range. */ thinkingBudget?: number; + + /** + * Whether to include "thought summaries" in the model's response. + * + * Thought summaries provide a brief overview of the model's internal thinking process, + * offering insight into how it arrived at the final answer. This can be useful for + * debugging, understanding the model's reasoning, and verifying its accuracy. + */ + includeThoughts?: boolean; } diff --git a/packages/ai/src/types/responses.ts b/packages/ai/src/types/responses.ts index 323699e646b..e249bd873da 100644 --- a/packages/ai/src/types/responses.ts +++ b/packages/ai/src/types/responses.ts @@ -69,6 +69,7 @@ export interface EnhancedGenerateContentResponse */ inlineDataParts: () => InlineDataPart[] | undefined; functionCalls: () => FunctionCall[] | undefined; + thoughtSummary: () => string | undefined; } /**