From 1861e76360407981ced3027a4df68a01b4114baf Mon Sep 17 00:00:00 2001 From: Benjamin Jesuiter Date: Mon, 2 Feb 2026 20:48:20 +0100 Subject: [PATCH] Memory: clamp QMD citations to injected budget --- src/agents/tools/memory-tool.ts | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/agents/tools/memory-tool.ts b/src/agents/tools/memory-tool.ts index 1cf5b3356..b9c5d8d06 100644 --- a/src/agents/tools/memory-tool.ts +++ b/src/agents/tools/memory-tool.ts @@ -2,6 +2,7 @@ import { Type } from "@sinclair/typebox"; import type { MoltbotConfig } from "../../config/config.js"; import type { MemoryCitationsMode } from "../../config/types.memory.js"; +import { resolveMemoryBackendConfig } from "../../memory/backend-config.js"; import { getMemorySearchManager } from "../../memory/index.js"; import type { MemorySearchResult } from "../../memory/types.js"; import { resolveSessionAgentId } from "../agent-scope.js"; @@ -61,7 +62,12 @@ export function createMemorySearchTool(options: { sessionKey: options.agentSessionKey, }); const status = manager.status(); - const results = decorateCitations(rawResults, includeCitations); + const decorated = decorateCitations(rawResults, includeCitations); + const resolved = resolveMemoryBackendConfig({ cfg, agentId }); + const results = + status.backend === "qmd" + ? clampResultsByInjectedChars(decorated, resolved.qmd?.limits.maxInjectedChars) + : decorated; return jsonResult({ results, provider: status.provider, @@ -145,6 +151,28 @@ function formatCitation(entry: MemorySearchResult): string { return `${entry.path}${lineRange}`; } +function clampResultsByInjectedChars( + results: MemorySearchResult[], + budget?: number, +): MemorySearchResult[] { + if (!budget || budget <= 0) return results; + let remaining = budget; + const clamped: MemorySearchResult[] = []; + for (const entry of results) { + if (remaining <= 0) break; + const snippet = entry.snippet ?? ""; + if (snippet.length <= remaining) { + clamped.push(entry); + remaining -= snippet.length; + } else { + const trimmed = snippet.slice(0, Math.max(0, remaining)); + clamped.push({ ...entry, snippet: trimmed }); + break; + } + } + return clamped; +} + function shouldIncludeCitations(params: { mode: MemoryCitationsMode; sessionKey?: string;