From 6949763bd65f2624c4ffd78d55f28475634e6726 Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Mon, 16 Mar 2026 13:02:44 -0700 Subject: [PATCH 01/13] feat(core): add experimental memory manager agent to replace save_memory tool Add experimental.memoryManager flag that, when enabled, replaces the built-in save_memory tool with a memory manager subagent. The subagent supports adding, removing, de-duplicating, and organizing memories across both global (~/.gemini/GEMINI.md) and project-level GEMINI.md files. Users can override the agent by placing a custom save_memory.md in ~/.gemini/agents/ or .gemini/agents/. --- docs/cli/settings.md | 1 + docs/reference/configuration.md | 7 ++ packages/cli/src/config/config.ts | 1 + packages/cli/src/config/settingsSchema.ts | 10 ++ .../src/agents/memory-manager-agent.test.ts | 65 ++++++++++ .../core/src/agents/memory-manager-agent.ts | 117 ++++++++++++++++++ packages/core/src/agents/registry.ts | 6 + packages/core/src/config/config.test.ts | 29 +++++ packages/core/src/config/config.ts | 15 ++- packages/core/src/core/prompts.test.ts | 2 + .../core/src/prompts/promptProvider.test.ts | 1 + packages/core/src/prompts/promptProvider.ts | 1 + .../prompts/snippets-memory-manager.test.ts | 30 +++++ packages/core/src/prompts/snippets.legacy.ts | 4 + packages/core/src/prompts/snippets.ts | 4 + schemas/settings.schema.json | 7 ++ 16 files changed, 297 insertions(+), 3 deletions(-) create mode 100644 packages/core/src/agents/memory-manager-agent.test.ts create mode 100644 packages/core/src/agents/memory-manager-agent.ts create mode 100644 packages/core/src/prompts/snippets-memory-manager.test.ts diff --git a/docs/cli/settings.md b/docs/cli/settings.md index eb9ba4158e7..9b08867cc42 100644 --- a/docs/cli/settings.md +++ b/docs/cli/settings.md @@ -152,6 +152,7 @@ they appear in the UI. | Plan | `experimental.plan` | Enable Plan Mode. | `true` | | Model Steering | `experimental.modelSteering` | Enable model steering (user hints) to guide the model during tool execution. | `false` | | Direct Web Fetch | `experimental.directWebFetch` | Enable web fetch behavior that bypasses LLM summarization. | `false` | +| Memory Manager Agent | `experimental.memoryManager` | Replace the built-in save_memory tool with a memory manager subagent that supports adding, removing, de-duplicating, and organizing memories. | `false` | | Topic & Update Narration | `experimental.topicUpdateNarration` | Enable the experimental Topic & Update communication model for reduced chattiness and structured progress reporting. | `false` | ### Skills diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 01aaea676f8..4312c94e17a 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -1249,6 +1249,13 @@ their corresponding top-level category object in your `settings.json` file. - **Default:** `"gemma3-1b-gpu-custom"` - **Requires restart:** Yes +- **`experimental.memoryManager`** (boolean): + - **Description:** Replace the built-in save_memory tool with a memory manager + subagent that supports adding, removing, de-duplicating, and organizing + memories. + - **Default:** `false` + - **Requires restart:** Yes + - **`experimental.topicUpdateNarration`** (boolean): - **Description:** Enable the experimental Topic & Update communication model for reduced chattiness and structured progress reporting. diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index ab6a22fb644..f62194d8b4a 100755 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -813,6 +813,7 @@ export async function loadCliConfig( skillsSupport: settings.skills?.enabled ?? true, disabledSkills: settings.skills?.disabled, experimentalJitContext: settings.experimental?.jitContext, + experimentalMemoryManager: settings.experimental?.memoryManager, modelSteering: settings.experimental?.modelSteering, topicUpdateNarration: settings.experimental?.topicUpdateNarration, toolOutputMasking: settings.experimental?.toolOutputMasking, diff --git a/packages/cli/src/config/settingsSchema.ts b/packages/cli/src/config/settingsSchema.ts index 87fbe98fc38..62d41d13ee9 100644 --- a/packages/cli/src/config/settingsSchema.ts +++ b/packages/cli/src/config/settingsSchema.ts @@ -2018,6 +2018,16 @@ const SETTINGS_SCHEMA = { }, }, }, + memoryManager: { + type: 'boolean', + label: 'Memory Manager Agent', + category: 'Experimental', + requiresRestart: true, + default: false, + description: + 'Replace the built-in save_memory tool with a memory manager subagent that supports adding, removing, de-duplicating, and organizing memories.', + showInDialog: true, + }, topicUpdateNarration: { type: 'boolean', label: 'Topic & Update Narration', diff --git a/packages/core/src/agents/memory-manager-agent.test.ts b/packages/core/src/agents/memory-manager-agent.test.ts new file mode 100644 index 00000000000..efc8cf4f135 --- /dev/null +++ b/packages/core/src/agents/memory-manager-agent.test.ts @@ -0,0 +1,65 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { describe, it, expect } from 'vitest'; +import { MemoryManagerAgent } from './memory-manager-agent.js'; + +describe('MemoryManagerAgent', () => { + it('should have the correct name "save_memory"', () => { + const agent = MemoryManagerAgent(); + expect(agent.name).toBe('save_memory'); + }); + + it('should be a local agent', () => { + const agent = MemoryManagerAgent(); + expect(agent.kind).toBe('local'); + }); + + it('should have a description', () => { + const agent = MemoryManagerAgent(); + expect(agent.description).toBeTruthy(); + expect(agent.description).toContain('memory'); + }); + + it('should have a system prompt with memory management instructions', () => { + const agent = MemoryManagerAgent(); + const prompt = agent.promptConfig.systemPrompt; + expect(prompt).toContain('Global (~/.gemini/)'); + expect(prompt).toContain('Project (.gemini/)'); + expect(prompt).toContain('Table of Contents'); + expect(prompt).toContain('De-duplicating'); + expect(prompt).toContain('Adding'); + expect(prompt).toContain('Removing stale'); + expect(prompt).toContain('Organizing'); + expect(prompt).toContain('Routing'); + }); + + it('should have file-management and search tools', () => { + const agent = MemoryManagerAgent(); + expect(agent.toolConfig).toBeDefined(); + expect(agent.toolConfig!.tools).toEqual( + expect.arrayContaining([ + 'read_file', + 'replace', + 'write_file', + 'grep_search', + ]), + ); + }); + + it('should require a "request" input parameter', () => { + const agent = MemoryManagerAgent(); + const schema = agent.inputConfig.inputSchema as Record; + expect(schema).toBeDefined(); + expect(schema['properties']).toHaveProperty('request'); + expect(schema['required']).toContain('request'); + }); + + it('should inherit the model from the parent agent', () => { + const agent = MemoryManagerAgent(); + expect(agent.modelConfig.model).toBe('inherit'); + }); +}); diff --git a/packages/core/src/agents/memory-manager-agent.ts b/packages/core/src/agents/memory-manager-agent.ts new file mode 100644 index 00000000000..f77506248bb --- /dev/null +++ b/packages/core/src/agents/memory-manager-agent.ts @@ -0,0 +1,117 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { z } from 'zod'; +import type { LocalAgentDefinition } from './types.js'; + +const MemoryManagerSchema = z.object({ + response: z + .string() + .describe('A summary of the memory operations performed.'), +}); + +const MEMORY_MANAGER_SYSTEM_PROMPT = ` +You are a memory management agent. You maintain the user's memories stored in +GEMINI.md files. + +# Memory Hierarchy + +## Global (~/.gemini/) +- \`~/.gemini/GEMINI.md\` — Cross-project user preferences, key personal info, + and habits that apply everywhere. + +## Project (.gemini/) +- \`.gemini/GEMINI.md\` — **Table of Contents** for project-specific context: + architecture decisions, conventions, key contacts, and references to + subdirectory GEMINI.md files for detailed context. +- Subdirectory GEMINI.md files (e.g. \`src/GEMINI.md\`, \`docs/GEMINI.md\`) — + detailed, domain-specific context for that part of the project. Reference + these from the root \`.gemini/GEMINI.md\`. + +## Routing + +When adding a memory, route it to the right store: +- User preferences, personal info, tool aliases, cross-project habits → **global** +- Project architecture, conventions, workflows, team info → **project root** +- Detailed context about a specific module or directory → **subdirectory + GEMINI.md**, with a reference added to the project root + +# Operations + +Always read the target file(s) before writing. When editing any memory file, +use \`grep_search\` to scan related files for duplicates before finishing. + +1. **Adding** — Route to the correct store and file. Check for duplicates first. +2. **Removing stale entries** — Delete outdated or unwanted entries. Clean up + dangling references. +3. **De-duplicating** — Search across related memory files for semantically + equivalent entries. Keep the most informative version. +4. **Organizing** — Restructure for clarity. Update references between files. + +# Guidelines + +- Keep GEMINI.md files lean — they are loaded into context every session. +- Keep entries concise. +- Edit surgically — preserve existing structure and user-authored content. +- Always read before write to avoid overwriting concurrent changes. +`.trim(); + +/** + * A memory management agent that replaces the built-in save_memory tool. + * It provides richer memory operations: adding, removing, de-duplicating, + * and organizing memories in the global GEMINI.md file. + * + * Users can override this agent by placing a custom save_memory.md + * in ~/.gemini/agents/ or .gemini/agents/. + */ +export const MemoryManagerAgent = (): LocalAgentDefinition< + typeof MemoryManagerSchema +> => ({ + kind: 'local', + name: 'save_memory', + displayName: 'Memory Manager', + description: + 'Manages the global memory file (~/.gemini/GEMINI.md). Use this agent to add, remove, de-duplicate, and organize persistent user memories. It replaces the built-in save_memory tool with structured memory management including categorization and a table of contents.', + inputConfig: { + inputSchema: { + type: 'object', + properties: { + request: { + type: 'string', + description: + 'The memory operation to perform. Examples: "Remember that I prefer tabs over spaces", "Clean up stale memories", "De-duplicate my memories", "Organize my memories".', + }, + }, + required: ['request'], + }, + }, + outputConfig: { + outputName: 'result', + description: 'A summary of the memory operations performed.', + schema: MemoryManagerSchema, + }, + modelConfig: { + model: 'inherit', + }, + toolConfig: { + tools: [ + 'read_file', + 'replace', + 'write_file', + 'list_directory', + 'glob', + 'grep_search', + ], + }, + promptConfig: { + systemPrompt: MEMORY_MANAGER_SYSTEM_PROMPT, + query: '${request}', + }, + runConfig: { + maxTimeMinutes: 5, + maxTurns: 10, + }, +}); diff --git a/packages/core/src/agents/registry.ts b/packages/core/src/agents/registry.ts index 23cf912055a..34a66f9dfb4 100644 --- a/packages/core/src/agents/registry.ts +++ b/packages/core/src/agents/registry.ts @@ -13,6 +13,7 @@ import { CodebaseInvestigatorAgent } from './codebase-investigator.js'; import { CliHelpAgent } from './cli-help-agent.js'; import { GeneralistAgent } from './generalist-agent.js'; import { BrowserAgentDefinition } from './browser/browserAgentDefinition.js'; +import { MemoryManagerAgent } from './memory-manager-agent.js'; import { A2AClientManager } from './a2a-client-manager.js'; import { A2AAuthProviderFactory } from './auth-provider/factory.js'; import type { AuthenticationHandler } from '@a2a-js/sdk/client'; @@ -250,6 +251,11 @@ export class AgentRegistry { if (browserConfig.enabled) { this.registerLocalAgent(BrowserAgentDefinition(this.config)); } + + // Register the memory manager agent as a replacement for the save_memory tool. + if (this.config.isMemoryManagerEnabled()) { + this.registerLocalAgent(MemoryManagerAgent()); + } } private async refreshAgents(): Promise { diff --git a/packages/core/src/config/config.test.ts b/packages/core/src/config/config.test.ts index fd478bba40b..fac3f0d2fd4 100644 --- a/packages/core/src/config/config.test.ts +++ b/packages/core/src/config/config.test.ts @@ -3086,6 +3086,35 @@ describe('Config JIT Initialization', () => { expect(config.getUserMemory()).toBe('Initial Memory'); }); + describe('isMemoryManagerEnabled', () => { + it('should default to false', () => { + const params: ConfigParameters = { + sessionId: 'test-session', + targetDir: '/tmp/test', + debugMode: false, + model: 'test-model', + cwd: '/tmp/test', + }; + + config = new Config(params); + expect(config.isMemoryManagerEnabled()).toBe(false); + }); + + it('should return true when experimentalMemoryManager is true', () => { + const params: ConfigParameters = { + sessionId: 'test-session', + targetDir: '/tmp/test', + debugMode: false, + model: 'test-model', + cwd: '/tmp/test', + experimentalMemoryManager: true, + }; + + config = new Config(params); + expect(config.isMemoryManagerEnabled()).toBe(true); + }); + }); + describe('reloadSkills', () => { it('should refresh disabledSkills and re-register ActivateSkillTool when skills exist', async () => { const mockOnReload = vi.fn().mockResolvedValue({ diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index 32c7f067f3e..83de205a7c2 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -623,6 +623,7 @@ export interface ConfigParameters { disabledSkills?: string[]; adminSkillsEnabled?: boolean; experimentalJitContext?: boolean; + experimentalMemoryManager?: boolean; topicUpdateNarration?: boolean; toolOutputMasking?: Partial; disableLLMCorrection?: boolean; @@ -845,6 +846,7 @@ export class Config implements McpContext, AgentLoopContext { private readonly adminSkillsEnabled: boolean; private readonly experimentalJitContext: boolean; + private readonly experimentalMemoryManager: boolean; private readonly topicUpdateNarration: boolean; private readonly disableLLMCorrection: boolean; private readonly planEnabled: boolean; @@ -994,6 +996,7 @@ export class Config implements McpContext, AgentLoopContext { ); this.experimentalJitContext = params.experimentalJitContext ?? false; + this.experimentalMemoryManager = params.experimentalMemoryManager ?? false; this.topicUpdateNarration = params.topicUpdateNarration ?? false; this.modelSteering = params.modelSteering ?? false; this.userHintService = new UserHintService(() => @@ -2065,6 +2068,10 @@ export class Config implements McpContext, AgentLoopContext { return this.experimentalJitContext; } + isMemoryManagerEnabled(): boolean { + return this.experimentalMemoryManager; + } + isTopicUpdateNarrationEnabled(): boolean { return this.topicUpdateNarration; } @@ -3088,9 +3095,11 @@ export class Config implements McpContext, AgentLoopContext { maybeRegister(ShellTool, () => registry.registerTool(new ShellTool(this, this.messageBus)), ); - maybeRegister(MemoryTool, () => - registry.registerTool(new MemoryTool(this.messageBus)), - ); + if (!this.isMemoryManagerEnabled()) { + maybeRegister(MemoryTool, () => + registry.registerTool(new MemoryTool(this.messageBus)), + ); + } maybeRegister(WebSearchTool, () => registry.registerTool(new WebSearchTool(this, this.messageBus)), ); diff --git a/packages/core/src/core/prompts.test.ts b/packages/core/src/core/prompts.test.ts index 02b30687189..7dc3cc11687 100644 --- a/packages/core/src/core/prompts.test.ts +++ b/packages/core/src/core/prompts.test.ts @@ -96,6 +96,7 @@ describe('Core System Prompt (prompts.ts)', () => { isInteractive: vi.fn().mockReturnValue(true), isInteractiveShellEnabled: vi.fn().mockReturnValue(true), isTopicUpdateNarrationEnabled: vi.fn().mockReturnValue(false), + isMemoryManagerEnabled: vi.fn().mockReturnValue(false), isAgentsEnabled: vi.fn().mockReturnValue(false), getPreviewFeatures: vi.fn().mockReturnValue(true), getModel: vi.fn().mockReturnValue(DEFAULT_GEMINI_MODEL_AUTO), @@ -410,6 +411,7 @@ describe('Core System Prompt (prompts.ts)', () => { isInteractive: vi.fn().mockReturnValue(false), isInteractiveShellEnabled: vi.fn().mockReturnValue(false), isTopicUpdateNarrationEnabled: vi.fn().mockReturnValue(false), + isMemoryManagerEnabled: vi.fn().mockReturnValue(false), isAgentsEnabled: vi.fn().mockReturnValue(false), getModel: vi.fn().mockReturnValue('auto'), getActiveModel: vi.fn().mockReturnValue(PREVIEW_GEMINI_MODEL), diff --git a/packages/core/src/prompts/promptProvider.test.ts b/packages/core/src/prompts/promptProvider.test.ts index c2253a9b570..700062de508 100644 --- a/packages/core/src/prompts/promptProvider.test.ts +++ b/packages/core/src/prompts/promptProvider.test.ts @@ -61,6 +61,7 @@ describe('PromptProvider', () => { isInteractive: vi.fn().mockReturnValue(true), isInteractiveShellEnabled: vi.fn().mockReturnValue(true), isTopicUpdateNarrationEnabled: vi.fn().mockReturnValue(false), + isMemoryManagerEnabled: vi.fn().mockReturnValue(false), getSkillManager: vi.fn().mockReturnValue({ getSkills: vi.fn().mockReturnValue([]), }), diff --git a/packages/core/src/prompts/promptProvider.ts b/packages/core/src/prompts/promptProvider.ts index ed71b035dce..cbb96f2a517 100644 --- a/packages/core/src/prompts/promptProvider.ts +++ b/packages/core/src/prompts/promptProvider.ts @@ -188,6 +188,7 @@ export class PromptProvider { interactiveShellEnabled: context.config.isInteractiveShellEnabled(), topicUpdateNarration: context.config.isTopicUpdateNarrationEnabled(), + memoryManagerEnabled: context.config.isMemoryManagerEnabled(), }), ), sandbox: this.withSection('sandbox', () => getSandboxMode()), diff --git a/packages/core/src/prompts/snippets-memory-manager.test.ts b/packages/core/src/prompts/snippets-memory-manager.test.ts new file mode 100644 index 00000000000..383515d93f8 --- /dev/null +++ b/packages/core/src/prompts/snippets-memory-manager.test.ts @@ -0,0 +1,30 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { describe, it, expect } from 'vitest'; +import { renderOperationalGuidelines } from './snippets.js'; + +describe('renderOperationalGuidelines - memoryManagerEnabled', () => { + const baseOptions = { + interactive: true, + interactiveShellEnabled: false, + topicUpdateNarration: false, + memoryManagerEnabled: false, + }; + + it('should include save_memory tool snippet when memoryManagerEnabled is false', () => { + const result = renderOperationalGuidelines(baseOptions); + expect(result).toContain('save_memory'); + }); + + it('should NOT include save_memory tool snippet when memoryManagerEnabled is true', () => { + const result = renderOperationalGuidelines({ + ...baseOptions, + memoryManagerEnabled: true, + }); + expect(result).not.toContain('save_memory'); + }); +}); diff --git a/packages/core/src/prompts/snippets.legacy.ts b/packages/core/src/prompts/snippets.legacy.ts index 227b06be45c..3bb4ad1588a 100644 --- a/packages/core/src/prompts/snippets.legacy.ts +++ b/packages/core/src/prompts/snippets.legacy.ts @@ -62,6 +62,7 @@ export interface OperationalGuidelinesOptions { isGemini3: boolean; enableShellEfficiency: boolean; interactiveShellEnabled: boolean; + memoryManagerEnabled: boolean; } export type SandboxMode = 'macos-seatbelt' | 'generic' | 'outside'; @@ -615,6 +616,9 @@ function toolUsageInteractive( function toolUsageRememberingFacts( options: OperationalGuidelinesOptions, ): string { + if (options.memoryManagerEnabled) { + return ''; + } const base = ` - **Remembering Facts:** Use the '${MEMORY_TOOL_NAME}' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information.`; const suffix = options.interactive diff --git a/packages/core/src/prompts/snippets.ts b/packages/core/src/prompts/snippets.ts index 11b559d1161..87dde0b371e 100644 --- a/packages/core/src/prompts/snippets.ts +++ b/packages/core/src/prompts/snippets.ts @@ -79,6 +79,7 @@ export interface OperationalGuidelinesOptions { interactive: boolean; interactiveShellEnabled: boolean; topicUpdateNarration: boolean; + memoryManagerEnabled: boolean; } export type SandboxMode = 'macos-seatbelt' | 'generic' | 'outside'; @@ -776,6 +777,9 @@ function toolUsageInteractive( function toolUsageRememberingFacts( options: OperationalGuidelinesOptions, ): string { + if (options.memoryManagerEnabled) { + return ''; + } const base = ` - **Memory Tool:** Use ${formatToolName(MEMORY_TOOL_NAME)} only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only.`; const suffix = options.interactive diff --git a/schemas/settings.schema.json b/schemas/settings.schema.json index f482053d9ff..f0f2218e74c 100644 --- a/schemas/settings.schema.json +++ b/schemas/settings.schema.json @@ -2107,6 +2107,13 @@ }, "additionalProperties": false }, + "memoryManager": { + "title": "Memory Manager Agent", + "description": "Replace the built-in save_memory tool with a memory manager subagent that supports adding, removing, de-duplicating, and organizing memories.", + "markdownDescription": "Replace the built-in save_memory tool with a memory manager subagent that supports adding, removing, de-duplicating, and organizing memories.\n\n- Category: `Experimental`\n- Requires restart: `yes`\n- Default: `false`", + "default": false, + "type": "boolean" + }, "topicUpdateNarration": { "title": "Topic & Update Narration", "description": "Enable the experimental Topic & Update communication model for reduced chattiness and structured progress reporting.", From 4708017e757084439cf06bbd264aa12f28d9f598 Mon Sep 17 00:00:00 2001 From: Christian Gunderman Date: Wed, 18 Mar 2026 19:00:07 +0000 Subject: [PATCH 02/13] Prototyped improvements for memory subagent (#22898) --- .../src/agents/memory-manager-agent.test.ts | 152 +++++++++++-- .../core/src/agents/memory-manager-agent.ts | 210 ++++++++++++------ packages/core/src/agents/registry.ts | 15 +- .../core/src/agents/subagent-tool.test.ts | 2 +- .../core/src/config/path-validation.test.ts | 68 ++++++ .../src/policy/memory-manager-policy.test.ts | 102 +++++++++ .../src/policy/policies/memory-manager.toml | 10 + .../prompts/snippets-memory-manager.test.ts | 4 +- packages/core/src/prompts/snippets.legacy.ts | 5 +- packages/core/src/prompts/snippets.ts | 5 +- packages/core/src/scheduler/scheduler.ts | 2 + packages/core/src/utils/bfsFileSearch.test.ts | 2 +- packages/core/src/utils/fastAckHelper.test.ts | 2 +- .../core/src/utils/getFolderStructure.test.ts | 2 +- packages/core/src/utils/toolCallContext.ts | 2 + 15 files changed, 488 insertions(+), 95 deletions(-) create mode 100644 packages/core/src/config/path-validation.test.ts create mode 100644 packages/core/src/policy/memory-manager-policy.test.ts create mode 100644 packages/core/src/policy/policies/memory-manager.toml diff --git a/packages/core/src/agents/memory-manager-agent.test.ts b/packages/core/src/agents/memory-manager-agent.test.ts index efc8cf4f135..a1fcdebe6c9 100644 --- a/packages/core/src/agents/memory-manager-agent.test.ts +++ b/packages/core/src/agents/memory-manager-agent.test.ts @@ -4,10 +4,40 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { MemoryManagerAgent } from './memory-manager-agent.js'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { + ASK_USER_TOOL_NAME, + EDIT_TOOL_NAME, + GLOB_TOOL_NAME, + GREP_TOOL_NAME, + LS_TOOL_NAME, + READ_FILE_TOOL_NAME, + WRITE_FILE_TOOL_NAME, +} from '../tools/tool-names.js'; +import { Storage } from '../config/storage.js'; + +vi.mock('node:fs', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + existsSync: vi.fn(), + statSync: vi.fn(), + readFileSync: vi.fn(), + }; +}); describe('MemoryManagerAgent', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + it('should have the correct name "save_memory"', () => { const agent = MemoryManagerAgent(); expect(agent.name).toBe('save_memory'); @@ -27,25 +57,116 @@ describe('MemoryManagerAgent', () => { it('should have a system prompt with memory management instructions', () => { const agent = MemoryManagerAgent(); const prompt = agent.promptConfig.systemPrompt; - expect(prompt).toContain('Global (~/.gemini/)'); - expect(prompt).toContain('Project (.gemini/)'); - expect(prompt).toContain('Table of Contents'); - expect(prompt).toContain('De-duplicating'); - expect(prompt).toContain('Adding'); - expect(prompt).toContain('Removing stale'); - expect(prompt).toContain('Organizing'); + const globalGeminiDir = Storage.getGlobalGeminiDir(); + expect(prompt).toContain(`Global (${globalGeminiDir}`); + expect(prompt).toContain('Project (.gemini/'); + expect(prompt).toContain('Hierarchy & Routing'); + expect(prompt).toContain('De-duplicate'); + expect(prompt).toContain('Add'); + expect(prompt).toContain('Remove'); + expect(prompt).toContain('Organize'); expect(prompt).toContain('Routing'); }); + it('should have efficiency guidelines in the system prompt', () => { + const agent = MemoryManagerAgent(); + const prompt = agent.promptConfig.systemPrompt; + expect(prompt).toContain('Efficiency & Performance'); + expect(prompt).toContain('Minimize Turns'); + expect(prompt).toContain('Stay Focused'); + expect(prompt).toContain('Be Decisive'); + expect(prompt).toContain('Context Awareness'); + }); + + it('should inject GEMINI.md files from global and project root into initial context', () => { + const globalDir = Storage.getGlobalGeminiDir(); + const projectRoot = '/test/project'; + const globalFile = path.join(globalDir, 'GEMINI.md'); + const projectFile = path.join(projectRoot, '.gemini', 'GEMINI.md'); + + vi.mocked(fs.existsSync).mockImplementation((p: fs.PathLike) => { + if (typeof p === 'string' && (p === globalFile || p === projectFile)) + return true; + return false; + }); + + vi.mocked(fs.statSync).mockImplementation((p: fs.PathLike) => { + if (typeof p === 'string' && (p === globalFile || p === projectFile)) { + return { isFile: () => true } as fs.Stats; + } + + return { isFile: () => false } as fs.Stats; + }); + + vi.mocked(fs.readFileSync).mockImplementation( + (p: fs.PathOrFileDescriptor) => { + if (p === globalFile) return 'global context'; + if (p === projectFile) return 'project context'; + return ''; + }, + ); + + const agent = MemoryManagerAgent(projectRoot); + const prompt = agent.promptConfig.systemPrompt; + + expect(prompt).toContain('# Initial Context'); + expect(prompt).toContain(`## File: ${globalFile}`); + expect(prompt).toContain('global context'); + expect(prompt).toContain(`## File: ${projectFile}`); + expect(prompt).toContain('project context'); + }); + + it('should inject GEMINI.md files along the CWD up to project root', () => { + const projectRoot = '/test/project'; + const cwd = '/test/project/src/module'; + const srcFile = path.join('/test/project/src', 'GEMINI.md'); + const moduleFile = path.join('/test/project/src/module', 'GEMINI.md'); + + vi.spyOn(process, 'cwd').mockReturnValue(cwd); + vi.mocked(fs.existsSync).mockImplementation((p: fs.PathLike) => { + if (typeof p === 'string' && (p === srcFile || p === moduleFile)) + return true; + return false; + }); + + vi.mocked(fs.statSync).mockImplementation((p: fs.PathLike) => { + if (typeof p === 'string' && (p === srcFile || p === moduleFile)) { + return { isFile: () => true } as fs.Stats; + } + + return { isFile: () => false } as fs.Stats; + }); + + vi.mocked(fs.readFileSync).mockImplementation( + (p: fs.PathOrFileDescriptor) => { + if (p === srcFile) return 'src context'; + if (p === moduleFile) return 'module context'; + return ''; + }, + ); + + const agent = MemoryManagerAgent(projectRoot); + const prompt = agent.promptConfig.systemPrompt; + + expect(prompt).toContain('# Initial Context'); + expect(prompt).toContain(`## File: ${srcFile}`); + expect(prompt).toContain('src context'); + expect(prompt).toContain(`## File: ${moduleFile}`); + expect(prompt).toContain('module context'); + }); + it('should have file-management and search tools', () => { const agent = MemoryManagerAgent(); expect(agent.toolConfig).toBeDefined(); expect(agent.toolConfig!.tools).toEqual( expect.arrayContaining([ - 'read_file', - 'replace', - 'write_file', - 'grep_search', + READ_FILE_TOOL_NAME, + EDIT_TOOL_NAME, + WRITE_FILE_TOOL_NAME, + LS_TOOL_NAME, + GLOB_TOOL_NAME, + GREP_TOOL_NAME, + ASK_USER_TOOL_NAME, ]), ); }); @@ -58,8 +179,11 @@ describe('MemoryManagerAgent', () => { expect(schema['required']).toContain('request'); }); - it('should inherit the model from the parent agent', () => { + it('should use a fast base model to avoid unnecessary thinking', () => { const agent = MemoryManagerAgent(); - expect(agent.modelConfig.model).toBe('inherit'); + expect(agent.modelConfig.model).toBe('gemini-2.5-flash-base'); + expect( + agent.modelConfig.generateContentConfig?.thinkingConfig?.thinkingBudget, + ).toBe(0); }); }); diff --git a/packages/core/src/agents/memory-manager-agent.ts b/packages/core/src/agents/memory-manager-agent.ts index f77506248bb..29882aa23f3 100644 --- a/packages/core/src/agents/memory-manager-agent.ts +++ b/packages/core/src/agents/memory-manager-agent.ts @@ -5,7 +5,20 @@ */ import { z } from 'zod'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; import type { LocalAgentDefinition } from './types.js'; +import { + ASK_USER_TOOL_NAME, + EDIT_TOOL_NAME, + GLOB_TOOL_NAME, + GREP_TOOL_NAME, + LS_TOOL_NAME, + READ_FILE_TOOL_NAME, + WRITE_FILE_TOOL_NAME, +} from '../tools/tool-names.js'; +import { Storage } from '../config/storage.js'; +import { isSubpath, normalizePath } from '../utils/paths.js'; const MemoryManagerSchema = z.object({ response: z @@ -13,14 +26,71 @@ const MemoryManagerSchema = z.object({ .describe('A summary of the memory operations performed.'), }); -const MEMORY_MANAGER_SYSTEM_PROMPT = ` -You are a memory management agent. You maintain the user's memories stored in -GEMINI.md files. +/** + * A memory management agent that replaces the built-in save_memory tool. + * It provides richer memory operations: adding, removing, de-duplicating, + * and organizing memories in the global GEMINI.md file. + * + * Users can override this agent by placing a custom save_memory.md + * in ~/.gemini/agents/ or .gemini/agents/. + */ +export const MemoryManagerAgent = ( + projectRoot?: string, +): LocalAgentDefinition => { + const globalGeminiDir = Storage.getGlobalGeminiDir(); + + const getInitialContext = (): string => { + const cwd = process.cwd(); + const filesToRead = new Set(); + + // Global GEMINI.md + filesToRead.add(path.join(globalGeminiDir, 'GEMINI.md')); + + if (projectRoot) { + // Project root .gemini/GEMINI.md + filesToRead.add(path.join(projectRoot, '.gemini', 'GEMINI.md')); + + // GEMINI.md files from cwd up to project root + if ( + isSubpath(projectRoot, cwd) || + normalizePath(projectRoot) === normalizePath(cwd) + ) { + let current = cwd; + while (true) { + filesToRead.add(path.join(current, 'GEMINI.md')); + if (normalizePath(current) === normalizePath(projectRoot)) break; + const parent = path.dirname(current); + if (parent === current) break; + current = parent; + } + } + } + + let context = '\n# Initial Context\n\n'; + let foundAny = false; + + for (const file of filesToRead) { + try { + if (fs.existsSync(file) && fs.statSync(file).isFile()) { + const content = fs.readFileSync(file, 'utf-8'); + context += `## File: ${file}\n\`\`\`markdown\n${content}\n\`\`\`\n\n`; + foundAny = true; + } + } catch { + // Ignore errors reading files + } + } + + return foundAny ? context : ''; + }; + + const MEMORY_MANAGER_SYSTEM_PROMPT = ` +You are a memory management agent maintaining user memories in GEMINI.md files. # Memory Hierarchy -## Global (~/.gemini/) -- \`~/.gemini/GEMINI.md\` — Cross-project user preferences, key personal info, +## Global (${globalGeminiDir}) +- \`${globalGeminiDir}/GEMINI.md\` — Cross-project user preferences, key personal info, and habits that apply everywhere. ## Project (.gemini/) @@ -34,84 +104,84 @@ GEMINI.md files. ## Routing When adding a memory, route it to the right store: -- User preferences, personal info, tool aliases, cross-project habits → **global** -- Project architecture, conventions, workflows, team info → **project root** -- Detailed context about a specific module or directory → **subdirectory +- **Global**: User preferences, personal info, tool aliases, cross-project habits → **global** +- **Project Root**: Project architecture, conventions, workflows, team info → **project root** +- **Subdirectory**: Detailed context about a specific module or directory → **subdirectory GEMINI.md**, with a reference added to the project root -# Operations +- **Ambiguity**: If a memory (like a coding preference or workflow) could be interpreted as either a global habit or a project-specific convention, you **MUST** use \`ask_user\` to clarify the user's intent. Do NOT make a unilateral decision when ambiguity exists between Global and Project stores. -Always read the target file(s) before writing. When editing any memory file, -use \`grep_search\` to scan related files for duplicates before finishing. +# Operations -1. **Adding** — Route to the correct store and file. Check for duplicates first. +1. **Adding** — Route to the correct store and file. Check for duplicates in your provided context first. 2. **Removing stale entries** — Delete outdated or unwanted entries. Clean up dangling references. -3. **De-duplicating** — Search across related memory files for semantically - equivalent entries. Keep the most informative version. +3. **De-duplicating** — Semantically equivalent entries should be combined. Keep the most informative version. 4. **Organizing** — Restructure for clarity. Update references between files. -# Guidelines - +# Restrictions - Keep GEMINI.md files lean — they are loaded into context every session. - Keep entries concise. - Edit surgically — preserve existing structure and user-authored content. -- Always read before write to avoid overwriting concurrent changes. +- NEVER write or read any files other than GEMINI.md files. + +# Efficiency & Performance +- **Use as few turns as possible.** Execute independent reads and writes to different files in parallel by calling multiple tools in a single turn. +- **Do not perform any exploration of the codebase. Try to use the provided file context and only search additional GEMINI.md files as needed to accomplish your task. +- **Be strategic with your thinking.** carefully decide where to route memories and how to de-duplicate memories, but be decisive with simple memory writes. +- **Minimize file system operations.** You should typically only modify the GEMINI.md files that are already provided in your context. Only read or write to other files if explicitly directed or if you are following a specific reference from an existing memory file. +- **Context Awareness.** If a file's content is already provided in the "Initial Context" section, you do not need to call \`read_file\` for it. + +# Insufficient context +If you find that you have insufficient context to read or modify the memories as described, +reply with what you need, and exit. Do not search the codebase for the missing context. +${getInitialContext()} `.trim(); -/** - * A memory management agent that replaces the built-in save_memory tool. - * It provides richer memory operations: adding, removing, de-duplicating, - * and organizing memories in the global GEMINI.md file. - * - * Users can override this agent by placing a custom save_memory.md - * in ~/.gemini/agents/ or .gemini/agents/. - */ -export const MemoryManagerAgent = (): LocalAgentDefinition< - typeof MemoryManagerSchema -> => ({ - kind: 'local', - name: 'save_memory', - displayName: 'Memory Manager', - description: - 'Manages the global memory file (~/.gemini/GEMINI.md). Use this agent to add, remove, de-duplicate, and organize persistent user memories. It replaces the built-in save_memory tool with structured memory management including categorization and a table of contents.', - inputConfig: { - inputSchema: { - type: 'object', - properties: { - request: { - type: 'string', - description: - 'The memory operation to perform. Examples: "Remember that I prefer tabs over spaces", "Clean up stale memories", "De-duplicate my memories", "Organize my memories".', + return { + kind: 'local', + name: 'save_memory', + displayName: 'Memory Manager', + description: `Writes and reads memory, preferences or facts across ALL future sessions. Use this for recurring instructions like coding styles or tool aliases.`, + inputConfig: { + inputSchema: { + type: 'object', + properties: { + request: { + type: 'string', + description: + 'The memory operation to perform. Examples: "Remember that I prefer tabs over spaces", "Clean up stale memories", "De-duplicate my memories", "Organize my memories".', + }, }, + required: ['request'], }, - required: ['request'], }, - }, - outputConfig: { - outputName: 'result', - description: 'A summary of the memory operations performed.', - schema: MemoryManagerSchema, - }, - modelConfig: { - model: 'inherit', - }, - toolConfig: { - tools: [ - 'read_file', - 'replace', - 'write_file', - 'list_directory', - 'glob', - 'grep_search', - ], - }, - promptConfig: { - systemPrompt: MEMORY_MANAGER_SYSTEM_PROMPT, - query: '${request}', - }, - runConfig: { - maxTimeMinutes: 5, - maxTurns: 10, - }, -}); + outputConfig: { + outputName: 'result', + description: 'A summary of the memory operations performed.', + schema: MemoryManagerSchema, + }, + modelConfig: { + model: 'gemini-3-flash-preview', + }, + toolConfig: { + tools: [ + READ_FILE_TOOL_NAME, + EDIT_TOOL_NAME, + WRITE_FILE_TOOL_NAME, + LS_TOOL_NAME, + GLOB_TOOL_NAME, + GREP_TOOL_NAME, + ASK_USER_TOOL_NAME, + ], + }, + promptConfig: { + systemPrompt: MEMORY_MANAGER_SYSTEM_PROMPT, + query: '${request}', + }, + runConfig: { + maxTimeMinutes: 5, + maxTurns: 10, + }, + }; +}; diff --git a/packages/core/src/agents/registry.ts b/packages/core/src/agents/registry.ts index 34a66f9dfb4..fe250889e0b 100644 --- a/packages/core/src/agents/registry.ts +++ b/packages/core/src/agents/registry.ts @@ -254,7 +254,20 @@ export class AgentRegistry { // Register the memory manager agent as a replacement for the save_memory tool. if (this.config.isMemoryManagerEnabled()) { - this.registerLocalAgent(MemoryManagerAgent()); + this.registerLocalAgent(MemoryManagerAgent(this.config.getProjectRoot())); + + // Ensure the global .gemini directory is accessible to tools. + // This allows the save_memory agent to read and write to it. + // Access control is enforced by the Policy Engine (memory-manager.toml). + try { + const globalDir = Storage.getGlobalGeminiDir(); + this.config.getWorkspaceContext().addDirectory(globalDir); + } catch (e) { + debugLogger.warn( + `[AgentRegistry] Could not add global .gemini directory to workspace:`, + e, + ); + } } } diff --git a/packages/core/src/agents/subagent-tool.test.ts b/packages/core/src/agents/subagent-tool.test.ts index c428fbdba0d..84bc3fd23f5 100644 --- a/packages/core/src/agents/subagent-tool.test.ts +++ b/packages/core/src/agents/subagent-tool.test.ts @@ -28,7 +28,7 @@ import { GEN_AI_AGENT_DESCRIPTION, GEN_AI_AGENT_NAME, } from '../telemetry/constants.js'; -import type { ToolRegistry } from 'src/tools/tool-registry.js'; +import type { ToolRegistry } from '../tools/tool-registry.js'; vi.mock('./subagent-tool-wrapper.js'); diff --git a/packages/core/src/config/path-validation.test.ts b/packages/core/src/config/path-validation.test.ts new file mode 100644 index 00000000000..742704e394a --- /dev/null +++ b/packages/core/src/config/path-validation.test.ts @@ -0,0 +1,68 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { Config } from './config.js'; +import * as path from 'node:path'; +import * as os from 'node:os'; + +vi.mock('node:fs', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + existsSync: vi.fn().mockReturnValue(true), + statSync: vi.fn().mockReturnValue({ + isDirectory: vi.fn().mockReturnValue(true), + }), + realpathSync: vi.fn((p) => p), + }; +}); + +vi.mock('../utils/paths.js', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + resolveToRealPath: vi.fn((p) => p), + isSubpath: (parent: string, child: string) => child.startsWith(parent), + }; +}); + +describe('Config Path Validation', () => { + let config: Config; + const targetDir = '/mock/workspace'; + const globalGeminiDir = path.join(os.homedir(), '.gemini'); + + beforeEach(() => { + config = new Config({ + targetDir, + sessionId: 'test-session', + debugMode: false, + cwd: targetDir, + model: 'test-model', + }); + }); + + it('should allow access to ~/.gemini if it is added to the workspace', () => { + const geminiMdPath = path.join(globalGeminiDir, 'GEMINI.md'); + + // Before adding, it should be denied + expect(config.isPathAllowed(geminiMdPath)).toBe(false); + + // Add to workspace + config.getWorkspaceContext().addDirectory(globalGeminiDir); + + // Now it should be allowed + expect(config.isPathAllowed(geminiMdPath)).toBe(true); + expect(config.validatePathAccess(geminiMdPath, 'read')).toBeNull(); + expect(config.validatePathAccess(geminiMdPath, 'write')).toBeNull(); + }); + + it('should still allow project workspace paths', () => { + const workspacePath = path.join(targetDir, 'src/index.ts'); + expect(config.isPathAllowed(workspacePath)).toBe(true); + expect(config.validatePathAccess(workspacePath, 'read')).toBeNull(); + }); +}); diff --git a/packages/core/src/policy/memory-manager-policy.test.ts b/packages/core/src/policy/memory-manager-policy.test.ts new file mode 100644 index 00000000000..dfd914d7900 --- /dev/null +++ b/packages/core/src/policy/memory-manager-policy.test.ts @@ -0,0 +1,102 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { describe, it, expect, beforeEach } from 'vitest'; +import { PolicyEngine } from './policy-engine.js'; +import { loadPoliciesFromToml } from './toml-loader.js'; +import { PolicyDecision, ApprovalMode } from './types.js'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +describe('Memory Manager Policy', () => { + let engine: PolicyEngine; + + beforeEach(async () => { + const policiesDir = path.join(__dirname, 'policies'); + const result = await loadPoliciesFromToml([policiesDir], () => 1); + engine = new PolicyEngine({ + rules: result.rules, + approvalMode: ApprovalMode.DEFAULT, + }); + }); + + it('should allow save_memory to read ~/.gemini/GEMINI.md', async () => { + const toolCall = { + name: 'read_file', + args: { file_path: '~/.gemini/GEMINI.md' }, + }; + const result = await engine.check( + toolCall, + undefined, + undefined, + 'save_memory', + ); + expect(result.decision).toBe(PolicyDecision.ALLOW); + }); + + it('should allow save_memory to write ~/.gemini/GEMINI.md', async () => { + const toolCall = { + name: 'write_file', + args: { file_path: '~/.gemini/GEMINI.md', content: 'test' }, + }; + const result = await engine.check( + toolCall, + undefined, + undefined, + 'save_memory', + ); + expect(result.decision).toBe(PolicyDecision.ALLOW); + }); + + it('should allow save_memory to list ~/.gemini/', async () => { + const toolCall = { + name: 'list_directory', + args: { dir_path: '~/.gemini/' }, + }; + const result = await engine.check( + toolCall, + undefined, + undefined, + 'save_memory', + ); + expect(result.decision).toBe(PolicyDecision.ALLOW); + }); + + it('should NOT allow save_memory to read other files', async () => { + const toolCall = { + name: 'read_file', + args: { file_path: '/etc/passwd' }, + }; + const result = await engine.check( + toolCall, + undefined, + undefined, + 'save_memory', + ); + // In the default project policy environment, read_file is allowed (priority 50). + // The memory-manager policy does not explicitly deny other files, so it falls through. + expect(result.decision).toBe(PolicyDecision.ALLOW); + }); + + it('should NOT allow other agents to access ~/.gemini/ automatically', async () => { + const toolCall = { + name: 'read_file', + args: { file_path: '~/.gemini/GEMINI.md' }, + }; + const result = await engine.check( + toolCall, + undefined, + undefined, + 'other_agent', + ); + // The memory-manager policy rule (priority 100) only applies to 'save_memory'. + // Other agents fall through to the global read_file allow rule (priority 50). + expect(result.decision).toBe(PolicyDecision.ALLOW); + }); +}); diff --git a/packages/core/src/policy/policies/memory-manager.toml b/packages/core/src/policy/policies/memory-manager.toml new file mode 100644 index 00000000000..36d9db7a41f --- /dev/null +++ b/packages/core/src/policy/policies/memory-manager.toml @@ -0,0 +1,10 @@ +# Policy for Memory Manager Agent +# Allows the save_memory agent to manage memories in the ~/.gemini/ folder. + +[[rule]] +subagent = "save_memory" +toolName = ["read_file", "write_file", "replace", "list_directory", "glob", "grep_search"] +decision = "allow" +priority = 100 +argsPattern = ".*\\.gemini/.*" +deny_message = "Memory Manager is only allowed to access the .gemini folder." diff --git a/packages/core/src/prompts/snippets-memory-manager.test.ts b/packages/core/src/prompts/snippets-memory-manager.test.ts index 383515d93f8..91e28e38775 100644 --- a/packages/core/src/prompts/snippets-memory-manager.test.ts +++ b/packages/core/src/prompts/snippets-memory-manager.test.ts @@ -20,11 +20,11 @@ describe('renderOperationalGuidelines - memoryManagerEnabled', () => { expect(result).toContain('save_memory'); }); - it('should NOT include save_memory tool snippet when memoryManagerEnabled is true', () => { + it('should include save_memory tool snippet when memoryManagerEnabled is true', () => { const result = renderOperationalGuidelines({ ...baseOptions, memoryManagerEnabled: true, }); - expect(result).not.toContain('save_memory'); + expect(result).toContain('save_memory'); }); }); diff --git a/packages/core/src/prompts/snippets.legacy.ts b/packages/core/src/prompts/snippets.legacy.ts index 3bb4ad1588a..4a630e2e452 100644 --- a/packages/core/src/prompts/snippets.legacy.ts +++ b/packages/core/src/prompts/snippets.legacy.ts @@ -617,10 +617,11 @@ function toolUsageRememberingFacts( options: OperationalGuidelinesOptions, ): string { if (options.memoryManagerEnabled) { - return ''; + return ` +- **Memory Tool:** You MUST use the '${MEMORY_TOOL_NAME}' tool to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the save_memory subagent. Never save transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is strictly for persistent general knowledge.`; } const base = ` -- **Remembering Facts:** Use the '${MEMORY_TOOL_NAME}' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information.`; +- **Remembering Facts:** Use the '${MEMORY_TOOL_NAME}' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases, or a workflow like "always lint after editing"). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information.`; const suffix = options.interactive ? ' If unsure whether to save something, you can ask the user, "Should I remember that for you?"' : ''; diff --git a/packages/core/src/prompts/snippets.ts b/packages/core/src/prompts/snippets.ts index 87dde0b371e..094a5b4d944 100644 --- a/packages/core/src/prompts/snippets.ts +++ b/packages/core/src/prompts/snippets.ts @@ -778,10 +778,11 @@ function toolUsageRememberingFacts( options: OperationalGuidelinesOptions, ): string { if (options.memoryManagerEnabled) { - return ''; + return ` +- **Memory Tool:** You MUST use ${formatToolName(MEMORY_TOOL_NAME)} to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the save_memory subagent. Never save transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is strictly for persistent general knowledge.`; } const base = ` -- **Memory Tool:** Use ${formatToolName(MEMORY_TOOL_NAME)} only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only.`; +- **Memory Tool:** You MUST use ${formatToolName(MEMORY_TOOL_NAME)} to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the ${formatToolName(MEMORY_TOOL_NAME)} tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only.`; const suffix = options.interactive ? ' If unsure whether a fact is worth remembering globally, ask the user.' : ''; diff --git a/packages/core/src/scheduler/scheduler.ts b/packages/core/src/scheduler/scheduler.ts index 4a92617e6d7..cc14e3d8756 100644 --- a/packages/core/src/scheduler/scheduler.ts +++ b/packages/core/src/scheduler/scheduler.ts @@ -363,6 +363,7 @@ export class Scheduler { callId: request.callId, schedulerId: this.schedulerId, parentCallId: this.parentCallId, + subagent: this.subagent, }, () => { try { @@ -670,6 +671,7 @@ export class Scheduler { callId: activeCall.request.callId, schedulerId: this.schedulerId, parentCallId: this.parentCallId, + subagent: this.subagent, }, () => this.executor.execute({ diff --git a/packages/core/src/utils/bfsFileSearch.test.ts b/packages/core/src/utils/bfsFileSearch.test.ts index 22e4ed67950..2a40109c400 100644 --- a/packages/core/src/utils/bfsFileSearch.test.ts +++ b/packages/core/src/utils/bfsFileSearch.test.ts @@ -10,7 +10,7 @@ import * as path from 'node:path'; import * as os from 'node:os'; import { bfsFileSearch, bfsFileSearchSync } from './bfsFileSearch.js'; import { FileDiscoveryService } from '../services/fileDiscoveryService.js'; -import { GEMINI_IGNORE_FILE_NAME } from 'src/config/constants.js'; +import { GEMINI_IGNORE_FILE_NAME } from '../config/constants.js'; describe('bfsFileSearch', () => { let testRootDir: string; diff --git a/packages/core/src/utils/fastAckHelper.test.ts b/packages/core/src/utils/fastAckHelper.test.ts index 3947c43f232..b71375b9a63 100644 --- a/packages/core/src/utils/fastAckHelper.test.ts +++ b/packages/core/src/utils/fastAckHelper.test.ts @@ -12,7 +12,7 @@ import { truncateFastAckInput, generateSteeringAckMessage, } from './fastAckHelper.js'; -import { LlmRole } from 'src/telemetry/llmRole.js'; +import { LlmRole } from '../telemetry/llmRole.js'; describe('truncateFastAckInput', () => { it('returns input as-is when below limit', () => { diff --git a/packages/core/src/utils/getFolderStructure.test.ts b/packages/core/src/utils/getFolderStructure.test.ts index 5a9a077e911..881de5b3a43 100644 --- a/packages/core/src/utils/getFolderStructure.test.ts +++ b/packages/core/src/utils/getFolderStructure.test.ts @@ -11,7 +11,7 @@ import { getFolderStructure } from './getFolderStructure.js'; import { FileDiscoveryService } from '../services/fileDiscoveryService.js'; import * as path from 'node:path'; import { GEMINI_DIR } from './paths.js'; -import { GEMINI_IGNORE_FILE_NAME } from 'src/config/constants.js'; +import { GEMINI_IGNORE_FILE_NAME } from '../config/constants.js'; describe('getFolderStructure', () => { let testRootDir: string; diff --git a/packages/core/src/utils/toolCallContext.ts b/packages/core/src/utils/toolCallContext.ts index e89d20ddef9..23c3bcaa466 100644 --- a/packages/core/src/utils/toolCallContext.ts +++ b/packages/core/src/utils/toolCallContext.ts @@ -16,6 +16,8 @@ export interface ToolCallContext { schedulerId: string; /** The ID of the parent tool call, if this is a nested execution (e.g., in a subagent). */ parentCallId?: string; + /** The name of the subagent executing the tool, if applicable. */ + subagent?: string; } /** From bd3cabd858d0cb33bb890ed84f3bea877ab6b2ac Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Wed, 18 Mar 2026 14:54:49 -0700 Subject: [PATCH 03/13] fix(core): align memory manager tests with implementation and use lazy prompt evaluation - Fix 3 failing tests in memory-manager-agent.test.ts: update prompt section assertions and model name to match actual implementation. - Update prompts.test.ts snapshots to reflect changed memory tool prompt verbiage. - Convert promptConfig to a getter so GEMINI.md files are read fresh on each invocation instead of being frozen at registration time. --- .../src/agents/memory-manager-agent.test.ts | 23 ++++---- .../core/src/agents/memory-manager-agent.ts | 11 ++-- .../core/src/agents/subagent-tool.test.ts | 2 +- .../core/__snapshots__/prompts.test.ts.snap | 58 +++++++++---------- packages/core/src/utils/bfsFileSearch.test.ts | 2 +- packages/core/src/utils/fastAckHelper.test.ts | 2 +- .../core/src/utils/getFolderStructure.test.ts | 2 +- 7 files changed, 50 insertions(+), 50 deletions(-) diff --git a/packages/core/src/agents/memory-manager-agent.test.ts b/packages/core/src/agents/memory-manager-agent.test.ts index a1fcdebe6c9..0a905ad4674 100644 --- a/packages/core/src/agents/memory-manager-agent.test.ts +++ b/packages/core/src/agents/memory-manager-agent.test.ts @@ -60,11 +60,11 @@ describe('MemoryManagerAgent', () => { const globalGeminiDir = Storage.getGlobalGeminiDir(); expect(prompt).toContain(`Global (${globalGeminiDir}`); expect(prompt).toContain('Project (.gemini/'); - expect(prompt).toContain('Hierarchy & Routing'); - expect(prompt).toContain('De-duplicate'); - expect(prompt).toContain('Add'); - expect(prompt).toContain('Remove'); - expect(prompt).toContain('Organize'); + expect(prompt).toContain('Memory Hierarchy'); + expect(prompt).toContain('De-duplicating'); + expect(prompt).toContain('Adding'); + expect(prompt).toContain('Removing stale entries'); + expect(prompt).toContain('Organizing'); expect(prompt).toContain('Routing'); }); @@ -72,9 +72,9 @@ describe('MemoryManagerAgent', () => { const agent = MemoryManagerAgent(); const prompt = agent.promptConfig.systemPrompt; expect(prompt).toContain('Efficiency & Performance'); - expect(prompt).toContain('Minimize Turns'); - expect(prompt).toContain('Stay Focused'); - expect(prompt).toContain('Be Decisive'); + expect(prompt).toContain('Use as few turns as possible'); + expect(prompt).toContain('Do not perform any exploration'); + expect(prompt).toContain('Be strategic with your thinking'); expect(prompt).toContain('Context Awareness'); }); @@ -179,11 +179,8 @@ describe('MemoryManagerAgent', () => { expect(schema['required']).toContain('request'); }); - it('should use a fast base model to avoid unnecessary thinking', () => { + it('should use a fast model', () => { const agent = MemoryManagerAgent(); - expect(agent.modelConfig.model).toBe('gemini-2.5-flash-base'); - expect( - agent.modelConfig.generateContentConfig?.thinkingConfig?.thinkingBudget, - ).toBe(0); + expect(agent.modelConfig.model).toBe('gemini-3-flash-preview'); }); }); diff --git a/packages/core/src/agents/memory-manager-agent.ts b/packages/core/src/agents/memory-manager-agent.ts index 29882aa23f3..7bf452a5978 100644 --- a/packages/core/src/agents/memory-manager-agent.ts +++ b/packages/core/src/agents/memory-manager-agent.ts @@ -84,7 +84,8 @@ export const MemoryManagerAgent = ( return foundAny ? context : ''; }; - const MEMORY_MANAGER_SYSTEM_PROMPT = ` + const buildSystemPrompt = (): string => + ` You are a memory management agent maintaining user memories in GEMINI.md files. # Memory Hierarchy @@ -175,9 +176,11 @@ ${getInitialContext()} ASK_USER_TOOL_NAME, ], }, - promptConfig: { - systemPrompt: MEMORY_MANAGER_SYSTEM_PROMPT, - query: '${request}', + get promptConfig() { + return { + systemPrompt: buildSystemPrompt(), + query: '${request}', + }; }, runConfig: { maxTimeMinutes: 5, diff --git a/packages/core/src/agents/subagent-tool.test.ts b/packages/core/src/agents/subagent-tool.test.ts index d940fd05f1c..438df59cd37 100644 --- a/packages/core/src/agents/subagent-tool.test.ts +++ b/packages/core/src/agents/subagent-tool.test.ts @@ -28,7 +28,7 @@ import { GEN_AI_AGENT_DESCRIPTION, GEN_AI_AGENT_NAME, } from '../telemetry/constants.js'; -import type { ToolRegistry } from '../tools/tool-registry.js'; +import type { ToolRegistry } from 'src/tools/tool-registry.js'; vi.mock('./subagent-tool-wrapper.js'); diff --git a/packages/core/src/core/__snapshots__/prompts.test.ts.snap b/packages/core/src/core/__snapshots__/prompts.test.ts.snap index 51468c9d8dd..3dcf96648a2 100644 --- a/packages/core/src/core/__snapshots__/prompts.test.ts.snap +++ b/packages/core/src/core/__snapshots__/prompts.test.ts.snap @@ -163,7 +163,7 @@ Use the \`exit_plan_mode\` tool to present the plan and formally request approva - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -340,7 +340,7 @@ An approved plan is available for this task at \`/tmp/plans/feature-x.md\`. - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -447,7 +447,7 @@ IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION. - **Command Execution:** Use the 'run_shell_command' tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" +- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases, or a workflow like "always lint after editing"). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" - **Respect User Confirmations:** Most tool calls (also denoted as 'function calls') will first require confirmation from the user, where they will either approve or cancel the function call. If a user cancels a function call, respect their choice and do _not_ try to make the function call again. It is okay to request the tool call again _only_ if the user requests that same tool call on a subsequent prompt. When a user cancels a function call, assume best intentions from the user and consider inquiring if they prefer any alternative paths forward. ## Interaction Details @@ -624,7 +624,7 @@ Use the \`exit_plan_mode\` tool to present the plan and formally request approva - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -778,7 +778,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -918,7 +918,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -1041,7 +1041,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -1148,7 +1148,7 @@ IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION. - **Command Execution:** Use the 'run_shell_command' tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" +- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases, or a workflow like "always lint after editing"). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" - **Respect User Confirmations:** Most tool calls (also denoted as 'function calls') will first require confirmation from the user, where they will either approve or cancel the function call. If a user cancels a function call, respect their choice and do _not_ try to make the function call again. It is okay to request the tool call again _only_ if the user requests that same tool call on a subsequent prompt. When a user cancels a function call, assume best intentions from the user and consider inquiring if they prefer any alternative paths forward. ## Interaction Details @@ -1261,7 +1261,7 @@ IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION. - **Command Execution:** Use the 'run_shell_command' tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" +- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases, or a workflow like "always lint after editing"). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" - **Respect User Confirmations:** Most tool calls (also denoted as 'function calls') will first require confirmation from the user, where they will either approve or cancel the function call. If a user cancels a function call, respect their choice and do _not_ try to make the function call again. It is okay to request the tool call again _only_ if the user requests that same tool call on a subsequent prompt. When a user cancels a function call, assume best intentions from the user and consider inquiring if they prefer any alternative paths forward. ## Interaction Details @@ -1382,7 +1382,7 @@ IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION. - **Command Execution:** Use the 'run_shell_command' tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" +- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases, or a workflow like "always lint after editing"). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" - **Respect User Confirmations:** Most tool calls (also denoted as 'function calls') will first require confirmation from the user, where they will either approve or cancel the function call. If a user cancels a function call, respect their choice and do _not_ try to make the function call again. It is okay to request the tool call again _only_ if the user requests that same tool call on a subsequent prompt. When a user cancels a function call, assume best intentions from the user and consider inquiring if they prefer any alternative paths forward. ## Interaction Details @@ -1508,7 +1508,7 @@ IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION. - **Command Execution:** Use the 'run_shell_command' tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" +- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases, or a workflow like "always lint after editing"). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" - **Respect User Confirmations:** Most tool calls (also denoted as 'function calls') will first require confirmation from the user, where they will either approve or cancel the function call. If a user cancels a function call, respect their choice and do _not_ try to make the function call again. It is okay to request the tool call again _only_ if the user requests that same tool call on a subsequent prompt. When a user cancels a function call, assume best intentions from the user and consider inquiring if they prefer any alternative paths forward. ## Interaction Details @@ -1681,7 +1681,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -1835,7 +1835,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -1993,7 +1993,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -2151,7 +2151,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -2305,7 +2305,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -2451,7 +2451,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -2604,7 +2604,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -2758,7 +2758,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -2876,7 +2876,7 @@ IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION. - **Command Execution:** Use the 'run_shell_command' tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" +- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases, or a workflow like "always lint after editing"). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" - **Respect User Confirmations:** Most tool calls (also denoted as 'function calls') will first require confirmation from the user, where they will either approve or cancel the function call. If a user cancels a function call, respect their choice and do _not_ try to make the function call again. It is okay to request the tool call again _only_ if the user requests that same tool call on a subsequent prompt. When a user cancels a function call, assume best intentions from the user and consider inquiring if they prefer any alternative paths forward. ## Interaction Details @@ -3047,7 +3047,7 @@ You are operating with a persistent file-based task tracking system located at \ - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -3154,7 +3154,7 @@ IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION. - **Command Execution:** Use the 'run_shell_command' tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" +- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases, or a workflow like "always lint after editing"). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" - **Respect User Confirmations:** Most tool calls (also denoted as 'function calls') will first require confirmation from the user, where they will either approve or cancel the function call. If a user cancels a function call, respect their choice and do _not_ try to make the function call again. It is okay to request the tool call again _only_ if the user requests that same tool call on a subsequent prompt. When a user cancels a function call, assume best intentions from the user and consider inquiring if they prefer any alternative paths forward. ## Interaction Details @@ -3268,7 +3268,7 @@ IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION. - **Command Execution:** Use the 'run_shell_command' tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" +- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases, or a workflow like "always lint after editing"). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" - **Respect User Confirmations:** Most tool calls (also denoted as 'function calls') will first require confirmation from the user, where they will either approve or cancel the function call. If a user cancels a function call, respect their choice and do _not_ try to make the function call again. It is okay to request the tool call again _only_ if the user requests that same tool call on a subsequent prompt. When a user cancels a function call, assume best intentions from the user and consider inquiring if they prefer any alternative paths forward. ## Interaction Details @@ -3442,7 +3442,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -3596,7 +3596,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -3702,7 +3702,7 @@ IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION. - **Command Execution:** Use the 'run_shell_command' tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). -- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. +- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases, or a workflow like "always lint after editing"). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. - **Respect User Confirmations:** Most tool calls (also denoted as 'function calls') will first require confirmation from the user, where they will either approve or cancel the function call. If a user cancels a function call, respect their choice and do _not_ try to make the function call again. It is okay to request the tool call again _only_ if the user requests that same tool call on a subsequent prompt. When a user cancels a function call, assume best intentions from the user and consider inquiring if they prefer any alternative paths forward. ## Interaction Details @@ -3862,7 +3862,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -4016,7 +4016,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -4123,7 +4123,7 @@ IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION. - **Command Execution:** Use the 'run_shell_command' tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" +- **Remembering Facts:** Use the 'save_memory' tool to remember specific, *user-related* facts or preferences when the user explicitly asks, or when they state a clear, concise piece of information that would help personalize or streamline *your future interactions with them* (e.g., preferred coding style, common project paths they use, personal tool aliases, or a workflow like "always lint after editing"). This tool is for user-specific information that should persist across sessions. Do *not* use it for general project context or information. If unsure whether to save something, you can ask the user, "Should I remember that for you?" - **Respect User Confirmations:** Most tool calls (also denoted as 'function calls') will first require confirmation from the user, where they will either approve or cancel the function call. If a user cancels a function call, respect their choice and do _not_ try to make the function call again. It is okay to request the tool call again _only_ if the user requests that same tool call on a subsequent prompt. When a user cancels a function call, assume best intentions from the user and consider inquiring if they prefer any alternative paths forward. ## Interaction Details diff --git a/packages/core/src/utils/bfsFileSearch.test.ts b/packages/core/src/utils/bfsFileSearch.test.ts index 2a40109c400..22e4ed67950 100644 --- a/packages/core/src/utils/bfsFileSearch.test.ts +++ b/packages/core/src/utils/bfsFileSearch.test.ts @@ -10,7 +10,7 @@ import * as path from 'node:path'; import * as os from 'node:os'; import { bfsFileSearch, bfsFileSearchSync } from './bfsFileSearch.js'; import { FileDiscoveryService } from '../services/fileDiscoveryService.js'; -import { GEMINI_IGNORE_FILE_NAME } from '../config/constants.js'; +import { GEMINI_IGNORE_FILE_NAME } from 'src/config/constants.js'; describe('bfsFileSearch', () => { let testRootDir: string; diff --git a/packages/core/src/utils/fastAckHelper.test.ts b/packages/core/src/utils/fastAckHelper.test.ts index b71375b9a63..3947c43f232 100644 --- a/packages/core/src/utils/fastAckHelper.test.ts +++ b/packages/core/src/utils/fastAckHelper.test.ts @@ -12,7 +12,7 @@ import { truncateFastAckInput, generateSteeringAckMessage, } from './fastAckHelper.js'; -import { LlmRole } from '../telemetry/llmRole.js'; +import { LlmRole } from 'src/telemetry/llmRole.js'; describe('truncateFastAckInput', () => { it('returns input as-is when below limit', () => { diff --git a/packages/core/src/utils/getFolderStructure.test.ts b/packages/core/src/utils/getFolderStructure.test.ts index 881de5b3a43..5a9a077e911 100644 --- a/packages/core/src/utils/getFolderStructure.test.ts +++ b/packages/core/src/utils/getFolderStructure.test.ts @@ -11,7 +11,7 @@ import { getFolderStructure } from './getFolderStructure.js'; import { FileDiscoveryService } from '../services/fileDiscoveryService.js'; import * as path from 'node:path'; import { GEMINI_DIR } from './paths.js'; -import { GEMINI_IGNORE_FILE_NAME } from '../config/constants.js'; +import { GEMINI_IGNORE_FILE_NAME } from 'src/config/constants.js'; describe('getFolderStructure', () => { let testRootDir: string; From 1bf384336cb8fe9d5a52112830745eb76822c645 Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Wed, 18 Mar 2026 15:02:05 -0700 Subject: [PATCH 04/13] fix(core): fix prompt formatting, test accuracy, and revert unintended prompt change - Fix missing closing ** in memory manager system prompt markdown. - Rename misleading policy test names to match their actual assertions. - Strengthen snippet tests to verify behavioral difference between enabled/disabled memory manager. - Revert non-experimental memory tool prompt back to original wording; only the experimental path should use the aggressive subagent prompt. --- .../core/src/agents/memory-manager-agent.ts | 2 +- .../core/__snapshots__/prompts.test.ts.snap | 38 +++++++++---------- .../src/policy/memory-manager-policy.test.ts | 8 ++-- .../prompts/snippets-memory-manager.test.ts | 8 +++- packages/core/src/prompts/snippets.ts | 2 +- 5 files changed, 31 insertions(+), 27 deletions(-) diff --git a/packages/core/src/agents/memory-manager-agent.ts b/packages/core/src/agents/memory-manager-agent.ts index 7bf452a5978..a331ea3ddae 100644 --- a/packages/core/src/agents/memory-manager-agent.ts +++ b/packages/core/src/agents/memory-manager-agent.ts @@ -128,7 +128,7 @@ When adding a memory, route it to the right store: # Efficiency & Performance - **Use as few turns as possible.** Execute independent reads and writes to different files in parallel by calling multiple tools in a single turn. -- **Do not perform any exploration of the codebase. Try to use the provided file context and only search additional GEMINI.md files as needed to accomplish your task. +- **Do not perform any exploration of the codebase.** Try to use the provided file context and only search additional GEMINI.md files as needed to accomplish your task. - **Be strategic with your thinking.** carefully decide where to route memories and how to de-duplicate memories, but be decisive with simple memory writes. - **Minimize file system operations.** You should typically only modify the GEMINI.md files that are already provided in your context. Only read or write to other files if explicitly directed or if you are following a specific reference from an existing memory file. - **Context Awareness.** If a file's content is already provided in the "Initial Context" section, you do not need to call \`read_file\` for it. diff --git a/packages/core/src/core/__snapshots__/prompts.test.ts.snap b/packages/core/src/core/__snapshots__/prompts.test.ts.snap index 3dcf96648a2..cf2635562d6 100644 --- a/packages/core/src/core/__snapshots__/prompts.test.ts.snap +++ b/packages/core/src/core/__snapshots__/prompts.test.ts.snap @@ -163,7 +163,7 @@ Use the \`exit_plan_mode\` tool to present the plan and formally request approva - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -340,7 +340,7 @@ An approved plan is available for this task at \`/tmp/plans/feature-x.md\`. - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -624,7 +624,7 @@ Use the \`exit_plan_mode\` tool to present the plan and formally request approva - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -778,7 +778,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -918,7 +918,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -1041,7 +1041,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -1681,7 +1681,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -1835,7 +1835,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -1993,7 +1993,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -2151,7 +2151,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -2305,7 +2305,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -2451,7 +2451,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -2604,7 +2604,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -2758,7 +2758,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -3047,7 +3047,7 @@ You are operating with a persistent file-based task tracking system located at \ - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -3442,7 +3442,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -3596,7 +3596,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -3862,7 +3862,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details @@ -4016,7 +4016,7 @@ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Executi - **Command Execution:** Use the \`run_shell_command\` tool for running shell commands, remembering the safety rule to explain modifying commands first. - **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user. - **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim). If you choose to execute an interactive command consider letting the user know they can press \`tab\` to focus into the shell to provide input. -- **Memory Tool:** You MUST use \`save_memory\` to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the \`save_memory\` tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. +- **Memory Tool:** Use \`save_memory\` only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only. If unsure whether a fact is worth remembering globally, ask the user. - **Confirmation Protocol:** If a tool call is declined or cancelled, respect the decision immediately. Do not re-attempt the action or "negotiate" for the same tool call unless the user explicitly directs you to. Offer an alternative technical path if possible. ## Interaction Details diff --git a/packages/core/src/policy/memory-manager-policy.test.ts b/packages/core/src/policy/memory-manager-policy.test.ts index dfd914d7900..e6e73e49723 100644 --- a/packages/core/src/policy/memory-manager-policy.test.ts +++ b/packages/core/src/policy/memory-manager-policy.test.ts @@ -68,7 +68,7 @@ describe('Memory Manager Policy', () => { expect(result.decision).toBe(PolicyDecision.ALLOW); }); - it('should NOT allow save_memory to read other files', async () => { + it('should fall through to global allow rule for save_memory reading non-.gemini files', async () => { const toolCall = { name: 'read_file', args: { file_path: '/etc/passwd' }, @@ -79,12 +79,12 @@ describe('Memory Manager Policy', () => { undefined, 'save_memory', ); - // In the default project policy environment, read_file is allowed (priority 50). - // The memory-manager policy does not explicitly deny other files, so it falls through. + // The memory-manager policy only matches .gemini/ paths. + // Other paths fall through to the global read_file allow rule (priority 50). expect(result.decision).toBe(PolicyDecision.ALLOW); }); - it('should NOT allow other agents to access ~/.gemini/ automatically', async () => { + it('should fall through to global allow rule for other agents accessing ~/.gemini/', async () => { const toolCall = { name: 'read_file', args: { file_path: '~/.gemini/GEMINI.md' }, diff --git a/packages/core/src/prompts/snippets-memory-manager.test.ts b/packages/core/src/prompts/snippets-memory-manager.test.ts index 91e28e38775..070e49f8c09 100644 --- a/packages/core/src/prompts/snippets-memory-manager.test.ts +++ b/packages/core/src/prompts/snippets-memory-manager.test.ts @@ -15,16 +15,20 @@ describe('renderOperationalGuidelines - memoryManagerEnabled', () => { memoryManagerEnabled: false, }; - it('should include save_memory tool snippet when memoryManagerEnabled is false', () => { + it('should include standard memory tool guidance when memoryManagerEnabled is false', () => { const result = renderOperationalGuidelines(baseOptions); expect(result).toContain('save_memory'); + expect(result).toContain('persistent user-related information'); + expect(result).not.toContain('subagent'); }); - it('should include save_memory tool snippet when memoryManagerEnabled is true', () => { + it('should include subagent memory guidance when memoryManagerEnabled is true', () => { const result = renderOperationalGuidelines({ ...baseOptions, memoryManagerEnabled: true, }); expect(result).toContain('save_memory'); + expect(result).toContain('subagent'); + expect(result).not.toContain('persistent user-related information'); }); }); diff --git a/packages/core/src/prompts/snippets.ts b/packages/core/src/prompts/snippets.ts index 308dd28fb97..d5ff8714b02 100644 --- a/packages/core/src/prompts/snippets.ts +++ b/packages/core/src/prompts/snippets.ts @@ -783,7 +783,7 @@ function toolUsageRememberingFacts( - **Memory Tool:** You MUST use ${formatToolName(MEMORY_TOOL_NAME)} to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the save_memory subagent. Never save transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is strictly for persistent general knowledge.`; } const base = ` -- **Memory Tool:** You MUST use ${formatToolName(MEMORY_TOOL_NAME)} to proactively record facts, preferences, and workflows that apply across all sessions. Whenever the user explicitly tells you to "remember" something, or when they state a preference or workflow (like "always lint after editing"), you MUST immediately call the ${formatToolName(MEMORY_TOOL_NAME)} tool. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only.`; +- **Memory Tool:** Use ${formatToolName(MEMORY_TOOL_NAME)} only for global user preferences, personal facts, or high-level information that applies across all sessions. Never save workspace-specific context, local file paths, or transient session state. Do not use memory to store summaries of code changes, bug fixes, or findings discovered during a task; this tool is for persistent user-related information only.`; const suffix = options.interactive ? ' If unsure whether a fact is worth remembering globally, ask the user.' : ''; From 37b605cbf7019f8818e808f051c9572d1ef99300 Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Wed, 18 Mar 2026 17:40:23 -0700 Subject: [PATCH 05/13] fix(core): correct project memory path from .gemini/ to ./ in agent prompt --- packages/core/src/agents/memory-manager-agent.test.ts | 2 +- packages/core/src/agents/memory-manager-agent.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/src/agents/memory-manager-agent.test.ts b/packages/core/src/agents/memory-manager-agent.test.ts index 0a905ad4674..9b93620d17c 100644 --- a/packages/core/src/agents/memory-manager-agent.test.ts +++ b/packages/core/src/agents/memory-manager-agent.test.ts @@ -59,7 +59,7 @@ describe('MemoryManagerAgent', () => { const prompt = agent.promptConfig.systemPrompt; const globalGeminiDir = Storage.getGlobalGeminiDir(); expect(prompt).toContain(`Global (${globalGeminiDir}`); - expect(prompt).toContain('Project (.gemini/'); + expect(prompt).toContain('Project (./'); expect(prompt).toContain('Memory Hierarchy'); expect(prompt).toContain('De-duplicating'); expect(prompt).toContain('Adding'); diff --git a/packages/core/src/agents/memory-manager-agent.ts b/packages/core/src/agents/memory-manager-agent.ts index a331ea3ddae..0b125cbad02 100644 --- a/packages/core/src/agents/memory-manager-agent.ts +++ b/packages/core/src/agents/memory-manager-agent.ts @@ -94,13 +94,13 @@ You are a memory management agent maintaining user memories in GEMINI.md files. - \`${globalGeminiDir}/GEMINI.md\` — Cross-project user preferences, key personal info, and habits that apply everywhere. -## Project (.gemini/) -- \`.gemini/GEMINI.md\` — **Table of Contents** for project-specific context: +## Project (./) +- \`./GEMINI.md\` — **Table of Contents** for project-specific context: architecture decisions, conventions, key contacts, and references to subdirectory GEMINI.md files for detailed context. - Subdirectory GEMINI.md files (e.g. \`src/GEMINI.md\`, \`docs/GEMINI.md\`) — detailed, domain-specific context for that part of the project. Reference - these from the root \`.gemini/GEMINI.md\`. + these from the root \`./GEMINI.md\`. ## Routing From b63559537a5bb9388043ca51b69500884ff6edb9 Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Wed, 18 Mar 2026 17:40:23 -0700 Subject: [PATCH 06/13] refactor(core): move initial context from system prompt to query in memory manager agent --- .../src/agents/memory-manager-agent.test.ts | 24 +++++++++---------- .../core/src/agents/memory-manager-agent.ts | 3 +-- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/core/src/agents/memory-manager-agent.test.ts b/packages/core/src/agents/memory-manager-agent.test.ts index 9b93620d17c..a4acd98ea3b 100644 --- a/packages/core/src/agents/memory-manager-agent.test.ts +++ b/packages/core/src/agents/memory-manager-agent.test.ts @@ -107,13 +107,13 @@ describe('MemoryManagerAgent', () => { ); const agent = MemoryManagerAgent(projectRoot); - const prompt = agent.promptConfig.systemPrompt; + const query = agent.promptConfig.query; - expect(prompt).toContain('# Initial Context'); - expect(prompt).toContain(`## File: ${globalFile}`); - expect(prompt).toContain('global context'); - expect(prompt).toContain(`## File: ${projectFile}`); - expect(prompt).toContain('project context'); + expect(query).toContain('# Initial Context'); + expect(query).toContain(`## File: ${globalFile}`); + expect(query).toContain('global context'); + expect(query).toContain(`## File: ${projectFile}`); + expect(query).toContain('project context'); }); it('should inject GEMINI.md files along the CWD up to project root', () => { @@ -146,13 +146,13 @@ describe('MemoryManagerAgent', () => { ); const agent = MemoryManagerAgent(projectRoot); - const prompt = agent.promptConfig.systemPrompt; + const query = agent.promptConfig.query; - expect(prompt).toContain('# Initial Context'); - expect(prompt).toContain(`## File: ${srcFile}`); - expect(prompt).toContain('src context'); - expect(prompt).toContain(`## File: ${moduleFile}`); - expect(prompt).toContain('module context'); + expect(query).toContain('# Initial Context'); + expect(query).toContain(`## File: ${srcFile}`); + expect(query).toContain('src context'); + expect(query).toContain(`## File: ${moduleFile}`); + expect(query).toContain('module context'); }); it('should have file-management and search tools', () => { diff --git a/packages/core/src/agents/memory-manager-agent.ts b/packages/core/src/agents/memory-manager-agent.ts index 0b125cbad02..17cfedb764c 100644 --- a/packages/core/src/agents/memory-manager-agent.ts +++ b/packages/core/src/agents/memory-manager-agent.ts @@ -136,7 +136,6 @@ When adding a memory, route it to the right store: # Insufficient context If you find that you have insufficient context to read or modify the memories as described, reply with what you need, and exit. Do not search the codebase for the missing context. -${getInitialContext()} `.trim(); return { @@ -179,7 +178,7 @@ ${getInitialContext()} get promptConfig() { return { systemPrompt: buildSystemPrompt(), - query: '${request}', + query: `${getInitialContext()}\${request}`, }; }, runConfig: { From 8ba14fd58b9475f11af4aa30141bf8009423374c Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Wed, 18 Mar 2026 17:40:24 -0700 Subject: [PATCH 07/13] fix(core): auto-update system instruction on memory change and fix jitContext memory refresh --- packages/cli/src/ui/AppContainer.tsx | 14 +++++++++++--- packages/core/src/core/client.test.ts | 19 ++++++++++++++++++- packages/core/src/core/client.ts | 6 ++++++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/ui/AppContainer.tsx b/packages/cli/src/ui/AppContainer.tsx index b2402f9fe91..5795cda7d4c 100644 --- a/packages/cli/src/ui/AppContainer.tsx +++ b/packages/cli/src/ui/AppContainer.tsx @@ -1008,10 +1008,18 @@ Logging in with Google... Restarting Gemini CLI to continue. Date.now(), ); try { - const { memoryContent, fileCount } = - await refreshServerHierarchicalMemory(config); + let flattenedMemory: string; + let fileCount: number; - const flattenedMemory = flattenMemory(memoryContent); + if (config.isJitContextEnabled()) { + await config.getContextManager()?.refresh(); + flattenedMemory = flattenMemory(config.getUserMemory()); + fileCount = config.getGeminiMdFileCount(); + } else { + const result = await refreshServerHierarchicalMemory(config); + flattenedMemory = flattenMemory(result.memoryContent); + fileCount = result.fileCount; + } historyManager.addItem( { diff --git a/packages/core/src/core/client.test.ts b/packages/core/src/core/client.test.ts index 77c4a5a4989..e93eedf055a 100644 --- a/packages/core/src/core/client.test.ts +++ b/packages/core/src/core/client.test.ts @@ -51,7 +51,7 @@ import { ClearcutLogger } from '../telemetry/clearcut-logger/clearcut-logger.js' import * as policyCatalog from '../availability/policyCatalog.js'; import { LlmRole, LoopType } from '../telemetry/types.js'; import { partToString } from '../utils/partUtils.js'; -import { coreEvents } from '../utils/events.js'; +import { coreEvents, CoreEvent } from '../utils/events.js'; import type { MessageBus } from '../confirmation-bus/message-bus.js'; // Mock fs module to prevent actual file system operations during tests @@ -1997,6 +1997,23 @@ ${JSON.stringify( ); }); + it('should update system instruction when MemoryChanged event is emitted', async () => { + vi.mocked(mockConfig.getSystemInstructionMemory).mockReturnValue( + 'Updated Memory', + ); + + const { getCoreSystemPrompt } = await import('./prompts.js'); + const mockGetCoreSystemPrompt = vi.mocked(getCoreSystemPrompt); + mockGetCoreSystemPrompt.mockClear(); + + coreEvents.emit(CoreEvent.MemoryChanged, { fileCount: 2 }); + + expect(mockGetCoreSystemPrompt).toHaveBeenCalledWith( + mockConfig, + 'Updated Memory', + ); + }); + it('should recursively call sendMessageStream with "Please continue." when InvalidStream event is received for Gemini 2 models', async () => { vi.spyOn(client['config'], 'getContinueOnFailedApiCall').mockReturnValue( true, diff --git a/packages/core/src/core/client.ts b/packages/core/src/core/client.ts index 01577452f46..f357a0decb1 100644 --- a/packages/core/src/core/client.ts +++ b/packages/core/src/core/client.ts @@ -117,6 +117,7 @@ export class GeminiClient { this.lastPromptId = this.config.getSessionId(); coreEvents.on(CoreEvent.ModelChanged, this.handleModelChanged); + coreEvents.on(CoreEvent.MemoryChanged, this.handleMemoryChanged); } private get config(): Config { @@ -127,6 +128,10 @@ export class GeminiClient { this.currentSequenceModel = null; }; + private handleMemoryChanged = () => { + this.updateSystemInstruction(); + }; + // Hook state to deduplicate BeforeAgent calls and track response for // AfterAgent private hookStateMap = new Map< @@ -306,6 +311,7 @@ export class GeminiClient { dispose() { coreEvents.off(CoreEvent.ModelChanged, this.handleModelChanged); + coreEvents.off(CoreEvent.MemoryChanged, this.handleMemoryChanged); } async resumeChat( From 86f346aafffc83c1085893a003c2e9e2c253659d Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Wed, 18 Mar 2026 17:40:24 -0700 Subject: [PATCH 08/13] fix(cli): disambiguate glob rule lookup in policy integration tests --- packages/cli/src/config/policy-engine.integration.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/config/policy-engine.integration.test.ts b/packages/cli/src/config/policy-engine.integration.test.ts index 847b47bbe39..2e74a282015 100644 --- a/packages/cli/src/config/policy-engine.integration.test.ts +++ b/packages/cli/src/config/policy-engine.integration.test.ts @@ -516,7 +516,9 @@ describe('Policy Engine Integration Tests', () => { ); expect(mcpServerRule?.priority).toBe(4.1); // MCP allowed server - const readOnlyToolRule = rules.find((r) => r.toolName === 'glob'); + const readOnlyToolRule = rules.find( + (r) => r.toolName === 'glob' && !r.subagent, + ); // Priority 70 in default tier → 1.07 (Overriding Plan Mode Deny) expect(readOnlyToolRule?.priority).toBeCloseTo(1.07, 5); @@ -673,7 +675,7 @@ describe('Policy Engine Integration Tests', () => { const server1Rule = rules.find((r) => r.toolName === 'mcp_server1_*'); expect(server1Rule?.priority).toBe(4.1); // Allowed servers (user tier) - const globRule = rules.find((r) => r.toolName === 'glob'); + const globRule = rules.find((r) => r.toolName === 'glob' && !r.subagent); // Priority 70 in default tier → 1.07 expect(globRule?.priority).toBeCloseTo(1.07, 5); // Auto-accept read-only From 7b0a0cf06fbe736cb185122e957c1c2e6ecbc55e Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Wed, 18 Mar 2026 20:05:48 -0700 Subject: [PATCH 09/13] refactor(core): use Config.getUserMemory() instead of manual FS reads in memory manager agent --- .../src/agents/memory-manager-agent.test.ts | 121 +++++++----------- .../core/src/agents/memory-manager-agent.ts | 58 ++------- packages/core/src/agents/registry.ts | 2 +- 3 files changed, 57 insertions(+), 124 deletions(-) diff --git a/packages/core/src/agents/memory-manager-agent.test.ts b/packages/core/src/agents/memory-manager-agent.test.ts index a4acd98ea3b..8ee4b72cd4a 100644 --- a/packages/core/src/agents/memory-manager-agent.test.ts +++ b/packages/core/src/agents/memory-manager-agent.test.ts @@ -6,8 +6,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { MemoryManagerAgent } from './memory-manager-agent.js'; -import * as fs from 'node:fs'; -import * as path from 'node:path'; import { ASK_USER_TOOL_NAME, EDIT_TOOL_NAME, @@ -18,16 +16,14 @@ import { WRITE_FILE_TOOL_NAME, } from '../tools/tool-names.js'; import { Storage } from '../config/storage.js'; +import type { Config } from '../config/config.js'; +import type { HierarchicalMemory } from '../config/memory.js'; -vi.mock('node:fs', async (importOriginal) => { - const actual = await importOriginal(); +function createMockConfig(memory: string | HierarchicalMemory = ''): Config { return { - ...actual, - existsSync: vi.fn(), - statSync: vi.fn(), - readFileSync: vi.fn(), - }; -}); + getUserMemory: vi.fn().mockReturnValue(memory), + } as unknown as Config; +} describe('MemoryManagerAgent', () => { beforeEach(() => { @@ -39,23 +35,23 @@ describe('MemoryManagerAgent', () => { }); it('should have the correct name "save_memory"', () => { - const agent = MemoryManagerAgent(); + const agent = MemoryManagerAgent(createMockConfig()); expect(agent.name).toBe('save_memory'); }); it('should be a local agent', () => { - const agent = MemoryManagerAgent(); + const agent = MemoryManagerAgent(createMockConfig()); expect(agent.kind).toBe('local'); }); it('should have a description', () => { - const agent = MemoryManagerAgent(); + const agent = MemoryManagerAgent(createMockConfig()); expect(agent.description).toBeTruthy(); expect(agent.description).toContain('memory'); }); it('should have a system prompt with memory management instructions', () => { - const agent = MemoryManagerAgent(); + const agent = MemoryManagerAgent(createMockConfig()); const prompt = agent.promptConfig.systemPrompt; const globalGeminiDir = Storage.getGlobalGeminiDir(); expect(prompt).toContain(`Global (${globalGeminiDir}`); @@ -69,7 +65,7 @@ describe('MemoryManagerAgent', () => { }); it('should have efficiency guidelines in the system prompt', () => { - const agent = MemoryManagerAgent(); + const agent = MemoryManagerAgent(createMockConfig()); const prompt = agent.promptConfig.systemPrompt; expect(prompt).toContain('Efficiency & Performance'); expect(prompt).toContain('Use as few turns as possible'); @@ -78,85 +74,56 @@ describe('MemoryManagerAgent', () => { expect(prompt).toContain('Context Awareness'); }); - it('should inject GEMINI.md files from global and project root into initial context', () => { - const globalDir = Storage.getGlobalGeminiDir(); - const projectRoot = '/test/project'; - const globalFile = path.join(globalDir, 'GEMINI.md'); - const projectFile = path.join(projectRoot, '.gemini', 'GEMINI.md'); - - vi.mocked(fs.existsSync).mockImplementation((p: fs.PathLike) => { - if (typeof p === 'string' && (p === globalFile || p === projectFile)) - return true; - return false; - }); - - vi.mocked(fs.statSync).mockImplementation((p: fs.PathLike) => { - if (typeof p === 'string' && (p === globalFile || p === projectFile)) { - return { isFile: () => true } as fs.Stats; - } - - return { isFile: () => false } as fs.Stats; + it('should inject hierarchical memory into initial context', () => { + const config = createMockConfig({ + global: + '--- Context from: ../../.gemini/GEMINI.md ---\nglobal context\n--- End of Context from: ../../.gemini/GEMINI.md ---', + project: + '--- Context from: .gemini/GEMINI.md ---\nproject context\n--- End of Context from: .gemini/GEMINI.md ---', }); - vi.mocked(fs.readFileSync).mockImplementation( - (p: fs.PathOrFileDescriptor) => { - if (p === globalFile) return 'global context'; - if (p === projectFile) return 'project context'; - return ''; - }, - ); - - const agent = MemoryManagerAgent(projectRoot); + const agent = MemoryManagerAgent(config); const query = agent.promptConfig.query; expect(query).toContain('# Initial Context'); - expect(query).toContain(`## File: ${globalFile}`); expect(query).toContain('global context'); - expect(query).toContain(`## File: ${projectFile}`); expect(query).toContain('project context'); }); - it('should inject GEMINI.md files along the CWD up to project root', () => { - const projectRoot = '/test/project'; - const cwd = '/test/project/src/module'; - const srcFile = path.join('/test/project/src', 'GEMINI.md'); - const moduleFile = path.join('/test/project/src/module', 'GEMINI.md'); - - vi.spyOn(process, 'cwd').mockReturnValue(cwd); - vi.mocked(fs.existsSync).mockImplementation((p: fs.PathLike) => { - if (typeof p === 'string' && (p === srcFile || p === moduleFile)) - return true; - return false; - }); + it('should inject flat string memory into initial context', () => { + const config = createMockConfig('flat memory content'); - vi.mocked(fs.statSync).mockImplementation((p: fs.PathLike) => { - if (typeof p === 'string' && (p === srcFile || p === moduleFile)) { - return { isFile: () => true } as fs.Stats; - } + const agent = MemoryManagerAgent(config); + const query = agent.promptConfig.query; - return { isFile: () => false } as fs.Stats; + expect(query).toContain('# Initial Context'); + expect(query).toContain('flat memory content'); + }); + + it('should exclude extension memory from initial context', () => { + const config = createMockConfig({ + global: 'global context', + extension: 'extension context that should be excluded', + project: 'project context', }); - vi.mocked(fs.readFileSync).mockImplementation( - (p: fs.PathOrFileDescriptor) => { - if (p === srcFile) return 'src context'; - if (p === moduleFile) return 'module context'; - return ''; - }, - ); + const agent = MemoryManagerAgent(config); + const query = agent.promptConfig.query; - const agent = MemoryManagerAgent(projectRoot); + expect(query).toContain('global context'); + expect(query).toContain('project context'); + expect(query).not.toContain('extension context'); + }); + + it('should not include initial context when memory is empty', () => { + const agent = MemoryManagerAgent(createMockConfig()); const query = agent.promptConfig.query; - expect(query).toContain('# Initial Context'); - expect(query).toContain(`## File: ${srcFile}`); - expect(query).toContain('src context'); - expect(query).toContain(`## File: ${moduleFile}`); - expect(query).toContain('module context'); + expect(query).not.toContain('# Initial Context'); }); it('should have file-management and search tools', () => { - const agent = MemoryManagerAgent(); + const agent = MemoryManagerAgent(createMockConfig()); expect(agent.toolConfig).toBeDefined(); expect(agent.toolConfig!.tools).toEqual( expect.arrayContaining([ @@ -172,7 +139,7 @@ describe('MemoryManagerAgent', () => { }); it('should require a "request" input parameter', () => { - const agent = MemoryManagerAgent(); + const agent = MemoryManagerAgent(createMockConfig()); const schema = agent.inputConfig.inputSchema as Record; expect(schema).toBeDefined(); expect(schema['properties']).toHaveProperty('request'); @@ -180,7 +147,7 @@ describe('MemoryManagerAgent', () => { }); it('should use a fast model', () => { - const agent = MemoryManagerAgent(); + const agent = MemoryManagerAgent(createMockConfig()); expect(agent.modelConfig.model).toBe('gemini-3-flash-preview'); }); }); diff --git a/packages/core/src/agents/memory-manager-agent.ts b/packages/core/src/agents/memory-manager-agent.ts index 17cfedb764c..acb161fd137 100644 --- a/packages/core/src/agents/memory-manager-agent.ts +++ b/packages/core/src/agents/memory-manager-agent.ts @@ -5,8 +5,6 @@ */ import { z } from 'zod'; -import * as fs from 'node:fs'; -import * as path from 'node:path'; import type { LocalAgentDefinition } from './types.js'; import { ASK_USER_TOOL_NAME, @@ -18,7 +16,8 @@ import { WRITE_FILE_TOOL_NAME, } from '../tools/tool-names.js'; import { Storage } from '../config/storage.js'; -import { isSubpath, normalizePath } from '../utils/paths.js'; +import { flattenMemory } from '../config/memory.js'; +import type { Config } from '../config/config.js'; const MemoryManagerSchema = z.object({ response: z @@ -35,53 +34,20 @@ const MemoryManagerSchema = z.object({ * in ~/.gemini/agents/ or .gemini/agents/. */ export const MemoryManagerAgent = ( - projectRoot?: string, + config: Config, ): LocalAgentDefinition => { const globalGeminiDir = Storage.getGlobalGeminiDir(); const getInitialContext = (): string => { - const cwd = process.cwd(); - const filesToRead = new Set(); - - // Global GEMINI.md - filesToRead.add(path.join(globalGeminiDir, 'GEMINI.md')); - - if (projectRoot) { - // Project root .gemini/GEMINI.md - filesToRead.add(path.join(projectRoot, '.gemini', 'GEMINI.md')); - - // GEMINI.md files from cwd up to project root - if ( - isSubpath(projectRoot, cwd) || - normalizePath(projectRoot) === normalizePath(cwd) - ) { - let current = cwd; - while (true) { - filesToRead.add(path.join(current, 'GEMINI.md')); - if (normalizePath(current) === normalizePath(projectRoot)) break; - const parent = path.dirname(current); - if (parent === current) break; - current = parent; - } - } - } - - let context = '\n# Initial Context\n\n'; - let foundAny = false; - - for (const file of filesToRead) { - try { - if (fs.existsSync(file) && fs.statSync(file).isFile()) { - const content = fs.readFileSync(file, 'utf-8'); - context += `## File: ${file}\n\`\`\`markdown\n${content}\n\`\`\`\n\n`; - foundAny = true; - } - } catch { - // Ignore errors reading files - } - } - - return foundAny ? context : ''; + const memory = config.getUserMemory(); + // Only include global and project memory — extension memory is read-only + // and not relevant to the memory manager. + const content = + typeof memory === 'string' + ? memory + : flattenMemory({ global: memory.global, project: memory.project }); + if (!content.trim()) return ''; + return `\n# Initial Context\n\n${content}\n`; }; const buildSystemPrompt = (): string => diff --git a/packages/core/src/agents/registry.ts b/packages/core/src/agents/registry.ts index 37ee8ef5b78..51d923001a7 100644 --- a/packages/core/src/agents/registry.ts +++ b/packages/core/src/agents/registry.ts @@ -253,7 +253,7 @@ export class AgentRegistry { // Register the memory manager agent as a replacement for the save_memory tool. if (this.config.isMemoryManagerEnabled()) { - this.registerLocalAgent(MemoryManagerAgent(this.config.getProjectRoot())); + this.registerLocalAgent(MemoryManagerAgent(this.config)); // Ensure the global .gemini directory is accessible to tools. // This allows the save_memory agent to read and write to it. From 9855f4d56a0bea9512b5e4fc1c7ce310f75ab217 Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Wed, 18 Mar 2026 20:08:45 -0700 Subject: [PATCH 10/13] chore: enable experimental memoryManager in project settings --- .gemini/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gemini/settings.json b/.gemini/settings.json index 1a4c889066f..9051dc78de5 100644 --- a/.gemini/settings.json +++ b/.gemini/settings.json @@ -2,7 +2,8 @@ "experimental": { "plan": true, "extensionReloading": true, - "modelSteering": true + "modelSteering": true, + "memoryManager": true }, "general": { "devtools": true From 90e98bf78912eaf823d63b5c82229e81dc7d206e Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Wed, 18 Mar 2026 21:35:23 -0700 Subject: [PATCH 11/13] fix(policy): tighten memory-manager argsPattern to reject substring matches --- .../src/policy/memory-manager-policy.test.ts | 17 +++++++++++++++++ .../src/policy/policies/memory-manager.toml | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/core/src/policy/memory-manager-policy.test.ts b/packages/core/src/policy/memory-manager-policy.test.ts index e6e73e49723..5de65861663 100644 --- a/packages/core/src/policy/memory-manager-policy.test.ts +++ b/packages/core/src/policy/memory-manager-policy.test.ts @@ -84,6 +84,23 @@ describe('Memory Manager Policy', () => { expect(result.decision).toBe(PolicyDecision.ALLOW); }); + it('should not match paths where .gemini is a substring (e.g. not.gemini)', async () => { + const toolCall = { + name: 'read_file', + args: { file_path: '/tmp/not.gemini/evil' }, + }; + const result = await engine.check( + toolCall, + undefined, + undefined, + 'save_memory', + ); + // The tighter argsPattern requires .gemini/ to be preceded by start-of-string + // or a path separator, so "not.gemini/" should NOT match the memory-manager rule. + // It falls through to the global read_file allow rule instead. + expect(result.decision).toBe(PolicyDecision.ALLOW); + }); + it('should fall through to global allow rule for other agents accessing ~/.gemini/', async () => { const toolCall = { name: 'read_file', diff --git a/packages/core/src/policy/policies/memory-manager.toml b/packages/core/src/policy/policies/memory-manager.toml index 36d9db7a41f..2055fcdf3a3 100644 --- a/packages/core/src/policy/policies/memory-manager.toml +++ b/packages/core/src/policy/policies/memory-manager.toml @@ -6,5 +6,5 @@ subagent = "save_memory" toolName = ["read_file", "write_file", "replace", "list_directory", "glob", "grep_search"] decision = "allow" priority = 100 -argsPattern = ".*\\.gemini/.*" +argsPattern = "(^|.*/)\\.gemini/.*" deny_message = "Memory Manager is only allowed to access the .gemini folder." From 755a200e788665df7480952139a67c95ea191e35 Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Wed, 18 Mar 2026 21:37:48 -0700 Subject: [PATCH 12/13] refactor: use ASK_USER_TOOL_NAME constant in memory-manager system prompt --- packages/core/src/agents/memory-manager-agent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/agents/memory-manager-agent.ts b/packages/core/src/agents/memory-manager-agent.ts index acb161fd137..8c6fce99c79 100644 --- a/packages/core/src/agents/memory-manager-agent.ts +++ b/packages/core/src/agents/memory-manager-agent.ts @@ -76,7 +76,7 @@ When adding a memory, route it to the right store: - **Subdirectory**: Detailed context about a specific module or directory → **subdirectory GEMINI.md**, with a reference added to the project root -- **Ambiguity**: If a memory (like a coding preference or workflow) could be interpreted as either a global habit or a project-specific convention, you **MUST** use \`ask_user\` to clarify the user's intent. Do NOT make a unilateral decision when ambiguity exists between Global and Project stores. +- **Ambiguity**: If a memory (like a coding preference or workflow) could be interpreted as either a global habit or a project-specific convention, you **MUST** use \`${ASK_USER_TOOL_NAME}\` to clarify the user's intent. Do NOT make a unilateral decision when ambiguity exists between Global and Project stores. # Operations From a0404eb6196f97d16eac1a680000e8d9cfaab77d Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Wed, 18 Mar 2026 21:51:11 -0700 Subject: [PATCH 13/13] refactor: use GEMINI_MODEL_ALIAS_FLASH instead of hardcoded model name --- packages/core/src/agents/memory-manager-agent.test.ts | 2 +- packages/core/src/agents/memory-manager-agent.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/core/src/agents/memory-manager-agent.test.ts b/packages/core/src/agents/memory-manager-agent.test.ts index 8ee4b72cd4a..c4f9879e8fc 100644 --- a/packages/core/src/agents/memory-manager-agent.test.ts +++ b/packages/core/src/agents/memory-manager-agent.test.ts @@ -148,6 +148,6 @@ describe('MemoryManagerAgent', () => { it('should use a fast model', () => { const agent = MemoryManagerAgent(createMockConfig()); - expect(agent.modelConfig.model).toBe('gemini-3-flash-preview'); + expect(agent.modelConfig.model).toBe('flash'); }); }); diff --git a/packages/core/src/agents/memory-manager-agent.ts b/packages/core/src/agents/memory-manager-agent.ts index 8c6fce99c79..1687da6d1f7 100644 --- a/packages/core/src/agents/memory-manager-agent.ts +++ b/packages/core/src/agents/memory-manager-agent.ts @@ -17,6 +17,7 @@ import { } from '../tools/tool-names.js'; import { Storage } from '../config/storage.js'; import { flattenMemory } from '../config/memory.js'; +import { GEMINI_MODEL_ALIAS_FLASH } from '../config/models.js'; import type { Config } from '../config/config.js'; const MemoryManagerSchema = z.object({ @@ -128,7 +129,7 @@ reply with what you need, and exit. Do not search the codebase for the missing c schema: MemoryManagerSchema, }, modelConfig: { - model: 'gemini-3-flash-preview', + model: GEMINI_MODEL_ALIAS_FLASH, }, toolConfig: { tools: [