diff --git a/docs/concepts/memory.md b/docs/concepts/memory.md index 8f326d92eb..2983074d3a 100644 --- a/docs/concepts/memory.md +++ b/docs/concepts/memory.md @@ -126,7 +126,7 @@ out to QMD for retrieval. Key points: - `paths[]`: add extra directories/files (`path`, optional `pattern`, optional stable `name`). - `sessions`: opt into session JSONL indexing (`enabled`, `retentionDays`, - `exportDir`, `redactToolOutputs`—defaults to redacting tool payloads). + `exportDir`). - `update`: controls refresh cadence (`interval`, `debounceMs`, `onBoot`). - `limits`: clamp recall payload (`maxResults`, `maxSnippetChars`, `maxInjectedChars`, `timeoutMs`). diff --git a/src/config/schema.ts b/src/config/schema.ts index 0628037378..edc203d3d5 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -266,7 +266,6 @@ const FIELD_LABELS: Record = { "memory.qmd.sessions.enabled": "QMD Session Indexing", "memory.qmd.sessions.exportDir": "QMD Session Export Directory", "memory.qmd.sessions.retentionDays": "QMD Session Retention (days)", - "memory.qmd.sessions.redactToolOutputs": "QMD Session Tool Redaction", "memory.qmd.update.interval": "QMD Update Interval", "memory.qmd.update.debounceMs": "QMD Update Debounce (ms)", "memory.qmd.update.onBoot": "QMD Update on Startup", @@ -587,8 +586,6 @@ const FIELD_HELP: Record = { "Override directory for sanitized session exports before indexing.", "memory.qmd.sessions.retentionDays": "Retention window for exported sessions before pruning (default: unlimited).", - "memory.qmd.sessions.redactToolOutputs": - "Strip tool call payloads/results when exporting sessions (default: true).", "memory.qmd.update.interval": "How often the QMD sidecar refreshes indexes (duration string, default: 5m).", "memory.qmd.update.debounceMs": diff --git a/src/config/types.memory.ts b/src/config/types.memory.ts index a6bb5eeb3d..dad2f97842 100644 --- a/src/config/types.memory.ts +++ b/src/config/types.memory.ts @@ -29,7 +29,6 @@ export type MemoryQmdSessionConfig = { enabled?: boolean; exportDir?: string; retentionDays?: number; - redactToolOutputs?: boolean; }; export type MemoryQmdUpdateConfig = { diff --git a/src/config/zod-schema.ts b/src/config/zod-schema.ts index 46f4fc16c6..1fb4c923cc 100644 --- a/src/config/zod-schema.ts +++ b/src/config/zod-schema.ts @@ -45,7 +45,6 @@ const MemoryQmdSessionSchema = z enabled: z.boolean().optional(), exportDir: z.string().optional(), retentionDays: z.number().int().nonnegative().optional(), - redactToolOutputs: z.boolean().optional(), }) .strict(); diff --git a/src/memory/backend-config.ts b/src/memory/backend-config.ts index c7c4a01220..15851ef297 100644 --- a/src/memory/backend-config.ts +++ b/src/memory/backend-config.ts @@ -42,7 +42,6 @@ export type ResolvedQmdSessionConfig = { enabled: boolean; exportDir?: string; retentionDays?: number; - redactToolOutputs: boolean; }; export type ResolvedQmdConfig = { @@ -147,12 +146,10 @@ function resolveSessionConfig( const exportDir = exportDirRaw ? resolvePath(exportDirRaw, workspaceDir) : undefined; const retentionDays = cfg?.retentionDays && cfg.retentionDays > 0 ? Math.floor(cfg.retentionDays) : undefined; - const redactToolOutputs = cfg?.redactToolOutputs !== false; return { enabled, exportDir, retentionDays, - redactToolOutputs, }; } diff --git a/src/memory/qmd-manager.ts b/src/memory/qmd-manager.ts index 28e68bca4b..a543901124 100644 --- a/src/memory/qmd-manager.ts +++ b/src/memory/qmd-manager.ts @@ -225,7 +225,7 @@ export class QmdMemoryManager implements MemorySearchManager { source: doc.source, }); } - return results.slice(0, limit); + return this.clampResultsByInjectedChars(results.slice(0, limit)); } async sync(params?: { @@ -609,4 +609,24 @@ export class QmdMemoryManager implements MemorySearchManager { const next = candidate.endsWith(path.sep) ? candidate : `${candidate}${path.sep}`; return next.startsWith(normalizedRoot); } + + private clampResultsByInjectedChars(results: MemorySearchResult[]): MemorySearchResult[] { + const budget = this.qmd.limits.maxInjectedChars; + 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; + } } diff --git a/src/memory/search-manager.ts b/src/memory/search-manager.ts index f3a0f07afa..a642f46581 100644 --- a/src/memory/search-manager.ts +++ b/src/memory/search-manager.ts @@ -111,10 +111,12 @@ class FallbackMemoryManager implements MemorySearchManager { return this.deps.primary.status(); } const fallbackStatus = this.fallback?.status(); + const fallbackInfo = { from: "qmd", reason: this.lastError ?? "unknown" }; if (fallbackStatus) { const custom = fallbackStatus.custom ?? {}; return { ...fallbackStatus, + fallback: fallbackInfo, custom: { ...custom, fallback: { disabled: true, reason: this.lastError ?? "unknown" }, @@ -125,6 +127,7 @@ class FallbackMemoryManager implements MemorySearchManager { const custom = primaryStatus.custom ?? {}; return { ...primaryStatus, + fallback: fallbackInfo, custom: { ...custom, fallback: { disabled: true, reason: this.lastError ?? "unknown" }, diff --git a/src/memory/types.ts b/src/memory/types.ts index c26940ede8..40abf99ea8 100644 --- a/src/memory/types.ts +++ b/src/memory/types.ts @@ -27,6 +27,7 @@ export type MemoryProviderStatus = { workspaceDir?: string; dbPath?: string; sources?: MemorySource[]; + sourceCounts?: Array<{ source: MemorySource; files: number; chunks: number }>; cache?: { enabled: boolean; entries?: number; maxEntries?: number }; fts?: { enabled: boolean; available: boolean; error?: string }; fallback?: { from: string; reason?: string };