agentx-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +561 -0
- package/dist/agent.d.ts +105 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +690 -0
- package/dist/agent.js.map +1 -0
- package/dist/config/config.d.ts +346 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +93 -0
- package/dist/config/config.js.map +1 -0
- package/dist/contracts/entities/agent-event.d.ts +97 -0
- package/dist/contracts/entities/agent-event.d.ts.map +1 -0
- package/dist/contracts/entities/agent-event.js +2 -0
- package/dist/contracts/entities/agent-event.js.map +1 -0
- package/dist/contracts/entities/agent-skill.d.ts +59 -0
- package/dist/contracts/entities/agent-skill.d.ts.map +1 -0
- package/dist/contracts/entities/agent-skill.js +2 -0
- package/dist/contracts/entities/agent-skill.js.map +1 -0
- package/dist/contracts/entities/agent-tool.d.ts +42 -0
- package/dist/contracts/entities/agent-tool.d.ts.map +1 -0
- package/dist/contracts/entities/agent-tool.js +2 -0
- package/dist/contracts/entities/agent-tool.js.map +1 -0
- package/dist/contracts/entities/chat-message.d.ts +13 -0
- package/dist/contracts/entities/chat-message.d.ts.map +1 -0
- package/dist/contracts/entities/chat-message.js +2 -0
- package/dist/contracts/entities/chat-message.js.map +1 -0
- package/dist/contracts/entities/content-part.d.ts +16 -0
- package/dist/contracts/entities/content-part.d.ts.map +1 -0
- package/dist/contracts/entities/content-part.js +2 -0
- package/dist/contracts/entities/content-part.js.map +1 -0
- package/dist/contracts/entities/execution-context.d.ts +9 -0
- package/dist/contracts/entities/execution-context.d.ts.map +1 -0
- package/dist/contracts/entities/execution-context.js +2 -0
- package/dist/contracts/entities/execution-context.js.map +1 -0
- package/dist/contracts/entities/index.d.ts +11 -0
- package/dist/contracts/entities/index.d.ts.map +1 -0
- package/dist/contracts/entities/index.js +2 -0
- package/dist/contracts/entities/index.js.map +1 -0
- package/dist/contracts/entities/knowledge.d.ts +21 -0
- package/dist/contracts/entities/knowledge.d.ts.map +1 -0
- package/dist/contracts/entities/knowledge.js +2 -0
- package/dist/contracts/entities/knowledge.js.map +1 -0
- package/dist/contracts/entities/stores.d.ts +18 -0
- package/dist/contracts/entities/stores.d.ts.map +1 -0
- package/dist/contracts/entities/stores.js +2 -0
- package/dist/contracts/entities/stores.js.map +1 -0
- package/dist/contracts/entities/token-usage.d.ts +7 -0
- package/dist/contracts/entities/token-usage.d.ts.map +1 -0
- package/dist/contracts/entities/token-usage.js +2 -0
- package/dist/contracts/entities/token-usage.js.map +1 -0
- package/dist/contracts/entities/tool-call.d.ts +16 -0
- package/dist/contracts/entities/tool-call.d.ts.map +1 -0
- package/dist/contracts/entities/tool-call.js +2 -0
- package/dist/contracts/entities/tool-call.js.map +1 -0
- package/dist/contracts/enums/index.d.ts +21 -0
- package/dist/contracts/enums/index.d.ts.map +1 -0
- package/dist/contracts/enums/index.js +8 -0
- package/dist/contracts/enums/index.js.map +1 -0
- package/dist/contracts/index.d.ts +3 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +3 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/core/compaction/autocompact.d.ts +18 -0
- package/dist/core/compaction/autocompact.d.ts.map +1 -0
- package/dist/core/compaction/autocompact.js +68 -0
- package/dist/core/compaction/autocompact.js.map +1 -0
- package/dist/core/compaction/microcompact.d.ts +20 -0
- package/dist/core/compaction/microcompact.d.ts.map +1 -0
- package/dist/core/compaction/microcompact.js +38 -0
- package/dist/core/compaction/microcompact.js.map +1 -0
- package/dist/core/compaction/snip-compact.d.ts +22 -0
- package/dist/core/compaction/snip-compact.d.ts.map +1 -0
- package/dist/core/compaction/snip-compact.js +61 -0
- package/dist/core/compaction/snip-compact.js.map +1 -0
- package/dist/core/compaction/tool-result-budget.d.ts +24 -0
- package/dist/core/compaction/tool-result-budget.d.ts.map +1 -0
- package/dist/core/compaction/tool-result-budget.js +67 -0
- package/dist/core/compaction/tool-result-budget.js.map +1 -0
- package/dist/core/context-analysis.d.ts +24 -0
- package/dist/core/context-analysis.d.ts.map +1 -0
- package/dist/core/context-analysis.js +37 -0
- package/dist/core/context-analysis.js.map +1 -0
- package/dist/core/context-builder.d.ts +25 -0
- package/dist/core/context-builder.d.ts.map +1 -0
- package/dist/core/context-builder.js +108 -0
- package/dist/core/context-builder.js.map +1 -0
- package/dist/core/conversation-manager.d.ts +19 -0
- package/dist/core/conversation-manager.d.ts.map +1 -0
- package/dist/core/conversation-manager.js +62 -0
- package/dist/core/conversation-manager.js.map +1 -0
- package/dist/core/execution-context.d.ts +6 -0
- package/dist/core/execution-context.d.ts.map +1 -0
- package/dist/core/execution-context.js +14 -0
- package/dist/core/execution-context.js.map +1 -0
- package/dist/core/loop-deps.d.ts +15 -0
- package/dist/core/loop-deps.d.ts.map +1 -0
- package/dist/core/loop-deps.js +8 -0
- package/dist/core/loop-deps.js.map +1 -0
- package/dist/core/loop-types.d.ts +34 -0
- package/dist/core/loop-types.d.ts.map +1 -0
- package/dist/core/loop-types.js +15 -0
- package/dist/core/loop-types.js.map +1 -0
- package/dist/core/message-normalize.d.ts +18 -0
- package/dist/core/message-normalize.d.ts.map +1 -0
- package/dist/core/message-normalize.js +69 -0
- package/dist/core/message-normalize.js.map +1 -0
- package/dist/core/prompt-builders.d.ts +36 -0
- package/dist/core/prompt-builders.d.ts.map +1 -0
- package/dist/core/prompt-builders.js +89 -0
- package/dist/core/prompt-builders.js.map +1 -0
- package/dist/core/prompt-cache.d.ts +25 -0
- package/dist/core/prompt-cache.d.ts.map +1 -0
- package/dist/core/prompt-cache.js +34 -0
- package/dist/core/prompt-cache.js.map +1 -0
- package/dist/core/react-loop.d.ts +43 -0
- package/dist/core/react-loop.d.ts.map +1 -0
- package/dist/core/react-loop.js +403 -0
- package/dist/core/react-loop.js.map +1 -0
- package/dist/core/stop-hooks.d.ts +18 -0
- package/dist/core/stop-hooks.d.ts.map +1 -0
- package/dist/core/stop-hooks.js +18 -0
- package/dist/core/stop-hooks.js.map +1 -0
- package/dist/core/stream-emitter.d.ts +24 -0
- package/dist/core/stream-emitter.d.ts.map +1 -0
- package/dist/core/stream-emitter.js +65 -0
- package/dist/core/stream-emitter.js.map +1 -0
- package/dist/core/streaming-tool-executor.d.ts +54 -0
- package/dist/core/streaming-tool-executor.d.ts.map +1 -0
- package/dist/core/streaming-tool-executor.js +164 -0
- package/dist/core/streaming-tool-executor.js.map +1 -0
- package/dist/core/turn-end-hooks.d.ts +39 -0
- package/dist/core/turn-end-hooks.d.ts.map +1 -0
- package/dist/core/turn-end-hooks.js +36 -0
- package/dist/core/turn-end-hooks.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/knowledge/chunking.d.ts +9 -0
- package/dist/knowledge/chunking.d.ts.map +1 -0
- package/dist/knowledge/chunking.js +49 -0
- package/dist/knowledge/chunking.js.map +1 -0
- package/dist/knowledge/embedding-service.d.ts +16 -0
- package/dist/knowledge/embedding-service.d.ts.map +1 -0
- package/dist/knowledge/embedding-service.js +43 -0
- package/dist/knowledge/embedding-service.js.map +1 -0
- package/dist/knowledge/knowledge-manager.d.ts +33 -0
- package/dist/knowledge/knowledge-manager.d.ts.map +1 -0
- package/dist/knowledge/knowledge-manager.js +62 -0
- package/dist/knowledge/knowledge-manager.js.map +1 -0
- package/dist/knowledge/sqlite-vector-store.d.ts +16 -0
- package/dist/knowledge/sqlite-vector-store.d.ts.map +1 -0
- package/dist/knowledge/sqlite-vector-store.js +56 -0
- package/dist/knowledge/sqlite-vector-store.js.map +1 -0
- package/dist/knowledge/vector-store.d.ts +2 -0
- package/dist/knowledge/vector-store.d.ts.map +1 -0
- package/dist/knowledge/vector-store.js +2 -0
- package/dist/knowledge/vector-store.js.map +1 -0
- package/dist/llm/errors.d.ts +15 -0
- package/dist/llm/errors.d.ts.map +1 -0
- package/dist/llm/errors.js +39 -0
- package/dist/llm/errors.js.map +1 -0
- package/dist/llm/message-types.d.ts +80 -0
- package/dist/llm/message-types.d.ts.map +1 -0
- package/dist/llm/message-types.js +2 -0
- package/dist/llm/message-types.js.map +1 -0
- package/dist/llm/openrouter-client.d.ts +18 -0
- package/dist/llm/openrouter-client.d.ts.map +1 -0
- package/dist/llm/openrouter-client.js +215 -0
- package/dist/llm/openrouter-client.js.map +1 -0
- package/dist/llm/reasoning.d.ts +10 -0
- package/dist/llm/reasoning.d.ts.map +1 -0
- package/dist/llm/reasoning.js +18 -0
- package/dist/llm/reasoning.js.map +1 -0
- package/dist/memory/file-memory-system.d.ts +98 -0
- package/dist/memory/file-memory-system.d.ts.map +1 -0
- package/dist/memory/file-memory-system.js +310 -0
- package/dist/memory/file-memory-system.js.map +1 -0
- package/dist/memory/memory-age.d.ts +22 -0
- package/dist/memory/memory-age.d.ts.map +1 -0
- package/dist/memory/memory-age.js +44 -0
- package/dist/memory/memory-age.js.map +1 -0
- package/dist/memory/memory-extractor.d.ts +56 -0
- package/dist/memory/memory-extractor.d.ts.map +1 -0
- package/dist/memory/memory-extractor.js +91 -0
- package/dist/memory/memory-extractor.js.map +1 -0
- package/dist/memory/memory-paths.d.ts +45 -0
- package/dist/memory/memory-paths.d.ts.map +1 -0
- package/dist/memory/memory-paths.js +121 -0
- package/dist/memory/memory-paths.js.map +1 -0
- package/dist/memory/memory-prompts.d.ts +41 -0
- package/dist/memory/memory-prompts.d.ts.map +1 -0
- package/dist/memory/memory-prompts.js +279 -0
- package/dist/memory/memory-prompts.js.map +1 -0
- package/dist/memory/memory-relevance.d.ts +16 -0
- package/dist/memory/memory-relevance.d.ts.map +1 -0
- package/dist/memory/memory-relevance.js +46 -0
- package/dist/memory/memory-relevance.js.map +1 -0
- package/dist/memory/memory-scanner.d.ts +22 -0
- package/dist/memory/memory-scanner.d.ts.map +1 -0
- package/dist/memory/memory-scanner.js +99 -0
- package/dist/memory/memory-scanner.js.map +1 -0
- package/dist/memory/memory-tools.d.ts +16 -0
- package/dist/memory/memory-tools.d.ts.map +1 -0
- package/dist/memory/memory-tools.js +196 -0
- package/dist/memory/memory-tools.js.map +1 -0
- package/dist/memory/memory-types.d.ts +47 -0
- package/dist/memory/memory-types.d.ts.map +1 -0
- package/dist/memory/memory-types.js +24 -0
- package/dist/memory/memory-types.js.map +1 -0
- package/dist/skills/skill-args.d.ts +23 -0
- package/dist/skills/skill-args.d.ts.map +1 -0
- package/dist/skills/skill-args.js +77 -0
- package/dist/skills/skill-args.js.map +1 -0
- package/dist/skills/skill-glob.d.ts +24 -0
- package/dist/skills/skill-glob.d.ts.map +1 -0
- package/dist/skills/skill-glob.js +60 -0
- package/dist/skills/skill-glob.js.map +1 -0
- package/dist/skills/skill-loader.d.ts +49 -0
- package/dist/skills/skill-loader.d.ts.map +1 -0
- package/dist/skills/skill-loader.js +197 -0
- package/dist/skills/skill-loader.js.map +1 -0
- package/dist/skills/skill-manager.d.ts +83 -0
- package/dist/skills/skill-manager.d.ts.map +1 -0
- package/dist/skills/skill-manager.js +338 -0
- package/dist/skills/skill-manager.js.map +1 -0
- package/dist/storage/sqlite-conversation-store.d.ts +15 -0
- package/dist/storage/sqlite-conversation-store.d.ts.map +1 -0
- package/dist/storage/sqlite-conversation-store.js +45 -0
- package/dist/storage/sqlite-conversation-store.js.map +1 -0
- package/dist/storage/sqlite-database.d.ts +14 -0
- package/dist/storage/sqlite-database.d.ts.map +1 -0
- package/dist/storage/sqlite-database.js +95 -0
- package/dist/storage/sqlite-database.js.map +1 -0
- package/dist/tools/builtin/ask-user.d.ts +7 -0
- package/dist/tools/builtin/ask-user.d.ts.map +1 -0
- package/dist/tools/builtin/ask-user.js +23 -0
- package/dist/tools/builtin/ask-user.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts +3 -0
- package/dist/tools/builtin/bash.d.ts.map +1 -0
- package/dist/tools/builtin/bash.js +54 -0
- package/dist/tools/builtin/bash.js.map +1 -0
- package/dist/tools/builtin/file-edit.d.ts +3 -0
- package/dist/tools/builtin/file-edit.d.ts.map +1 -0
- package/dist/tools/builtin/file-edit.js +50 -0
- package/dist/tools/builtin/file-edit.js.map +1 -0
- package/dist/tools/builtin/file-read.d.ts +3 -0
- package/dist/tools/builtin/file-read.d.ts.map +1 -0
- package/dist/tools/builtin/file-read.js +47 -0
- package/dist/tools/builtin/file-read.js.map +1 -0
- package/dist/tools/builtin/file-write.d.ts +3 -0
- package/dist/tools/builtin/file-write.d.ts.map +1 -0
- package/dist/tools/builtin/file-write.js +29 -0
- package/dist/tools/builtin/file-write.js.map +1 -0
- package/dist/tools/builtin/glob.d.ts +3 -0
- package/dist/tools/builtin/glob.d.ts.map +1 -0
- package/dist/tools/builtin/glob.js +67 -0
- package/dist/tools/builtin/glob.js.map +1 -0
- package/dist/tools/builtin/grep.d.ts +3 -0
- package/dist/tools/builtin/grep.d.ts.map +1 -0
- package/dist/tools/builtin/grep.js +94 -0
- package/dist/tools/builtin/grep.js.map +1 -0
- package/dist/tools/builtin/index.d.ts +49 -0
- package/dist/tools/builtin/index.d.ts.map +1 -0
- package/dist/tools/builtin/index.js +65 -0
- package/dist/tools/builtin/index.js.map +1 -0
- package/dist/tools/builtin/web-fetch.d.ts +3 -0
- package/dist/tools/builtin/web-fetch.d.ts.map +1 -0
- package/dist/tools/builtin/web-fetch.js +56 -0
- package/dist/tools/builtin/web-fetch.js.map +1 -0
- package/dist/tools/json-schema-to-zod.d.ts +30 -0
- package/dist/tools/json-schema-to-zod.d.ts.map +1 -0
- package/dist/tools/json-schema-to-zod.js +123 -0
- package/dist/tools/json-schema-to-zod.js.map +1 -0
- package/dist/tools/mcp-adapter.d.ts +80 -0
- package/dist/tools/mcp-adapter.d.ts.map +1 -0
- package/dist/tools/mcp-adapter.js +326 -0
- package/dist/tools/mcp-adapter.js.map +1 -0
- package/dist/tools/skill-tool.d.ts +41 -0
- package/dist/tools/skill-tool.d.ts.map +1 -0
- package/dist/tools/skill-tool.js +149 -0
- package/dist/tools/skill-tool.js.map +1 -0
- package/dist/tools/sql/index.d.ts +4 -0
- package/dist/tools/sql/index.d.ts.map +1 -0
- package/dist/tools/sql/index.js +2 -0
- package/dist/tools/sql/index.js.map +1 -0
- package/dist/tools/sql/sql-query-def.d.ts +22 -0
- package/dist/tools/sql/sql-query-def.d.ts.map +1 -0
- package/dist/tools/sql/sql-query-def.js +2 -0
- package/dist/tools/sql/sql-query-def.js.map +1 -0
- package/dist/tools/sql/sql-tool-factory.d.ts +28 -0
- package/dist/tools/sql/sql-tool-factory.d.ts.map +1 -0
- package/dist/tools/sql/sql-tool-factory.js +136 -0
- package/dist/tools/sql/sql-tool-factory.js.map +1 -0
- package/dist/tools/tool-executor.d.ts +67 -0
- package/dist/tools/tool-executor.d.ts.map +1 -0
- package/dist/tools/tool-executor.js +232 -0
- package/dist/tools/tool-executor.js.map +1 -0
- package/dist/utils/cache.d.ts +22 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +61 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/logger.d.ts +15 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +46 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/model-context.d.ts +14 -0
- package/dist/utils/model-context.d.ts.map +1 -0
- package/dist/utils/model-context.js +52 -0
- package/dist/utils/model-context.js.map +1 -0
- package/dist/utils/retry.d.ts +13 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +41 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/token-counter.d.ts +6 -0
- package/dist/utils/token-counter.d.ts.map +1 -0
- package/dist/utils/token-counter.js +19 -0
- package/dist/utils/token-counter.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based memory system — main orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* Manages Markdown memory files with YAML frontmatter and a MEMORY.md index.
|
|
5
|
+
* Supports thread-isolated memory: each threadId gets its own subdirectory.
|
|
6
|
+
* Global memories (no threadId) live in the root memoryDir.
|
|
7
|
+
*
|
|
8
|
+
* Layout:
|
|
9
|
+
* memoryDir/
|
|
10
|
+
* MEMORY.md ← global index
|
|
11
|
+
* project-info.md ← global memory
|
|
12
|
+
* threads/
|
|
13
|
+
* telegram-123/
|
|
14
|
+
* MEMORY.md ← thread index
|
|
15
|
+
* user-name.md ← thread-scoped memory
|
|
16
|
+
* teams-456/
|
|
17
|
+
* MEMORY.md
|
|
18
|
+
* ...
|
|
19
|
+
*/
|
|
20
|
+
import { readFile, writeFile, unlink, stat, readdir, mkdir } from 'node:fs/promises';
|
|
21
|
+
import { join } from 'node:path';
|
|
22
|
+
import { ENTRYPOINT_NAME, MAX_ENTRYPOINT_LINES, MAX_ENTRYPOINT_BYTES, parseMemoryType, } from './memory-types.js';
|
|
23
|
+
import { resolveMemoryDir, ensureMemoryDir, sanitizeFilename } from './memory-paths.js';
|
|
24
|
+
import { scanMemoryFiles, formatMemoryManifest, parseFrontmatter } from './memory-scanner.js';
|
|
25
|
+
import { selectRelevantMemories } from './memory-relevance.js';
|
|
26
|
+
import { memoryFreshnessNote } from './memory-age.js';
|
|
27
|
+
import { buildMemoryInstructions } from './memory-prompts.js';
|
|
28
|
+
const THREADS_DIR = 'threads';
|
|
29
|
+
export class FileMemorySystem {
|
|
30
|
+
memoryDir;
|
|
31
|
+
client;
|
|
32
|
+
logger;
|
|
33
|
+
relevanceModel;
|
|
34
|
+
writeLock = false;
|
|
35
|
+
constructor(config, client, logger) {
|
|
36
|
+
this.memoryDir = resolveMemoryDir(config.memoryDir);
|
|
37
|
+
this.client = client;
|
|
38
|
+
this.logger = logger;
|
|
39
|
+
this.relevanceModel = config.relevanceModel;
|
|
40
|
+
}
|
|
41
|
+
/** Ensure the memory directory exists (idempotent). */
|
|
42
|
+
async ensureDir() {
|
|
43
|
+
await ensureMemoryDir(this.memoryDir);
|
|
44
|
+
}
|
|
45
|
+
/** Get the resolved memory directory path. */
|
|
46
|
+
getMemoryDir() {
|
|
47
|
+
return this.memoryDir;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Resolve the effective directory for a threadId.
|
|
51
|
+
* No threadId → root memoryDir (global).
|
|
52
|
+
* With threadId → memoryDir/threads/{threadId}/
|
|
53
|
+
*/
|
|
54
|
+
resolveDir(threadId) {
|
|
55
|
+
if (!threadId)
|
|
56
|
+
return this.memoryDir;
|
|
57
|
+
return join(this.memoryDir, THREADS_DIR, threadId);
|
|
58
|
+
}
|
|
59
|
+
/** Ensure a thread directory exists. */
|
|
60
|
+
async ensureThreadDir(threadId) {
|
|
61
|
+
const dir = this.resolveDir(threadId);
|
|
62
|
+
await mkdir(dir, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Save a new memory file and update the MEMORY.md index.
|
|
66
|
+
* When threadId is provided, saves to the thread subdirectory.
|
|
67
|
+
*/
|
|
68
|
+
async saveMemory(input, threadId) {
|
|
69
|
+
await this.ensureThreadDir(threadId);
|
|
70
|
+
const dir = this.resolveDir(threadId);
|
|
71
|
+
const filename = sanitizeFilename(input.name);
|
|
72
|
+
const filePath = join(dir, filename);
|
|
73
|
+
const fileContent = [
|
|
74
|
+
'---',
|
|
75
|
+
`name: ${input.name}`,
|
|
76
|
+
`description: ${input.description}`,
|
|
77
|
+
`type: ${input.type}`,
|
|
78
|
+
'---',
|
|
79
|
+
'',
|
|
80
|
+
input.content,
|
|
81
|
+
'',
|
|
82
|
+
].join('\n');
|
|
83
|
+
await writeFile(filePath, fileContent, 'utf-8');
|
|
84
|
+
await this.addToIndex(filename, input.description, threadId);
|
|
85
|
+
this.logger.debug('Memory saved', { filename, type: input.type, threadId: threadId ?? 'global' });
|
|
86
|
+
return filename;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Read and parse a memory file.
|
|
90
|
+
* When threadId is provided, reads from thread subdirectory.
|
|
91
|
+
*/
|
|
92
|
+
async readMemory(filename, threadId) {
|
|
93
|
+
try {
|
|
94
|
+
const dir = this.resolveDir(threadId);
|
|
95
|
+
const filePath = join(dir, filename);
|
|
96
|
+
const content = await readFile(filePath, 'utf-8');
|
|
97
|
+
const fileStat = await stat(filePath);
|
|
98
|
+
const frontmatter = parseFrontmatter(content);
|
|
99
|
+
const bodyMatch = content.match(/^---\s*\n[\s\S]*?\n---\s*\n?([\s\S]*)/);
|
|
100
|
+
const body = bodyMatch?.[1]?.trim() ?? content;
|
|
101
|
+
return {
|
|
102
|
+
filename,
|
|
103
|
+
filePath,
|
|
104
|
+
mtimeMs: fileStat.mtimeMs,
|
|
105
|
+
name: frontmatter.name ?? null,
|
|
106
|
+
description: frontmatter.description ?? null,
|
|
107
|
+
type: parseMemoryType(frontmatter.type),
|
|
108
|
+
content: body,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Delete a memory file and remove its entry from the index.
|
|
117
|
+
*/
|
|
118
|
+
async deleteMemory(filename, threadId) {
|
|
119
|
+
try {
|
|
120
|
+
const dir = this.resolveDir(threadId);
|
|
121
|
+
const filePath = join(dir, filename);
|
|
122
|
+
await unlink(filePath);
|
|
123
|
+
await this.removeFromIndex(filename, threadId);
|
|
124
|
+
this.logger.debug('Memory deleted', { filename, threadId: threadId ?? 'global' });
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Scan memory files. When threadId is provided, scans thread dir + global dir (merged).
|
|
133
|
+
*/
|
|
134
|
+
async scanMemories(signal, threadId) {
|
|
135
|
+
const globalMemories = await scanMemoryFiles(this.memoryDir, signal);
|
|
136
|
+
if (!threadId)
|
|
137
|
+
return globalMemories;
|
|
138
|
+
const threadDir = this.resolveDir(threadId);
|
|
139
|
+
const threadMemories = await scanMemoryFiles(threadDir, signal);
|
|
140
|
+
// Merge: thread memories first (higher priority), then global
|
|
141
|
+
// Dedupe by filename (thread wins)
|
|
142
|
+
const seen = new Set(threadMemories.map(m => m.filename));
|
|
143
|
+
const merged = [...threadMemories, ...globalMemories.filter(m => !seen.has(m.filename))];
|
|
144
|
+
return merged;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Find relevant memories for a query using LLM selection.
|
|
148
|
+
* Scans thread + global memories when threadId is provided.
|
|
149
|
+
*/
|
|
150
|
+
async findRelevant(query, signal, excludeFilenames, threadId) {
|
|
151
|
+
const memories = await this.scanMemories(signal, threadId);
|
|
152
|
+
if (memories.length === 0)
|
|
153
|
+
return [];
|
|
154
|
+
const filtered = excludeFilenames?.size
|
|
155
|
+
? memories.filter(m => !excludeFilenames.has(m.filename))
|
|
156
|
+
: memories;
|
|
157
|
+
if (filtered.length === 0)
|
|
158
|
+
return [];
|
|
159
|
+
const manifest = formatMemoryManifest(filtered);
|
|
160
|
+
const validFilenames = new Set(filtered.map(m => m.filename));
|
|
161
|
+
const selectedFilenames = await selectRelevantMemories(query, manifest, validFilenames, this.client, { model: this.relevanceModel, signal });
|
|
162
|
+
const results = [];
|
|
163
|
+
for (const filename of selectedFilenames) {
|
|
164
|
+
// Try thread dir first, then global
|
|
165
|
+
const memory = threadId
|
|
166
|
+
? (await this.readMemory(filename, threadId) ?? await this.readMemory(filename))
|
|
167
|
+
: await this.readMemory(filename);
|
|
168
|
+
if (memory)
|
|
169
|
+
results.push(memory);
|
|
170
|
+
}
|
|
171
|
+
return results;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Build the context prompt from MEMORY.md.
|
|
175
|
+
* When threadId is provided, merges global + thread MEMORY.md.
|
|
176
|
+
*/
|
|
177
|
+
async buildContextPrompt(threadId) {
|
|
178
|
+
const parts = [];
|
|
179
|
+
// Global MEMORY.md
|
|
180
|
+
try {
|
|
181
|
+
const globalContent = await readFile(join(this.memoryDir, ENTRYPOINT_NAME), 'utf-8');
|
|
182
|
+
if (globalContent.trim())
|
|
183
|
+
parts.push(globalContent.trim());
|
|
184
|
+
}
|
|
185
|
+
catch { /* no global index */ }
|
|
186
|
+
// Thread MEMORY.md
|
|
187
|
+
if (threadId) {
|
|
188
|
+
try {
|
|
189
|
+
const threadContent = await readFile(join(this.resolveDir(threadId), ENTRYPOINT_NAME), 'utf-8');
|
|
190
|
+
if (threadContent.trim())
|
|
191
|
+
parts.push(threadContent.trim());
|
|
192
|
+
}
|
|
193
|
+
catch { /* no thread index */ }
|
|
194
|
+
}
|
|
195
|
+
if (parts.length === 0)
|
|
196
|
+
return '';
|
|
197
|
+
return truncateEntrypointContent(parts.join('\n'));
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Build the behavioral instructions prompt for the memory system.
|
|
201
|
+
*/
|
|
202
|
+
getMemoryInstructions() {
|
|
203
|
+
return buildMemoryInstructions(this.memoryDir);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Build the full memory context for injection (MEMORY.md + relevant memories).
|
|
207
|
+
*/
|
|
208
|
+
async buildFullContext(query, signal, threadId) {
|
|
209
|
+
const parts = [];
|
|
210
|
+
const indexContent = await this.buildContextPrompt(threadId);
|
|
211
|
+
if (indexContent) {
|
|
212
|
+
parts.push('# Memory Index\n' + indexContent);
|
|
213
|
+
}
|
|
214
|
+
const relevant = await this.findRelevant(query, signal, undefined, threadId);
|
|
215
|
+
if (relevant.length > 0) {
|
|
216
|
+
parts.push('# Relevant Memories');
|
|
217
|
+
for (const mem of relevant) {
|
|
218
|
+
const freshness = memoryFreshnessNote(mem.mtimeMs);
|
|
219
|
+
const header = mem.name ? `## ${mem.name}` : `## ${mem.filename}`;
|
|
220
|
+
parts.push(`${header}\n${freshness}${mem.content}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return parts.join('\n\n');
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Check if any memory files were created or modified since the given timestamp.
|
|
227
|
+
* When threadId is provided, checks only the thread directory.
|
|
228
|
+
*/
|
|
229
|
+
async hasWritesSince(sinceMs, threadId) {
|
|
230
|
+
const dir = this.resolveDir(threadId);
|
|
231
|
+
try {
|
|
232
|
+
const entries = await readdir(dir);
|
|
233
|
+
for (const entry of entries) {
|
|
234
|
+
if (!entry.endsWith('.md') || entry === ENTRYPOINT_NAME)
|
|
235
|
+
continue;
|
|
236
|
+
const fileStat = await stat(join(dir, entry));
|
|
237
|
+
if (fileStat.mtimeMs > sinceMs)
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// --- Private helpers ---
|
|
247
|
+
async addToIndex(filename, description, threadId) {
|
|
248
|
+
await this.withWriteLock(async () => {
|
|
249
|
+
const dir = this.resolveDir(threadId);
|
|
250
|
+
const entrypoint = join(dir, ENTRYPOINT_NAME);
|
|
251
|
+
let existing = '';
|
|
252
|
+
try {
|
|
253
|
+
existing = await readFile(entrypoint, 'utf-8');
|
|
254
|
+
}
|
|
255
|
+
catch { /* File doesn't exist yet */ }
|
|
256
|
+
if (existing.includes(`(${filename})`))
|
|
257
|
+
return;
|
|
258
|
+
const newEntry = `- [${description}](${filename}) — ${description}`;
|
|
259
|
+
const updated = existing ? `${existing.trimEnd()}\n${newEntry}\n` : `${newEntry}\n`;
|
|
260
|
+
await writeFile(entrypoint, updated, 'utf-8');
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
async removeFromIndex(filename, threadId) {
|
|
264
|
+
await this.withWriteLock(async () => {
|
|
265
|
+
const dir = this.resolveDir(threadId);
|
|
266
|
+
const entrypoint = join(dir, ENTRYPOINT_NAME);
|
|
267
|
+
try {
|
|
268
|
+
const content = await readFile(entrypoint, 'utf-8');
|
|
269
|
+
const lines = content.split('\n').filter(line => !line.includes(`(${filename})`));
|
|
270
|
+
await writeFile(entrypoint, lines.join('\n'), 'utf-8');
|
|
271
|
+
}
|
|
272
|
+
catch { /* Index doesn't exist */ }
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
async withWriteLock(fn) {
|
|
276
|
+
while (this.writeLock) {
|
|
277
|
+
await new Promise(r => setTimeout(r, 10));
|
|
278
|
+
}
|
|
279
|
+
this.writeLock = true;
|
|
280
|
+
try {
|
|
281
|
+
return await fn();
|
|
282
|
+
}
|
|
283
|
+
finally {
|
|
284
|
+
this.writeLock = false;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Truncate MEMORY.md content to limits: 200 lines, 25KB.
|
|
290
|
+
*/
|
|
291
|
+
export function truncateEntrypointContent(content) {
|
|
292
|
+
const lines = content.split('\n');
|
|
293
|
+
if (lines.length > MAX_ENTRYPOINT_LINES) {
|
|
294
|
+
const truncated = lines.slice(0, MAX_ENTRYPOINT_LINES).join('\n');
|
|
295
|
+
return truncated + `\n\n[... truncated: ${lines.length - MAX_ENTRYPOINT_LINES} more lines]`;
|
|
296
|
+
}
|
|
297
|
+
const bytes = new TextEncoder().encode(content).length;
|
|
298
|
+
if (bytes > MAX_ENTRYPOINT_BYTES) {
|
|
299
|
+
let cutoff = content.length;
|
|
300
|
+
while (new TextEncoder().encode(content.slice(0, cutoff)).length > MAX_ENTRYPOINT_BYTES) {
|
|
301
|
+
const lastNewline = content.lastIndexOf('\n', cutoff - 1);
|
|
302
|
+
if (lastNewline <= 0)
|
|
303
|
+
break;
|
|
304
|
+
cutoff = lastNewline;
|
|
305
|
+
}
|
|
306
|
+
return content.slice(0, cutoff) + '\n\n[... truncated: exceeded 25KB limit]';
|
|
307
|
+
}
|
|
308
|
+
return content;
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=file-memory-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-memory-system.js","sourceRoot":"","sources":["../../src/memory/file-memory-system.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory staleness tracking.
|
|
3
|
+
*
|
|
4
|
+
* Models are poor at date arithmetic — a raw ISO timestamp doesn't trigger
|
|
5
|
+
* staleness reasoning the way "47 days ago" does.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Days elapsed since mtime. Floor-rounded — 0 for today, 1 for yesterday.
|
|
9
|
+
* Negative inputs (future mtime, clock skew) clamp to 0.
|
|
10
|
+
*/
|
|
11
|
+
export declare function memoryAgeDays(mtimeMs: number): number;
|
|
12
|
+
/** Human-readable age string. */
|
|
13
|
+
export declare function memoryAge(mtimeMs: number): string;
|
|
14
|
+
/**
|
|
15
|
+
* Staleness caveat for memories >1 day old. Returns '' for fresh memories.
|
|
16
|
+
*/
|
|
17
|
+
export declare function memoryFreshnessText(mtimeMs: number): string;
|
|
18
|
+
/**
|
|
19
|
+
* Per-memory staleness note. Returns '' for memories ≤ 1 day old.
|
|
20
|
+
*/
|
|
21
|
+
export declare function memoryFreshnessNote(mtimeMs: number): string;
|
|
22
|
+
//# sourceMappingURL=memory-age.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-age.d.ts","sourceRoot":"","sources":["../../src/memory/memory-age.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,iCAAiC;AACjC,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAS3D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAI3D"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory staleness tracking.
|
|
3
|
+
*
|
|
4
|
+
* Models are poor at date arithmetic — a raw ISO timestamp doesn't trigger
|
|
5
|
+
* staleness reasoning the way "47 days ago" does.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Days elapsed since mtime. Floor-rounded — 0 for today, 1 for yesterday.
|
|
9
|
+
* Negative inputs (future mtime, clock skew) clamp to 0.
|
|
10
|
+
*/
|
|
11
|
+
export function memoryAgeDays(mtimeMs) {
|
|
12
|
+
return Math.max(0, Math.floor((Date.now() - mtimeMs) / 86_400_000));
|
|
13
|
+
}
|
|
14
|
+
/** Human-readable age string. */
|
|
15
|
+
export function memoryAge(mtimeMs) {
|
|
16
|
+
const d = memoryAgeDays(mtimeMs);
|
|
17
|
+
if (d === 0)
|
|
18
|
+
return 'today';
|
|
19
|
+
if (d === 1)
|
|
20
|
+
return 'yesterday';
|
|
21
|
+
return `${d} days ago`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Staleness caveat for memories >1 day old. Returns '' for fresh memories.
|
|
25
|
+
*/
|
|
26
|
+
export function memoryFreshnessText(mtimeMs) {
|
|
27
|
+
const d = memoryAgeDays(mtimeMs);
|
|
28
|
+
if (d <= 1)
|
|
29
|
+
return '';
|
|
30
|
+
return (`This memory is ${d} days old. ` +
|
|
31
|
+
`Memories are point-in-time observations, not live state — ` +
|
|
32
|
+
`claims about code behavior or file citations may be outdated. ` +
|
|
33
|
+
`Verify against current code before asserting as fact.`);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Per-memory staleness note. Returns '' for memories ≤ 1 day old.
|
|
37
|
+
*/
|
|
38
|
+
export function memoryFreshnessNote(mtimeMs) {
|
|
39
|
+
const text = memoryFreshnessText(mtimeMs);
|
|
40
|
+
if (!text)
|
|
41
|
+
return '';
|
|
42
|
+
return `[staleness warning] ${text}\n`;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=memory-age.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-age.js","sourceRoot":"","sources":["../../src/memory/memory-age.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;AACtE,CAAC;AAED,iCAAiC;AACjC,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,MAAM,CAAC,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IAC5B,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IAChC,OAAO,GAAG,CAAC,WAAW,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,CAAC,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACtB,OAAO,CACL,kBAAkB,CAAC,aAAa;QAChC,4DAA4D;QAC5D,gEAAgE;QAChE,uDAAuD,CACxD,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,IAAI,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,OAAO,uBAAuB,IAAI,IAAI,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background memory extraction service.
|
|
3
|
+
*
|
|
4
|
+
* Analyzes recent conversation to extract memories worth saving.
|
|
5
|
+
* Fire-and-forget — called after each completed turn.
|
|
6
|
+
*
|
|
7
|
+
* Uses the forked agent pattern (like old_src/services/extractMemories/):
|
|
8
|
+
* - Pre-injects manifest of existing memories to avoid duplicates
|
|
9
|
+
* - Gives the forked agent memory tools (read, write, edit, delete)
|
|
10
|
+
* - Agent reads existing files before deciding to update or create
|
|
11
|
+
* - Limited to 5 iterations to prevent rabbit holes
|
|
12
|
+
*/
|
|
13
|
+
import type { FileMemorySystem } from './file-memory-system.js';
|
|
14
|
+
/**
|
|
15
|
+
* Check if a message contains explicit memory save triggers.
|
|
16
|
+
*/
|
|
17
|
+
export declare function hasExplicitTrigger(message: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Determine if extraction should run based on triggers.
|
|
20
|
+
* - Explicit keyword → always extract
|
|
21
|
+
* - Turn interval → extract every N turns
|
|
22
|
+
* - Random sampling → probabilistic extraction
|
|
23
|
+
*/
|
|
24
|
+
export declare function shouldExtract(lastMessage: string, turnsSinceExtraction: number, config: {
|
|
25
|
+
samplingRate?: number;
|
|
26
|
+
extractionInterval?: number;
|
|
27
|
+
}): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Interface for the fork function — avoids circular import with Agent.
|
|
30
|
+
* Matches the signature of Agent.fork().
|
|
31
|
+
*/
|
|
32
|
+
export interface ForkFn {
|
|
33
|
+
(prompt: string, options?: {
|
|
34
|
+
systemPrompt?: string;
|
|
35
|
+
model?: string;
|
|
36
|
+
tools?: import('../contracts/entities/agent-tool.js').AgentTool[];
|
|
37
|
+
background?: boolean;
|
|
38
|
+
}): Promise<string>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Extract memories from conversation using a forked agent with memory tools.
|
|
42
|
+
*
|
|
43
|
+
* The forked agent can:
|
|
44
|
+
* - List existing memories (manifest)
|
|
45
|
+
* - Read existing memory content
|
|
46
|
+
* - Edit existing memories (update, not duplicate)
|
|
47
|
+
* - Write new memories
|
|
48
|
+
* - Delete outdated memories
|
|
49
|
+
*
|
|
50
|
+
* Fire-and-forget — errors are swallowed.
|
|
51
|
+
*/
|
|
52
|
+
export declare function extractMemories(conversationText: string, memorySystem: FileMemorySystem, fork: ForkFn, options?: {
|
|
53
|
+
model?: string;
|
|
54
|
+
threadId?: string;
|
|
55
|
+
}): Promise<void>;
|
|
56
|
+
//# sourceMappingURL=memory-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-extractor.d.ts","sourceRoot":"","sources":["../../src/memory/memory-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAiBhE;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG3D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,oBAAoB,EAAE,MAAM,EAC5B,MAAM,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7D,OAAO,CAKT;AAED;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QACzB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,OAAO,qCAAqC,EAAE,SAAS,EAAE,CAAC;QAClE,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,gBAAgB,EAAE,MAAM,EACxB,YAAY,EAAE,gBAAgB,EAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAAC,IAAI,CAAC,CAgCf"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background memory extraction service.
|
|
3
|
+
*
|
|
4
|
+
* Analyzes recent conversation to extract memories worth saving.
|
|
5
|
+
* Fire-and-forget — called after each completed turn.
|
|
6
|
+
*
|
|
7
|
+
* Uses the forked agent pattern (like old_src/services/extractMemories/):
|
|
8
|
+
* - Pre-injects manifest of existing memories to avoid duplicates
|
|
9
|
+
* - Gives the forked agent memory tools (read, write, edit, delete)
|
|
10
|
+
* - Agent reads existing files before deciding to update or create
|
|
11
|
+
* - Limited to 5 iterations to prevent rabbit holes
|
|
12
|
+
*/
|
|
13
|
+
import { formatMemoryManifest } from './memory-scanner.js';
|
|
14
|
+
import { buildForkedExtractionPrompt } from './memory-prompts.js';
|
|
15
|
+
import { createMemoryTools } from './memory-tools.js';
|
|
16
|
+
/** Extraction trigger keywords (multilingual) */
|
|
17
|
+
const EXPLICIT_TRIGGERS = [
|
|
18
|
+
'remember that',
|
|
19
|
+
'memorize',
|
|
20
|
+
'lembra que',
|
|
21
|
+
'lembre',
|
|
22
|
+
'não esqueça',
|
|
23
|
+
'keep in mind',
|
|
24
|
+
'note that',
|
|
25
|
+
'for future reference',
|
|
26
|
+
];
|
|
27
|
+
/**
|
|
28
|
+
* Check if a message contains explicit memory save triggers.
|
|
29
|
+
*/
|
|
30
|
+
export function hasExplicitTrigger(message) {
|
|
31
|
+
const lower = message.toLowerCase();
|
|
32
|
+
return EXPLICIT_TRIGGERS.some(t => lower.includes(t));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Determine if extraction should run based on triggers.
|
|
36
|
+
* - Explicit keyword → always extract
|
|
37
|
+
* - Turn interval → extract every N turns
|
|
38
|
+
* - Random sampling → probabilistic extraction
|
|
39
|
+
*/
|
|
40
|
+
export function shouldExtract(lastMessage, turnsSinceExtraction, config) {
|
|
41
|
+
if (hasExplicitTrigger(lastMessage))
|
|
42
|
+
return true;
|
|
43
|
+
if (turnsSinceExtraction >= (config.extractionInterval ?? 10))
|
|
44
|
+
return true;
|
|
45
|
+
if (Math.random() < (config.samplingRate ?? 0.3))
|
|
46
|
+
return true;
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Extract memories from conversation using a forked agent with memory tools.
|
|
51
|
+
*
|
|
52
|
+
* The forked agent can:
|
|
53
|
+
* - List existing memories (manifest)
|
|
54
|
+
* - Read existing memory content
|
|
55
|
+
* - Edit existing memories (update, not duplicate)
|
|
56
|
+
* - Write new memories
|
|
57
|
+
* - Delete outdated memories
|
|
58
|
+
*
|
|
59
|
+
* Fire-and-forget — errors are swallowed.
|
|
60
|
+
*/
|
|
61
|
+
export async function extractMemories(conversationText, memorySystem, fork, options) {
|
|
62
|
+
if (!conversationText.trim())
|
|
63
|
+
return;
|
|
64
|
+
try {
|
|
65
|
+
// Pre-scan existing memories (thread + global) for the manifest
|
|
66
|
+
const existingMemories = await memorySystem.scanMemories(undefined, options?.threadId);
|
|
67
|
+
const existingManifest = formatMemoryManifest(existingMemories);
|
|
68
|
+
// Count approximate messages for the prompt
|
|
69
|
+
const messageCount = conversationText.split('\n').filter(l => l.match(/^(user|assistant|tool):/)).length;
|
|
70
|
+
const prompt = [
|
|
71
|
+
buildForkedExtractionPrompt(Math.max(messageCount, 2), existingManifest),
|
|
72
|
+
'',
|
|
73
|
+
'## Recent conversation',
|
|
74
|
+
'',
|
|
75
|
+
conversationText,
|
|
76
|
+
].join('\n');
|
|
77
|
+
// Create memory tools scoped to the right directory
|
|
78
|
+
const tools = createMemoryTools(memorySystem.getMemoryDir(), options?.threadId);
|
|
79
|
+
// Fork a subagent with memory tools — background, fire-and-forget
|
|
80
|
+
await fork(prompt, {
|
|
81
|
+
systemPrompt: 'You are a memory extraction subagent. Use your memory tools to save, update, or delete memories based on the conversation provided. Be efficient — minimize tool calls.',
|
|
82
|
+
model: options?.model,
|
|
83
|
+
tools,
|
|
84
|
+
background: true,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Extraction is best-effort — never propagate errors
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=memory-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-extractor.js","sourceRoot":"","sources":["../../src/memory/memory-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,iDAAiD;AACjD,MAAM,iBAAiB,GAAG;IACxB,eAAe;IACf,UAAU;IACV,YAAY;IACZ,QAAQ;IACR,aAAa;IACb,cAAc;IACd,WAAW;IACX,sBAAsB;CACvB,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACpC,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC3B,WAAmB,EACnB,oBAA4B,EAC5B,MAA8D;IAE9D,IAAI,kBAAkB,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,oBAAoB,IAAI,CAAC,MAAM,CAAC,kBAAkB,IAAI,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3E,IAAI,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9D,OAAO,KAAK,CAAC;AACf,CAAC;AAeD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,gBAAwB,EACxB,YAA8B,EAC9B,IAAY,EACZ,OAA+C;IAE/C,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE;QAAE,OAAO;IAErC,IAAI,CAAC;QACH,gEAAgE;QAChE,MAAM,gBAAgB,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QACvF,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;QAEhE,4CAA4C;QAC5C,MAAM,YAAY,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC,MAAM,CAAC;QAEzG,MAAM,MAAM,GAAG;YACb,2BAA2B,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,gBAAgB,CAAC;YACxE,EAAE;YACF,wBAAwB;YACxB,EAAE;YACF,gBAAgB;SACjB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,oDAAoD;QACpD,MAAM,KAAK,GAAG,iBAAiB,CAAC,YAAY,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAEhF,kEAAkE;QAClE,MAAM,IAAI,CAAC,MAAM,EAAE;YACjB,YAAY,EAAE,yKAAyK;YACvL,KAAK,EAAE,OAAO,EAAE,KAAK;YACrB,KAAK;YACL,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,qDAAqD;IACvD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory directory path resolution and security validation.
|
|
3
|
+
*
|
|
4
|
+
* Security model ported from old_src/memdir/paths.ts:
|
|
5
|
+
* - Rejects relative paths, root/near-root, Windows drive roots, UNC paths, null bytes
|
|
6
|
+
* - Tilde expansion only from config (~/), not from bare ~ or ~/. or ~/..
|
|
7
|
+
* - All paths normalized to NFC to prevent Unicode normalization attacks
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the memory directory from config, env var, or default.
|
|
11
|
+
* Priority: config.memoryDir → AGENT_MEMORY_DIR env → ~/.agent/memory/
|
|
12
|
+
*
|
|
13
|
+
* Config paths support ~/ expansion (user-friendly).
|
|
14
|
+
* Env var paths must be absolute (set programmatically).
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveMemoryDir(memoryDir?: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Validate that a path is safely within the memory directory.
|
|
19
|
+
*
|
|
20
|
+
* SECURITY: Rejects paths that would be dangerous:
|
|
21
|
+
* - Empty or contains null bytes (truncation in syscalls)
|
|
22
|
+
* - Relative paths (!isAbsolute)
|
|
23
|
+
* - Root/near-root (length < 3)
|
|
24
|
+
* - Windows drive-root (C:)
|
|
25
|
+
* - UNC paths (\\server\share or //server/share)
|
|
26
|
+
* - URL-encoded traversal (%2e%2e)
|
|
27
|
+
* - Outside memory directory after normalization
|
|
28
|
+
*
|
|
29
|
+
* Returns the normalized path if valid, undefined if rejected.
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateMemoryPath(path: string, memoryDir: string): string | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Sanitize a name into a safe kebab-case filename with .md extension.
|
|
34
|
+
*/
|
|
35
|
+
export declare function sanitizeFilename(name: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Idempotent memory directory creation.
|
|
38
|
+
*/
|
|
39
|
+
export declare function ensureMemoryDir(memoryDir: string): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Check if an absolute path is within the memory directory.
|
|
42
|
+
* Uses NFC normalization to prevent Unicode-based path traversal.
|
|
43
|
+
*/
|
|
44
|
+
export declare function isMemoryPath(absolutePath: string, memoryDir: string): boolean;
|
|
45
|
+
//# sourceMappingURL=memory-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-paths.d.ts","sourceRoot":"","sources":["../../src/memory/memory-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAY3D;AAyBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAqBpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYrD;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAI7E"}
|