/** * Public entry for the memory tool family. * * `buildMemoryTools` is the one function host calls. It returns an array * of LangChain tools with scope captured in a closure — the LLM cannot * override the `(agentId, userId)` pair through any tool argument. * * Phase 2: accepts independent `readEnabled` / `writeEnabled` flags that * mirror host's existing `agent.memory_read_enabled` / * `agent.memory_write_enabled` fields. Either flag can be set without the * other: a read-only agent can consult memory without mutating it; a * write-only agent can reflect without reading. */ import type { StructuredToolInterface } from '@langchain/core/tools'; import type { MemoryConfig, MemoryPhase } from '@/memory/types'; import { createMemorySearchTool } from './memorySearchTool'; import { createMemoryGetTool } from './memoryGetTool'; import { createMemoryAppendTool } from './memoryAppendTool'; import type { MemoryToolBinding } from './shared'; export * from './shared'; export { createMemorySearchTool } from './memorySearchTool'; export { createMemoryGetTool } from './memoryGetTool'; export { createMemoryAppendTool } from './memoryAppendTool'; export interface BuildMemoryToolsOptions extends MemoryConfig { /** * Attach `memory_search` + `memory_get`. Maps to * `agent.memory_read_enabled` on the host Agent document. */ readEnabled?: boolean; /** * Attach `memory_append` (still phase-gated to `memory_flushing`). * Maps to `agent.memory_write_enabled` on the host Agent document. */ writeEnabled?: boolean; /** * @deprecated — legacy Phase 1 flag. When set, equivalent to * `{ readEnabled: true, writeEnabled: false }`. Kept so existing tests * don't break during the Phase 1→2 transition. New callers should pass * `readEnabled`/`writeEnabled` explicitly. */ readOnly?: boolean; } export function buildMemoryTools( options: BuildMemoryToolsOptions ): StructuredToolInterface[] { // Back-compat for the Phase 1 readOnly flag — maps to read-only mode. let readEnabled = options.readEnabled; let writeEnabled = options.writeEnabled; if (options.readOnly) { readEnabled = true; writeEnabled = false; } // Default: if neither flag supplied, attach both (back-compat with the // pre-Phase-2 single-flag caller). if (readEnabled === undefined && writeEnabled === undefined) { readEnabled = true; writeEnabled = true; } const binding: MemoryToolBinding = { backend: options.backend, scope: options.scope, maxInjectedChars: options.search?.maxInjectedChars, searchOptions: { mmr: options.search?.mmr, temporalDecay: options.search?.temporalDecay, citations: options.search?.citations, }, recallTracker: options.recallTracker, }; const tools: StructuredToolInterface[] = []; if (readEnabled) { tools.push( createMemorySearchTool(binding) as unknown as StructuredToolInterface, createMemoryGetTool(binding) as unknown as StructuredToolInterface ); } if (writeEnabled) { const getPhase: () => MemoryPhase = options.getPhase ?? ((): MemoryPhase => 'normal'); tools.push( createMemoryAppendTool({ ...binding, getPhase, }) as unknown as StructuredToolInterface ); } return tools; }