feat(FN-3718): add agent workspace memory reader and include workspace memo
Merged branch lands two features: FN-3718 wires workspace memory into the agent instruction pipeline — adding a reader helper, injecting workspace memory into agent instructions and identity snapshots, and documenting the resolution order — and FN-3716 adds planning mode priority controls for task r Fusion-Task-Id: FN-3718
This commit is contained in:
@@ -19,7 +19,6 @@ import { ResearchStepRunner } from "./research-step-runner.js";
|
||||
import type { ToolDefinition } from "@mariozechner/pi-coding-agent";
|
||||
import { Type, type Static } from "@mariozechner/pi-ai";
|
||||
import type { AgentReflectionService } from "./agent-reflection.js";
|
||||
import { MAX_INSTRUCTIONS_TEXT_LENGTH, MAX_MEMORY_LENGTH, MAX_SOUL_LENGTH } from "./agent-instructions.js";
|
||||
import { createLogger } from "./logger.js";
|
||||
|
||||
// ── Tool parameter schemas (canonical definitions) ────────────────────────
|
||||
@@ -194,6 +193,10 @@ type MemorySearchHit = {
|
||||
|
||||
const log = createLogger("agent-tools");
|
||||
|
||||
const MAX_INSTRUCTIONS_TEXT_LENGTH = 50_000;
|
||||
const MAX_MEMORY_LENGTH = 50_000;
|
||||
const MAX_SOUL_LENGTH = 10_000;
|
||||
|
||||
const AGENT_MEMORY_ROOT = ".fusion/agent-memory";
|
||||
const AGENT_MEMORY_FILENAME = "MEMORY.md";
|
||||
const AGENT_DREAMS_FILENAME = "DREAMS.md";
|
||||
@@ -201,11 +204,11 @@ const agentQmdRefreshState = new Map<string, { lastStartedAt: number; inFlight?:
|
||||
const AGENT_QMD_REFRESH_INTERVAL_MS = 5 * 60 * 1000;
|
||||
const DAILY_AGENT_MEMORY_RE = /^\d{4}-\d{2}-\d{2}\.md$/;
|
||||
|
||||
function sanitizeAgentMemoryId(agentId: string): string {
|
||||
export function sanitizeAgentMemoryId(agentId: string): string {
|
||||
return agentId.trim().replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "agent";
|
||||
}
|
||||
|
||||
function agentMemoryDisplayPath(agentId: string): string {
|
||||
export function agentMemoryDisplayPath(agentId: string): string {
|
||||
return `${AGENT_MEMORY_ROOT}/${sanitizeAgentMemoryId(agentId)}/${AGENT_MEMORY_FILENAME}`;
|
||||
}
|
||||
|
||||
@@ -217,7 +220,7 @@ function agentMemoryDirectory(rootDir: string, agentId: string): string {
|
||||
return join(rootDir, AGENT_MEMORY_ROOT, sanitizeAgentMemoryId(agentId));
|
||||
}
|
||||
|
||||
function agentMemoryFilePath(rootDir: string, agentId: string): string {
|
||||
export function agentMemoryFilePath(rootDir: string, agentId: string): string {
|
||||
return join(agentMemoryDirectory(rootDir, agentId), AGENT_MEMORY_FILENAME);
|
||||
}
|
||||
|
||||
@@ -229,6 +232,26 @@ function agentDailyFilePath(rootDir: string, agentId: string, date = new Date())
|
||||
return join(agentMemoryDirectory(rootDir, agentId), `${date.toISOString().slice(0, 10)}.md`);
|
||||
}
|
||||
|
||||
export async function readAgentMemoryWorkspaceLongTerm(rootDir: string, agentId: string): Promise<string> {
|
||||
const safeRoot = typeof rootDir === "string" ? rootDir.trim() : "";
|
||||
const safeAgentId = typeof agentId === "string" ? agentId.trim() : "";
|
||||
if (!safeRoot || !safeAgentId) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const filePath = agentMemoryFilePath(safeRoot, safeAgentId);
|
||||
try {
|
||||
const fileStat = await stat(filePath);
|
||||
if (!fileStat.isFile()) {
|
||||
return "";
|
||||
}
|
||||
const content = await readFile(filePath, "utf-8");
|
||||
return typeof content === "string" ? content.trim() : "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
export function qmdAgentMemoryCollectionName(rootDir: string, agentId: string): string {
|
||||
const hash = createHash("sha1").update(`${rootDir}:${agentId}`).digest("hex").slice(0, 12);
|
||||
return `fusion-agent-memory-${sanitizeAgentMemoryId(agentId).toLowerCase()}-${hash}`;
|
||||
|
||||
Reference in New Issue
Block a user