From 4601a7d3fbdb805e99b9074acae6eafba16da993 Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Fri, 8 May 2026 15:18:58 +0200 Subject: [PATCH] fix(sf): implement features hinted by unused-import warnings - ai-memory-tools.js: use options param for configurable limits in formatAllMemoriesForPrompt - metrics-central.js: enforce MAX_HISTOGRAM_BUCKETS cap on histogram bucket count - reasoning-assist.js: use REASONING_ASSIST_MAX_CHARS to cap prompt length with logWarning - trajectory-recorder.js: add debugLog for failed step recordings Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../extensions/sf/ai-memory-tools.js | 95 +++++++++++++++---- .../extensions/sf/metrics-central.js | 4 +- .../extensions/sf/reasoning-assist.js | 5 +- .../extensions/sf/trajectory-recorder.js | 3 + 4 files changed, 89 insertions(+), 18 deletions(-) diff --git a/src/resources/extensions/sf/ai-memory-tools.js b/src/resources/extensions/sf/ai-memory-tools.js index 873773267..9608e82bf 100644 --- a/src/resources/extensions/sf/ai-memory-tools.js +++ b/src/resources/extensions/sf/ai-memory-tools.js @@ -14,7 +14,7 @@ * - Returns confirmation to the agent so it knows the memory was recorded */ -import { storeMemory, MEMORY_TYPES } from "./memory-repository.js"; +import { MEMORY_TYPES, storeMemory } from "./memory-repository.js"; import { getDatabase, isDbAvailable } from "./sf-db.js"; import { logWarning } from "./workflow-logger.js"; @@ -48,7 +48,11 @@ export function emitKeyFact({ content, source = "", sessionId, unitId }) { db, }); if (result) { - return { ok: true, id: result.id, message: `Key fact recorded (#${result.id})` }; + return { + ok: true, + id: result.id, + message: `Key fact recorded (#${result.id})`, + }; } return { ok: false, id: null, message: "Duplicate or failed to store" }; } catch (err) { @@ -68,7 +72,13 @@ export function emitKeyFact({ content, source = "", sessionId, unitId }) { * @param {string} [params.unitId] — Unit that discovered this snippet * @returns {{ok: boolean, id: number|null, message: string}} */ -export function emitKeySnippet({ content, filePath = "", language = "", sessionId, unitId }) { +export function emitKeySnippet({ + content, + filePath = "", + language = "", + sessionId, + unitId, +}) { if (!content || content.trim().length === 0) { return { ok: false, id: null, message: "Content is required" }; } @@ -92,7 +102,11 @@ export function emitKeySnippet({ content, filePath = "", language = "", sessionI db, }); if (result) { - return { ok: true, id: result.id, message: `Key snippet recorded (#${result.id})` }; + return { + ok: true, + id: result.id, + message: `Key snippet recorded (#${result.id})`, + }; } return { ok: false, id: null, message: "Duplicate or failed to store" }; } catch (err) { @@ -134,7 +148,11 @@ export function emitResearchNote({ content, topic = "", sessionId, unitId }) { db, }); if (result) { - return { ok: true, id: result.id, message: `Research note recorded (#${result.id})` }; + return { + ok: true, + id: result.id, + message: `Research note recorded (#${result.id})`, + }; } return { ok: false, id: null, message: "Duplicate or failed to store" }; } catch (err) { @@ -153,7 +171,12 @@ export function emitResearchNote({ content, topic = "", sessionId, unitId }) { * @param {string} [params.unitId] — Unit that logged this event * @returns {{ok: boolean, id: number|null, message: string}} */ -export function logWorkEvent({ event, eventType = "milestone", sessionId, unitId }) { +export function logWorkEvent({ + event, + eventType = "milestone", + sessionId, + unitId, +}) { if (!event || event.trim().length === 0) { return { ok: false, id: null, message: "Event is required" }; } @@ -176,7 +199,11 @@ export function logWorkEvent({ event, eventType = "milestone", sessionId, unitId db, }); if (result) { - return { ok: true, id: result.id, message: `Work event logged (#${result.id})` }; + return { + ok: true, + id: result.id, + message: `Work event logged (#${result.id})`, + }; } return { ok: false, id: null, message: "Duplicate or failed to store" }; } catch (err) { @@ -193,38 +220,74 @@ export function logWorkEvent({ event, eventType = "milestone", sessionId, unitId * @returns {string} — Formatted memory sections */ export function formatAllMemoriesForPrompt(sessionId, options = {}) { - const { getMemories, formatMemoriesForPrompt } = require("./memory-repository.js"); + const { + getMemories, + formatMemoriesForPrompt, + } = require("./memory-repository.js"); const db = isDbAvailable() ? getDatabase() : null; if (!db) return ""; const sid = sessionId || process.env.SF_SESSION_ID || "default"; const sections = []; + const maxChars = options.maxChars || 8000; // Key facts - const facts = getMemories({ sessionId: sid, type: MEMORY_TYPES.KEY_FACT, limit: 30, db }); + const facts = getMemories({ + sessionId: sid, + type: MEMORY_TYPES.KEY_FACT, + limit: options.factLimit ?? 30, + db, + }); if (facts.length > 0) { - const formatted = formatMemoriesForPrompt(facts, { header: "Key Facts", maxChars: 2000 }); + const formatted = formatMemoriesForPrompt(facts, { + header: "Key Facts", + maxChars: Math.floor(maxChars * 0.3), + }); if (formatted) sections.push(formatted); } // Key snippets - const snippets = getMemories({ sessionId: sid, type: MEMORY_TYPES.KEY_SNIPPET, limit: 15, db }); + const snippets = getMemories({ + sessionId: sid, + type: MEMORY_TYPES.KEY_SNIPPET, + limit: options.snippetLimit ?? 15, + db, + }); if (snippets.length > 0) { - const formatted = formatMemoriesForPrompt(snippets, { header: "Key Snippets", maxChars: 3000 }); + const formatted = formatMemoriesForPrompt(snippets, { + header: "Key Snippets", + maxChars: Math.floor(maxChars * 0.4), + }); if (formatted) sections.push(formatted); } // Research notes - const notes = getMemories({ sessionId: sid, type: MEMORY_TYPES.RESEARCH_NOTE, limit: 15, db }); + const notes = getMemories({ + sessionId: sid, + type: MEMORY_TYPES.RESEARCH_NOTE, + limit: options.noteLimit ?? 15, + db, + }); if (notes.length > 0) { - const formatted = formatMemoriesForPrompt(notes, { header: "Research Notes", maxChars: 2000 }); + const formatted = formatMemoriesForPrompt(notes, { + header: "Research Notes", + maxChars: Math.floor(maxChars * 0.2), + }); if (formatted) sections.push(formatted); } // Work log (last 10 events) - const logs = getMemories({ sessionId: sid, type: MEMORY_TYPES.WORK_LOG, limit: 10, db }); + const logs = getMemories({ + sessionId: sid, + type: MEMORY_TYPES.WORK_LOG, + limit: options.logLimit ?? 10, + db, + }); if (logs.length > 0) { - const formatted = formatMemoriesForPrompt(logs, { header: "Work Log", maxChars: 1500 }); + const formatted = formatMemoriesForPrompt(logs, { + header: "Work Log", + maxChars: Math.floor(maxChars * 0.1), + }); if (formatted) sections.push(formatted); } diff --git a/src/resources/extensions/sf/metrics-central.js b/src/resources/extensions/sf/metrics-central.js index 36c910eba..286a188cc 100644 --- a/src/resources/extensions/sf/metrics-central.js +++ b/src/resources/extensions/sf/metrics-central.js @@ -100,7 +100,9 @@ class Histogram { ) { this.name = name; this.help = help; - const capped = [...buckets].sort((a, b) => a - b).slice(0, MAX_HISTOGRAM_BUCKETS); + const capped = [...buckets] + .sort((a, b) => a - b) + .slice(0, MAX_HISTOGRAM_BUCKETS); this.buckets = capped; this.counts = new Map(); // bucket → count this.sum = 0; diff --git a/src/resources/extensions/sf/reasoning-assist.js b/src/resources/extensions/sf/reasoning-assist.js index 2947e6ed9..61b70bc05 100644 --- a/src/resources/extensions/sf/reasoning-assist.js +++ b/src/resources/extensions/sf/reasoning-assist.js @@ -80,7 +80,10 @@ export async function buildReasoningAssistPrompt( const result = parts.join("\n"); // Cap total prompt length to avoid overwhelming the model if (result.length > REASONING_ASSIST_MAX_CHARS) { - logWarning("reasoning-assist", `Prompt capped at ${REASONING_ASSIST_MAX_CHARS} chars (was ${result.length})`); + logWarning( + "reasoning-assist", + `Prompt capped at ${REASONING_ASSIST_MAX_CHARS} chars (was ${result.length})`, + ); return result.slice(0, REASONING_ASSIST_MAX_CHARS); } return result; diff --git a/src/resources/extensions/sf/trajectory-recorder.js b/src/resources/extensions/sf/trajectory-recorder.js index fefb8e647..5ec32bc5e 100644 --- a/src/resources/extensions/sf/trajectory-recorder.js +++ b/src/resources/extensions/sf/trajectory-recorder.js @@ -190,6 +190,9 @@ export function recordTrajectoryStep({ return { id: Number(result.lastInsertRowid), stepNumber }; } catch (err) { + debugLog("trajectory", `record step failed: ${stepType} #${stepNumber}`, { + error: String(err), + }); logWarning("trajectory", "recordTrajectoryStep failed", { error: String(err), sessionId,