diff --git a/packages/core/src/core/geminiChat.ts b/packages/core/src/core/geminiChat.ts index 319f994ba0..411c9a2724 100644 --- a/packages/core/src/core/geminiChat.ts +++ b/packages/core/src/core/geminiChat.ts @@ -41,6 +41,7 @@ import { logContentRetry, logContentRetryFailure, } from '../telemetry/loggers.js'; +import { clearDetailedSpanState } from '../telemetry/detailed-span-attributes.js'; import { type ChatRecordingService } from '../services/chatRecordingService.js'; import { ChatCompressionService, @@ -1400,6 +1401,7 @@ export class GeminiChat { this.setHistory(newHistory); debugLogger.debug('[FILE_READ_CACHE] clear after auto tryCompress'); this.config.getFileReadCache().clear(); + clearDetailedSpanState(); this.lastPromptTokenCount = info.newTokenCount; this.telemetryService?.setLastPromptTokenCount(info.newTokenCount); // Reset the consecutive-failure counter on success so a forced /compress diff --git a/packages/core/src/telemetry/detailed-span-attributes.test.ts b/packages/core/src/telemetry/detailed-span-attributes.test.ts index 918e8d2a2b..a0ee1bb217 100644 --- a/packages/core/src/telemetry/detailed-span-attributes.test.ts +++ b/packages/core/src/telemetry/detailed-span-attributes.test.ts @@ -400,5 +400,28 @@ describe('detailed-span-attributes', () => { addSystemPromptAttributes(config, span2, 'Same prompt'); expect(span2.attrs['system_prompt']).toBe('Same prompt'); }); + + it('resets seenHashes so tool schema full body is re-emitted after compression', () => { + const config = createMockConfig(); + const tools = [ + { name: 'Read', description: 'Read a file', parameters: {} }, + ]; + + const span1 = createMockSpan(); + addToolSchemaAttributes(config, span1, tools); + expect(span1.events.length).toBe(1); + expect(span1.events[0]!.attributes['tool_definition']).toBeDefined(); + + const span2 = createMockSpan(); + addToolSchemaAttributes(config, span2, tools); + expect(span2.events.length).toBe(0); + + clearDetailedSpanState(); + + const span3 = createMockSpan(); + addToolSchemaAttributes(config, span3, tools); + expect(span3.events.length).toBe(1); + expect(span3.events[0]!.attributes['tool_definition']).toBeDefined(); + }); }); }); diff --git a/packages/core/src/telemetry/detailed-span-attributes.ts b/packages/core/src/telemetry/detailed-span-attributes.ts index e38c57e819..cf1db36547 100644 --- a/packages/core/src/telemetry/detailed-span-attributes.ts +++ b/packages/core/src/telemetry/detailed-span-attributes.ts @@ -13,8 +13,8 @@ import { safeJsonStringify } from '../utils/safeJsonStringify.js'; const MAX_CONTENT_SIZE = 60 * 1024; // 60KB const SYSTEM_PROMPT_PREVIEW_LENGTH = 500; -// Process-global; intentionally never cleared in production. Bounded by the -// number of unique system prompts + tool schemas seen in one session. +// Process-global dedup set. Cleared on chat compression so post-compaction +// spans re-emit full system prompts and tool schemas. const seenHashes = new Set(); function isEnabled(config: Config): boolean { diff --git a/packages/core/src/telemetry/index.ts b/packages/core/src/telemetry/index.ts index 6ad5cb13c3..cd8aad316b 100644 --- a/packages/core/src/telemetry/index.ts +++ b/packages/core/src/telemetry/index.ts @@ -172,4 +172,5 @@ export { addToolInputAttributes, addToolResultAttributes, truncateContent, + clearDetailedSpanState, } from './detailed-span-attributes.js';