diff --git a/packages/core/src/core/geminiChat.ts b/packages/core/src/core/geminiChat.ts index 87d0c235f40..ae5f46db37c 100644 --- a/packages/core/src/core/geminiChat.ts +++ b/packages/core/src/core/geminiChat.ts @@ -691,9 +691,13 @@ export class GeminiChat { const history = curated ? extractCuratedHistory(this.history) : this.history; - // Deep copy the history to avoid mutating the history outside of the - // chat session. - return structuredClone(history); + // Return a shallow copy of the array to prevent callers from mutating + // the internal history array (push/pop/splice). Content objects are + // shared references — callers MUST NOT mutate them in place. + // This replaces a prior structuredClone() which deep-copied the entire + // conversation on every call, causing O(n) memory pressure per turn + // that compounded into OOM crashes in long-running sessions. + return [...history]; } /** diff --git a/packages/core/src/core/turn.ts b/packages/core/src/core/turn.ts index 4fd6af2185b..9c0e536c48d 100644 --- a/packages/core/src/core/turn.ts +++ b/packages/core/src/core/turn.ts @@ -241,6 +241,7 @@ export class Turn { readonly pendingToolCalls: ToolCallRequestInfo[] = []; private debugResponses: GenerateContentResponse[] = []; private pendingCitations = new Set(); + private cachedResponseText: string | undefined = undefined; finishReason: FinishReason | undefined = undefined; constructor( @@ -432,11 +433,15 @@ export class Turn { /** * Get the concatenated response text from all responses in this turn. * This extracts and joins all text content from the model's responses. + * The result is cached since this is called multiple times per turn. */ getResponseText(): string { - return this.debugResponses - .map((response) => getResponseText(response)) - .filter((text): text is string => text !== null) - .join(' '); + if (this.cachedResponseText === undefined) { + this.cachedResponseText = this.debugResponses + .map((response) => getResponseText(response)) + .filter((text): text is string => text !== null) + .join(' '); + } + return this.cachedResponseText; } }