/** * Autonomous memory — shared constants. * * Single source of truth for defaults, limits, and magic strings used across * the memory store, tools, flush phase, and tests. Changing a value here * changes it everywhere — no hunting through files. */ /** Default embedding provider when {@link process.env.MEMORY_EMBEDDINGS_PROVIDER} is unset. */ export const DEFAULT_MEMORY_PROVIDER = 'bedrock' as const; /** Default embedding model (Titan v2 — AWS-native, 6× cheaper than Cohere v4). */ export const DEFAULT_MEMORY_MODEL = 'amazon.titan-embed-text-v2:0'; /** Default vector width (Titan v2 supports 256 / 512 / 1024). */ export const DEFAULT_MEMORY_DIMENSIONS = 1024; /** Default Postgres table name; can be overridden via env for dev/prod sharing. */ export const DEFAULT_MEMORY_TABLE = 'agent_memories'; /** Default Postgres schema. */ export const DEFAULT_MEMORY_SCHEMA = 'public'; /** Phase values used by the flush-phase gate. */ export const MEMORY_PHASE_NORMAL = 'normal'; export const MEMORY_PHASE_FLUSHING = 'memory_flushing'; /** * Search defaults — aligned with upstream's upstream defaults. * * Sources: * - `upstream reference` → maxResults=6 * - `upstream reference` → maxInjectedChars=4000 * * Keeping these in lockstep with upstream means the mandatory-recall tool * description, budget clamps, and eval corpora line up with upstream's * tuning — we inherit their calibration instead of re-tuning from scratch. */ export const DEFAULT_MAX_SEARCH_RESULTS = 6; export const DEFAULT_MIN_SCORE = 0.1; export const DEFAULT_MAX_INJECTED_CHARS = 4000; /** Hybrid retrieval weights — 70% vector cosine, 30% BM25 / ts_rank text score. */ export const HYBRID_VECTOR_WEIGHT = 0.7; export const HYBRID_TEXT_WEIGHT = 0.3; /** * Phase 2 rerank defaults — ported from upstream. * * Sources: * - `upstream reference` → lambda=0.7 * - `upstream reference` → halfLifeDays=30 * * Both features are opt-in (enabled=false by default) — the Phase 2 * features are layered on top of hybrid search and don't change default * behavior for callers that upgrade in place. */ export const DEFAULT_MMR_ENABLED = false; export const DEFAULT_MMR_LAMBDA = 0.7; export const DEFAULT_TEMPORAL_DECAY_ENABLED = false; export const DEFAULT_TEMPORAL_DECAY_HALF_LIFE_DAYS = 30; export const DEFAULT_RECALL_TRACKING_ENABLED = false; export const DEFAULT_CITATIONS_MODE = 'auto' as const; /** * Flush trigger margins (token counts) — aligned with upstream upstream. * * Sources: * - `upstream reference` → softThreshold=4000 * - `upstream reference` → reserveFloor=20000 */ export const DEFAULT_FLUSH_SOFT_THRESHOLD_TOKENS = 4000; export const DEFAULT_FLUSH_RESERVE_FLOOR_TOKENS = 20000; /** Hard cap on append calls per flush phase — prevents runaway writes. */ export const DEFAULT_MAX_APPENDS_PER_FLUSH = 20; /** * Hard cap on agentic loop iterations inside {@link runMemoryFlush}. * * Each iteration = one model.invoke() followed by execution of any * `memory_append` tool_calls it emits. Mirrors upstream's flush-plan * loop cap; 8 is enough for ~2–3 reflections of batched notes while * protecting against runaway cycles if the model refuses to stop. */ export const DEFAULT_MAX_FLUSH_ITERATIONS = 8; /** Path prefix enforced on every append. Paths outside this are rejected. */ export const MEMORY_PATH_PREFIX = 'memory/'; /** Tool names — kept as constants so server code + tests never drift. */ export const MEMORY_SEARCH_TOOL_NAME = 'memory_search'; export const MEMORY_GET_TOOL_NAME = 'memory_get'; export const MEMORY_APPEND_TOOL_NAME = 'memory_append'; /** * Mandatory-recall description — the single most load-bearing line in the * whole memory system. Do not soften, shorten, or reword without an eval run. * * Ported VERBATIM from upstream `extensions/memory-core/src/tools.ts:186`. * The wiki/corpus clause is retained even though Phase 1 doesn't ship * compiled-wiki supplements — keeping the string identical means upstream's * eval corpora remain drop-in valid. */ export const MEMORY_SEARCH_DESCRIPTION = 'Mandatory recall step: semantically search MEMORY.md + memory/*.md ' + '(and optional session transcripts) before answering questions about ' + 'prior work, decisions, dates, people, preferences, or todos. Optional ' + '`corpus=wiki` or `corpus=all` also searches registered compiled-wiki ' + 'supplements. If response has disabled=true, memory retrieval is ' + 'unavailable and should be surfaced to the user.'; /** * Ported VERBATIM from upstream `extensions/memory-core/src/tools.ts:322`. */ export const MEMORY_GET_DESCRIPTION = 'Safe snippet read from MEMORY.md or memory/*.md with optional from/lines; ' + '`corpus=wiki` reads from registered compiled-wiki supplements. Use after ' + 'search to pull only the needed lines and keep context small.'; /** * `memory_append` tool description. * * Phase 1 historically wrote to a single date-keyed file * (`memory/YYYY-MM-DD.md`), ported verbatim from upstream. That scheme * is now replaced by an 8-path canonical whitelist — see * {@link ./paths.MEMORY_ALL_PATHS}. The tool description no longer * names a specific file; the flush-turn prompt renders the full rubric * inline so the model sees every writable path at inference time. */ export const MEMORY_APPEND_DESCRIPTION = "Append a durable note to one of the agent's canonical memory documents. " + 'The `path` argument MUST be one of the whitelisted paths listed in the ' + 'flush prompt rubric — unknown paths are rejected. Content is merged into ' + 'the existing row for that document via UPSERT, so the same document ' + 'accumulates across sessions.'; /** * Reply token that signals the flush turn produced no user-visible output. * Ported VERBATIM from upstream `src/auto-reply/tokens.ts:4`. */ export const SILENT_REPLY_TOKEN = 'NO_REPLY'; /** * Placeholder replaced at flush time with the rendered path-rubric for * the caller's scope. See `renderPathsRubric()` in `./paths.ts` and * `resolveFlushPrompts()` in `../prompts/memoryFlushPrompt.ts`. * * Kept as a unique sentinel so `replaceAll` is safe even if the rubric * content happens to contain regex metacharacters. */ export const FLUSH_PROMPT_RUBRIC_PLACEHOLDER = '{{MEMORY_PATHS_RUBRIC}}'; /** * Memory-flush prompts — canonical-document model. * * Every durable memory routes into one of 8 stable canonical documents * (4 agent-tier + 4 user-tier). The rubric is injected at flush time so * the model reads the authoritative path list with descriptions, and for * isolated/autonomous agents the user-tier rows are transparently omitted * from the rubric — making "user-tier writes require a scoped caller" a * compile-time guarantee rather than a runtime check alone. * * Two-tier semantics the prompt enforces: * - **agent/** — shared operational knowledge; every user of this agent * benefits from rows written here. Do NOT put personal facts here. * - **user/** — personalization for the specific caller only. Row is * private to that user; other users never see it. */ const MEMORY_FLUSH_ROUTING_HINT = 'Route every note into exactly one of the canonical documents below by ' + 'picking the best match. Do NOT invent new paths; do NOT create date-keyed ' + 'files; unknown paths are rejected by the store.'; const MEMORY_FLUSH_TIER_HINT = 'Two tiers: `memory/agent/*` is SHARED operational knowledge visible to ' + 'every user of this agent — put successful patterns, pitfalls, domain ' + 'facts, and house-style there. `memory/user/*` is PRIVATE to the specific ' + 'caller — put their identity, preferences, projects, and references there. ' + 'Never put user-specific facts in an agent/* document.'; const MEMORY_FLUSH_READ_ONLY_HINT = 'Treat workspace bootstrap/reference files such as MEMORY.md, DREAMS.md, SOUL.md, TOOLS.md, and AGENTS.md as read-only during this flush; never overwrite, replace, or edit them.'; /** * Learning hint — steers the flush turn to capture the things that * matter most for future turns: reusable patterns, tool failures * (so the same mistake is not repeated), explicit corrections, and * durable user-specific facts. Append-only via `memory_append`; one * note per lesson. */ const MEMORY_FLUSH_LEARNING_HINT = 'Capture durable lessons the agent (and future turns) should retain: ' + '(a) successful task patterns and workflows → memory/agent/playbook.md; ' + '(b) tool failures and schema mistakes → memory/agent/pitfalls.md; ' + '(c) stable domain facts about the systems/APIs → memory/agent/domain.md; ' + "(d) this user's preferences, tone, and corrections → memory/user/preferences.md; " + "(e) this user's identity and role → memory/user/profile.md. " + 'Write one note per distinct lesson. Do not log conversation summaries ' + 'or anything derivable from the code or recent history.'; const MEMORY_FLUSH_RUBRIC_BLOCK = 'Canonical documents available for this turn (path — tag — description):\n' + FLUSH_PROMPT_RUBRIC_PLACEHOLDER; export const DEFAULT_MEMORY_FLUSH_PROMPT = [ 'Pre-compaction memory flush.', MEMORY_FLUSH_ROUTING_HINT, MEMORY_FLUSH_TIER_HINT, MEMORY_FLUSH_READ_ONLY_HINT, MEMORY_FLUSH_LEARNING_HINT, 'Call the `memory_append` tool for every note you want to persist, passing one of the whitelisted paths as the `path` argument. Do NOT describe what you are about to write; just call the tool.', `If nothing worth storing, reply with exactly ${SILENT_REPLY_TOKEN}.`, '', MEMORY_FLUSH_RUBRIC_BLOCK, ].join('\n'); export const DEFAULT_MEMORY_FLUSH_SYSTEM_PROMPT = [ 'Pre-compaction memory flush turn.', 'The session is near auto-compaction; capture durable memories to disk.', MEMORY_FLUSH_ROUTING_HINT, MEMORY_FLUSH_TIER_HINT, MEMORY_FLUSH_READ_ONLY_HINT, MEMORY_FLUSH_LEARNING_HINT, 'Use the `memory_append` tool for every durable note, with `path` set to one of the whitelisted canonical documents. Never claim you wrote a note without actually calling the tool.', `If there is nothing worth storing, reply with exactly ${SILENT_REPLY_TOKEN}.`, '', MEMORY_FLUSH_RUBRIC_BLOCK, ].join('\n');