diff --git a/api/server/controllers/agents/filterAuthorizedTools.spec.js b/api/server/controllers/agents/filterAuthorizedTools.spec.js index 89835fac06..677bccdfe0 100644 --- a/api/server/controllers/agents/filterAuthorizedTools.spec.js +++ b/api/server/controllers/agents/filterAuthorizedTools.spec.js @@ -183,12 +183,12 @@ describe('MCP Tool Authorization', () => { test('should keep system tools without querying MCP registry', async () => { const result = await filterAuthorizedTools({ - tools: ['execute_code', 'file_search', 'web_search'], + tools: ['execute_code', 'file_search', 'web_search', 'memory'], userId, availableTools: {}, }); - expect(result).toEqual(['execute_code', 'file_search', 'web_search']); + expect(result).toEqual(['execute_code', 'file_search', 'web_search', 'memory']); expect(mockGetAllServerConfigs).not.toHaveBeenCalled(); }); diff --git a/api/server/controllers/agents/v1.js b/api/server/controllers/agents/v1.js index b7f7a9bd29..eb0fd001d0 100644 --- a/api/server/controllers/agents/v1.js +++ b/api/server/controllers/agents/v1.js @@ -56,6 +56,7 @@ const systemTools = { [Tools.execute_code]: true, [Tools.file_search]: true, [Tools.web_search]: true, + [Tools.memory]: true, }; const MAX_SEARCH_LEN = 100; diff --git a/packages/api/src/agents/memory.spec.ts b/packages/api/src/agents/memory.spec.ts index f1a8f33e38..124cf346ff 100644 --- a/packages/api/src/agents/memory.spec.ts +++ b/packages/api/src/agents/memory.spec.ts @@ -8,6 +8,7 @@ import { createDeleteMemoryTool, getRequestMemories, invalidateRequestMemories, + agentHasInlineMemoryTools, } from './memory'; jest.mock('~/stream/GenerationJobManager'); @@ -663,6 +664,30 @@ describe('createMemoryTool tokenLimit enforcement', () => { }); }); +describe('agentHasInlineMemoryTools', () => { + it('returns false for a nullish agent', () => { + expect(agentHasInlineMemoryTools(null)).toBe(false); + expect(agentHasInlineMemoryTools(undefined)).toBe(false); + }); + + it('honors an explicit memoryToolsRegistered flag over the raw marker', () => { + /** Initialized config whose registration was denied (memoryAvailable false) + * but whose raw `memory` marker survived in tools must not be treated as + * memory-enabled. */ + expect(agentHasInlineMemoryTools({ memoryToolsRegistered: false, tools: ['memory'] })).toBe( + false, + ); + expect(agentHasInlineMemoryTools({ memoryToolsRegistered: true, tools: [] })).toBe(true); + }); + + it('falls back to the raw memory marker when no flag is present', () => { + expect(agentHasInlineMemoryTools({ tools: ['memory'] })).toBe(true); + expect(agentHasInlineMemoryTools({ tools: [{ name: 'memory' }] })).toBe(true); + expect(agentHasInlineMemoryTools({ tools: ['execute_code'] })).toBe(false); + expect(agentHasInlineMemoryTools({ tools: [] })).toBe(false); + }); +}); + describe('getRequestMemories caching', () => { it('memoizes per request, then re-fetches after invalidation', async () => { const getFormattedMemories = jest diff --git a/packages/api/src/agents/memory.ts b/packages/api/src/agents/memory.ts index aa53907d5a..e6b3dbebb3 100644 --- a/packages/api/src/agents/memory.ts +++ b/packages/api/src/agents/memory.ts @@ -447,8 +447,12 @@ export function agentHasInlineMemoryTools(agent: InlineMemoryAgent): boolean { if (!agent) { return false; } - if (agent.memoryToolsRegistered === true) { - return true; + /** An initialized config carries an explicit boolean: honor it so an agent + * whose registration was denied (`false`) is not treated as memory-enabled + * just because the raw `memory` marker survives in `tools`. Fall back to the + * marker only for the raw agent, where the flag is absent. */ + if (typeof agent.memoryToolsRegistered === 'boolean') { + return agent.memoryToolsRegistered; } return (agent.tools ?? []).some( (entry) =>