Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ function safeParseInt(value: string | undefined, fallback: number): number {
const DATA_DIR = join(homedir(), ".agentmemory");
const ENV_FILE = join(DATA_DIR, ".env");

/**
* Resolved paths that the runtime actually reads. Exported so error
* messages can show users the exact location where their flags belong,
* which matters when HOME differs from the expected user dir (LaunchAgent
* plists, systemd units, Docker, etc.).
*/
export const RESOLVED_PATHS = {
dataDir: DATA_DIR,
envFile: ENV_FILE,
envFileExists: (): boolean => existsSync(ENV_FILE),
};

function loadEnvFile(): Record<string, string> {
if (!existsSync(ENV_FILE)) return {};
const content = readFileSync(ENV_FILE, "utf-8");
Expand Down
33 changes: 28 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
isConsolidationEnabled,
isContextInjectionEnabled,
isDropStaleIndexEnabled,
RESOLVED_PATHS,
} from "./config.js";
import {
createProvider,
Expand Down Expand Up @@ -387,18 +388,40 @@ async function main() {
`AGENTMEMORY_DROP_STALE_INDEX=true is set — discarding the persisted ` +
`vectors. Live observations will rebuild the index over time.`,
);
// Persist the empty vector index back so subsequent starts don't
// trip the same guard. Without this, the KV still holds the stale
// payload, so removing AGENTMEMORY_DROP_STALE_INDEX from .env would
// crash-loop the server again on the next boot.
await indexPersistence.save().catch((err) => {
console.warn(
`[agentmemory] Failed to persist cleared vector index:`,
err,
);
});
} else {
const envExists = RESOLVED_PATHS.envFileExists();
throw new Error(
`[agentmemory] Refusing to start: persisted vector index has ` +
`${mismatches.length} of ${loaded.vector.size} vectors with the ` +
`wrong dimension. Active provider (${embeddingProvider?.name}) ` +
`declares ${activeDim}; dimensions seen on disk: ${distinct}. ` +
`First mismatched obsIds: ${sample}. Loading would silently corrupt ` +
`search (cross-dimension cosine returns 0). Choose one:\n` +
` - Re-embed the existing index against the new provider, then start.\n` +
` - Set AGENTMEMORY_DROP_STALE_INDEX=true to discard the persisted ` +
`vectors and rebuild from live observations.\n` +
` - Switch the embedding provider back to the one that wrote the index.`,
`search (cross-dimension cosine returns 0).\n` +
`\n` +
`Resolved paths:\n` +
` data dir: ${RESOLVED_PATHS.dataDir}\n` +
` env file: ${RESOLVED_PATHS.envFile} (exists: ${envExists})\n` +
`\n` +
`Recovery — pick ONE:\n` +
` 1. One-shot drop + rebuild (recommended):\n` +
` echo 'AGENTMEMORY_DROP_STALE_INDEX=true' >> ${RESOLVED_PATHS.envFile}\n` +
` # restart agentmemory; the flag can be removed after the next clean boot.\n` +
Comment on lines +416 to +418
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Quote the env-file path in the recovery command.

Line 417 inserts the raw path into shell syntax. If the resolved HOME path contains spaces or shell metacharacters, the suggested copy-paste recovery step breaks, which undercuts the main operator guidance in this error path. Please shell-quote or escape RESOLVED_PATHS.envFile before printing it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/index.ts` around lines 416 - 418, The printed recovery command inserts
RESOLVED_PATHS.envFile raw into the shell snippet which breaks if the path
contains spaces or shell metacharacters; update the template in src/index.ts to
shell-quote or escape RESOLVED_PATHS.envFile before interpolation (e.g., call an
escape helper like escapeShellArg or wrap the path in single quotes while
escaping any embedded single quotes) so the printed command is safe to
copy-paste; ensure you replace the direct interpolation of
RESOLVED_PATHS.envFile in the multiline string with the escaped/quoted value.

` 2. Re-embed the existing index against the new provider, then start.\n` +
` 3. Switch the embedding provider back to the one that wrote the index.\n` +
`\n` +
`If running under a service manager (LaunchAgent, systemd, Docker), confirm\n` +
`HOME points at the user account that owns ${RESOLVED_PATHS.dataDir} —\n` +
`the .env file above is what the running process actually reads.`,
);
}
} else {
Expand Down