@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.
Files changed (41) hide show
  1. package/dist/{chunk-VB5GGBGB.js → chunk-7DNVIKQ3.js} +88 -4
  2. package/dist/chunk-7DNVIKQ3.js.map +1 -0
  3. package/dist/{chunk-RZPYOMPO.js → chunk-BTR4T5L3.js} +155 -25
  4. package/dist/chunk-BTR4T5L3.js.map +1 -0
  5. package/dist/{chunk-L2KRIMDA.cjs → chunk-CSGZH2SG.cjs} +5 -5
  6. package/dist/chunk-CSGZH2SG.cjs.map +1 -0
  7. package/dist/{chunk-5SZWJKD5.js → chunk-J2C5USXH.js} +2 -2
  8. package/dist/{chunk-HPGHPKK3.cjs → chunk-JYQB2DOK.cjs} +159 -29
  9. package/dist/chunk-JYQB2DOK.cjs.map +1 -0
  10. package/dist/chunk-LA5OP5VI.cjs.map +1 -1
  11. package/dist/{chunk-MQEBVCH5.cjs → chunk-NYZMAY73.cjs} +90 -6
  12. package/dist/chunk-NYZMAY73.cjs.map +1 -0
  13. package/dist/cli/index.cjs +3 -3
  14. package/dist/cli/index.cjs.map +1 -1
  15. package/dist/cli/index.js +3 -3
  16. package/dist/index.cjs +4 -4
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +52 -2
  19. package/dist/index.d.ts +52 -2
  20. package/dist/index.js +3 -3
  21. package/dist/memory-service-B2BAEKR2.cjs +9 -0
  22. package/dist/memory-service-B2BAEKR2.cjs.map +1 -0
  23. package/dist/memory-service-ZTLGPIUH.js +9 -0
  24. package/dist/{server-D-3OqU-T.d.ts → server-CtNlCow7.d.cts} +50 -0
  25. package/dist/{server-D-3OqU-T.d.cts → server-CtNlCow7.d.ts} +50 -0
  26. package/dist/server.cjs +3 -3
  27. package/dist/server.cjs.map +1 -1
  28. package/dist/server.d.cts +1 -1
  29. package/dist/server.d.ts +1 -1
  30. package/dist/server.js +2 -2
  31. package/package.json +1 -1
  32. package/dist/chunk-HPGHPKK3.cjs.map +0 -1
  33. package/dist/chunk-L2KRIMDA.cjs.map +0 -1
  34. package/dist/chunk-MQEBVCH5.cjs.map +0 -1
  35. package/dist/chunk-RZPYOMPO.js.map +0 -1
  36. package/dist/chunk-VB5GGBGB.js.map +0 -1
  37. package/dist/memory-service-4ZPYUN4L.js +0 -9
  38. package/dist/memory-service-LURM3FBB.cjs +0 -9
  39. package/dist/memory-service-LURM3FBB.cjs.map +0 -1
  40. /package/dist/{chunk-5SZWJKD5.js.map → chunk-J2C5USXH.js.map} +0 -0
  41. /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
- } from "./chunk-RZPYOMPO.js";
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
- }).get("/api/sync/queue", () => {
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-VB5GGBGB.js.map
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(50);
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(`[sync-queue] Processing ${items.length} items`);
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.sqlite.updateSyncQueueItem(item.id, item.attempts + 1, errorMsg);
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 exceeded max retries`);
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).then((results) => {
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.searchSemantic(request, scopes, limit).then((results) => {
1696
- layerStats.qdrant.count = results.length;
1697
- allResults.push(...results);
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.searchGraph(request, limit).then((results) => {
1704
- layerStats.age.count = results.length;
1705
- allResults.push(...results);
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-RZPYOMPO.js.map
2012
+ //# sourceMappingURL=chunk-BTR4T5L3.js.map