@melandlabs/memory-store 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/http.d.ts +13 -0
- package/dist/http.js +52 -6
- package/dist/http.js.map +1 -1
- package/dist/mcp.js +55 -6
- package/dist/mcp.js.map +1 -1
- package/dist/server/cli-http.js +383 -18
- package/dist/server/cli-http.js.map +1 -1
- package/dist/server/cli-mcp.js +395 -7
- package/dist/server/cli-mcp.js.map +1 -1
- package/dist/server/cli-shared.d.ts +39 -0
- package/dist/server/cli-shared.js +373 -0
- package/dist/server/cli-shared.js.map +1 -0
- package/package.json +12 -7
package/dist/server/cli-http.js
CHANGED
|
@@ -462,6 +462,34 @@ function createUnifiedSearch(deps = {}) {
|
|
|
462
462
|
}
|
|
463
463
|
|
|
464
464
|
// src/http.ts
|
|
465
|
+
async function embedMissingMessages(messages, deps) {
|
|
466
|
+
if (typeof deps.embedQuery !== "function") {
|
|
467
|
+
return messages;
|
|
468
|
+
}
|
|
469
|
+
const out = [];
|
|
470
|
+
for (const message of messages) {
|
|
471
|
+
if (Array.isArray(message.embedding) && message.embedding.length > 0) {
|
|
472
|
+
out.push(message);
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
if (typeof message.content !== "string" || message.content.length === 0) {
|
|
476
|
+
out.push(message);
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
const vector = await deps.embedQuery({
|
|
480
|
+
userId: message.userId,
|
|
481
|
+
query: message.content
|
|
482
|
+
});
|
|
483
|
+
out.push({
|
|
484
|
+
...message,
|
|
485
|
+
embedding: vector,
|
|
486
|
+
embeddingModel: message.embeddingModel ?? "server",
|
|
487
|
+
embeddingDimensions: vector.length,
|
|
488
|
+
embeddingUpdatedAt: Date.now()
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
return out;
|
|
492
|
+
}
|
|
465
493
|
async function startHttpServer(options = {}) {
|
|
466
494
|
const port = options.port ?? Number.parseInt(process.env.MEMORY_HTTP_PORT ?? "7421", 10);
|
|
467
495
|
const host = options.host ?? process.env.MEMORY_HTTP_HOST ?? "127.0.0.1";
|
|
@@ -497,16 +525,34 @@ async function startHttpServer(options = {}) {
|
|
|
497
525
|
return c.json({ error: "userId and messages[] required" }, 400);
|
|
498
526
|
}
|
|
499
527
|
const manager2 = await rawStore.getManager();
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
528
|
+
const incoming = body.messages;
|
|
529
|
+
const messages = body.embedOnInsert === true ? await embedMissingMessages(
|
|
530
|
+
incoming.map((m) => ({ ...m, userId: m.userId ?? body.userId })),
|
|
531
|
+
options.unified ?? {}
|
|
532
|
+
) : incoming.map((m) => ({ ...m, userId: m.userId ?? body.userId }));
|
|
533
|
+
let result;
|
|
534
|
+
if (typeof manager2.upsertRawMessages === "function") {
|
|
535
|
+
result = await manager2.upsertRawMessages({
|
|
536
|
+
userId: body.userId,
|
|
537
|
+
messages
|
|
538
|
+
});
|
|
539
|
+
} else if (typeof manager2.storeMessages === "function") {
|
|
540
|
+
const ids = await manager2.storeMessages(messages);
|
|
541
|
+
result = { inserted: ids.length, ids };
|
|
542
|
+
} else {
|
|
543
|
+
return c.json(
|
|
544
|
+
{
|
|
545
|
+
error: "active raw-message manager exposes neither upsertRawMessages nor storeMessages"
|
|
546
|
+
},
|
|
547
|
+
500
|
|
548
|
+
);
|
|
549
|
+
}
|
|
504
550
|
try {
|
|
505
|
-
await upsertRawMessagesToChroma(
|
|
551
|
+
await upsertRawMessagesToChroma(messages);
|
|
506
552
|
} catch (error) {
|
|
507
553
|
console.warn("[memory-store/http] chroma upsert failed:", error);
|
|
508
554
|
}
|
|
509
|
-
return c.json({ ok: true, result });
|
|
555
|
+
return c.json({ ok: true, count: messages.length, result });
|
|
510
556
|
});
|
|
511
557
|
app.get("/v1/raw-messages/:id", async (c) => {
|
|
512
558
|
const id = c.req.param("id");
|
|
@@ -528,33 +574,352 @@ async function startHttpServer(options = {}) {
|
|
|
528
574
|
};
|
|
529
575
|
}
|
|
530
576
|
|
|
577
|
+
// src/storage/sqlite-vector-index.ts
|
|
578
|
+
function getMemoryVectorStoreBackend() {
|
|
579
|
+
const backend = (process.env.INSIGHT_VECTOR_STORE_BACKEND || process.env.MEMORY_VECTOR_STORE_BACKEND || process.env.VECTOR_STORE_BACKEND || "sqlite-vec").toLowerCase();
|
|
580
|
+
return backend === "chroma" ? "chroma" : "sqlite-vec";
|
|
581
|
+
}
|
|
582
|
+
function isInsightSQLiteVecEnabled(_env) {
|
|
583
|
+
return getMemoryVectorStoreBackend() === "sqlite-vec";
|
|
584
|
+
}
|
|
585
|
+
async function getInsightSQLiteVecStore(_env) {
|
|
586
|
+
const dbPath = resolveSQLiteRawMessageDbPath();
|
|
587
|
+
const { getSQLiteVecStore } = await import('@melandlabs/rag/sqlite-vec-store');
|
|
588
|
+
return await getSQLiteVecStore(dbPath, void 0, {
|
|
589
|
+
collectionName: process.env.SQLITE_VEC_INSIGHTS_COLLECTION || "opencontext_insights"
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
async function searchInsightsWithSQLiteVec(input, env) {
|
|
593
|
+
const store = await getInsightSQLiteVecStore();
|
|
594
|
+
const overfetchLimit = Math.max(input.limit * 8, input.limit);
|
|
595
|
+
const results = await store.similaritySearchWithOptions(input.queryEmbedding, {
|
|
596
|
+
limit: overfetchLimit,
|
|
597
|
+
filter: { userId: input.userId }
|
|
598
|
+
});
|
|
599
|
+
return results.filter((result) => result.score >= input.threshold).filter((result) => {
|
|
600
|
+
const metadata = result.metadata ?? {};
|
|
601
|
+
if (input.botIds?.length && !input.botIds.includes(String(metadata.botId ?? ""))) {
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
return input.includeArchived || metadata.archived !== true;
|
|
605
|
+
}).slice(0, input.limit);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// src/server/cli-shared.ts
|
|
609
|
+
async function loadAiRag() {
|
|
610
|
+
try {
|
|
611
|
+
const [local, chroma] = await Promise.all([
|
|
612
|
+
import('@melandlabs/ai-rag/local-transformers-embedding-provider'),
|
|
613
|
+
import('@melandlabs/ai-rag/chroma-store')
|
|
614
|
+
]);
|
|
615
|
+
return {
|
|
616
|
+
LocalTransformersEmbeddingProvider: local.LocalTransformersEmbeddingProvider,
|
|
617
|
+
ChromaVectorStore: chroma.ChromaVectorStore
|
|
618
|
+
};
|
|
619
|
+
} catch (error) {
|
|
620
|
+
throw new Error(
|
|
621
|
+
`--embedding-provider local / --*-backend=chroma require @melandlabs/ai-rag to be installed. Run \`pnpm add @melandlabs/ai-rag\` and try again. (${error.message})`
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
function parseUnifiedArgs(argv) {
|
|
626
|
+
const env = process.env;
|
|
627
|
+
const args = {
|
|
628
|
+
embeddingProvider: env.EMBEDDING_PROVIDER ?? "none",
|
|
629
|
+
embeddingModel: env.EMBEDDING_MODEL,
|
|
630
|
+
chromaUrl: env.CHROMA_URL,
|
|
631
|
+
memoryBackend: env.MEMORY_BACKEND ?? "none",
|
|
632
|
+
insightsBackend: env.INSIGHTS_BACKEND ?? "none",
|
|
633
|
+
insightsCollection: env.INSIGHTS_COLLECTION ?? "opencontext_insights",
|
|
634
|
+
knowledgeBackend: env.KNOWLEDGE_BACKEND ?? "none",
|
|
635
|
+
knowledgeCollection: env.KNOWLEDGE_COLLECTION ?? "opencontext_knowledge"
|
|
636
|
+
};
|
|
637
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
638
|
+
const arg = argv[i];
|
|
639
|
+
const next = argv[i + 1];
|
|
640
|
+
const takeValue = () => {
|
|
641
|
+
if (next === void 0) throw new Error(`[memory-store/http] ${arg} requires a value`);
|
|
642
|
+
i += 1;
|
|
643
|
+
return next;
|
|
644
|
+
};
|
|
645
|
+
switch (arg) {
|
|
646
|
+
case "--embedding-provider":
|
|
647
|
+
args.embeddingProvider = takeValue();
|
|
648
|
+
break;
|
|
649
|
+
case "--embedding-model":
|
|
650
|
+
args.embeddingModel = takeValue();
|
|
651
|
+
break;
|
|
652
|
+
case "--chroma-url":
|
|
653
|
+
args.chromaUrl = takeValue();
|
|
654
|
+
break;
|
|
655
|
+
case "--memory-backend":
|
|
656
|
+
args.memoryBackend = takeValue();
|
|
657
|
+
break;
|
|
658
|
+
case "--insights-backend":
|
|
659
|
+
args.insightsBackend = takeValue();
|
|
660
|
+
break;
|
|
661
|
+
case "--insights-collection":
|
|
662
|
+
args.insightsCollection = takeValue();
|
|
663
|
+
break;
|
|
664
|
+
case "--knowledge-backend":
|
|
665
|
+
args.knowledgeBackend = takeValue();
|
|
666
|
+
break;
|
|
667
|
+
case "--knowledge-collection":
|
|
668
|
+
args.knowledgeCollection = takeValue();
|
|
669
|
+
break;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
for (const [name, value] of [
|
|
673
|
+
["--embedding-provider", args.embeddingProvider],
|
|
674
|
+
["--memory-backend", args.memoryBackend],
|
|
675
|
+
["--insights-backend", args.insightsBackend],
|
|
676
|
+
["--knowledge-backend", args.knowledgeBackend]
|
|
677
|
+
]) {
|
|
678
|
+
const allowed = ["local", "openrouter", "none", "chroma", "sqlite-vec"];
|
|
679
|
+
if (!allowed.includes(value)) {
|
|
680
|
+
throw new Error(`[memory-store/cli] ${name} must be one of: ${allowed.join(", ")} (got "${value}")`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
return args;
|
|
684
|
+
}
|
|
685
|
+
async function buildUnified(args) {
|
|
686
|
+
const unified = {};
|
|
687
|
+
const log = (msg) => console.warn(`[memory-store/cli] ${msg}`);
|
|
688
|
+
const wantsAiRag = args.embeddingProvider === "local" || args.memoryBackend === "chroma" || args.insightsBackend === "chroma" || args.knowledgeBackend === "chroma";
|
|
689
|
+
const aiRag = wantsAiRag ? await loadAiRag() : null;
|
|
690
|
+
if (args.embeddingProvider === "local") {
|
|
691
|
+
const provider = new aiRag.LocalTransformersEmbeddingProvider({ modelName: args.embeddingModel });
|
|
692
|
+
unified.embedQuery = async ({ query }) => provider.embedQuery(query);
|
|
693
|
+
log(
|
|
694
|
+
`embedQuery wired via LocalTransformersEmbeddingProvider (model=${args.embeddingModel ?? "Xenova/all-MiniLM-L6-v2"})`
|
|
695
|
+
);
|
|
696
|
+
} else if (args.embeddingProvider === "openrouter") {
|
|
697
|
+
const apiKey = process.env.OPENROUTER_API_KEY;
|
|
698
|
+
if (!apiKey) {
|
|
699
|
+
throw new Error("--embedding-provider openrouter requires OPENROUTER_API_KEY in the environment");
|
|
700
|
+
}
|
|
701
|
+
const model = args.embeddingModel ?? "text-embedding-3-small";
|
|
702
|
+
const baseURL = "https://openrouter.ai/api/v1";
|
|
703
|
+
unified.embedQuery = async ({ query }) => {
|
|
704
|
+
const res = await fetch(`${baseURL}/embeddings`, {
|
|
705
|
+
method: "POST",
|
|
706
|
+
headers: {
|
|
707
|
+
"content-type": "application/json",
|
|
708
|
+
authorization: `Bearer ${apiKey}`,
|
|
709
|
+
"HTTP-Referer": process.env.NEXT_PUBLIC_APP_URL ?? "https://opencontext.ai",
|
|
710
|
+
"X-Title": "opencontext AI"
|
|
711
|
+
},
|
|
712
|
+
body: JSON.stringify({ model, input: query })
|
|
713
|
+
});
|
|
714
|
+
if (!res.ok) {
|
|
715
|
+
throw new Error(`openrouter embeddings ${res.status}: ${await res.text()}`);
|
|
716
|
+
}
|
|
717
|
+
const body = await res.json();
|
|
718
|
+
const embedding = body.data?.[0]?.embedding;
|
|
719
|
+
if (!embedding) throw new Error("openrouter embeddings response missing data[0].embedding");
|
|
720
|
+
return embedding;
|
|
721
|
+
};
|
|
722
|
+
log(`embedQuery wired via openrouter (model=${model})`);
|
|
723
|
+
}
|
|
724
|
+
if (args.memoryBackend === "sqlite-vec") {
|
|
725
|
+
const store = createRawMessageStore({ env: void 0 });
|
|
726
|
+
const manager2 = await store.getManager();
|
|
727
|
+
if (typeof manager2.searchMessagesSemantically !== "function") {
|
|
728
|
+
throw new Error(
|
|
729
|
+
"the active raw-message manager does not implement searchMessagesSemantically; sqlite-vec ANN for the memory source is unavailable in this build"
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
unified.searchRawMessagesAnn = async ({ userId, queryEmbedding, limit, threshold, botId }) => {
|
|
733
|
+
const rows = await manager2.searchMessagesSemantically({
|
|
734
|
+
userId,
|
|
735
|
+
queryEmbedding,
|
|
736
|
+
limit,
|
|
737
|
+
threshold,
|
|
738
|
+
botId
|
|
739
|
+
});
|
|
740
|
+
return rows.map((r) => ({
|
|
741
|
+
id: r.id,
|
|
742
|
+
content: r.content,
|
|
743
|
+
similarity: r.similarity,
|
|
744
|
+
metadata: r.metadata ?? {}
|
|
745
|
+
}));
|
|
746
|
+
};
|
|
747
|
+
log("memory backend wired via sqlite-vec (uses the manager's searchMessagesSemantically)");
|
|
748
|
+
} else if (args.memoryBackend === "chroma") {
|
|
749
|
+
if (!args.chromaUrl)
|
|
750
|
+
throw new Error("--memory-backend=chroma requires --chroma-url <url> (or CHROMA_URL env)");
|
|
751
|
+
const store = new aiRag.ChromaVectorStore({
|
|
752
|
+
url: args.chromaUrl,
|
|
753
|
+
collectionName: "opencontext_raw_messages"
|
|
754
|
+
});
|
|
755
|
+
unified.searchRawMessagesAnn = async ({ queryEmbedding, limit, threshold }) => {
|
|
756
|
+
const results = await store.similaritySearchWithOptions(queryEmbedding, { limit: limit + 1 });
|
|
757
|
+
return results.filter((r) => r.score >= threshold).map((r) => ({ id: r.id, content: r.content, similarity: r.score, metadata: r.metadata ?? {} }));
|
|
758
|
+
};
|
|
759
|
+
log("memory backend wired via chroma (collection=opencontext_raw_messages)");
|
|
760
|
+
}
|
|
761
|
+
if (args.insightsBackend === "sqlite-vec" && isInsightSQLiteVecEnabled()) {
|
|
762
|
+
if (!unified.embedQuery) {
|
|
763
|
+
throw new Error("--insights-backend=sqlite-vec requires --embedding-provider local|openrouter");
|
|
764
|
+
}
|
|
765
|
+
const embedQuery = unified.embedQuery;
|
|
766
|
+
unified.searchInsights = async ({ userId, query, limit, threshold, botIds, includeArchived }) => {
|
|
767
|
+
const emb = await embedQuery({ userId, query });
|
|
768
|
+
const rows = await searchInsightsWithSQLiteVec({
|
|
769
|
+
userId,
|
|
770
|
+
queryEmbedding: emb,
|
|
771
|
+
limit,
|
|
772
|
+
threshold,
|
|
773
|
+
botIds,
|
|
774
|
+
includeArchived
|
|
775
|
+
});
|
|
776
|
+
return rows.map((r) => ({
|
|
777
|
+
id: r.id,
|
|
778
|
+
content: r.content,
|
|
779
|
+
similarity: r.score,
|
|
780
|
+
metadata: r.metadata ?? {}
|
|
781
|
+
}));
|
|
782
|
+
};
|
|
783
|
+
log("insights backend wired via sqlite-vec");
|
|
784
|
+
} else if (args.insightsBackend === "chroma") {
|
|
785
|
+
if (!args.chromaUrl)
|
|
786
|
+
throw new Error("--insights-backend=chroma requires --chroma-url <url> (or CHROMA_URL env)");
|
|
787
|
+
if (!unified.embedQuery)
|
|
788
|
+
throw new Error("--insights-backend=chroma requires --embedding-provider local|openrouter");
|
|
789
|
+
const store = new aiRag.ChromaVectorStore({
|
|
790
|
+
url: args.chromaUrl,
|
|
791
|
+
collectionName: args.insightsCollection
|
|
792
|
+
});
|
|
793
|
+
const embedQuery = unified.embedQuery;
|
|
794
|
+
unified.searchInsights = async ({ query, limit, threshold }) => {
|
|
795
|
+
const emb = await embedQuery({ userId: "", query });
|
|
796
|
+
const results = await store.similaritySearchWithOptions(emb, { limit: limit + 1 });
|
|
797
|
+
return results.filter((r) => r.score >= threshold).map((r) => ({ id: r.id, content: r.content, similarity: r.score, metadata: r.metadata ?? {} }));
|
|
798
|
+
};
|
|
799
|
+
log(`insights backend wired via chroma (collection=${args.insightsCollection})`);
|
|
800
|
+
}
|
|
801
|
+
if (args.knowledgeBackend === "chroma") {
|
|
802
|
+
if (!args.chromaUrl)
|
|
803
|
+
throw new Error("--knowledge-backend=chroma requires --chroma-url <url> (or CHROMA_URL env)");
|
|
804
|
+
if (!unified.embedQuery)
|
|
805
|
+
throw new Error("--knowledge-backend=chroma requires --embedding-provider local|openrouter");
|
|
806
|
+
const store = new aiRag.ChromaVectorStore({
|
|
807
|
+
url: args.chromaUrl,
|
|
808
|
+
collectionName: args.knowledgeCollection
|
|
809
|
+
});
|
|
810
|
+
const embedQuery = unified.embedQuery;
|
|
811
|
+
unified.searchKnowledge = async ({ query, options }) => {
|
|
812
|
+
const emb = await embedQuery({ userId: "", query });
|
|
813
|
+
const results = await store.similaritySearchWithOptions(emb, { limit: options.limit + 1 });
|
|
814
|
+
return results.filter((r) => r.score >= options.threshold).map((r, i) => ({
|
|
815
|
+
chunkId: r.id,
|
|
816
|
+
documentId: r.documentId || String(r.metadata?.documentId ?? r.id),
|
|
817
|
+
documentName: String(r.metadata?.documentName ?? ""),
|
|
818
|
+
content: r.content,
|
|
819
|
+
similarity: r.score,
|
|
820
|
+
chunkIndex: i
|
|
821
|
+
}));
|
|
822
|
+
};
|
|
823
|
+
log(`knowledge backend wired via chroma (collection=${args.knowledgeCollection})`);
|
|
824
|
+
}
|
|
825
|
+
return unified;
|
|
826
|
+
}
|
|
827
|
+
function printUnifiedHelp() {
|
|
828
|
+
console.log(`Embedding (wires unified.embedQuery):
|
|
829
|
+
--embedding-provider <name> local | openrouter | none
|
|
830
|
+
(env: EMBEDDING_PROVIDER, default: none)
|
|
831
|
+
--embedding-model <name> Model name
|
|
832
|
+
(env: EMBEDDING_MODEL; local \u2192 Xenova/all-MiniLM-L6-v2,
|
|
833
|
+
openrouter \u2192 text-embedding-3-small)
|
|
834
|
+
Note: "local" dynamically imports @melandlabs/ai-rag (a peer install).
|
|
835
|
+
|
|
836
|
+
Cross-source search (wires unified.searchKnowledge / searchInsights / searchRawMessagesAnn):
|
|
837
|
+
--chroma-url <url> Chroma server URL
|
|
838
|
+
(env: CHROMA_URL; required when any *-backend=chroma)
|
|
839
|
+
--memory-backend <name> sqlite-vec | chroma | none
|
|
840
|
+
(env: MEMORY_BACKEND, default: none)
|
|
841
|
+
--insights-backend <name> sqlite-vec | chroma | none
|
|
842
|
+
(env: INSIGHTS_BACKEND, default: none)
|
|
843
|
+
--insights-collection <name> Chroma collection (default: opencontext_insights)
|
|
844
|
+
--knowledge-backend <name> chroma | none
|
|
845
|
+
(env: KNOWLEDGE_BACKEND, default: none)
|
|
846
|
+
--knowledge-collection <name> Chroma collection (default: opencontext_knowledge)
|
|
847
|
+
Note: the chroma backends dynamically import @melandlabs/ai-rag.`);
|
|
848
|
+
}
|
|
849
|
+
|
|
531
850
|
// src/server/cli-http.ts
|
|
532
851
|
function parseArgs(argv) {
|
|
852
|
+
const env = process.env;
|
|
853
|
+
const unified = parseUnifiedArgs(argv);
|
|
533
854
|
const args = {
|
|
534
|
-
|
|
535
|
-
|
|
855
|
+
...unified,
|
|
856
|
+
port: Number.parseInt(env.MEMORY_HTTP_PORT ?? "7421", 10),
|
|
857
|
+
host: env.MEMORY_HTTP_HOST ?? "127.0.0.1"
|
|
536
858
|
};
|
|
537
859
|
for (let i = 0; i < argv.length; i += 1) {
|
|
538
860
|
const arg = argv[i];
|
|
539
861
|
const next = argv[i + 1];
|
|
540
|
-
|
|
541
|
-
|
|
862
|
+
const takeValue = () => {
|
|
863
|
+
if (next === void 0) throw new Error(`[memory-store/http] ${arg} requires a value`);
|
|
542
864
|
i += 1;
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
865
|
+
return next;
|
|
866
|
+
};
|
|
867
|
+
switch (arg) {
|
|
868
|
+
case "--port":
|
|
869
|
+
args.port = Number.parseInt(takeValue(), 10);
|
|
870
|
+
break;
|
|
871
|
+
case "--host":
|
|
872
|
+
args.host = takeValue();
|
|
873
|
+
break;
|
|
874
|
+
case "--help":
|
|
875
|
+
case "-h":
|
|
876
|
+
printHelp();
|
|
877
|
+
process.exit(0);
|
|
549
878
|
}
|
|
550
879
|
}
|
|
880
|
+
if (!Number.isFinite(args.port) || args.port <= 0) {
|
|
881
|
+
throw new Error(`[memory-store/http] invalid --port: ${args.port}`);
|
|
882
|
+
}
|
|
551
883
|
return args;
|
|
552
884
|
}
|
|
885
|
+
function printHelp() {
|
|
886
|
+
console.log(`opencontext-memory-http \u2014 standalone memory-store HTTP daemon.
|
|
887
|
+
|
|
888
|
+
Usage:
|
|
889
|
+
opencontext-memory-http [options]
|
|
890
|
+
|
|
891
|
+
Server:
|
|
892
|
+
--port <port> Port to listen on (default: 7421, env: MEMORY_HTTP_PORT)
|
|
893
|
+
--host <host> Host to bind (default: 127.0.0.1, env: MEMORY_HTTP_HOST)
|
|
894
|
+
`);
|
|
895
|
+
printUnifiedHelp();
|
|
896
|
+
console.log(`
|
|
897
|
+
Examples:
|
|
898
|
+
# Minimal \u2014 same as before, all three *not_configured warnings remain
|
|
899
|
+
opencontext-memory-http
|
|
900
|
+
|
|
901
|
+
# Local ONNX embedder + sqlite-vec ANN for the memory source (no API key,
|
|
902
|
+
# no extra services). Removes embedQuery + memory warnings; the
|
|
903
|
+
# insights/knowledge sources still need a backend of their own.
|
|
904
|
+
opencontext-memory-http \\
|
|
905
|
+
--embedding-provider local \\
|
|
906
|
+
--memory-backend sqlite-vec
|
|
907
|
+
|
|
908
|
+
# Wire everything via a running Chroma server
|
|
909
|
+
opencontext-memory-http \\
|
|
910
|
+
--embedding-provider openrouter \\
|
|
911
|
+
--chroma-url http://127.0.0.1:8000 \\
|
|
912
|
+
--memory-backend chroma \\
|
|
913
|
+
--insights-backend chroma \\
|
|
914
|
+
--knowledge-backend chroma`);
|
|
915
|
+
}
|
|
553
916
|
async function main() {
|
|
554
917
|
const args = parseArgs(process.argv.slice(2));
|
|
555
|
-
const
|
|
918
|
+
const unified = await buildUnified(args);
|
|
919
|
+
const { url, stop } = await startHttpServer({
|
|
556
920
|
port: args.port,
|
|
557
|
-
host: args.host
|
|
921
|
+
host: args.host,
|
|
922
|
+
unified
|
|
558
923
|
});
|
|
559
924
|
console.log(`[memory-store/http] listening at ${url}`);
|
|
560
925
|
const shutdown = async (signal) => {
|