@poprobertdaniel/openclaw-memory 0.1.2 → 0.1.3
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/dist/{chunk-VB5GGBGB.js → chunk-7DNVIKQ3.js} +88 -4
- package/dist/chunk-7DNVIKQ3.js.map +1 -0
- package/dist/{chunk-RZPYOMPO.js → chunk-BTR4T5L3.js} +155 -25
- package/dist/chunk-BTR4T5L3.js.map +1 -0
- package/dist/{chunk-L2KRIMDA.cjs → chunk-CSGZH2SG.cjs} +5 -5
- package/dist/chunk-CSGZH2SG.cjs.map +1 -0
- package/dist/{chunk-5SZWJKD5.js → chunk-J2C5USXH.js} +2 -2
- package/dist/{chunk-HPGHPKK3.cjs → chunk-JYQB2DOK.cjs} +159 -29
- package/dist/chunk-JYQB2DOK.cjs.map +1 -0
- package/dist/chunk-LA5OP5VI.cjs.map +1 -1
- package/dist/{chunk-MQEBVCH5.cjs → chunk-NYZMAY73.cjs} +90 -6
- package/dist/chunk-NYZMAY73.cjs.map +1 -0
- package/dist/cli/index.cjs +3 -3
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +3 -3
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -2
- package/dist/index.d.ts +52 -2
- package/dist/index.js +3 -3
- package/dist/memory-service-B2BAEKR2.cjs +9 -0
- package/dist/memory-service-B2BAEKR2.cjs.map +1 -0
- package/dist/memory-service-ZTLGPIUH.js +9 -0
- package/dist/{server-D-3OqU-T.d.ts → server-CtNlCow7.d.cts} +50 -0
- package/dist/{server-D-3OqU-T.d.cts → server-CtNlCow7.d.ts} +50 -0
- package/dist/server.cjs +3 -3
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-HPGHPKK3.cjs.map +0 -1
- package/dist/chunk-L2KRIMDA.cjs.map +0 -1
- package/dist/chunk-MQEBVCH5.cjs.map +0 -1
- package/dist/chunk-RZPYOMPO.js.map +0 -1
- package/dist/chunk-VB5GGBGB.js.map +0 -1
- package/dist/memory-service-4ZPYUN4L.js +0 -9
- package/dist/memory-service-LURM3FBB.cjs +0 -9
- package/dist/memory-service-LURM3FBB.cjs.map +0 -1
- /package/dist/{chunk-5SZWJKD5.js.map → chunk-J2C5USXH.js.map} +0 -0
- /package/dist/{memory-service-4ZPYUN4L.js.map → memory-service-ZTLGPIUH.js.map} +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ConversationSummarizer,
|
|
3
3
|
SearchEngine,
|
|
4
|
-
StorageOrchestrator
|
|
5
|
-
|
|
4
|
+
StorageOrchestrator,
|
|
5
|
+
SyncQueueProcessor
|
|
6
|
+
} from "./chunk-BTR4T5L3.js";
|
|
6
7
|
import {
|
|
7
8
|
AuthError,
|
|
8
9
|
MemoryError,
|
|
@@ -503,7 +504,63 @@ function adminRoutes(orchestrator) {
|
|
|
503
504
|
details: error instanceof Error ? error.message : String(error)
|
|
504
505
|
};
|
|
505
506
|
}
|
|
506
|
-
}).
|
|
507
|
+
}).post(
|
|
508
|
+
"/api/admin/resync",
|
|
509
|
+
async ({ query, set }) => {
|
|
510
|
+
const layerParam = parseLayerParam(query.layer);
|
|
511
|
+
if (!layerParam) {
|
|
512
|
+
set.status = 400;
|
|
513
|
+
return {
|
|
514
|
+
error: "Invalid layer parameter",
|
|
515
|
+
details: "Use ?layer=qdrant|age|both"
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
const batch = parseBatchParam(query.batch);
|
|
519
|
+
if (batch === null) {
|
|
520
|
+
set.status = 400;
|
|
521
|
+
return {
|
|
522
|
+
error: "Invalid batch parameter",
|
|
523
|
+
details: "Use a positive integer for ?batch=50"
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
const layers = layerParam === "both" ? ["qdrant", "age"] : [layerParam];
|
|
527
|
+
try {
|
|
528
|
+
const memories = listAllMemories(orchestrator);
|
|
529
|
+
let queuedItems = 0;
|
|
530
|
+
for (const memory of memories) {
|
|
531
|
+
for (const layer of layers) {
|
|
532
|
+
orchestrator.sqlite.addToSyncQueue(memory.id, layer, "upsert");
|
|
533
|
+
queuedItems++;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
const syncResults = await SyncQueueProcessor.withBatchSize(batch, async () => {
|
|
537
|
+
return await orchestrator.retrySyncQueue();
|
|
538
|
+
});
|
|
539
|
+
return {
|
|
540
|
+
layer: layerParam,
|
|
541
|
+
layers,
|
|
542
|
+
batch,
|
|
543
|
+
memory_count: memories.length,
|
|
544
|
+
queued_items: queuedItems,
|
|
545
|
+
sync_results: syncResults
|
|
546
|
+
};
|
|
547
|
+
} catch (error) {
|
|
548
|
+
set.status = 500;
|
|
549
|
+
return {
|
|
550
|
+
error: "Resync failed",
|
|
551
|
+
details: error instanceof Error ? error.message : String(error)
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
query: t5.Object({
|
|
557
|
+
layer: t5.Optional(
|
|
558
|
+
t5.Union([t5.Literal("qdrant"), t5.Literal("age"), t5.Literal("both")])
|
|
559
|
+
),
|
|
560
|
+
batch: t5.Optional(t5.String())
|
|
561
|
+
})
|
|
562
|
+
}
|
|
563
|
+
).get("/api/sync/queue", () => {
|
|
507
564
|
const items = orchestrator.sqlite.getSyncQueue(100);
|
|
508
565
|
return { items, count: items.length };
|
|
509
566
|
}).post(
|
|
@@ -532,6 +589,33 @@ function adminRoutes(orchestrator) {
|
|
|
532
589
|
return { error: "Not yet implemented" };
|
|
533
590
|
});
|
|
534
591
|
}
|
|
592
|
+
function parseLayerParam(layer) {
|
|
593
|
+
if (!layer) return "both";
|
|
594
|
+
if (layer === "qdrant" || layer === "age" || layer === "both") return layer;
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
function parseBatchParam(batch) {
|
|
598
|
+
if (!batch) return 50;
|
|
599
|
+
const parsed = Number.parseInt(batch, 10);
|
|
600
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return null;
|
|
601
|
+
return parsed;
|
|
602
|
+
}
|
|
603
|
+
function listAllMemories(orchestrator) {
|
|
604
|
+
const pageSize = 5e3;
|
|
605
|
+
const memories = [];
|
|
606
|
+
let offset = 0;
|
|
607
|
+
while (true) {
|
|
608
|
+
const page = orchestrator.sqlite.listMemories({
|
|
609
|
+
limit: pageSize,
|
|
610
|
+
offset,
|
|
611
|
+
order: "asc"
|
|
612
|
+
});
|
|
613
|
+
memories.push(...page);
|
|
614
|
+
if (page.length < pageSize) break;
|
|
615
|
+
offset += pageSize;
|
|
616
|
+
}
|
|
617
|
+
return memories;
|
|
618
|
+
}
|
|
535
619
|
async function migrateMarkdownFiles(orchestrator, request) {
|
|
536
620
|
const { markdown_paths, agent_id, dry_run } = request;
|
|
537
621
|
let migrated = 0;
|
|
@@ -755,4 +839,4 @@ export {
|
|
|
755
839
|
createApp,
|
|
756
840
|
createServer
|
|
757
841
|
};
|
|
758
|
-
//# sourceMappingURL=chunk-
|
|
842
|
+
//# sourceMappingURL=chunk-7DNVIKQ3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.ts","../src/api/router.ts","../src/api/memories.ts","../src/api/search.ts","../src/api/conversations.ts","../src/api/entities.ts","../src/api/admin.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport { resolve } from \"node:path\";\nimport { loadConfig, configSummary } from \"./config/index.js\";\nimport { StorageOrchestrator } from \"./storage/orchestrator.js\";\nimport { createApp } from \"./api/router.js\";\n\n// ── Server Entry Point ──────────────────────────────────────────────────\n\nexport async function createServer(configPath?: string) {\n const config = await loadConfig(configPath);\n const orchestrator = new StorageOrchestrator(config);\n await orchestrator.init();\n\n const app = createApp(orchestrator, config);\n\n return { app, orchestrator, config };\n}\n\n// ── Main ────────────────────────────────────────────────────────────────\n\nasync function main() {\n console.log(\"┌──────────────────────────────────────────┐\");\n console.log(\"│ openclaw-memory service v0.1.0 │\");\n console.log(\"│ Triple-Layer Memory System │\");\n console.log(\"└──────────────────────────────────────────┘\");\n\n const { app, orchestrator, config } = await createServer();\n\n console.log(\"[config]\");\n console.log(configSummary(config).split(\"\\n\").map((l) => ` ${l}`).join(\"\\n\"));\n\n app.listen(config.port);\n console.log(`[server] Listening on http://${config.host}:${config.port}`);\n console.log(`[server] Health check: http://localhost:${config.port}/api/health`);\n\n const shutdown = async () => {\n console.log(\"\\n[server] Shutting down...\");\n await orchestrator.close();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n}\n\n// Run if executed directly (works in both Bun and Node ESM)\nfunction isMainModule(): boolean {\n try {\n // Bun runtime\n const bun = (globalThis as typeof globalThis & { Bun?: { main?: string } }).Bun;\n if (typeof bun !== \"undefined\") {\n return bun.main === fileURLToPath(import.meta.url);\n }\n // Node.js\n if (process.argv[1]) {\n return resolve(process.argv[1]) === resolve(fileURLToPath(import.meta.url));\n }\n return false;\n } catch {\n return false;\n }\n}\n\nif (isMainModule()) {\n main().catch((error) => {\n console.error(\"[fatal]\", error);\n process.exit(1);\n });\n}\n","import { Elysia } from \"elysia\";\nimport { cors } from \"@elysiajs/cors\";\nimport type { ResolvedConfig } from \"../config/index.js\";\nimport type { StorageOrchestrator } from \"../storage/orchestrator.js\";\nimport { AuthError, MemoryError, NotFoundError, ValidationError } from \"../core/errors.js\";\nimport { memoriesRoutes } from \"./memories.js\";\nimport { searchRoutes } from \"./search.js\";\nimport { conversationRoutes } from \"./conversations.js\";\nimport { entityRoutes } from \"./entities.js\";\nimport { adminRoutes } from \"./admin.js\";\n\n// ── App Router ──────────────────────────────────────────────────────────\n\nexport function createApp(orchestrator: StorageOrchestrator, config: ResolvedConfig) {\n const app = new Elysia()\n .use(cors())\n\n // ── Auth Middleware ────────────────────────────────────────────────\n .derive(({ headers, set, path }) => {\n // Skip auth for health check\n if (path === \"/api/health\" || path === \"/health\") return {};\n\n // Skip auth if disabled\n if (!config.auth.enabled || !config.auth.token) return {};\n\n const authHeader = headers.authorization;\n if (!authHeader || !authHeader.startsWith(\"Bearer \")) {\n set.status = 401;\n throw new AuthError(\"Missing or invalid Authorization header\");\n }\n\n const token = authHeader.slice(7);\n if (token !== config.auth.token) {\n set.status = 403;\n throw new AuthError(\"Invalid token\");\n }\n\n return {};\n })\n\n // ── Error Handler ─────────────────────────────────────────────────\n .onError(({ code, error, set }) => {\n // Handle AuthError\n if (error instanceof AuthError) {\n const status = error.message.includes(\"Invalid token\") ? 403 : 401;\n set.status = status;\n return { error: error.message, code: error.code };\n }\n\n // Handle other custom errors\n if (error instanceof NotFoundError) {\n set.status = 404;\n return { error: error.message, code: error.code };\n }\n\n if (error instanceof ValidationError) {\n set.status = 400;\n return { error: error.message, code: error.code, details: error.details };\n }\n\n if (error instanceof MemoryError) {\n set.status = 500;\n return { error: error.message, code: error.code };\n }\n\n // Elysia validation errors\n if (code === \"VALIDATION\") {\n const msg = error && \"message\" in error ? (error as Error).message : String(error);\n set.status = 400;\n return { error: \"Validation error\", details: msg };\n }\n\n // Elysia built-in not found errors\n if (code === \"NOT_FOUND\") {\n const msg =\n error && \"message\" in error ? (error as Error).message : \"Route not found\";\n set.status = 404;\n return { error: msg, code };\n }\n\n // Unknown errors\n const msg = error instanceof Error ? error.stack || error.message : String(error);\n console.error(`[api] Unhandled error: ${msg}`);\n set.status = 500;\n return { error: \"Internal server error\" };\n })\n\n // ── Mount Routes ──────────────────────────────────────────────────\n .use(memoriesRoutes(orchestrator))\n .use(searchRoutes(orchestrator))\n .use(conversationRoutes(orchestrator, config))\n .use(entityRoutes(orchestrator))\n .use(adminRoutes(orchestrator));\n\n return app;\n}\n","import { Elysia, t } from \"elysia\";\nimport type { StorageOrchestrator } from \"../storage/orchestrator.js\";\nimport type { CreateMemoryRequest, UpdateMemoryRequest, MemoryScope, MemorySource } from \"../core/types.js\";\n\n// ── Memory CRUD Routes ──────────────────────────────────────────────────\n\nexport function memoriesRoutes(orchestrator: StorageOrchestrator) {\n return new Elysia({ prefix: \"/api/memories\" })\n // POST /api/memories — Create a new memory\n .post(\n \"/\",\n async ({ body, set }) => {\n try {\n const result = await orchestrator.createMemory(body as CreateMemoryRequest);\n set.status = 201;\n return result;\n } catch (error) {\n set.status = 500;\n return {\n error: \"Failed to create memory\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n },\n {\n body: t.Object({\n agent_id: t.String(),\n scope: t.Union([\n t.Literal(\"user\"),\n t.Literal(\"agent\"),\n t.Literal(\"global\"),\n t.Literal(\"project\"),\n t.Literal(\"session\"),\n ]),\n subject_id: t.Optional(t.Nullable(t.String())),\n content: t.String(),\n tags: t.Optional(t.Array(t.String())),\n source: t.Optional(\n t.Union([\n t.Literal(\"explicit\"),\n t.Literal(\"derived\"),\n t.Literal(\"observation\"),\n t.Literal(\"conversation_summary\"),\n t.Literal(\"entity_extraction\"),\n t.Literal(\"daily_digest\"),\n t.Literal(\"migration\"),\n ])\n ),\n created_by: t.Optional(t.Nullable(t.String())),\n extract_entities: t.Optional(t.Boolean()),\n expires_at: t.Optional(t.Nullable(t.String())),\n }),\n }\n )\n\n // GET /api/memories/:id — Get a memory by ID\n .get(\"/:id\", ({ params, set }) => {\n const memory = orchestrator.sqlite.getMemory(params.id);\n if (!memory) {\n set.status = 404;\n return { error: \"Memory not found\" };\n }\n return memory;\n })\n\n // PUT /api/memories/:id — Update a memory\n .put(\n \"/:id\",\n async ({ params, body, set }) => {\n try {\n const result = await orchestrator.updateMemory(\n params.id,\n body as UpdateMemoryRequest\n );\n if (!result) {\n set.status = 404;\n return { error: \"Memory not found\" };\n }\n return result;\n } catch (error) {\n set.status = 500;\n return {\n error: \"Failed to update memory\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n },\n {\n body: t.Object({\n content: t.Optional(t.String()),\n tags: t.Optional(t.Array(t.String())),\n scope: t.Optional(\n t.Union([\n t.Literal(\"user\"),\n t.Literal(\"agent\"),\n t.Literal(\"global\"),\n t.Literal(\"project\"),\n t.Literal(\"session\"),\n ])\n ),\n subject_id: t.Optional(t.Nullable(t.String())),\n expires_at: t.Optional(t.Nullable(t.String())),\n extract_entities: t.Optional(t.Boolean()),\n }),\n }\n )\n\n // DELETE /api/memories/:id — Delete a memory\n .delete(\"/:id\", async ({ params, set }) => {\n try {\n const deleted = await orchestrator.deleteMemory(params.id);\n if (!deleted) {\n set.status = 404;\n return { error: \"Memory not found\" };\n }\n return { deleted: true, id: params.id };\n } catch (error) {\n set.status = 500;\n return {\n error: \"Failed to delete memory\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n })\n\n // GET /api/memories — List memories with filters\n .get(\"/\", ({ query }) => {\n const memories = orchestrator.sqlite.listMemories({\n agent_id: query.agent_id as string | undefined,\n scope: query.scope as MemoryScope | undefined,\n subject_id: query.subject_id as string | undefined,\n source: query.source as MemorySource | undefined,\n tags: query.tags as string | undefined,\n limit: query.limit ? parseInt(String(query.limit), 10) : undefined,\n offset: query.offset ? parseInt(String(query.offset), 10) : undefined,\n order: (query.order as \"asc\" | \"desc\") || \"desc\",\n });\n return { memories, count: memories.length };\n });\n}\n","import { Elysia, t } from \"elysia\";\nimport { SearchEngine } from \"../search/engine.js\";\nimport type { StorageOrchestrator } from \"../storage/orchestrator.js\";\nimport type { SearchRequest } from \"../core/types.js\";\n\n// ── Search Routes ───────────────────────────────────────────────────────\n\nexport function searchRoutes(orchestrator: StorageOrchestrator) {\n const searchEngine = new SearchEngine(orchestrator);\n\n return new Elysia({ prefix: \"/api/search\" })\n // POST /api/search — Smart search (auto-selects layers)\n .post(\n \"/\",\n async ({ body, set }) => {\n try {\n const req = body as SearchRequest;\n if (!req.agent_id) req.cross_agent = true;\n return await searchEngine.search(req);\n } catch (error) {\n set.status = 500;\n return {\n error: \"Search failed\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n },\n {\n body: t.Object({\n agent_id: t.Optional(t.String()),\n query: t.String(),\n scopes: t.Optional(\n t.Array(\n t.Union([\n t.Literal(\"user\"),\n t.Literal(\"agent\"),\n t.Literal(\"global\"),\n t.Literal(\"project\"),\n t.Literal(\"session\"),\n ])\n )\n ),\n subject_id: t.Optional(t.Nullable(t.String())),\n limit: t.Optional(t.Number()),\n include_graph: t.Optional(t.Boolean()),\n cross_agent: t.Optional(t.Boolean()),\n strategy: t.Optional(\n t.Union([\n t.Literal(\"auto\"),\n t.Literal(\"semantic\"),\n t.Literal(\"fulltext\"),\n t.Literal(\"graph\"),\n t.Literal(\"all\"),\n ])\n ),\n }),\n }\n )\n\n // POST /api/search/semantic — Force Qdrant semantic search\n .post(\n \"/semantic\",\n async ({ body, set }) => {\n try {\n return await searchEngine.search({\n ...(body as SearchRequest),\n strategy: \"semantic\",\n });\n } catch (error) {\n set.status = 500;\n return {\n error: \"Semantic search failed\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n },\n {\n body: t.Object({\n agent_id: t.Optional(t.String()),\n query: t.String(),\n scopes: t.Optional(\n t.Array(\n t.Union([\n t.Literal(\"user\"),\n t.Literal(\"agent\"),\n t.Literal(\"global\"),\n t.Literal(\"project\"),\n t.Literal(\"session\"),\n ])\n )\n ),\n subject_id: t.Optional(t.Nullable(t.String())),\n limit: t.Optional(t.Number()),\n cross_agent: t.Optional(t.Boolean()),\n }),\n }\n )\n\n // POST /api/search/graph — Force AGE graph traversal\n .post(\n \"/graph\",\n async ({ body, set }) => {\n try {\n return await searchEngine.search({\n ...(body as SearchRequest),\n strategy: \"graph\",\n include_graph: true,\n });\n } catch (error) {\n set.status = 500;\n return {\n error: \"Graph search failed\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n },\n {\n body: t.Object({\n agent_id: t.Optional(t.String()),\n query: t.String(),\n scopes: t.Optional(\n t.Array(\n t.Union([\n t.Literal(\"user\"),\n t.Literal(\"agent\"),\n t.Literal(\"global\"),\n t.Literal(\"project\"),\n t.Literal(\"session\"),\n ])\n )\n ),\n subject_id: t.Optional(t.Nullable(t.String())),\n limit: t.Optional(t.Number()),\n }),\n }\n )\n\n // POST /api/search/fulltext — Force SQLite FTS search\n .post(\n \"/fulltext\",\n async ({ body, set }) => {\n try {\n return await searchEngine.search({\n ...(body as SearchRequest),\n strategy: \"fulltext\",\n include_graph: false,\n });\n } catch (error) {\n set.status = 500;\n return {\n error: \"Fulltext search failed\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n },\n {\n body: t.Object({\n agent_id: t.Optional(t.String()),\n query: t.String(),\n scopes: t.Optional(t.Array(t.String())),\n subject_id: t.Optional(t.Nullable(t.String())),\n limit: t.Optional(t.Number()),\n }),\n }\n );\n}\n","import { Elysia, t } from \"elysia\";\nimport type { StorageOrchestrator } from \"../storage/orchestrator.js\";\nimport type { ResolvedConfig } from \"../config/index.js\";\nimport { ConversationSummarizer } from \"../extraction/summarizer.js\";\nimport type { ConversationLogEntry, CreateMemoryRequest, SummarizeResponse } from \"../core/types.js\";\n\n// ── Conversation Routes ─────────────────────────────────────────────────\n\nexport function conversationRoutes(\n orchestrator: StorageOrchestrator,\n config: ResolvedConfig\n) {\n // Summarizer is only available if extraction config is present\n const summarizer = config.extraction\n ? new ConversationSummarizer({\n apiKey: config.extraction.apiKey,\n baseUrl: config.extraction.baseUrl,\n model: config.extraction.model,\n })\n : null;\n\n return new Elysia({ prefix: \"/api/conversations\" })\n // POST /api/conversations/log — Append conversation entry\n .post(\n \"/log\",\n ({ body, set }) => {\n try {\n orchestrator.sqlite.appendConversationLog(body as ConversationLogEntry);\n set.status = 201;\n return { ok: true };\n } catch (error) {\n set.status = 500;\n return {\n error: \"Failed to append conversation log\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n },\n {\n body: t.Object({\n agent_id: t.String(),\n session_id: t.String(),\n user_id: t.String(),\n channel: t.String(),\n role: t.Union([\n t.Literal(\"user\"),\n t.Literal(\"assistant\"),\n t.Literal(\"system\"),\n ]),\n content: t.String(),\n timestamp: t.String(),\n }),\n }\n )\n\n // POST /api/conversations/summarize — Summarize a session\n .post(\n \"/summarize\",\n async ({ body, set }) => {\n if (!summarizer) {\n set.status = 501;\n return { error: \"Summarization not available — extraction config required\" };\n }\n\n try {\n const { agent_id, session_id, user_id, channel, messages } = body;\n\n const summary = await summarizer.summarize(messages);\n if (!summary) {\n set.status = 422;\n return { error: \"Failed to generate summary\" };\n }\n\n const memoryReq: CreateMemoryRequest = {\n agent_id,\n scope: \"session\",\n subject_id: user_id,\n content: summary,\n tags: [\"conversation_summary\", channel, `session:${session_id}`],\n source: \"conversation_summary\",\n created_by: agent_id,\n extract_entities: true,\n };\n\n const result = await orchestrator.createMemory(memoryReq);\n\n const response: SummarizeResponse = {\n memory_id: result.id,\n summary,\n entities_extracted: result.entities,\n relationships_created: 0,\n };\n\n set.status = 201;\n return response;\n } catch (error) {\n set.status = 500;\n return {\n error: \"Summarization failed\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n },\n {\n body: t.Object({\n agent_id: t.String(),\n session_id: t.String(),\n user_id: t.String(),\n channel: t.String(),\n messages: t.Array(\n t.Object({\n role: t.Union([\n t.Literal(\"user\"),\n t.Literal(\"assistant\"),\n t.Literal(\"system\"),\n ]),\n content: t.String(),\n timestamp: t.String(),\n })\n ),\n reason: t.Optional(t.String()),\n }),\n }\n );\n}\n","import { Elysia, t } from \"elysia\";\nimport type { StorageOrchestrator } from \"../storage/orchestrator.js\";\n\n// ── Entity Routes ───────────────────────────────────────────────────────\n\nexport function entityRoutes(orchestrator: StorageOrchestrator) {\n return new Elysia({ prefix: \"/api/entities\" })\n // GET /api/entities/:type — List entities by type\n .get(\"/:type\", async ({ params, query, set }) => {\n if (!orchestrator.age) {\n set.status = 501;\n return { error: \"Graph layer not available — requires Full tier\" };\n }\n\n try {\n const entities = await orchestrator.age.listEntities(\n params.type,\n query.agent_id as string | undefined,\n query.limit ? parseInt(String(query.limit), 10) : 50\n );\n return { entities, count: entities.length };\n } catch (error) {\n set.status = 500;\n return {\n error: \"Failed to list entities\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n })\n\n // GET /api/entities/:type/:id — Get entity with relationships\n .get(\"/:type/:id\", async ({ params, set }) => {\n if (!orchestrator.age) {\n set.status = 501;\n return { error: \"Graph layer not available — requires Full tier\" };\n }\n\n try {\n const result = await orchestrator.age.getEntityWithRelationships(\n params.type,\n params.id\n );\n if (!result.entity) {\n set.status = 404;\n return { error: \"Entity not found\" };\n }\n return result;\n } catch (error) {\n set.status = 500;\n return {\n error: \"Failed to get entity\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n })\n\n // GET /api/entities/:type/:id/related — Get related entities\n .get(\"/:type/:id/related\", async ({ params, query, set }) => {\n if (!orchestrator.age) {\n set.status = 501;\n return { error: \"Graph layer not available — requires Full tier\" };\n }\n\n try {\n const depth = query.depth ? parseInt(String(query.depth), 10) : 2;\n const related = await orchestrator.age.getRelatedEntities(\n params.id,\n depth\n );\n return { related, count: related.length };\n } catch (error) {\n set.status = 500;\n return {\n error: \"Failed to get related entities\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n })\n\n // POST /api/entities/extract — Manually trigger entity extraction\n .post(\n \"/extract\",\n async ({ body, set }) => {\n if (!orchestrator.entityExtractor) {\n set.status = 501;\n return { error: \"Entity extraction not available — requires extraction config\" };\n }\n\n try {\n const result = await orchestrator.entityExtractor.extract(body.text);\n return result;\n } catch (error) {\n set.status = 500;\n return {\n error: \"Entity extraction failed\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n },\n {\n body: t.Object({\n text: t.String(),\n }),\n }\n );\n}\n","import { Elysia, t } from \"elysia\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { StorageOrchestrator } from \"../storage/orchestrator.js\";\nimport type { CreateMemoryRequest, MigrateMarkdownRequest } from \"../core/types.js\";\nimport { SyncQueueProcessor } from \"../storage/sync-queue.js\";\n\n// ── Admin Routes ────────────────────────────────────────────────────────\n\nexport function adminRoutes(orchestrator: StorageOrchestrator) {\n const healthHandler = async () => {\n return await orchestrator.healthCheck();\n };\n\n return new Elysia()\n // GET /api/health and /health — Health checks\n .get(\"/api/health\", healthHandler)\n .get(\"/health\", healthHandler)\n\n // POST /api/sync/retry — Retry failed L2/L3 syncs\n .post(\"/api/sync/retry\", async ({ set }) => {\n try {\n const result = await orchestrator.retrySyncQueue();\n return result;\n } catch (error) {\n set.status = 500;\n return {\n error: \"Sync retry failed\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n })\n\n // POST /api/admin/resync — Requeue all memories for L2/L3 sync\n .post(\n \"/api/admin/resync\",\n async ({ query, set }) => {\n const layerParam = parseLayerParam(query.layer as string | undefined);\n if (!layerParam) {\n set.status = 400;\n return {\n error: \"Invalid layer parameter\",\n details: \"Use ?layer=qdrant|age|both\",\n };\n }\n\n const batch = parseBatchParam(query.batch as string | undefined);\n if (batch === null) {\n set.status = 400;\n return {\n error: \"Invalid batch parameter\",\n details: \"Use a positive integer for ?batch=50\",\n };\n }\n\n const layers: Array<\"qdrant\" | \"age\"> =\n layerParam === \"both\" ? [\"qdrant\", \"age\"] : [layerParam];\n\n try {\n const memories = listAllMemories(orchestrator);\n let queuedItems = 0;\n\n for (const memory of memories) {\n for (const layer of layers) {\n orchestrator.sqlite.addToSyncQueue(memory.id, layer, \"upsert\");\n queuedItems++;\n }\n }\n\n const syncResults = await SyncQueueProcessor.withBatchSize(batch, async () => {\n return await orchestrator.retrySyncQueue();\n });\n\n return {\n layer: layerParam,\n layers,\n batch,\n memory_count: memories.length,\n queued_items: queuedItems,\n sync_results: syncResults,\n };\n } catch (error) {\n set.status = 500;\n return {\n error: \"Resync failed\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n },\n {\n query: t.Object({\n layer: t.Optional(\n t.Union([t.Literal(\"qdrant\"), t.Literal(\"age\"), t.Literal(\"both\")])\n ),\n batch: t.Optional(t.String()),\n }),\n }\n )\n\n // GET /api/sync/queue — View pending sync queue\n .get(\"/api/sync/queue\", () => {\n const items = orchestrator.sqlite.getSyncQueue(100);\n return { items, count: items.length };\n })\n\n // POST /api/admin/migrate-markdown — Migrate markdown files\n .post(\n \"/api/admin/migrate-markdown\",\n async ({ body, set }) => {\n try {\n const results = await migrateMarkdownFiles(orchestrator, body);\n return results;\n } catch (error) {\n set.status = 500;\n return {\n error: \"Migration failed\",\n details: error instanceof Error ? error.message : String(error),\n };\n }\n },\n {\n body: t.Object({\n markdown_paths: t.Array(t.String()),\n agent_id: t.String(),\n dry_run: t.Optional(t.Boolean()),\n }),\n }\n )\n\n // POST /api/admin/daily-digest — Trigger daily digest\n .post(\"/api/admin/daily-digest\", async ({ set }) => {\n set.status = 501;\n return { error: \"Not yet implemented\" };\n });\n}\n\ntype ResyncLayer = \"qdrant\" | \"age\" | \"both\";\n\nfunction parseLayerParam(layer: string | undefined): ResyncLayer | null {\n if (!layer) return \"both\";\n if (layer === \"qdrant\" || layer === \"age\" || layer === \"both\") return layer;\n return null;\n}\n\nfunction parseBatchParam(batch: string | undefined): number | null {\n if (!batch) return 50;\n const parsed = Number.parseInt(batch, 10);\n if (!Number.isFinite(parsed) || parsed <= 0) return null;\n return parsed;\n}\n\nfunction listAllMemories(orchestrator: StorageOrchestrator) {\n const pageSize = 5_000;\n const memories: ReturnType<typeof orchestrator.sqlite.listMemories> = [];\n let offset = 0;\n\n while (true) {\n const page = orchestrator.sqlite.listMemories({\n limit: pageSize,\n offset,\n order: \"asc\",\n });\n\n memories.push(...page);\n if (page.length < pageSize) break;\n offset += pageSize;\n }\n\n return memories;\n}\n\n// ── Markdown Migration ──────────────────────────────────────────────────\n\nasync function migrateMarkdownFiles(\n orchestrator: StorageOrchestrator,\n request: MigrateMarkdownRequest\n): Promise<{\n migrated: number;\n skipped: number;\n errors: string[];\n memories: Array<{ id: string; content_preview: string }>;\n}> {\n const { markdown_paths, agent_id, dry_run } = request;\n let migrated = 0;\n let skipped = 0;\n const errors: string[] = [];\n const memories: Array<{ id: string; content_preview: string }> = [];\n\n for (const filePath of markdown_paths) {\n try {\n if (!fs.existsSync(filePath)) {\n errors.push(`File not found: ${filePath}`);\n skipped++;\n continue;\n }\n\n const content = fs.readFileSync(filePath, \"utf-8\");\n const fileName = path.basename(filePath, \".md\");\n const sections = parseMarkdownSections(content);\n\n for (const section of sections) {\n if (section.content.trim().length < 10) {\n skipped++;\n continue;\n }\n\n if (dry_run) {\n memories.push({\n id: \"(dry-run)\",\n content_preview: section.content.slice(0, 100),\n });\n migrated++;\n continue;\n }\n\n const scope = inferScope(section.heading, fileName);\n const source = inferSource(fileName);\n const tags = inferTags(section.heading, fileName);\n\n const req: CreateMemoryRequest = {\n agent_id,\n scope,\n subject_id: null,\n content: section.content.trim(),\n tags,\n source: source || \"migration\",\n created_by: \"migration\",\n extract_entities: true,\n };\n\n try {\n const result = await orchestrator.createMemory(req);\n memories.push({\n id: result.id,\n content_preview: section.content.slice(0, 100),\n });\n migrated++;\n } catch (error) {\n errors.push(\n `Failed to migrate section \"${section.heading}\": ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n } catch (error) {\n errors.push(\n `Failed to process ${filePath}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n return { migrated, skipped, errors, memories };\n}\n\n// ── Markdown Parsing Helpers ────────────────────────────────────────────\n\ninterface MarkdownSection {\n heading: string;\n content: string;\n level: number;\n}\n\nfunction parseMarkdownSections(markdown: string): MarkdownSection[] {\n const lines = markdown.split(\"\\n\");\n const sections: MarkdownSection[] = [];\n let currentHeading = \"root\";\n let currentLevel = 0;\n let currentContent: string[] = [];\n\n for (const line of lines) {\n const headingMatch = line.match(/^(#{1,3})\\s+(.+)/);\n if (headingMatch) {\n if (currentContent.length > 0) {\n sections.push({\n heading: currentHeading,\n content: currentContent.join(\"\\n\").trim(),\n level: currentLevel,\n });\n }\n currentHeading = headingMatch[2].trim();\n currentLevel = headingMatch[1].length;\n currentContent = [];\n } else {\n currentContent.push(line);\n }\n }\n\n if (currentContent.length > 0) {\n sections.push({\n heading: currentHeading,\n content: currentContent.join(\"\\n\").trim(),\n level: currentLevel,\n });\n }\n\n return sections;\n}\n\nfunction inferScope(heading: string, fileName: string): CreateMemoryRequest[\"scope\"] {\n const h = heading.toLowerCase();\n const f = fileName.toLowerCase();\n\n if (h.includes(\"about\") || h.includes(\"personal\")) return \"user\";\n if (h.includes(\"project\")) return \"project\";\n if (h.includes(\"agent\")) return \"agent\";\n if (h.includes(\"session\") || f.match(/^\\d{4}-\\d{2}-\\d{2}/)) return \"session\";\n return \"global\";\n}\n\nfunction inferSource(fileName: string): CreateMemoryRequest[\"source\"] | null {\n if (fileName.match(/^\\d{4}-\\d{2}-\\d{2}/)) return \"daily_digest\";\n return \"migration\";\n}\n\nfunction inferTags(heading: string, fileName: string): string[] {\n const tags: string[] = [\"migration\"];\n if (fileName.match(/^\\d{4}-\\d{2}-\\d{2}/)) {\n tags.push(\"daily\", fileName);\n }\n if (heading !== \"root\") {\n tags.push(heading.toLowerCase().replace(/[^a-z0-9]+/g, \"-\"));\n }\n return tags;\n}\n"],"mappings":"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","names":["Elysia","Elysia","t","Elysia","t","Elysia","t","Elysia","t","Elysia","t","Elysia","t","Elysia","t","Elysia","path","msg"]}
|
|
@@ -1045,7 +1045,11 @@ function slugify(input) {
|
|
|
1045
1045
|
}
|
|
1046
1046
|
|
|
1047
1047
|
// src/storage/sync-queue.ts
|
|
1048
|
-
var SyncQueueProcessor = class {
|
|
1048
|
+
var SyncQueueProcessor = class _SyncQueueProcessor {
|
|
1049
|
+
static batchSizeOverride = null;
|
|
1050
|
+
static SQLITE_ATTEMPT_CEILING = 5;
|
|
1051
|
+
static DEFAULT_BATCH_SIZE = 50;
|
|
1052
|
+
static DEFAULT_MAX_RETRIES = 20;
|
|
1049
1053
|
sqlite;
|
|
1050
1054
|
qdrant;
|
|
1051
1055
|
age;
|
|
@@ -1058,6 +1062,18 @@ var SyncQueueProcessor = class {
|
|
|
1058
1062
|
this.age = age;
|
|
1059
1063
|
this.embeddings = embeddings;
|
|
1060
1064
|
}
|
|
1065
|
+
static async withBatchSize(batchSize, fn) {
|
|
1066
|
+
const previous = _SyncQueueProcessor.batchSizeOverride;
|
|
1067
|
+
_SyncQueueProcessor.batchSizeOverride = clampPositiveInt(
|
|
1068
|
+
batchSize,
|
|
1069
|
+
_SyncQueueProcessor.DEFAULT_BATCH_SIZE
|
|
1070
|
+
);
|
|
1071
|
+
try {
|
|
1072
|
+
return await fn();
|
|
1073
|
+
} finally {
|
|
1074
|
+
_SyncQueueProcessor.batchSizeOverride = previous;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1061
1077
|
start(intervalMs = 6e4) {
|
|
1062
1078
|
if (this.interval) return;
|
|
1063
1079
|
console.log(`[sync-queue] Starting processor (every ${intervalMs / 1e3}s)`);
|
|
@@ -1073,18 +1089,22 @@ var SyncQueueProcessor = class {
|
|
|
1073
1089
|
console.log("[sync-queue] Stopped");
|
|
1074
1090
|
}
|
|
1075
1091
|
}
|
|
1076
|
-
async processQueue() {
|
|
1092
|
+
async processQueue(batchSize) {
|
|
1077
1093
|
if (this.processing) return { processed: 0, succeeded: 0, failed: 0 };
|
|
1078
1094
|
this.processing = true;
|
|
1079
1095
|
let processed = 0;
|
|
1080
1096
|
let succeeded = 0;
|
|
1081
1097
|
let failed = 0;
|
|
1098
|
+
const effectiveBatchSize = this.resolveBatchSize(batchSize);
|
|
1099
|
+
const maxRetries = this.resolveMaxRetries();
|
|
1082
1100
|
try {
|
|
1083
|
-
const items = this.sqlite.getSyncQueue(
|
|
1101
|
+
const items = this.sqlite.getSyncQueue(effectiveBatchSize);
|
|
1084
1102
|
if (items.length === 0) {
|
|
1085
1103
|
return { processed: 0, succeeded: 0, failed: 0 };
|
|
1086
1104
|
}
|
|
1087
|
-
console.log(
|
|
1105
|
+
console.log(
|
|
1106
|
+
`[sync-queue] Processing ${items.length} items (batch=${effectiveBatchSize}, maxRetries=${maxRetries})`
|
|
1107
|
+
);
|
|
1088
1108
|
for (const item of items) {
|
|
1089
1109
|
processed++;
|
|
1090
1110
|
try {
|
|
@@ -1093,7 +1113,7 @@ var SyncQueueProcessor = class {
|
|
|
1093
1113
|
succeeded++;
|
|
1094
1114
|
} catch (error) {
|
|
1095
1115
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
1096
|
-
this.
|
|
1116
|
+
this.handleFailure(item, errorMsg, maxRetries);
|
|
1097
1117
|
failed++;
|
|
1098
1118
|
console.warn(
|
|
1099
1119
|
`[sync-queue] Failed item ${item.id} (${item.layer}/${item.operation}/${item.memory_id}): ${errorMsg}`
|
|
@@ -1102,7 +1122,7 @@ var SyncQueueProcessor = class {
|
|
|
1102
1122
|
}
|
|
1103
1123
|
const cleared = this.sqlite.clearCompletedSyncItems();
|
|
1104
1124
|
if (cleared > 0) {
|
|
1105
|
-
console.log(`[sync-queue] Cleared ${cleared} items that
|
|
1125
|
+
console.log(`[sync-queue] Cleared ${cleared} items that reached retry limit`);
|
|
1106
1126
|
}
|
|
1107
1127
|
} finally {
|
|
1108
1128
|
this.processing = false;
|
|
@@ -1146,7 +1166,75 @@ var SyncQueueProcessor = class {
|
|
|
1146
1166
|
await this.age.linkMemoryToEntity(memory.id, entityId);
|
|
1147
1167
|
}
|
|
1148
1168
|
}
|
|
1169
|
+
resolveBatchSize(batchSize) {
|
|
1170
|
+
if (batchSize !== void 0) {
|
|
1171
|
+
return clampPositiveInt(batchSize, _SyncQueueProcessor.DEFAULT_BATCH_SIZE);
|
|
1172
|
+
}
|
|
1173
|
+
if (_SyncQueueProcessor.batchSizeOverride !== null) {
|
|
1174
|
+
return _SyncQueueProcessor.batchSizeOverride;
|
|
1175
|
+
}
|
|
1176
|
+
return clampPositiveInt(
|
|
1177
|
+
parseInt(process.env.SYNC_QUEUE_BATCH_SIZE || "", 10),
|
|
1178
|
+
_SyncQueueProcessor.DEFAULT_BATCH_SIZE
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
resolveMaxRetries() {
|
|
1182
|
+
return Math.max(
|
|
1183
|
+
_SyncQueueProcessor.SQLITE_ATTEMPT_CEILING,
|
|
1184
|
+
clampPositiveInt(
|
|
1185
|
+
parseInt(process.env.SYNC_QUEUE_MAX_RETRIES || "", 10),
|
|
1186
|
+
_SyncQueueProcessor.DEFAULT_MAX_RETRIES
|
|
1187
|
+
)
|
|
1188
|
+
);
|
|
1189
|
+
}
|
|
1190
|
+
handleFailure(item, errorMessage, maxRetries) {
|
|
1191
|
+
const priorLogicalAttempts = extractLogicalAttempts(item.last_error, item.attempts);
|
|
1192
|
+
const nextLogicalAttempts = priorLogicalAttempts + 1;
|
|
1193
|
+
const physicalNextAttempt = item.attempts + 1;
|
|
1194
|
+
if (nextLogicalAttempts >= maxRetries) {
|
|
1195
|
+
this.sqlite.updateSyncQueueItem(
|
|
1196
|
+
item.id,
|
|
1197
|
+
_SyncQueueProcessor.SQLITE_ATTEMPT_CEILING,
|
|
1198
|
+
formatAttemptError(errorMessage, nextLogicalAttempts, maxRetries)
|
|
1199
|
+
);
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
if (physicalNextAttempt >= _SyncQueueProcessor.SQLITE_ATTEMPT_CEILING) {
|
|
1203
|
+
this.sqlite.updateSyncQueueItem(
|
|
1204
|
+
item.id,
|
|
1205
|
+
0,
|
|
1206
|
+
formatAttemptError(errorMessage, nextLogicalAttempts, maxRetries)
|
|
1207
|
+
);
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
this.sqlite.updateSyncQueueItem(
|
|
1211
|
+
item.id,
|
|
1212
|
+
physicalNextAttempt,
|
|
1213
|
+
formatAttemptError(errorMessage, nextLogicalAttempts, maxRetries)
|
|
1214
|
+
);
|
|
1215
|
+
}
|
|
1149
1216
|
};
|
|
1217
|
+
function clampPositiveInt(value, fallback) {
|
|
1218
|
+
if (!Number.isFinite(value)) return fallback;
|
|
1219
|
+
const rounded = Math.floor(value);
|
|
1220
|
+
if (rounded <= 0) return fallback;
|
|
1221
|
+
return rounded;
|
|
1222
|
+
}
|
|
1223
|
+
function formatAttemptError(errorMessage, attempts, maxRetries) {
|
|
1224
|
+
return `[attempt ${attempts}/${maxRetries}] ${errorMessage}`;
|
|
1225
|
+
}
|
|
1226
|
+
function extractLogicalAttempts(lastError, fallback) {
|
|
1227
|
+
if (lastError) {
|
|
1228
|
+
const match = /^\[attempt (\d+)\/\d+\]\s*/.exec(lastError);
|
|
1229
|
+
if (match) {
|
|
1230
|
+
const parsed = Number.parseInt(match[1], 10);
|
|
1231
|
+
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
1232
|
+
return parsed;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
return fallback;
|
|
1237
|
+
}
|
|
1150
1238
|
|
|
1151
1239
|
// src/extraction/embeddings.ts
|
|
1152
1240
|
import OpenAI from "openai";
|
|
@@ -1665,7 +1753,8 @@ function applyBoosts(result, layerAppearances) {
|
|
|
1665
1753
|
}
|
|
1666
1754
|
|
|
1667
1755
|
// src/search/engine.ts
|
|
1668
|
-
var SearchEngine = class {
|
|
1756
|
+
var SearchEngine = class _SearchEngine {
|
|
1757
|
+
static LAYER_TIMEOUT_MS = 5e3;
|
|
1669
1758
|
orchestrator;
|
|
1670
1759
|
constructor(orchestrator) {
|
|
1671
1760
|
this.orchestrator = orchestrator;
|
|
@@ -1684,34 +1773,38 @@ var SearchEngine = class {
|
|
|
1684
1773
|
const searches = [];
|
|
1685
1774
|
if (shouldSearchFulltext(strategy)) {
|
|
1686
1775
|
searches.push(
|
|
1687
|
-
this.searchFulltext(request, scopes, limit)
|
|
1688
|
-
layerStats.sqlite.count = results.length;
|
|
1689
|
-
allResults.push(...results);
|
|
1690
|
-
})
|
|
1776
|
+
this.collectLayerResults("sqlite", () => this.searchFulltext(request, scopes, limit), layerStats, allResults)
|
|
1691
1777
|
);
|
|
1692
1778
|
}
|
|
1693
1779
|
if (shouldSearchSemantic(strategy) && this.orchestrator.qdrant && this.orchestrator.embeddings) {
|
|
1694
1780
|
searches.push(
|
|
1695
|
-
this.
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1781
|
+
this.collectLayerResults(
|
|
1782
|
+
"qdrant",
|
|
1783
|
+
() => this.withLayerTimeout(
|
|
1784
|
+
"qdrant",
|
|
1785
|
+
() => this.searchSemantic(request, scopes, limit),
|
|
1786
|
+
_SearchEngine.LAYER_TIMEOUT_MS
|
|
1787
|
+
),
|
|
1788
|
+
layerStats,
|
|
1789
|
+
allResults
|
|
1790
|
+
)
|
|
1699
1791
|
);
|
|
1700
1792
|
}
|
|
1701
1793
|
if (shouldSearchGraph(strategy) && includeGraph && this.orchestrator.age) {
|
|
1702
1794
|
searches.push(
|
|
1703
|
-
this.
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1795
|
+
this.collectLayerResults(
|
|
1796
|
+
"age",
|
|
1797
|
+
() => this.withLayerTimeout(
|
|
1798
|
+
"age",
|
|
1799
|
+
() => this.searchGraph(request, limit),
|
|
1800
|
+
_SearchEngine.LAYER_TIMEOUT_MS
|
|
1801
|
+
),
|
|
1802
|
+
layerStats,
|
|
1803
|
+
allResults
|
|
1804
|
+
)
|
|
1707
1805
|
);
|
|
1708
1806
|
}
|
|
1709
|
-
const startTime = Date.now();
|
|
1710
1807
|
await Promise.allSettled(searches);
|
|
1711
|
-
const elapsed = Date.now() - startTime;
|
|
1712
|
-
if (layerStats.sqlite.count > 0) layerStats.sqlite.ms = elapsed;
|
|
1713
|
-
if (layerStats.qdrant.count > 0) layerStats.qdrant.ms = elapsed;
|
|
1714
|
-
if (layerStats.age.count > 0) layerStats.age.ms = elapsed;
|
|
1715
1808
|
const merged = this.mergeResults(allResults, limit);
|
|
1716
1809
|
return {
|
|
1717
1810
|
results: merged,
|
|
@@ -1773,6 +1866,42 @@ var SearchEngine = class {
|
|
|
1773
1866
|
return [];
|
|
1774
1867
|
}
|
|
1775
1868
|
}
|
|
1869
|
+
async collectLayerResults(layer, fn, layerStats, allResults) {
|
|
1870
|
+
const startedAt = Date.now();
|
|
1871
|
+
try {
|
|
1872
|
+
const results = await fn();
|
|
1873
|
+
layerStats[layer].count = results.length;
|
|
1874
|
+
allResults.push(...results);
|
|
1875
|
+
} finally {
|
|
1876
|
+
layerStats[layer].ms = Date.now() - startedAt;
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
async withLayerTimeout(layer, fn, timeoutMs) {
|
|
1880
|
+
let timeoutId;
|
|
1881
|
+
let timedOut = false;
|
|
1882
|
+
const layerPromise = fn().catch((error) => {
|
|
1883
|
+
console.warn(`[search] ${layer} search failed: ${error}`);
|
|
1884
|
+
return [];
|
|
1885
|
+
});
|
|
1886
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
1887
|
+
timeoutId = setTimeout(() => {
|
|
1888
|
+
timedOut = true;
|
|
1889
|
+
console.warn(
|
|
1890
|
+
`[search] ${layer} search timed out after ${timeoutMs}ms, returning results from other layers`
|
|
1891
|
+
);
|
|
1892
|
+
resolve([]);
|
|
1893
|
+
}, timeoutMs);
|
|
1894
|
+
});
|
|
1895
|
+
try {
|
|
1896
|
+
const results = await Promise.race([layerPromise, timeoutPromise]);
|
|
1897
|
+
return results;
|
|
1898
|
+
} finally {
|
|
1899
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
1900
|
+
if (timedOut) {
|
|
1901
|
+
void layerPromise;
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1776
1905
|
// ── Result Merging ──────────────────────────────────────────────────
|
|
1777
1906
|
mergeResults(allResults, limit) {
|
|
1778
1907
|
const byId = /* @__PURE__ */ new Map();
|
|
@@ -1875,8 +2004,9 @@ var ConversationSummarizer = class {
|
|
|
1875
2004
|
};
|
|
1876
2005
|
|
|
1877
2006
|
export {
|
|
2007
|
+
SyncQueueProcessor,
|
|
1878
2008
|
StorageOrchestrator,
|
|
1879
2009
|
SearchEngine,
|
|
1880
2010
|
ConversationSummarizer
|
|
1881
2011
|
};
|
|
1882
|
-
//# sourceMappingURL=chunk-
|
|
2012
|
+
//# sourceMappingURL=chunk-BTR4T5L3.js.map
|