midas-memory-mcp 0.0.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/README.md +65 -0
- package/dist/bin/midas-mcp.d.ts +2 -0
- package/dist/bin/midas-mcp.js +6 -0
- package/dist/bm25.d.ts +11 -0
- package/dist/bm25.js +55 -0
- package/dist/embeddings.d.ts +14 -0
- package/dist/embeddings.js +62 -0
- package/dist/guard.d.ts +17 -0
- package/dist/guard.js +37 -0
- package/dist/importance.d.ts +6 -0
- package/dist/importance.js +81 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/mcp.d.ts +7 -0
- package/dist/mcp.js +309 -0
- package/dist/memory.d.ts +113 -0
- package/dist/memory.js +472 -0
- package/dist/policy.d.ts +5 -0
- package/dist/policy.js +19 -0
- package/dist/store.d.ts +35 -0
- package/dist/store.js +159 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.js +16 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# midas-memory-mcp (TypeScript) — experimental
|
|
2
|
+
|
|
3
|
+
A TypeScript port of [Midas](https://github.com/vornicx/Midas): local-first, source-traceable
|
|
4
|
+
memory for AI agents over MCP — **no LLM and no network at ingest or query**.
|
|
5
|
+
|
|
6
|
+
> **Status: experimental.** The Python server (`pip install "midas-memory[mcp,local]"`) is the
|
|
7
|
+
> reference implementation with semantic ONNX embeddings, NLI-gated belief revision, and the full
|
|
8
|
+
> eval harness behind it. This port covers the core for Node-first setups.
|
|
9
|
+
|
|
10
|
+
## Why it exists
|
|
11
|
+
|
|
12
|
+
Most MCP clients live in the Node ecosystem. This package gives them a zero-Python install:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx midas-memory-mcp # or: npm i -g midas-memory-mcp && midas-mcp
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"mcpServers": {
|
|
21
|
+
"midas": {
|
|
22
|
+
"command": "npx",
|
|
23
|
+
"args": ["-y", "midas-memory-mcp"],
|
|
24
|
+
"env": { "MIDAS_MCP_DB": "/home/you/.midas/memory.sqlite3" }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Parity with the Python server
|
|
31
|
+
|
|
32
|
+
- **Same SQLite schema and float32 blob encoding** — a TS server and a Python server can point at
|
|
33
|
+
the **same DB file** and share one live memory (both probe SQLite's `data_version` and refresh
|
|
34
|
+
on other connections' writes). Verified bidirectionally in tests.
|
|
35
|
+
- **Bit-comparable hashing embedder** (md5 token hashing, identical sign/index math) — vectors
|
|
36
|
+
written by one runtime are recalled semantically by the other. Parity is pinned by a fixture
|
|
37
|
+
generated from the Python implementation.
|
|
38
|
+
- **Same tool surface** — `remember`, `capture` (policy-gated, no LLM), `recall`
|
|
39
|
+
(source-traceable), `build_context` (lean dated lines + "Today is" anchor), `inspect_memory`,
|
|
40
|
+
`check_memory_use` (provenance guard), `forget`, `forget_matching` (dry-run + audit),
|
|
41
|
+
`forget_all`, `maintain`, `stats`, `memory_policy` — plus the same env knobs
|
|
42
|
+
(`MIDAS_MCP_DB`, `MIDAS_MCP_MAX_RECORDS`, `MIDAS_MCP_MIN_IMPORTANCE`, `MIDAS_MCP_NAMESPACE`,
|
|
43
|
+
`MIDAS_MCP_ACTOR`, `MIDAS_MCP_SUPERSEDE`) and the same injected agent policy text.
|
|
44
|
+
- **Same shipping behaviour** — relevance × importance × recency ranking, the measured-safe
|
|
45
|
+
scale-free parsimony floor (`minRelevanceRatio` 0.3), BM25+RRF hybrid (cached index), typed
|
|
46
|
+
belief revision with supersession chains, no-LLM importance scoring, selective forgetting with
|
|
47
|
+
durable-tier protection.
|
|
48
|
+
|
|
49
|
+
## Not ported (yet)
|
|
50
|
+
|
|
51
|
+
- **Semantic ONNX embeddings** (bge / multilingual) — the default embedder here is the offline
|
|
52
|
+
hashing one (lexical-ish). For real semantic recall today, run the Python server; both can share
|
|
53
|
+
the same DB.
|
|
54
|
+
- Local NLI contradiction gating, the cross-encoder reranker, and the eval harness.
|
|
55
|
+
|
|
56
|
+
## Requirements
|
|
57
|
+
|
|
58
|
+
Node **>= 22.5** (uses the built-in `node:sqlite`; you may see its experimental warning on stderr).
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm test # builds + runs the suite, including the Python-parity fixture
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
MIT — same license, same repo, same [PRIVACY.md](../../PRIVACY.md) posture: everything stays on
|
|
65
|
+
your machine.
|
package/dist/bm25.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MemoryRecord } from "./types.js";
|
|
2
|
+
export declare class BM25 {
|
|
3
|
+
private readonly records;
|
|
4
|
+
private readonly dls;
|
|
5
|
+
private readonly postings;
|
|
6
|
+
private readonly idf;
|
|
7
|
+
private readonly avgdl;
|
|
8
|
+
constructor(records: MemoryRecord[]);
|
|
9
|
+
/** Map record id -> BM25 score (only positive scores included). */
|
|
10
|
+
scores(query: string): Map<string, number>;
|
|
11
|
+
}
|
package/dist/bm25.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** BM25 lexical ranking — port of `midas/bm25.py` (Okapi BM25, non-negative IDF, per-term
|
|
2
|
+
* posting lists so a query touches only documents sharing a term with it). */
|
|
3
|
+
import { tokenize } from "./embeddings.js";
|
|
4
|
+
const K1 = 1.5;
|
|
5
|
+
const B = 0.75;
|
|
6
|
+
export class BM25 {
|
|
7
|
+
records;
|
|
8
|
+
dls = [];
|
|
9
|
+
postings = new Map();
|
|
10
|
+
idf = new Map();
|
|
11
|
+
avgdl;
|
|
12
|
+
constructor(records) {
|
|
13
|
+
this.records = records;
|
|
14
|
+
for (let i = 0; i < records.length; i++) {
|
|
15
|
+
const doc = tokenize(records[i].content);
|
|
16
|
+
this.dls.push(doc.length);
|
|
17
|
+
const tf = new Map();
|
|
18
|
+
for (const t of doc)
|
|
19
|
+
tf.set(t, (tf.get(t) ?? 0) + 1);
|
|
20
|
+
for (const [term, f] of tf) {
|
|
21
|
+
let list = this.postings.get(term);
|
|
22
|
+
if (!list)
|
|
23
|
+
this.postings.set(term, (list = []));
|
|
24
|
+
list.push([i, f]);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
this.avgdl = this.dls.length ? this.dls.reduce((a, b) => a + b, 0) / this.dls.length : 0;
|
|
28
|
+
const n = records.length;
|
|
29
|
+
for (const [t, p] of this.postings) {
|
|
30
|
+
this.idf.set(t, Math.log(1 + (n - p.length + 0.5) / (p.length + 0.5)));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Map record id -> BM25 score (only positive scores included). */
|
|
34
|
+
scores(query) {
|
|
35
|
+
const qTerms = tokenize(query);
|
|
36
|
+
const avgdl = this.avgdl || 1.0;
|
|
37
|
+
const byDoc = new Map();
|
|
38
|
+
for (const term of qTerms) {
|
|
39
|
+
const postings = this.postings.get(term);
|
|
40
|
+
if (!postings)
|
|
41
|
+
continue;
|
|
42
|
+
const idf = this.idf.get(term);
|
|
43
|
+
for (const [i, f] of postings) {
|
|
44
|
+
const dl = this.dls[i];
|
|
45
|
+
const s = (byDoc.get(i) ?? 0) + (idf * (f * (K1 + 1))) / (f + K1 * (1 - B + (B * dl) / avgdl));
|
|
46
|
+
byDoc.set(i, s);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const out = new Map();
|
|
50
|
+
for (const [i, s] of byDoc)
|
|
51
|
+
if (s > 0)
|
|
52
|
+
out.set(this.records[i].id, s);
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function tokenize(text: string): string[];
|
|
2
|
+
export interface Embedder {
|
|
3
|
+
dim: number;
|
|
4
|
+
embed(text: string): Float32Array;
|
|
5
|
+
embedMany(texts: string[]): Float32Array[];
|
|
6
|
+
}
|
|
7
|
+
export declare function l2Normalize(vec: Float32Array): Float32Array;
|
|
8
|
+
export declare function cosine(a: Float32Array, b: Float32Array): number;
|
|
9
|
+
export declare class HashingEmbedder implements Embedder {
|
|
10
|
+
readonly dim: number;
|
|
11
|
+
constructor(dim?: number);
|
|
12
|
+
embed(text: string): Float32Array;
|
|
13
|
+
embedMany(texts: string[]): Float32Array[];
|
|
14
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** Embeddings — the offline `HashingEmbedder` is a byte-for-byte port of the Python one
|
|
2
|
+
* (same md5 token hashing, same sign/index math), so a TypeScript process produces the SAME
|
|
3
|
+
* vectors as a Python process and both can share one on-disk store semantically.
|
|
4
|
+
* A local ONNX semantic embedder (bge / multilingual) is the planned next step. */
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
const WORD = /[\p{L}\p{N}_]+/gu;
|
|
7
|
+
export function tokenize(text) {
|
|
8
|
+
const out = [];
|
|
9
|
+
for (const m of text.toLowerCase().matchAll(WORD)) {
|
|
10
|
+
if (m[0].length > 2)
|
|
11
|
+
out.push(m[0]);
|
|
12
|
+
}
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
export function l2Normalize(vec) {
|
|
16
|
+
let norm = 0;
|
|
17
|
+
for (const v of vec)
|
|
18
|
+
norm += v * v;
|
|
19
|
+
norm = Math.sqrt(norm);
|
|
20
|
+
if (norm === 0)
|
|
21
|
+
return vec;
|
|
22
|
+
const out = new Float32Array(vec.length);
|
|
23
|
+
for (let i = 0; i < vec.length; i++)
|
|
24
|
+
out[i] = vec[i] / norm;
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
export function cosine(a, b) {
|
|
28
|
+
let s = 0;
|
|
29
|
+
const n = Math.min(a.length, b.length);
|
|
30
|
+
for (let i = 0; i < n; i++)
|
|
31
|
+
s += a[i] * b[i];
|
|
32
|
+
return s;
|
|
33
|
+
}
|
|
34
|
+
export class HashingEmbedder {
|
|
35
|
+
dim;
|
|
36
|
+
constructor(dim = 256) {
|
|
37
|
+
this.dim = dim;
|
|
38
|
+
}
|
|
39
|
+
embed(text) {
|
|
40
|
+
const vec = new Float64Array(this.dim);
|
|
41
|
+
for (const tok of tokenize(text)) {
|
|
42
|
+
const digest = createHash("md5").update(tok, "utf8").digest();
|
|
43
|
+
const h = digest.readBigUInt64BE(0); // == Python int.from_bytes(digest[:8], "big")
|
|
44
|
+
const idx = Number(h % BigInt(this.dim));
|
|
45
|
+
const sign = (h >> 8n) & 1n ? 1.0 : -1.0;
|
|
46
|
+
vec[idx] += sign;
|
|
47
|
+
}
|
|
48
|
+
// Normalize in float64 BEFORE casting to float32 — the same order Python uses, so the two
|
|
49
|
+
// implementations produce bit-comparable vectors.
|
|
50
|
+
let norm = 0;
|
|
51
|
+
for (const v of vec)
|
|
52
|
+
norm += v * v;
|
|
53
|
+
norm = Math.sqrt(norm);
|
|
54
|
+
if (norm > 0)
|
|
55
|
+
for (let i = 0; i < vec.length; i++)
|
|
56
|
+
vec[i] /= norm;
|
|
57
|
+
return Float32Array.from(vec);
|
|
58
|
+
}
|
|
59
|
+
embedMany(texts) {
|
|
60
|
+
return texts.map((t) => this.embed(t));
|
|
61
|
+
}
|
|
62
|
+
}
|
package/dist/guard.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Provenance guard — port of `midas/guard.py`'s decision core: low-trust memory may guide
|
|
2
|
+
* planning, but external/destructive actions require explicit user confirmation. */
|
|
3
|
+
import type { MemoryRecord } from "./types.js";
|
|
4
|
+
export type MemoryUse = "planning" | "answer" | "external_action" | "destructive_action";
|
|
5
|
+
export declare const MEMORY_USES: readonly MemoryUse[];
|
|
6
|
+
export interface GuardDecision {
|
|
7
|
+
allowed: boolean;
|
|
8
|
+
intended_use: MemoryUse;
|
|
9
|
+
acting_agent: string | null;
|
|
10
|
+
allowed_ids: string[];
|
|
11
|
+
blocked_ids: string[];
|
|
12
|
+
reason: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function decideMemoryUse(records: MemoryRecord[], opts?: {
|
|
15
|
+
intendedUse?: MemoryUse;
|
|
16
|
+
actingAgent?: string | null;
|
|
17
|
+
}): GuardDecision;
|
package/dist/guard.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { MEMORY_PROVENANCE } from "./types.js";
|
|
2
|
+
export const MEMORY_USES = [
|
|
3
|
+
"planning",
|
|
4
|
+
"answer",
|
|
5
|
+
"external_action",
|
|
6
|
+
"destructive_action",
|
|
7
|
+
];
|
|
8
|
+
const ALLOWED_BY_USE = {
|
|
9
|
+
planning: MEMORY_PROVENANCE,
|
|
10
|
+
answer: ["action", "observation", "user_confirmation"],
|
|
11
|
+
external_action: ["user_confirmation"],
|
|
12
|
+
destructive_action: ["user_confirmation"],
|
|
13
|
+
};
|
|
14
|
+
export function decideMemoryUse(records, opts = {}) {
|
|
15
|
+
const use = opts.intendedUse ?? "planning";
|
|
16
|
+
const allowedProv = ALLOWED_BY_USE[use];
|
|
17
|
+
if (!allowedProv)
|
|
18
|
+
throw new Error(`invalid memory use '${use}'`);
|
|
19
|
+
const allowedIds = [];
|
|
20
|
+
const blockedIds = [];
|
|
21
|
+
for (const r of records) {
|
|
22
|
+
(allowedProv.includes(r.provenance) ? allowedIds : blockedIds).push(r.id);
|
|
23
|
+
}
|
|
24
|
+
const allowed = allowedIds.length > 0;
|
|
25
|
+
const reason = allowed
|
|
26
|
+
? `allowed: ${allowedIds.length} memory(ies) satisfy provenance for ${use}`
|
|
27
|
+
: `blocked: ${use} requires provenance in [${allowedProv.join(", ")}]; ` +
|
|
28
|
+
"ask the user to confirm in the current turn";
|
|
29
|
+
return {
|
|
30
|
+
allowed,
|
|
31
|
+
intended_use: use,
|
|
32
|
+
acting_agent: opts.actingAgent ?? null,
|
|
33
|
+
allowed_ids: allowedIds,
|
|
34
|
+
blocked_ids: blockedIds,
|
|
35
|
+
reason,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** No-LLM per-turn importance scoring — a faithful port of `midas/importance.py`.
|
|
2
|
+
* ContentImportance: content-word density + specifics (digits, proper-noun-likes) with an
|
|
3
|
+
* anti-backchannel floor. StructuralImportance adds assertion-vs-question structure. */
|
|
4
|
+
export type ImportanceScorer = (text: string) => number;
|
|
5
|
+
export declare function contentImportance(text: string): number;
|
|
6
|
+
export declare function structuralImportance(text: string): number;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** No-LLM per-turn importance scoring — a faithful port of `midas/importance.py`.
|
|
2
|
+
* ContentImportance: content-word density + specifics (digits, proper-noun-likes) with an
|
|
3
|
+
* anti-backchannel floor. StructuralImportance adds assertion-vs-question structure. */
|
|
4
|
+
const STOP = new Set([
|
|
5
|
+
"the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "for", "of", "with", "by", "is",
|
|
6
|
+
"are", "was", "were", "be", "been", "being", "have", "has", "had", "do", "does", "did", "will",
|
|
7
|
+
"would", "could", "should", "may", "might", "must", "can", "we", "our", "us", "it", "its", "this",
|
|
8
|
+
"that", "these", "those", "i", "you", "he", "she", "they", "them", "my", "your", "his", "her",
|
|
9
|
+
"their", "me", "him", "so", "just", "yeah", "yes", "no", "ok", "okay", "haha", "lol", "hey", "hi",
|
|
10
|
+
"oh", "well", "really", "very", "too", "also", "then", "than", "as", "if", "not", "what", "when",
|
|
11
|
+
"how", "why", "who", "about", "from", "up", "out", "get", "got", "like", "good", "nice", "cool",
|
|
12
|
+
"thanks", "thank", "please", "sure",
|
|
13
|
+
]);
|
|
14
|
+
const WORD = /^[A-Za-z][A-Za-z'-]*$/;
|
|
15
|
+
const HAS_DIGIT = /\d/;
|
|
16
|
+
const SENT_END = /[.!?]$/;
|
|
17
|
+
const PUNCT = /^[.,;:!?"'()[\]]+|[.,;:!?"'()[\]]+$/g;
|
|
18
|
+
export function contentImportance(text) {
|
|
19
|
+
text = (text ?? "").trim();
|
|
20
|
+
if (!text)
|
|
21
|
+
return 1;
|
|
22
|
+
const tokens = text.split(/\s+/);
|
|
23
|
+
const content = new Set();
|
|
24
|
+
for (const w of tokens) {
|
|
25
|
+
const core = w.replace(PUNCT, "");
|
|
26
|
+
if (WORD.test(core) && core.length > 3 && !STOP.has(core.toLowerCase())) {
|
|
27
|
+
content.add(core.toLowerCase());
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const nContent = content.size;
|
|
31
|
+
const nDigit = tokens.filter((w) => HAS_DIGIT.test(w)).length;
|
|
32
|
+
let nProper = 0;
|
|
33
|
+
let prevEndsSentence = true;
|
|
34
|
+
for (const w of tokens) {
|
|
35
|
+
const core = w.replace(PUNCT, "");
|
|
36
|
+
if (!prevEndsSentence &&
|
|
37
|
+
core.length > 2 &&
|
|
38
|
+
core[0] >= "A" &&
|
|
39
|
+
core[0] <= "Z" &&
|
|
40
|
+
/^[A-Za-z]+$/.test(core) &&
|
|
41
|
+
!STOP.has(core.toLowerCase())) {
|
|
42
|
+
nProper += 1;
|
|
43
|
+
}
|
|
44
|
+
prevEndsSentence = SENT_END.test(w);
|
|
45
|
+
}
|
|
46
|
+
if (tokens.length <= 4 && nDigit === 0 && nProper === 0 && nContent <= 1)
|
|
47
|
+
return 1;
|
|
48
|
+
let score = 1;
|
|
49
|
+
if (nContent >= 3)
|
|
50
|
+
score += 1;
|
|
51
|
+
if (nContent >= 7)
|
|
52
|
+
score += 1;
|
|
53
|
+
if (nDigit >= 1)
|
|
54
|
+
score += 1;
|
|
55
|
+
if (nProper >= 1)
|
|
56
|
+
score += 1;
|
|
57
|
+
return Math.max(1, Math.min(5, score));
|
|
58
|
+
}
|
|
59
|
+
const FIRST_PERSON = /\b(i'?m|i\s+am|my|mine|i\s+have|i'?ve|i\s+(?:prefer|like|love|hate|need|use|own|drive|speak|work|live)|i\s+was\s+born)\b/i;
|
|
60
|
+
const DURABLE = /\b(prefer|allergic|favou?rite|deadline|due|born|named|called|decided|always|never|must|require|policy|rule)\b/i;
|
|
61
|
+
const COPULA = /\b(is|are|was|were|named|called)\b/i;
|
|
62
|
+
const META = /\b(let'?s|let\s+me|can\s+you|could\s+you|should\s+we|shall\s+we|please|thanks|thank\s+you|sounds?\s+good|got\s+it|no\s+problem)\b/i;
|
|
63
|
+
export function structuralImportance(text) {
|
|
64
|
+
text = (text ?? "").trim();
|
|
65
|
+
const base = contentImportance(text);
|
|
66
|
+
const isQuestion = text.endsWith("?");
|
|
67
|
+
let boost = 0;
|
|
68
|
+
if (FIRST_PERSON.test(text))
|
|
69
|
+
boost += 1;
|
|
70
|
+
if (DURABLE.test(text))
|
|
71
|
+
boost += 1;
|
|
72
|
+
if (!isQuestion && COPULA.test(text))
|
|
73
|
+
boost += 1;
|
|
74
|
+
let penalty = 0;
|
|
75
|
+
if (isQuestion)
|
|
76
|
+
penalty += 1;
|
|
77
|
+
else if (boost === 0 && META.test(text))
|
|
78
|
+
penalty += 1;
|
|
79
|
+
const score = base + Math.min(boost, 2) - penalty;
|
|
80
|
+
return Math.max(1, Math.min(5, score));
|
|
81
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export { HashingEmbedder, cosine, l2Normalize, tokenize, type Embedder } from "./embeddings.js";
|
|
3
|
+
export { contentImportance, structuralImportance, type ImportanceScorer } from "./importance.js";
|
|
4
|
+
export { BM25 } from "./bm25.js";
|
|
5
|
+
export { InMemoryStore, SQLiteStore, type Predicate } from "./store.js";
|
|
6
|
+
export { Memory, DEFAULT_POLICY, DURABLE_KINDS, approxTokens, formatRecord, type CaptureResult, type ContextBlock, type MemoryOptions, type MemoryPolicy, type RecallOptions, type RememberOptions, } from "./memory.js";
|
|
7
|
+
export { AGENT_MEMORY_INSTRUCTIONS, policySummary } from "./policy.js";
|
|
8
|
+
export { decideMemoryUse, MEMORY_USES, type GuardDecision, type MemoryUse } from "./guard.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export { HashingEmbedder, cosine, l2Normalize, tokenize } from "./embeddings.js";
|
|
3
|
+
export { contentImportance, structuralImportance } from "./importance.js";
|
|
4
|
+
export { BM25 } from "./bm25.js";
|
|
5
|
+
export { InMemoryStore, SQLiteStore } from "./store.js";
|
|
6
|
+
export { Memory, DEFAULT_POLICY, DURABLE_KINDS, approxTokens, formatRecord, } from "./memory.js";
|
|
7
|
+
export { AGENT_MEMORY_INSTRUCTIONS, policySummary } from "./policy.js";
|
|
8
|
+
export { decideMemoryUse, MEMORY_USES } from "./guard.js";
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Midas as an MCP server (TypeScript) — same tool surface, env knobs, injected policy, and
|
|
2
|
+
* SQLite schema as the Python `midas.mcp_server`, so the two are interchangeable and can even
|
|
3
|
+
* share one DB file live. No LLM and no network at ingest/query (hashing embedder; a local ONNX
|
|
4
|
+
* semantic embedder is the planned next step — use the Python server when you need bge today). */
|
|
5
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
|
+
export declare function createServer(): McpServer;
|
|
7
|
+
export declare function main(): Promise<void>;
|