@mce-bt/microagents-memory 0.7.0 → 0.8.1

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/mtm.js CHANGED
@@ -11,8 +11,10 @@ export class MidTermMemory {
11
11
  pool = null;
12
12
  config;
13
13
  agentId = '';
14
+ namespace;
14
15
  constructor(config) {
15
16
  this.config = config;
17
+ this.namespace = config.namespace ?? 'default';
16
18
  }
17
19
  async start(agentId) {
18
20
  this.agentId = agentId;
@@ -32,6 +34,7 @@ export class MidTermMemory {
32
34
  CREATE TABLE IF NOT EXISTS mtm_episodes (
33
35
  id TEXT PRIMARY KEY,
34
36
  agent_id TEXT NOT NULL,
37
+ namespace TEXT NOT NULL DEFAULT 'default',
35
38
  session_id TEXT NOT NULL,
36
39
  summary TEXT NOT NULL,
37
40
  tags TEXT[] DEFAULT '{}',
@@ -42,7 +45,10 @@ export class MidTermMemory {
42
45
  created_at TIMESTAMPTZ DEFAULT NOW()
43
46
  );
44
47
 
45
- CREATE INDEX IF NOT EXISTS idx_mtm_agent_id ON mtm_episodes(agent_id);
48
+ ALTER TABLE mtm_episodes
49
+ ADD COLUMN IF NOT EXISTS namespace TEXT NOT NULL DEFAULT 'default';
50
+
51
+ CREATE INDEX IF NOT EXISTS idx_mtm_agent_id ON mtm_episodes(namespace, agent_id);
46
52
  CREATE INDEX IF NOT EXISTS idx_mtm_domain ON mtm_episodes(domain);
47
53
  CREATE INDEX IF NOT EXISTS idx_mtm_tags ON mtm_episodes USING GIN(tags);
48
54
  CREATE INDEX IF NOT EXISTS idx_mtm_started_at ON mtm_episodes(started_at DESC);
@@ -55,10 +61,11 @@ export class MidTermMemory {
55
61
  if (!this.pool)
56
62
  throw new Error('MTM not started');
57
63
  const id = `ep-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
58
- await this.pool.query(`INSERT INTO mtm_episodes (id, agent_id, session_id, summary, tags, domain, started_at, ended_at, metadata)
59
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`, [
64
+ await this.pool.query(`INSERT INTO mtm_episodes (id, agent_id, namespace, session_id, summary, tags, domain, started_at, ended_at, metadata)
65
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, [
60
66
  id,
61
67
  episode.agentId,
68
+ this.namespace,
62
69
  episode.sessionId,
63
70
  episode.summary,
64
71
  episode.tags,
@@ -78,6 +85,11 @@ export class MidTermMemory {
78
85
  const conditions = [];
79
86
  const params = [];
80
87
  let idx = 1;
88
+ // The namespace is never caller-overridable: `options.agentId` may reach
89
+ // across agents, but only ever within this instance's own boundary.
90
+ conditions.push(`namespace = $${idx}`);
91
+ params.push(this.namespace);
92
+ idx++;
81
93
  // Default to current agent
82
94
  conditions.push(`agent_id = $${idx}`);
83
95
  params.push(options.agentId ?? this.agentId);
@@ -103,12 +115,13 @@ export class MidTermMemory {
103
115
  return result.rows.map(this.rowToEpisode);
104
116
  }
105
117
  /**
106
- * Get a specific episode by ID.
118
+ * Get a specific episode by ID, within this instance's scope. An id from
119
+ * another namespace or agent reads as "not found".
107
120
  */
108
121
  async getById(id) {
109
122
  if (!this.pool)
110
123
  throw new Error('MTM not started');
111
- const result = await this.pool.query('SELECT * FROM mtm_episodes WHERE id = $1', [id]);
124
+ const result = await this.pool.query('SELECT * FROM mtm_episodes WHERE id = $1 AND namespace = $2 AND agent_id = $3', [id, this.namespace, this.agentId]);
112
125
  if (result.rows.length === 0)
113
126
  return null;
114
127
  return this.rowToEpisode(result.rows[0]);
@@ -119,7 +132,7 @@ export class MidTermMemory {
119
132
  async delete(id) {
120
133
  if (!this.pool)
121
134
  throw new Error('MTM not started');
122
- await this.pool.query('DELETE FROM mtm_episodes WHERE id = $1', [id]);
135
+ await this.pool.query('DELETE FROM mtm_episodes WHERE id = $1 AND namespace = $2 AND agent_id = $3', [id, this.namespace, this.agentId]);
123
136
  }
124
137
  rowToEpisode(row) {
125
138
  return {
package/dist/mtm.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mtm.js","sourceRoot":"","sources":["../src/mtm.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mtm.js","sourceRoot":"","sources":["../src/mtm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type pg from 'pg';
2
+ /**
3
+ * Below this many rows an exact sequential scan is both fast and correct, and
4
+ * an approximate index is actively harmful — see why in ensureVectorIndex.
5
+ */
6
+ export declare const IVFFLAT_MIN_ROWS = 1000;
7
+ /** pgvector's own guidance: roughly rows/1000 lists, with a sane floor. */
8
+ export declare function listsForRowCount(rows: number): number;
9
+ /**
10
+ * Create — or deliberately decline to create — the ivfflat index for a vector
11
+ * column.
12
+ *
13
+ * This exists because of a silent, measured failure. `CREATE INDEX ... USING
14
+ * ivfflat WITH (lists = 100)` succeeds on an empty table, and ivfflat is an
15
+ * APPROXIMATE index: at the default `ivfflat.probes = 1` a query scans exactly
16
+ * one list. Built on no data, the lists are degenerate, so a query usually
17
+ * probes a list that holds nothing and returns ZERO rows — even for
18
+ * `ORDER BY ... LIMIT 1` against a table that does contain a match.
19
+ *
20
+ * Observed on a table with one row: three of four query vectors returned
21
+ * nothing; dropping the index made all four return the row. Nothing errors.
22
+ * Semantic recall simply appears to find nothing, which is indistinguishable
23
+ * from having no memories at all.
24
+ *
25
+ * So: no index until there is enough data for one to be meaningful, and when
26
+ * there is, size `lists` from the actual row count rather than a constant. An
27
+ * existing wrongly-sized index is dropped rather than left in place, since a
28
+ * deployment that grew past the threshold would otherwise keep the degenerate
29
+ * one it built while empty.
30
+ */
31
+ export declare function ensureVectorIndex(pool: pg.Pool, table: string, indexName: string): Promise<void>;
32
+ /**
33
+ * Minimum cosine similarity for a vector hit to count.
34
+ *
35
+ * Measured, not chosen: against a stored fact reading "strongly prefers
36
+ * espresso over filter coffee", text-embedding-3-small scored genuinely
37
+ * relevant questions at 0.31 ("what beverage should I be offered at a morning
38
+ * meeting"), 0.44, 0.47 ("what does the user like to drink") and 0.55 ("coffee
39
+ * preference"). The previous 0.7 default admitted none of them, so recall
40
+ * returned nothing for every real question while appearing to work.
41
+ *
42
+ * Short, asymmetric question-vs-statement text does not reach 0.7 with this
43
+ * model family. `limit` still bounds how much reaches the prompt.
44
+ */
45
+ export declare const DEFAULT_SIMILARITY_THRESHOLD = 0.25;
46
+ //# sourceMappingURL=vector-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vector-index.d.ts","sourceRoot":"","sources":["../src/vector-index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB;;;GAGG;AACH,eAAO,MAAM,gBAAgB,OAAQ,CAAC;AAEtC,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA0Cf;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAC"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Below this many rows an exact sequential scan is both fast and correct, and
3
+ * an approximate index is actively harmful — see why in ensureVectorIndex.
4
+ */
5
+ export const IVFFLAT_MIN_ROWS = 1_000;
6
+ /** pgvector's own guidance: roughly rows/1000 lists, with a sane floor. */
7
+ export function listsForRowCount(rows) {
8
+ return Math.max(1, Math.min(2_000, Math.round(rows / 1_000)));
9
+ }
10
+ /**
11
+ * Create — or deliberately decline to create — the ivfflat index for a vector
12
+ * column.
13
+ *
14
+ * This exists because of a silent, measured failure. `CREATE INDEX ... USING
15
+ * ivfflat WITH (lists = 100)` succeeds on an empty table, and ivfflat is an
16
+ * APPROXIMATE index: at the default `ivfflat.probes = 1` a query scans exactly
17
+ * one list. Built on no data, the lists are degenerate, so a query usually
18
+ * probes a list that holds nothing and returns ZERO rows — even for
19
+ * `ORDER BY ... LIMIT 1` against a table that does contain a match.
20
+ *
21
+ * Observed on a table with one row: three of four query vectors returned
22
+ * nothing; dropping the index made all four return the row. Nothing errors.
23
+ * Semantic recall simply appears to find nothing, which is indistinguishable
24
+ * from having no memories at all.
25
+ *
26
+ * So: no index until there is enough data for one to be meaningful, and when
27
+ * there is, size `lists` from the actual row count rather than a constant. An
28
+ * existing wrongly-sized index is dropped rather than left in place, since a
29
+ * deployment that grew past the threshold would otherwise keep the degenerate
30
+ * one it built while empty.
31
+ */
32
+ export async function ensureVectorIndex(pool, table, indexName) {
33
+ let rows;
34
+ try {
35
+ const result = await pool.query(`SELECT COUNT(*)::int AS c FROM ${table} WHERE embedding IS NOT NULL`);
36
+ rows = result.rows[0]?.c ?? 0;
37
+ }
38
+ catch {
39
+ // Table not ready yet; a later boot will settle it.
40
+ return;
41
+ }
42
+ if (rows < IVFFLAT_MIN_ROWS) {
43
+ // Exact search below the threshold. Dropping matters: an index built when
44
+ // the table was empty stays degenerate forever otherwise.
45
+ await pool.query(`DROP INDEX IF EXISTS ${indexName}`).catch(() => { });
46
+ return;
47
+ }
48
+ const lists = listsForRowCount(rows);
49
+ const existing = await pool
50
+ .query(`SELECT indexdef FROM pg_indexes WHERE indexname = $1`, [indexName])
51
+ .catch(() => ({ rows: [] }));
52
+ const current = existing.rows[0]?.indexdef;
53
+ // Rebuild only when the list count is actually wrong, so a normal boot is
54
+ // not paying to reindex a large table every time.
55
+ if (current) {
56
+ if (current.includes(`lists='${lists}'`) || current.includes(`lists=${lists}`))
57
+ return;
58
+ await pool.query(`DROP INDEX IF EXISTS ${indexName}`).catch(() => { });
59
+ }
60
+ await pool
61
+ .query(`CREATE INDEX IF NOT EXISTS ${indexName}
62
+ ON ${table} USING ivfflat (embedding vector_cosine_ops)
63
+ WITH (lists = ${lists})`)
64
+ .catch(() => {
65
+ // An index is an optimisation; failing to build one must never stop an
66
+ // agent booting. Exact search still returns correct results.
67
+ });
68
+ }
69
+ /**
70
+ * Minimum cosine similarity for a vector hit to count.
71
+ *
72
+ * Measured, not chosen: against a stored fact reading "strongly prefers
73
+ * espresso over filter coffee", text-embedding-3-small scored genuinely
74
+ * relevant questions at 0.31 ("what beverage should I be offered at a morning
75
+ * meeting"), 0.44, 0.47 ("what does the user like to drink") and 0.55 ("coffee
76
+ * preference"). The previous 0.7 default admitted none of them, so recall
77
+ * returned nothing for every real question while appearing to work.
78
+ *
79
+ * Short, asymmetric question-vs-statement text does not reach 0.7 with this
80
+ * model family. `limit` still bounds how much reaches the prompt.
81
+ */
82
+ export const DEFAULT_SIMILARITY_THRESHOLD = 0.25;
83
+ //# sourceMappingURL=vector-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vector-index.js","sourceRoot":"","sources":["../src/vector-index.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAEtC,2EAA2E;AAC3E,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAa,EACb,KAAa,EACb,SAAiB;IAEjB,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B,kCAAkC,KAAK,8BAA8B,CACtE,CAAC;QACF,IAAI,GAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAY,IAAI,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,oDAAoD;QACpD,OAAO;IACT,CAAC;IAED,IAAI,IAAI,GAAG,gBAAgB,EAAE,CAAC;QAC5B,0EAA0E;QAC1E,0DAA0D;QAC1D,MAAM,IAAI,CAAC,KAAK,CAAC,wBAAwB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACtE,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,MAAM,IAAI;SACxB,KAAK,CAAC,sDAAsD,EAAE,CAAC,SAAS,CAAC,CAAC;SAC1E,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAkC,EAAE,CAAC,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;IAE3C,0EAA0E;IAC1E,kDAAkD;IAClD,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,KAAK,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,KAAK,EAAE,CAAC;YAAE,OAAO;QACvF,MAAM,IAAI,CAAC,KAAK,CAAC,wBAAwB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,IAAI;SACP,KAAK,CACJ,8BAA8B,SAAS;YACjC,KAAK;uBACM,KAAK,GAAG,CAC1B;SACA,KAAK,CAAC,GAAG,EAAE;QACV,uEAAuE;QACvE,6DAA6D;IAC/D,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,IAAI,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mce-bt/microagents-memory",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
4
4
  "description": "3-tier memory system — STM (Redis), MTM (Postgres), LTM (Postgres + pgvector)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",