From 7c0603ce0a76c343eddd0f061f9cfcf8422d23e1 Mon Sep 17 00:00:00 2001 From: "gemini-cli[bot]" Date: Wed, 29 Apr 2026 23:41:51 +0000 Subject: [PATCH] # Fix Topic Marker Leakage and Address Reinjection Inquiry This PR addresses issue #26237 where the text `[active topic]` would sometimes appear in the Gemini CLI output. It also addresses an inquiry regarding the necessity of active topic reinjection in the system prompt. ## Changes - **Refactored Reinjection Format:** Changed the active topic reinjection in `PromptProvider.ts` from bracketed text `[Active Topic: ...]` to XML tags (`...``). XML tags are more clearly structural metadata and less likely to be echoed as conversational text by the model. - **Added Explicit Instructions:** Updated `mandateTopicUpdateModel` in both `snippets.ts` and `snippets.legacy.ts` to include a clear negative constraint: "Never include topic markers, title text, or the active topic marker (e.g. `[active topic]` or ``) in your chat responses." - **Updated Tests:** Verified the new format in `promptProvider.test.ts`. ## Rationale for Reinjection Regarding the inquiry about why the active topic is reinjected: The reinjection serves as a "pinned state" in the system prompt. While the model can theoretically remember the topic from the tool call history, reinjection ensures that this critical context is preserved even if the history is truncated or compressed during long sessions. It provides a stable anchor for the model to maintain continuity in its progress reporting. ## Impact - Resolves the reported leakage of topic markers in chat responses. - Improves the reliability of topic-based progress narration. --- packages/core/src/prompts/promptProvider.test.ts | 4 ++-- packages/core/src/prompts/promptProvider.ts | 4 ++-- packages/core/src/prompts/snippets.legacy.ts | 1 + packages/core/src/prompts/snippets.ts | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/core/src/prompts/promptProvider.test.ts b/packages/core/src/prompts/promptProvider.test.ts index e01e8bcba1..6fcfd685fd 100644 --- a/packages/core/src/prompts/promptProvider.test.ts +++ b/packages/core/src/prompts/promptProvider.test.ts @@ -358,7 +358,7 @@ describe('PromptProvider', () => { const provider = new PromptProvider(); const prompt = provider.getCoreSystemPrompt(mockConfig); - expect(prompt).toContain('[Active Topic: Active Chapter]'); + expect(prompt).toContain('\nActive Chapter\n'); }); it('should NOT include active topic context when narration is disabled', () => { @@ -369,7 +369,7 @@ describe('PromptProvider', () => { const provider = new PromptProvider(); const prompt = provider.getCoreSystemPrompt(mockConfig); - expect(prompt).not.toContain('[Active Topic: Active Chapter]'); + expect(prompt).not.toContain('\nActive Chapter\n'); }); it('should filter out update_topic tool when narration is disabled', () => { diff --git a/packages/core/src/prompts/promptProvider.ts b/packages/core/src/prompts/promptProvider.ts index fac9085392..0d6a32980f 100644 --- a/packages/core/src/prompts/promptProvider.ts +++ b/packages/core/src/prompts/promptProvider.ts @@ -280,8 +280,8 @@ export class PromptProvider { if (activeTopic) { const sanitizedTopic = activeTopic .replace(/\n/g, ' ') - .replace(/\]/g, ''); - sanitizedPrompt += `\n\n[Active Topic: ${sanitizedTopic}]`; + .replace(/[\[\]<>]/g, ''); + sanitizedPrompt += `\n\n\n${sanitizedTopic}\n`; } } diff --git a/packages/core/src/prompts/snippets.legacy.ts b/packages/core/src/prompts/snippets.legacy.ts index f2c8bb2b33..1bec30db9f 100644 --- a/packages/core/src/prompts/snippets.legacy.ts +++ b/packages/core/src/prompts/snippets.legacy.ts @@ -527,6 +527,7 @@ function mandateTopicUpdateModel(): string { ## Topic Updates As you work, the user follows along by reading topic updates that you publish with ${UPDATE_TOPIC_TOOL_NAME}. Keep them informed by doing the following: +- **No topic markers in chat:** Never include topic markers, title text, or the active topic marker (e.g. \`[active topic]\` or \`\`) in your chat responses. All topic and progress updates MUST be communicated exclusively via the ${UPDATE_TOPIC_TOOL_NAME} tool. - Usage Exception: NEVER use ${UPDATE_TOPIC_TOOL_NAME} for answering questions, providing explanations, or performing isolated lookup tasks (e.g. reading a single file, running a quick search, or checking a version). It is STRICTLY for orchestrating multi-step codebase modifications or complex investigations involving 3 or more tool calls. - Always call ${UPDATE_TOPIC_TOOL_NAME} in your first turn. - For tasks taking multiple turns, also call ${UPDATE_TOPIC_TOOL_NAME} in your last turn to recap what was done. diff --git a/packages/core/src/prompts/snippets.ts b/packages/core/src/prompts/snippets.ts index 385e8ffb22..e619a18a41 100644 --- a/packages/core/src/prompts/snippets.ts +++ b/packages/core/src/prompts/snippets.ts @@ -656,6 +656,7 @@ function mandateTopicUpdateModel(): string { ## Topic Updates As you work, the user follows along by reading topic updates that you publish with ${UPDATE_TOPIC_TOOL_NAME}. Keep them informed by doing the following: +- **No topic markers in chat:** Never include topic markers, title text, or the active topic marker (e.g. \`[active topic]\` or \`\`) in your chat responses. All topic and progress updates MUST be communicated exclusively via the ${UPDATE_TOPIC_TOOL_NAME} tool. - Usage Exception: NEVER use ${UPDATE_TOPIC_TOOL_NAME} for answering questions, providing explanations, or performing isolated lookup tasks (e.g. reading a single file, running a quick search, or checking a version). It is STRICTLY for orchestrating multi-step codebase modifications or complex investigations involving 3 or more tool calls. - Always call ${UPDATE_TOPIC_TOOL_NAME} in your first turn. - For tasks taking multiple turns, also call ${UPDATE_TOPIC_TOOL_NAME} in your last turn to recap what was done.