@intentface/latch-memory 0.9.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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +163 -0
  3. package/dist/extraction-key.d.ts +20 -0
  4. package/dist/extraction-key.d.ts.map +1 -0
  5. package/dist/extraction-key.js +43 -0
  6. package/dist/extraction-key.js.map +1 -0
  7. package/dist/index-file.d.ts +77 -0
  8. package/dist/index-file.d.ts.map +1 -0
  9. package/dist/index-file.js +169 -0
  10. package/dist/index-file.js.map +1 -0
  11. package/dist/index.d.ts +23 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +23 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/jobs/types.d.ts +133 -0
  16. package/dist/jobs/types.d.ts.map +1 -0
  17. package/dist/jobs/types.js +12 -0
  18. package/dist/jobs/types.js.map +1 -0
  19. package/dist/prompts/consolidator.d.ts +18 -0
  20. package/dist/prompts/consolidator.d.ts.map +1 -0
  21. package/dist/prompts/consolidator.js +76 -0
  22. package/dist/prompts/consolidator.js.map +1 -0
  23. package/dist/prompts/extractor.d.ts +34 -0
  24. package/dist/prompts/extractor.d.ts.map +1 -0
  25. package/dist/prompts/extractor.js +60 -0
  26. package/dist/prompts/extractor.js.map +1 -0
  27. package/dist/prompts/inject.d.ts +20 -0
  28. package/dist/prompts/inject.d.ts.map +1 -0
  29. package/dist/prompts/inject.js +58 -0
  30. package/dist/prompts/inject.js.map +1 -0
  31. package/dist/provider.d.ts +47 -0
  32. package/dist/provider.d.ts.map +1 -0
  33. package/dist/provider.js +101 -0
  34. package/dist/provider.js.map +1 -0
  35. package/dist/sanitize.d.ts +29 -0
  36. package/dist/sanitize.d.ts.map +1 -0
  37. package/dist/sanitize.js +88 -0
  38. package/dist/sanitize.js.map +1 -0
  39. package/dist/schema.d.ts +60 -0
  40. package/dist/schema.d.ts.map +1 -0
  41. package/dist/schema.js +144 -0
  42. package/dist/schema.js.map +1 -0
  43. package/dist/scope.d.ts +62 -0
  44. package/dist/scope.d.ts.map +1 -0
  45. package/dist/scope.js +136 -0
  46. package/dist/scope.js.map +1 -0
  47. package/dist/search-evidence.d.ts +34 -0
  48. package/dist/search-evidence.d.ts.map +1 -0
  49. package/dist/search-evidence.js +40 -0
  50. package/dist/search-evidence.js.map +1 -0
  51. package/dist/store/loredex.d.ts +61 -0
  52. package/dist/store/loredex.d.ts.map +1 -0
  53. package/dist/store/loredex.js +558 -0
  54. package/dist/store/loredex.js.map +1 -0
  55. package/dist/store/memory.d.ts +31 -0
  56. package/dist/store/memory.d.ts.map +1 -0
  57. package/dist/store/memory.js +156 -0
  58. package/dist/store/memory.js.map +1 -0
  59. package/dist/tools.d.ts +91 -0
  60. package/dist/tools.d.ts.map +1 -0
  61. package/dist/tools.js +389 -0
  62. package/dist/tools.js.map +1 -0
  63. package/dist/types.d.ts +130 -0
  64. package/dist/types.d.ts.map +1 -0
  65. package/dist/types.js +13 -0
  66. package/dist/types.js.map +1 -0
  67. package/package.json +60 -0
@@ -0,0 +1,31 @@
1
+ import type { MemorySearchHit, MemoryStore } from "../types.js";
2
+ /**
3
+ * In-memory `MemoryStore`: a `Map<path, text>` behind the store seam, with a
4
+ * deterministic keyword (BM25-style, NO embeddings) search. Two consumers:
5
+ *
6
+ * - tests that need a real store without a Loredex connection;
7
+ * - the offline retrieval evals (`evals/`), which measure the real
8
+ * `memory_search` tool over this store.
9
+ *
10
+ * Determinism is a hard requirement (the evals byte-compare reports across
11
+ * runs): no `Date.now()`, no `Math.random()` — episode filenames come from
12
+ * `meta.extractedAt`, snapshot names from a monotonic counter, and search
13
+ * ties break on lexicographic path order.
14
+ */
15
+ export interface InMemoryStoreHandle extends MemoryStore<unknown> {
16
+ /** The backing file map (path → text), exposed for seeding and assertions. */
17
+ readonly files: Map<string, string>;
18
+ }
19
+ export declare function createInMemoryStore(opts?: {
20
+ /** Seed files (workspace-relative path → markdown text). */
21
+ files?: Record<string, string> | Map<string, string>;
22
+ }): InMemoryStoreHandle;
23
+ /** Lowercase word tokens (len ≥ 2), stopwords removed. Exported for the evals. */
24
+ export declare function contentTokens(text: string): string[];
25
+ /**
26
+ * BM25-lite over (path, text) docs. The filename contributes tokens twice
27
+ * (title weight, mirroring how Loredex indexes file names alongside content).
28
+ * Fully deterministic: score desc, then path asc.
29
+ */
30
+ export declare function keywordSearch(docs: Array<[path: string, text: string]>, query: string, limit: number): MemorySearchHit[];
31
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/store/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,eAAe,EAAE,WAAW,EAAY,MAAM,aAAa,CAAC;AASvF;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,mBAAoB,SAAQ,WAAW,CAAC,OAAO,CAAC;IAC/D,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE;IACzC,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtD,GAAG,mBAAmB,CA2EtB;AA0BD,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAKpD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,EACzC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,eAAe,EAAE,CAsCnB"}
@@ -0,0 +1,156 @@
1
+ import { isUnderScopeRoot } from "../scope.js";
2
+ import { IndexValidationError, MEMORY_INDEX_FILENAME, memoryIdsIn, validateIndexRewrite, } from "../index-file.js";
3
+ export function createInMemoryStore(opts) {
4
+ const files = new Map(opts?.files instanceof Map ? opts.files : Object.entries(opts?.files ?? {}));
5
+ let snapshotSeq = 0;
6
+ const indexPath = (scope) => `${scope.root}/${MEMORY_INDEX_FILENAME}`;
7
+ return {
8
+ files,
9
+ async available() {
10
+ return true;
11
+ },
12
+ async readIndex(_principal, scope) {
13
+ return files.get(indexPath(scope));
14
+ },
15
+ async writeIndex(_principal, scope, text) {
16
+ const prev = files.get(indexPath(scope));
17
+ const problems = validateIndexRewrite(prev, text);
18
+ if (problems.length > 0)
19
+ throw new IndexValidationError(problems);
20
+ if (prev !== undefined && prev.trim().length > 0) {
21
+ snapshotSeq += 1;
22
+ files.set(`${scope.root}/archive/index-snapshots/MEMORY-${String(snapshotSeq).padStart(4, "0")}.md`, prev);
23
+ }
24
+ files.set(indexPath(scope), text);
25
+ },
26
+ async writeEpisode(_principal, scope, episode) {
27
+ const dir = `${scope.root}/episodes`;
28
+ const stamp = episode.meta.extractedAt.slice(0, 16).replace("T", "-").replace(":", "-");
29
+ const slug = episode.slug
30
+ .replace(/[^a-zA-Z0-9_-]/g, "-")
31
+ .replace(/-{2,}/g, "-")
32
+ .replace(/^-+|-+$/g, "")
33
+ .slice(0, 48) || "note";
34
+ let name = `${stamp}-${slug}.md`;
35
+ // Same minute + same slug: disambiguate deterministically.
36
+ for (let n = 2; files.has(`${dir}/${name}`); n++)
37
+ name = `${stamp}-${slug}-${n}.md`;
38
+ const content = `${episodeFrontmatter(episode.meta)}\n\n${episode.body.trim()}\n`;
39
+ files.set(`${dir}/${name}`, content);
40
+ return { path: `${dir}/${name}`, name };
41
+ },
42
+ async readEpisodes(_principal, scope, paths) {
43
+ const out = [];
44
+ for (const path of paths) {
45
+ if (!isUnderScopeRoot(scope.root, path))
46
+ continue;
47
+ const text = files.get(path);
48
+ if (text !== undefined)
49
+ out.push({ path, text });
50
+ }
51
+ return out;
52
+ },
53
+ async search(_principal, scope, query, limit = 6) {
54
+ const docs = Array.from(files.entries())
55
+ .filter(([path]) => isUnderScopeRoot(scope.root, path))
56
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
57
+ return keywordSearch(docs, query, limit);
58
+ },
59
+ async readFile(_principal, { path }) {
60
+ return files.get(path);
61
+ },
62
+ async writeFile(_principal, { path, content }) {
63
+ files.set(path, content);
64
+ },
65
+ };
66
+ }
67
+ function episodeFrontmatter(meta) {
68
+ return [
69
+ "---",
70
+ ...(meta.chat ? [`chat: ${meta.chat}`] : []),
71
+ `agent: ${meta.agent}`,
72
+ `extracted_at: ${meta.extractedAt}`,
73
+ `provenance: ${meta.provenance}`,
74
+ "---",
75
+ ].join("\n");
76
+ }
77
+ // ---------------------------------------------------------------------------
78
+ // Deterministic keyword search (grep-style BM25-lite, no embeddings)
79
+ // ---------------------------------------------------------------------------
80
+ /** Minimal english stopword list — enough to keep filler words from scoring. */
81
+ const STOPWORDS = new Set([
82
+ "a", "an", "and", "are", "as", "at", "be", "but", "by", "do", "does", "for",
83
+ "from", "has", "have", "he", "her", "his", "i", "in", "is", "it", "its",
84
+ "me", "my", "no", "not", "of", "on", "or", "our", "she", "so", "that",
85
+ "the", "their", "them", "they", "this", "to", "up", "was", "we", "what",
86
+ "when", "where", "which", "who", "will", "with", "you", "your",
87
+ ]);
88
+ /** Lowercase word tokens (len ≥ 2), stopwords removed. Exported for the evals. */
89
+ export function contentTokens(text) {
90
+ return text
91
+ .toLowerCase()
92
+ .split(/[^a-z0-9]+/)
93
+ .filter((t) => t.length >= 2 && !STOPWORDS.has(t));
94
+ }
95
+ /**
96
+ * BM25-lite over (path, text) docs. The filename contributes tokens twice
97
+ * (title weight, mirroring how Loredex indexes file names alongside content).
98
+ * Fully deterministic: score desc, then path asc.
99
+ */
100
+ export function keywordSearch(docs, query, limit) {
101
+ const queryTokens = Array.from(new Set(contentTokens(query)));
102
+ if (queryTokens.length === 0)
103
+ return [];
104
+ const indexed = docs.map(([path, text]) => {
105
+ const nameTokens = contentTokens(path.split("/").pop() ?? "");
106
+ const tokens = [...contentTokens(text), ...nameTokens, ...nameTokens];
107
+ const tf = new Map();
108
+ for (const t of tokens)
109
+ tf.set(t, (tf.get(t) ?? 0) + 1);
110
+ return { path, text, tf, length: tokens.length };
111
+ });
112
+ const n = indexed.length;
113
+ if (n === 0)
114
+ return [];
115
+ const avgLen = indexed.reduce((sum, d) => sum + d.length, 0) / n || 1;
116
+ const scored = indexed
117
+ .map((doc) => {
118
+ let score = 0;
119
+ for (const term of queryTokens) {
120
+ const tf = doc.tf.get(term) ?? 0;
121
+ if (tf === 0)
122
+ continue;
123
+ const df = indexed.reduce((c, d) => c + (d.tf.has(term) ? 1 : 0), 0);
124
+ const idf = Math.log(1 + (n - df + 0.5) / (df + 0.5));
125
+ // k1 = 1.2, b = 0.75 — the standard BM25 saturation curve.
126
+ score += idf * ((tf * 2.2) / (tf + 1.2 * (0.25 + 0.75 * (doc.length / avgLen))));
127
+ }
128
+ return { doc, score };
129
+ })
130
+ .filter((s) => s.score > 0)
131
+ .sort((a, b) => b.score - a.score || (a.doc.path < b.doc.path ? -1 : 1));
132
+ return scored.slice(0, limit).map(({ doc }) => {
133
+ const snippet = bestSnippet(doc.text, queryTokens);
134
+ const memoryIds = memoryIdsIn(snippet);
135
+ if (/\/episodes\//.test(doc.path))
136
+ memoryIds.push(doc.path);
137
+ return { path: doc.path, snippet, memoryIds: Array.from(new Set(memoryIds)) };
138
+ });
139
+ }
140
+ /** The line matching the most query tokens (first on ties), capped at 240 chars. */
141
+ function bestSnippet(text, queryTokens) {
142
+ let best = "";
143
+ let bestCount = 0;
144
+ for (const line of text.split("\n")) {
145
+ const lineTokens = new Set(contentTokens(line));
146
+ const count = queryTokens.reduce((c, t) => c + (lineTokens.has(t) ? 1 : 0), 0);
147
+ if (count > bestCount) {
148
+ best = line.trim();
149
+ bestCount = count;
150
+ }
151
+ }
152
+ if (!best)
153
+ best = text.split("\n").find((l) => l.trim().length > 0)?.trim() ?? "";
154
+ return best.length > 240 ? `${best.slice(0, 237)}…` : best;
155
+ }
156
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/store/memory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,WAAW,EACX,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAqB1B,MAAM,UAAU,mBAAmB,CAAC,IAGnC;IACC,MAAM,KAAK,GAAG,IAAI,GAAG,CACnB,IAAI,EAAE,KAAK,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAC5E,CAAC;IACF,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,MAAM,SAAS,GAAG,CAAC,KAAe,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,qBAAqB,EAAE,CAAC;IAEhF,OAAO;QACL,KAAK;QAEL,KAAK,CAAC,SAAS;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,CAAC,SAAS,CAAC,UAAU,EAAE,KAAK;YAC/B,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QACrC,CAAC;QAED,KAAK,CAAC,UAAU,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI;YACtC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;YACzC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAClD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;gBAAE,MAAM,IAAI,oBAAoB,CAAC,QAAQ,CAAC,CAAC;YAClE,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjD,WAAW,IAAI,CAAC,CAAC;gBACjB,KAAK,CAAC,GAAG,CACP,GAAG,KAAK,CAAC,IAAI,mCAAmC,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,EACzF,IAAI,CACL,CAAC;YACJ,CAAC;YACD,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;QACpC,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO;YAC3C,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,IAAI,WAAW,CAAC;YACrC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACxF,MAAM,IAAI,GACR,OAAO,CAAC,IAAI;iBACT,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC;iBAC/B,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;iBACtB,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;iBACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC;YAC5B,IAAI,IAAI,GAAG,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC;YACjC,2DAA2D;YAC3D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE;gBAAE,IAAI,GAAG,GAAG,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC;YACpF,MAAM,OAAO,GAAG,GAAG,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;YAClF,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;YACrC,OAAO,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC;QAC1C,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK;YACzC,MAAM,GAAG,GAA0C,EAAE,CAAC;YACtD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC;oBAAE,SAAS;gBAClD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC7B,IAAI,IAAI,KAAK,SAAS;oBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC;YAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;iBACrC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;iBACtD,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpD,OAAO,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAC3C,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE;YACjC,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QAED,KAAK,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;YAC3C,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3B,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAiB;IAC3C,OAAO;QACL,KAAK;QACL,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,UAAU,IAAI,CAAC,KAAK,EAAE;QACtB,iBAAiB,IAAI,CAAC,WAAW,EAAE;QACnC,eAAe,IAAI,CAAC,UAAU,EAAE;QAChC,KAAK;KACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,qEAAqE;AACrE,8EAA8E;AAE9E,gFAAgF;AAChF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;IACxB,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK;IAC3E,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK;IACvE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM;IACrE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM;IACvE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAC/D,CAAC,CAAC;AAEH,kFAAkF;AAClF,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI;SACR,WAAW,EAAE;SACb,KAAK,CAAC,YAAY,CAAC;SACnB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAyC,EACzC,KAAa,EACb,KAAa;IAEb,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9D,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAExC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE;QACxC,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,EAAE,GAAG,UAAU,EAAE,GAAG,UAAU,CAAC,CAAC;QACtE,MAAM,EAAE,GAAG,IAAI,GAAG,EAAkB,CAAC;QACrC,KAAK,MAAM,CAAC,IAAI,MAAM;YAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IACzB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAEtE,MAAM,MAAM,GAAG,OAAO;SACnB,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACX,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjC,IAAI,EAAE,KAAK,CAAC;gBAAE,SAAS;YACvB,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACrE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;YACtD,2DAA2D;YAC3D,KAAK,IAAI,GAAG,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACnF,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IACxB,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;SAC1B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3E,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE;QAC5C,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5D,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;IAChF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,oFAAoF;AACpF,SAAS,WAAW,CAAC,IAAY,EAAE,WAAqB;IACtD,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/E,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;YACtB,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACnB,SAAS,GAAG,KAAK,CAAC;QACpB,CAAC;IACH,CAAC;IACD,IAAI,CAAC,IAAI;QAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAClF,OAAO,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,91 @@
1
+ import type { MemoryScope } from "@intentface/latch-core";
2
+ import type { MemoryStore, ScopeRef } from "./types.js";
3
+ /**
4
+ * Tool factories. Two families:
5
+ *
6
+ * - Agent-facing (`memory_search`, `memory_save`): merged into a memory-enabled
7
+ * agent's turn by the provider.
8
+ * - Job-facing (`memory_read_index`, `memory_write_episode`,
9
+ * `memory_read_episodes`, `memory_write_index`): given to the built-in
10
+ * extractor/consolidator agents.
11
+ *
12
+ * Every factory binds `store + principal + scope` at construction — the model
13
+ * never chooses paths, so it cannot read or write outside its scope.
14
+ */
15
+ export interface BoundScope<P> {
16
+ store: MemoryStore<P>;
17
+ principal: P;
18
+ scope: ScopeRef;
19
+ }
20
+ /**
21
+ * One participating memory level and its bound scope. Multi-level tools
22
+ * (`memory_search` fan-out, level-routed `memory_write_episode`,
23
+ * `memory_read_index` across levels) take an array of these; a single-element
24
+ * array behaves exactly like the classic single-scope binding.
25
+ */
26
+ export interface LevelBoundScope<P> {
27
+ level: MemoryScope;
28
+ bound: BoundScope<P>;
29
+ }
30
+ /**
31
+ * Explicit (portable) shape for the authored tools — declaration emit cannot
32
+ * name the AI SDK's inferred `Tool<…>` type across package boundaries
33
+ * (TS2742), and agent configs only need `Record<string, unknown>` anyway.
34
+ */
35
+ export interface MemoryTool {
36
+ description?: unknown;
37
+ inputSchema: unknown;
38
+ execute?: (input: never, options: never) => unknown;
39
+ }
40
+ export declare function memorySearchTool<P>(targets: LevelBoundScope<P>[], opts?: {
41
+ recordUsage?: (scopeKey: string, memoryIds: string[]) => void | Promise<void>;
42
+ }): MemoryTool;
43
+ export declare function memorySaveTool<P>(bound: BoundScope<P>, opts: {
44
+ agent: string;
45
+ onEpisodeWritten?: (args: {
46
+ path: string;
47
+ name: string;
48
+ }) => void | Promise<void>;
49
+ /** Invalidate the provider's cached index block for this scope. */
50
+ invalidate?: () => void;
51
+ }): MemoryTool;
52
+ export declare function memoryReadIndexTool<P>(bound: BoundScope<P>): MemoryTool;
53
+ /**
54
+ * The extractor's cross-level index read: every participating level's compiled
55
+ * index in one call, so "what is already known" covers each level it may
56
+ * write to.
57
+ */
58
+ export declare function memoryReadIndexesTool<P>(targets: LevelBoundScope<P>[]): MemoryTool;
59
+ export declare function memoryWriteEpisodeTool<P>(targets: LevelBoundScope<P>[], opts: {
60
+ agent: string;
61
+ chatId?: string;
62
+ onEpisodeWritten?: (args: {
63
+ level: MemoryScope;
64
+ scope: ScopeRef;
65
+ path: string;
66
+ name: string;
67
+ }) => void | Promise<void>;
68
+ /**
69
+ * Outcome of each write attempt — the same three-way distinction
70
+ * `memoryWriteIndexTool` needs: episode written, nothing durable to write
71
+ * (never called), or the store refused. Only the last may tombstone the
72
+ * transcript window, and the run's answer can't tell them apart.
73
+ */
74
+ onWriteAttempt?: (ok: boolean) => void;
75
+ }): MemoryTool;
76
+ export declare function memoryReadEpisodesTool<P>(bound: BoundScope<P>): MemoryTool;
77
+ export declare function memoryWriteIndexTool<P>(bound: BoundScope<P>, opts?: {
78
+ invalidate?: () => void;
79
+ /** This level's index-schema outline — advisory, see below. */
80
+ schema?: string;
81
+ /**
82
+ * Outcome of each write attempt. The caller needs it to tell three cases
83
+ * apart that all look identical from the run's answer: the index was
84
+ * rewritten, nothing needed changing (never called), and every attempt
85
+ * failed. Only the last one must keep the episodes pending for a retry —
86
+ * a model that gives up after a failed write still answers with a tidy
87
+ * summary, so the answer alone cannot be trusted as proof of a write.
88
+ */
89
+ onWriteAttempt?: (ok: boolean) => void;
90
+ }): MemoryTool;
91
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}