@xandout/libra-harness 0.1.8

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 (289) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +486 -0
  3. package/dist/agent.d.ts +174 -0
  4. package/dist/agent.d.ts.map +1 -0
  5. package/dist/agent.js +575 -0
  6. package/dist/agent.js.map +1 -0
  7. package/dist/ai-sdk-model.d.ts +26 -0
  8. package/dist/ai-sdk-model.d.ts.map +1 -0
  9. package/dist/ai-sdk-model.js +260 -0
  10. package/dist/ai-sdk-model.js.map +1 -0
  11. package/dist/context.d.ts +75 -0
  12. package/dist/context.d.ts.map +1 -0
  13. package/dist/context.js +2 -0
  14. package/dist/context.js.map +1 -0
  15. package/dist/errors.d.ts +33 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +59 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/extension.d.ts +63 -0
  20. package/dist/extension.d.ts.map +1 -0
  21. package/dist/extension.js +2 -0
  22. package/dist/extension.js.map +1 -0
  23. package/dist/extras/extension-loader.d.ts +205 -0
  24. package/dist/extras/extension-loader.d.ts.map +1 -0
  25. package/dist/extras/extension-loader.js +315 -0
  26. package/dist/extras/extension-loader.js.map +1 -0
  27. package/dist/extras/extensions/auto-steer/extension.d.ts +46 -0
  28. package/dist/extras/extensions/auto-steer/extension.d.ts.map +1 -0
  29. package/dist/extras/extensions/auto-steer/extension.js +52 -0
  30. package/dist/extras/extensions/auto-steer/extension.js.map +1 -0
  31. package/dist/extras/extensions/auto-steer/extension.json +7 -0
  32. package/dist/extras/extensions/auto-steer/index.d.ts +3 -0
  33. package/dist/extras/extensions/auto-steer/index.d.ts.map +1 -0
  34. package/dist/extras/extensions/auto-steer/index.js +2 -0
  35. package/dist/extras/extensions/auto-steer/index.js.map +1 -0
  36. package/dist/extras/extensions/disk-session/extension.d.ts +167 -0
  37. package/dist/extras/extensions/disk-session/extension.d.ts.map +1 -0
  38. package/dist/extras/extensions/disk-session/extension.js +492 -0
  39. package/dist/extras/extensions/disk-session/extension.js.map +1 -0
  40. package/dist/extras/extensions/disk-session/extension.json +6 -0
  41. package/dist/extras/extensions/disk-session/extension.test.d.ts +2 -0
  42. package/dist/extras/extensions/disk-session/extension.test.d.ts.map +1 -0
  43. package/dist/extras/extensions/disk-session/extension.test.js +672 -0
  44. package/dist/extras/extensions/disk-session/extension.test.js.map +1 -0
  45. package/dist/extras/extensions/disk-session/index.d.ts +3 -0
  46. package/dist/extras/extensions/disk-session/index.d.ts.map +1 -0
  47. package/dist/extras/extensions/disk-session/index.js +2 -0
  48. package/dist/extras/extensions/disk-session/index.js.map +1 -0
  49. package/dist/extras/extensions/emoji/extension.d.ts +20 -0
  50. package/dist/extras/extensions/emoji/extension.d.ts.map +1 -0
  51. package/dist/extras/extensions/emoji/extension.js +22 -0
  52. package/dist/extras/extensions/emoji/extension.js.map +1 -0
  53. package/dist/extras/extensions/emoji/extension.json +7 -0
  54. package/dist/extras/extensions/emoji/index.d.ts +3 -0
  55. package/dist/extras/extensions/emoji/index.d.ts.map +1 -0
  56. package/dist/extras/extensions/emoji/index.js +2 -0
  57. package/dist/extras/extensions/emoji/index.js.map +1 -0
  58. package/dist/extras/extensions/filesystem/extension.d.ts +53 -0
  59. package/dist/extras/extensions/filesystem/extension.d.ts.map +1 -0
  60. package/dist/extras/extensions/filesystem/extension.js +350 -0
  61. package/dist/extras/extensions/filesystem/extension.js.map +1 -0
  62. package/dist/extras/extensions/filesystem/extension.json +6 -0
  63. package/dist/extras/extensions/filesystem/extension.test.d.ts +2 -0
  64. package/dist/extras/extensions/filesystem/extension.test.d.ts.map +1 -0
  65. package/dist/extras/extensions/filesystem/extension.test.js +387 -0
  66. package/dist/extras/extensions/filesystem/extension.test.js.map +1 -0
  67. package/dist/extras/extensions/filesystem/index.d.ts +2 -0
  68. package/dist/extras/extensions/filesystem/index.d.ts.map +1 -0
  69. package/dist/extras/extensions/filesystem/index.js +2 -0
  70. package/dist/extras/extensions/filesystem/index.js.map +1 -0
  71. package/dist/extras/extensions/keyword-extractor/extension.d.ts +53 -0
  72. package/dist/extras/extensions/keyword-extractor/extension.d.ts.map +1 -0
  73. package/dist/extras/extensions/keyword-extractor/extension.js +61 -0
  74. package/dist/extras/extensions/keyword-extractor/extension.js.map +1 -0
  75. package/dist/extras/extensions/keyword-extractor/extension.json +6 -0
  76. package/dist/extras/extensions/keyword-extractor/extension.test.d.ts +2 -0
  77. package/dist/extras/extensions/keyword-extractor/extension.test.d.ts.map +1 -0
  78. package/dist/extras/extensions/keyword-extractor/extension.test.js +105 -0
  79. package/dist/extras/extensions/keyword-extractor/extension.test.js.map +1 -0
  80. package/dist/extras/extensions/keyword-extractor/index.d.ts +5 -0
  81. package/dist/extras/extensions/keyword-extractor/index.d.ts.map +1 -0
  82. package/dist/extras/extensions/keyword-extractor/index.js +3 -0
  83. package/dist/extras/extensions/keyword-extractor/index.js.map +1 -0
  84. package/dist/extras/extensions/keyword-extractor/nlp.d.ts +68 -0
  85. package/dist/extras/extensions/keyword-extractor/nlp.d.ts.map +1 -0
  86. package/dist/extras/extensions/keyword-extractor/nlp.js +156 -0
  87. package/dist/extras/extensions/keyword-extractor/nlp.js.map +1 -0
  88. package/dist/extras/extensions/keyword-extractor/nlp.test.d.ts +2 -0
  89. package/dist/extras/extensions/keyword-extractor/nlp.test.d.ts.map +1 -0
  90. package/dist/extras/extensions/keyword-extractor/nlp.test.js +176 -0
  91. package/dist/extras/extensions/keyword-extractor/nlp.test.js.map +1 -0
  92. package/dist/extras/extensions/logger/extension.d.ts +52 -0
  93. package/dist/extras/extensions/logger/extension.d.ts.map +1 -0
  94. package/dist/extras/extensions/logger/extension.js +68 -0
  95. package/dist/extras/extensions/logger/extension.js.map +1 -0
  96. package/dist/extras/extensions/logger/extension.json +7 -0
  97. package/dist/extras/extensions/logger/index.d.ts +3 -0
  98. package/dist/extras/extensions/logger/index.d.ts.map +1 -0
  99. package/dist/extras/extensions/logger/index.js +2 -0
  100. package/dist/extras/extensions/logger/index.js.map +1 -0
  101. package/dist/extras/extensions/mcp/extension.d.ts +63 -0
  102. package/dist/extras/extensions/mcp/extension.d.ts.map +1 -0
  103. package/dist/extras/extensions/mcp/extension.js +437 -0
  104. package/dist/extras/extensions/mcp/extension.js.map +1 -0
  105. package/dist/extras/extensions/mcp/extension.json +7 -0
  106. package/dist/extras/extensions/mcp/extension.test.d.ts +2 -0
  107. package/dist/extras/extensions/mcp/extension.test.d.ts.map +1 -0
  108. package/dist/extras/extensions/mcp/extension.test.js +286 -0
  109. package/dist/extras/extensions/mcp/extension.test.js.map +1 -0
  110. package/dist/extras/extensions/mcp/index.d.ts +3 -0
  111. package/dist/extras/extensions/mcp/index.d.ts.map +1 -0
  112. package/dist/extras/extensions/mcp/index.js +2 -0
  113. package/dist/extras/extensions/mcp/index.js.map +1 -0
  114. package/dist/extras/extensions/mem-session/extension.d.ts +24 -0
  115. package/dist/extras/extensions/mem-session/extension.d.ts.map +1 -0
  116. package/dist/extras/extensions/mem-session/extension.js +49 -0
  117. package/dist/extras/extensions/mem-session/extension.js.map +1 -0
  118. package/dist/extras/extensions/mem-session/extension.json +6 -0
  119. package/dist/extras/extensions/mem-session/index.d.ts +2 -0
  120. package/dist/extras/extensions/mem-session/index.d.ts.map +1 -0
  121. package/dist/extras/extensions/mem-session/index.js +2 -0
  122. package/dist/extras/extensions/mem-session/index.js.map +1 -0
  123. package/dist/extras/extensions/memory/extension.d.ts +54 -0
  124. package/dist/extras/extensions/memory/extension.d.ts.map +1 -0
  125. package/dist/extras/extensions/memory/extension.js +143 -0
  126. package/dist/extras/extensions/memory/extension.js.map +1 -0
  127. package/dist/extras/extensions/memory/extension.json +7 -0
  128. package/dist/extras/extensions/memory/index.d.ts +5 -0
  129. package/dist/extras/extensions/memory/index.d.ts.map +1 -0
  130. package/dist/extras/extensions/memory/index.js +3 -0
  131. package/dist/extras/extensions/memory/index.js.map +1 -0
  132. package/dist/extras/extensions/memory/llm-extractor.d.ts +42 -0
  133. package/dist/extras/extensions/memory/llm-extractor.d.ts.map +1 -0
  134. package/dist/extras/extensions/memory/llm-extractor.js +89 -0
  135. package/dist/extras/extensions/memory/llm-extractor.js.map +1 -0
  136. package/dist/extras/extensions/memory/types.d.ts +142 -0
  137. package/dist/extras/extensions/memory/types.d.ts.map +1 -0
  138. package/dist/extras/extensions/memory/types.js +2 -0
  139. package/dist/extras/extensions/memory/types.js.map +1 -0
  140. package/dist/extras/extensions/otel/extension.d.ts +57 -0
  141. package/dist/extras/extensions/otel/extension.d.ts.map +1 -0
  142. package/dist/extras/extensions/otel/extension.js +253 -0
  143. package/dist/extras/extensions/otel/extension.js.map +1 -0
  144. package/dist/extras/extensions/otel/extension.json +7 -0
  145. package/dist/extras/extensions/otel/extension.test.d.ts +2 -0
  146. package/dist/extras/extensions/otel/extension.test.d.ts.map +1 -0
  147. package/dist/extras/extensions/otel/extension.test.js +399 -0
  148. package/dist/extras/extensions/otel/extension.test.js.map +1 -0
  149. package/dist/extras/extensions/otel/index.d.ts +4 -0
  150. package/dist/extras/extensions/otel/index.d.ts.map +1 -0
  151. package/dist/extras/extensions/otel/index.js +3 -0
  152. package/dist/extras/extensions/otel/index.js.map +1 -0
  153. package/dist/extras/extensions/otel/jsonl-span-exporter.d.ts +60 -0
  154. package/dist/extras/extensions/otel/jsonl-span-exporter.d.ts.map +1 -0
  155. package/dist/extras/extensions/otel/jsonl-span-exporter.js +134 -0
  156. package/dist/extras/extensions/otel/jsonl-span-exporter.js.map +1 -0
  157. package/dist/extras/extensions/scripts/extension.d.ts +180 -0
  158. package/dist/extras/extensions/scripts/extension.d.ts.map +1 -0
  159. package/dist/extras/extensions/scripts/extension.js +618 -0
  160. package/dist/extras/extensions/scripts/extension.js.map +1 -0
  161. package/dist/extras/extensions/scripts/extension.json +7 -0
  162. package/dist/extras/extensions/scripts/extension.test.d.ts +2 -0
  163. package/dist/extras/extensions/scripts/extension.test.d.ts.map +1 -0
  164. package/dist/extras/extensions/scripts/extension.test.js +552 -0
  165. package/dist/extras/extensions/scripts/extension.test.js.map +1 -0
  166. package/dist/extras/extensions/scripts/index.d.ts +3 -0
  167. package/dist/extras/extensions/scripts/index.d.ts.map +1 -0
  168. package/dist/extras/extensions/scripts/index.js +2 -0
  169. package/dist/extras/extensions/scripts/index.js.map +1 -0
  170. package/dist/extras/extensions/skills/extension.d.ts +105 -0
  171. package/dist/extras/extensions/skills/extension.d.ts.map +1 -0
  172. package/dist/extras/extensions/skills/extension.js +419 -0
  173. package/dist/extras/extensions/skills/extension.js.map +1 -0
  174. package/dist/extras/extensions/skills/extension.json +7 -0
  175. package/dist/extras/extensions/skills/extension.test.d.ts +2 -0
  176. package/dist/extras/extensions/skills/extension.test.d.ts.map +1 -0
  177. package/dist/extras/extensions/skills/extension.test.js +184 -0
  178. package/dist/extras/extensions/skills/extension.test.js.map +1 -0
  179. package/dist/extras/extensions/skills/index.d.ts +4 -0
  180. package/dist/extras/extensions/skills/index.d.ts.map +1 -0
  181. package/dist/extras/extensions/skills/index.js +3 -0
  182. package/dist/extras/extensions/skills/index.js.map +1 -0
  183. package/dist/extras/extensions/streaming/extension.d.ts +15 -0
  184. package/dist/extras/extensions/streaming/extension.d.ts.map +1 -0
  185. package/dist/extras/extensions/streaming/extension.js +41 -0
  186. package/dist/extras/extensions/streaming/extension.js.map +1 -0
  187. package/dist/extras/extensions/streaming/extension.json +6 -0
  188. package/dist/extras/extensions/streaming/index.d.ts +2 -0
  189. package/dist/extras/extensions/streaming/index.d.ts.map +1 -0
  190. package/dist/extras/extensions/streaming/index.js +2 -0
  191. package/dist/extras/extensions/streaming/index.js.map +1 -0
  192. package/dist/extras/extensions/structured-output/extension.d.ts +11 -0
  193. package/dist/extras/extensions/structured-output/extension.d.ts.map +1 -0
  194. package/dist/extras/extensions/structured-output/extension.js +102 -0
  195. package/dist/extras/extensions/structured-output/extension.js.map +1 -0
  196. package/dist/extras/extensions/structured-output/extension.json +7 -0
  197. package/dist/extras/extensions/structured-output/index.d.ts +3 -0
  198. package/dist/extras/extensions/structured-output/index.d.ts.map +1 -0
  199. package/dist/extras/extensions/structured-output/index.js +2 -0
  200. package/dist/extras/extensions/structured-output/index.js.map +1 -0
  201. package/dist/extras/extensions/timestamp/extension.d.ts +11 -0
  202. package/dist/extras/extensions/timestamp/extension.d.ts.map +1 -0
  203. package/dist/extras/extensions/timestamp/extension.js +21 -0
  204. package/dist/extras/extensions/timestamp/extension.js.map +1 -0
  205. package/dist/extras/extensions/timestamp/extension.json +6 -0
  206. package/dist/extras/extensions/timestamp/index.d.ts +2 -0
  207. package/dist/extras/extensions/timestamp/index.d.ts.map +1 -0
  208. package/dist/extras/extensions/timestamp/index.js +2 -0
  209. package/dist/extras/extensions/timestamp/index.js.map +1 -0
  210. package/dist/extras/extensions/token-stats/extension.d.ts +50 -0
  211. package/dist/extras/extensions/token-stats/extension.d.ts.map +1 -0
  212. package/dist/extras/extensions/token-stats/extension.js +99 -0
  213. package/dist/extras/extensions/token-stats/extension.js.map +1 -0
  214. package/dist/extras/extensions/token-stats/extension.json +7 -0
  215. package/dist/extras/extensions/token-stats/extension.test.d.ts +2 -0
  216. package/dist/extras/extensions/token-stats/extension.test.d.ts.map +1 -0
  217. package/dist/extras/extensions/token-stats/extension.test.js +197 -0
  218. package/dist/extras/extensions/token-stats/extension.test.js.map +1 -0
  219. package/dist/extras/extensions/token-stats/index.d.ts +3 -0
  220. package/dist/extras/extensions/token-stats/index.d.ts.map +1 -0
  221. package/dist/extras/extensions/token-stats/index.js +2 -0
  222. package/dist/extras/extensions/token-stats/index.js.map +1 -0
  223. package/dist/extras/extensions/tool-buffer/extension.d.ts +89 -0
  224. package/dist/extras/extensions/tool-buffer/extension.d.ts.map +1 -0
  225. package/dist/extras/extensions/tool-buffer/extension.js +182 -0
  226. package/dist/extras/extensions/tool-buffer/extension.js.map +1 -0
  227. package/dist/extras/extensions/tool-buffer/extension.json +7 -0
  228. package/dist/extras/extensions/tool-buffer/extension.test.d.ts +2 -0
  229. package/dist/extras/extensions/tool-buffer/extension.test.d.ts.map +1 -0
  230. package/dist/extras/extensions/tool-buffer/extension.test.js +549 -0
  231. package/dist/extras/extensions/tool-buffer/extension.test.js.map +1 -0
  232. package/dist/extras/extensions/tool-buffer/index.d.ts +3 -0
  233. package/dist/extras/extensions/tool-buffer/index.d.ts.map +1 -0
  234. package/dist/extras/extensions/tool-buffer/index.js +2 -0
  235. package/dist/extras/extensions/tool-buffer/index.js.map +1 -0
  236. package/dist/extras/extensions/weather-tool/extension.d.ts +22 -0
  237. package/dist/extras/extensions/weather-tool/extension.d.ts.map +1 -0
  238. package/dist/extras/extensions/weather-tool/extension.js +33 -0
  239. package/dist/extras/extensions/weather-tool/extension.js.map +1 -0
  240. package/dist/extras/extensions/weather-tool/extension.json +7 -0
  241. package/dist/extras/extensions/weather-tool/index.d.ts +3 -0
  242. package/dist/extras/extensions/weather-tool/index.d.ts.map +1 -0
  243. package/dist/extras/extensions/weather-tool/index.js +2 -0
  244. package/dist/extras/extensions/weather-tool/index.js.map +1 -0
  245. package/dist/extras/models/ai-sdk-resolver.d.ts +15 -0
  246. package/dist/extras/models/ai-sdk-resolver.d.ts.map +1 -0
  247. package/dist/extras/models/ai-sdk-resolver.js +57 -0
  248. package/dist/extras/models/ai-sdk-resolver.js.map +1 -0
  249. package/dist/extras/models/index.d.ts +5 -0
  250. package/dist/extras/models/index.d.ts.map +1 -0
  251. package/dist/extras/models/index.js +3 -0
  252. package/dist/extras/models/index.js.map +1 -0
  253. package/dist/extras/models/routing-model.d.ts +18 -0
  254. package/dist/extras/models/routing-model.d.ts.map +1 -0
  255. package/dist/extras/models/routing-model.js +24 -0
  256. package/dist/extras/models/routing-model.js.map +1 -0
  257. package/dist/extras/openai-provider/index.d.ts +3 -0
  258. package/dist/extras/openai-provider/index.d.ts.map +1 -0
  259. package/dist/extras/openai-provider/index.js +2 -0
  260. package/dist/extras/openai-provider/index.js.map +1 -0
  261. package/dist/extras/openai-provider/server.d.ts +34 -0
  262. package/dist/extras/openai-provider/server.d.ts.map +1 -0
  263. package/dist/extras/openai-provider/server.js +335 -0
  264. package/dist/extras/openai-provider/server.js.map +1 -0
  265. package/dist/handle.d.ts +56 -0
  266. package/dist/handle.d.ts.map +1 -0
  267. package/dist/handle.js +2 -0
  268. package/dist/handle.js.map +1 -0
  269. package/dist/hooks.d.ts +98 -0
  270. package/dist/hooks.d.ts.map +1 -0
  271. package/dist/hooks.js +53 -0
  272. package/dist/hooks.js.map +1 -0
  273. package/dist/index.d.ts +16 -0
  274. package/dist/index.d.ts.map +1 -0
  275. package/dist/index.js +9 -0
  276. package/dist/index.js.map +1 -0
  277. package/dist/model.d.ts +75 -0
  278. package/dist/model.d.ts.map +1 -0
  279. package/dist/model.js +2 -0
  280. package/dist/model.js.map +1 -0
  281. package/dist/tool.d.ts +78 -0
  282. package/dist/tool.d.ts.map +1 -0
  283. package/dist/tool.js +78 -0
  284. package/dist/tool.js.map +1 -0
  285. package/dist/types.d.ts +83 -0
  286. package/dist/types.d.ts.map +1 -0
  287. package/dist/types.js +21 -0
  288. package/dist/types.js.map +1 -0
  289. package/package.json +178 -0
@@ -0,0 +1,286 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mkdtempSync, rmSync, writeFileSync, utimesSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import { Agent } from '../../../agent.js';
6
+ import { createMcpExtension } from './index.js';
7
+ // ── Test MCP server ────────────────────────────────────────────────
8
+ // Path to the minimal stdio MCP server script.
9
+ const SERVER_SCRIPT = new URL('./test-server.mjs', import.meta.url).pathname;
10
+ // ── Mock model ─────────────────────────────────────────────────────
11
+ // Returns a fixed assistant message.
12
+ function mockModel() {
13
+ return {
14
+ async generate() {
15
+ return {
16
+ message: { role: 'assistant', content: 'ok' },
17
+ finishReason: 'stop',
18
+ };
19
+ },
20
+ };
21
+ }
22
+ // ── Helpers ────────────────────────────────────────────────────────
23
+ function makeConfig(path, servers) {
24
+ writeFileSync(path, JSON.stringify({ mcpServers: servers }, null, 2));
25
+ }
26
+ function stdioServer(command, args = []) {
27
+ return { type: 'stdio', command, args };
28
+ }
29
+ // ── Test setup ─────────────────────────────────────────────────────
30
+ let tmpDir;
31
+ let configPath;
32
+ beforeEach(() => {
33
+ tmpDir = mkdtempSync(join(tmpdir(), 'mcp-test-'));
34
+ configPath = join(tmpDir, 'mcpServers.json');
35
+ });
36
+ afterEach(() => {
37
+ rmSync(tmpDir, { recursive: true, force: true });
38
+ });
39
+ // ── Tests ──────────────────────────────────────────────────────────
40
+ describe('mcp extension', () => {
41
+ it('returns undefined when no mcpConfigPaths provided', async () => {
42
+ const ext = await createMcpExtension({});
43
+ expect(ext).toBeUndefined();
44
+ });
45
+ it('returns undefined when no servers in config', async () => {
46
+ makeConfig(configPath, {});
47
+ const ext = await createMcpExtension({ mcpConfigPaths: configPath });
48
+ expect(ext).toBeUndefined();
49
+ });
50
+ it('connects to a stdio server and discovers tools', async () => {
51
+ makeConfig(configPath, {
52
+ 'test': stdioServer('node', [SERVER_SCRIPT]),
53
+ });
54
+ const ext = await createMcpExtension({ mcpConfigPaths: configPath });
55
+ expect(ext).toBeDefined();
56
+ const agent = new Agent({ model: mockModel() });
57
+ agent.use(ext);
58
+ // MCP tools should NOT be registered on the agent at install time.
59
+ // They are injected per-turn via the beforeTurn hook.
60
+ const agentTools = agent.getTools();
61
+ expect(agentTools).not.toContain('test__echo');
62
+ expect(agentTools).not.toContain('test__ping');
63
+ // Meta-tools SHOULD be registered at install time.
64
+ expect(agentTools).toContain('list_resources');
65
+ expect(agentTools).toContain('read_resource');
66
+ expect(agentTools).toContain('list_prompts');
67
+ expect(agentTools).toContain('use_prompt');
68
+ });
69
+ it('injects MCP tools into turn.tools via beforeTurn hook', async () => {
70
+ makeConfig(configPath, {
71
+ 'test': stdioServer('node', [SERVER_SCRIPT]),
72
+ });
73
+ const ext = (await createMcpExtension({ mcpConfigPaths: configPath }));
74
+ const agent = new Agent({ model: mockModel() });
75
+ agent.use(ext);
76
+ // Run a turn and check that the model sees MCP tools.
77
+ let seenToolNames = [];
78
+ const model = {
79
+ async generate(req) {
80
+ seenToolNames = (req.tools ?? []).map((t) => t.function?.name ?? t.name);
81
+ return {
82
+ message: { role: 'assistant', content: 'ok' },
83
+ finishReason: 'stop',
84
+ };
85
+ },
86
+ };
87
+ const agent2 = new Agent({ model: model });
88
+ agent2.use(ext);
89
+ await agent2.run({ message: 'hi' });
90
+ expect(seenToolNames).toContain('test__echo');
91
+ expect(seenToolNames).toContain('test__ping');
92
+ // Meta-tools should also be visible.
93
+ expect(seenToolNames).toContain('list_resources');
94
+ });
95
+ it('can call an MCP tool through the agent', async () => {
96
+ makeConfig(configPath, {
97
+ 'test': stdioServer('node', [SERVER_SCRIPT]),
98
+ });
99
+ const ext = (await createMcpExtension({ mcpConfigPaths: configPath }));
100
+ let callCount = 0;
101
+ let toolResult = '';
102
+ const model = {
103
+ async generate(req) {
104
+ callCount++;
105
+ if (callCount === 1) {
106
+ return {
107
+ message: {
108
+ role: 'assistant',
109
+ content: '',
110
+ toolCalls: [{
111
+ id: 'call_1',
112
+ name: 'test__echo',
113
+ arguments: JSON.stringify({ text: 'hello mcp' }),
114
+ }],
115
+ },
116
+ finishReason: 'tool_calls',
117
+ };
118
+ }
119
+ const toolMsg = req.messages.find((m) => m.role === 'tool');
120
+ toolResult = toolMsg?.content ?? '';
121
+ return {
122
+ message: { role: 'assistant', content: 'done' },
123
+ finishReason: 'stop',
124
+ };
125
+ },
126
+ };
127
+ const agent = new Agent({ model: model });
128
+ agent.use(ext);
129
+ const result = await agent.run({ message: 'echo hello mcp' });
130
+ expect(result.finishReason).toBe('stop');
131
+ expect(result.toolCalls?.some((tc) => tc.name === 'test__echo')).toBe(true);
132
+ expect(toolResult).toBe('hello mcp');
133
+ });
134
+ it('reloads when config file changes at runtime', async () => {
135
+ // Start with one server.
136
+ makeConfig(configPath, {
137
+ 'test': stdioServer('node', [SERVER_SCRIPT]),
138
+ });
139
+ const ext = (await createMcpExtension({ mcpConfigPaths: configPath }));
140
+ let seenToolNames = [];
141
+ const model = {
142
+ async generate(req) {
143
+ seenToolNames = (req.tools ?? []).map((t) => t.function?.name ?? t.name);
144
+ return {
145
+ message: { role: 'assistant', content: 'ok' },
146
+ finishReason: 'stop',
147
+ };
148
+ },
149
+ };
150
+ const agent = new Agent({ model: model });
151
+ agent.use(ext);
152
+ // First turn: should see test__echo and test__ping.
153
+ await agent.run({ message: 'turn 1' });
154
+ expect(seenToolNames).toContain('test__echo');
155
+ expect(seenToolNames).toContain('test__ping');
156
+ // Modify the config to add a second server (same script, different name).
157
+ // We need to ensure the mtime changes — writeFileSync may not always
158
+ // update mtime on fast systems, so we force it with utimesSync.
159
+ makeConfig(configPath, {
160
+ 'test': stdioServer('node', [SERVER_SCRIPT]),
161
+ 'test2': stdioServer('node', [SERVER_SCRIPT]),
162
+ });
163
+ // Force mtime change (set to 1 second in the future).
164
+ const future = new Date(Date.now() / 1000 + 1);
165
+ utimesSync(configPath, future, future);
166
+ // Second turn: should see tools from both servers.
167
+ await agent.run({ message: 'turn 2' });
168
+ expect(seenToolNames).toContain('test__echo');
169
+ expect(seenToolNames).toContain('test2__echo');
170
+ expect(seenToolNames).toContain('test2__ping');
171
+ });
172
+ it('respects excludeTools pattern', async () => {
173
+ makeConfig(configPath, {
174
+ 'test': stdioServer('node', [SERVER_SCRIPT]),
175
+ });
176
+ const ext = (await createMcpExtension({
177
+ mcpConfigPaths: configPath,
178
+ excludeTools: ['test__ping'],
179
+ }));
180
+ let seenToolNames = [];
181
+ const model = {
182
+ async generate(req) {
183
+ seenToolNames = (req.tools ?? []).map((t) => t.function?.name ?? t.name);
184
+ return {
185
+ message: { role: 'assistant', content: 'ok' },
186
+ finishReason: 'stop',
187
+ };
188
+ },
189
+ };
190
+ const agent = new Agent({ model: model });
191
+ agent.use(ext);
192
+ await agent.run({ message: 'hi' });
193
+ expect(seenToolNames).toContain('test__echo');
194
+ expect(seenToolNames).not.toContain('test__ping');
195
+ });
196
+ it('meta-tools read from live state after reload', async () => {
197
+ makeConfig(configPath, {
198
+ 'test': stdioServer('node', [SERVER_SCRIPT]),
199
+ });
200
+ const ext = (await createMcpExtension({ mcpConfigPaths: configPath }));
201
+ let callCount = 0;
202
+ let resourceList = '';
203
+ const model = {
204
+ async generate(req) {
205
+ callCount++;
206
+ if (callCount === 1) {
207
+ return {
208
+ message: {
209
+ role: 'assistant',
210
+ content: '',
211
+ toolCalls: [{
212
+ id: 'call_1',
213
+ name: 'list_resources',
214
+ arguments: '{}',
215
+ }],
216
+ },
217
+ finishReason: 'tool_calls',
218
+ };
219
+ }
220
+ const toolMsg = req.messages.find((m) => m.role === 'tool');
221
+ resourceList = toolMsg?.content ?? '';
222
+ return {
223
+ message: { role: 'assistant', content: 'done' },
224
+ finishReason: 'stop',
225
+ };
226
+ },
227
+ };
228
+ const agent = new Agent({ model: model });
229
+ agent.use(ext);
230
+ await agent.run({ message: 'list resources' });
231
+ expect(resourceList).toContain('test://greeting');
232
+ });
233
+ it('can read an MCP resource via read_resource tool', async () => {
234
+ makeConfig(configPath, {
235
+ 'test': stdioServer('node', [SERVER_SCRIPT]),
236
+ });
237
+ const ext = (await createMcpExtension({ mcpConfigPaths: configPath }));
238
+ let callCount = 0;
239
+ let resourceContent = '';
240
+ const model = {
241
+ async generate(req) {
242
+ callCount++;
243
+ if (callCount === 1) {
244
+ return {
245
+ message: {
246
+ role: 'assistant',
247
+ content: '',
248
+ toolCalls: [{
249
+ id: 'call_1',
250
+ name: 'read_resource',
251
+ arguments: JSON.stringify({ uri: 'test://greeting' }),
252
+ }],
253
+ },
254
+ finishReason: 'tool_calls',
255
+ };
256
+ }
257
+ const toolMsg = req.messages.find((m) => m.role === 'tool');
258
+ resourceContent = toolMsg?.content ?? '';
259
+ return {
260
+ message: { role: 'assistant', content: 'done' },
261
+ finishReason: 'stop',
262
+ };
263
+ },
264
+ };
265
+ const agent = new Agent({ model: model });
266
+ agent.use(ext);
267
+ await agent.run({ message: 'read the greeting resource' });
268
+ expect(resourceContent).toContain('Hello from MCP');
269
+ });
270
+ it('close() cleans up client connections', async () => {
271
+ makeConfig(configPath, {
272
+ 'test': stdioServer('node', [SERVER_SCRIPT]),
273
+ });
274
+ const ext = await createMcpExtension({ mcpConfigPaths: configPath });
275
+ if (!ext)
276
+ throw new Error('extension was undefined');
277
+ const agent = new Agent({ model: mockModel() });
278
+ agent.use(ext);
279
+ // Should not throw.
280
+ await ext.close();
281
+ // Unload should also work (calls close internally).
282
+ // We can't easily test that the subprocess is killed, but we can
283
+ // verify close() doesn't throw.
284
+ });
285
+ });
286
+ //# sourceMappingURL=extension.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.test.js","sourceRoot":"","sources":["../../../../src/extras/extensions/mcp/extension.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { default as createMcpExtension } from './extension.js';
2
+ export type { McpExtensionConfig } from './extension.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC/D,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { default as createMcpExtension } from './extension.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/extras/extensions/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { Extension } from '../../../extension.js';
2
+ import type { Message } from '../../../types.js';
3
+ /**
4
+ * A simple in-memory session extension.
5
+ *
6
+ * Stores conversation history per session ID in a Map. On each turn:
7
+ * - `beforeTurn`: loads prior messages and prepends them to the turn context
8
+ * - `afterTurn`: saves the full conversation (including this turn) back
9
+ *
10
+ * Low priority so it loads after mutators (emoji, timestamp) — this means
11
+ * `afterTurn` saves the final decorated response, and `beforeTurn` prepends
12
+ * history after other extensions have processed the raw input.
13
+ *
14
+ * The returned extension has extra methods (`getMessages`, `clear`,
15
+ * `clearAll`) on the object for host-side inspection. These are not part
16
+ * of the `Extension` interface — the host can access them by finding the
17
+ * extension in the loaded array and casting.
18
+ */
19
+ export default function createMemSessionExtension(): Extension & {
20
+ getMessages(sessionId?: string): Message[];
21
+ clear(sessionId?: string): void;
22
+ clearAll(): void;
23
+ };
24
+ //# sourceMappingURL=extension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/mem-session/extension.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,OAAO,UAAU,yBAAyB,IAAI,SAAS,GAAG;IAC/D,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,CAAC;IAC3C,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,IAAI,IAAI,CAAC;CAClB,CAiCA"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * A simple in-memory session extension.
3
+ *
4
+ * Stores conversation history per session ID in a Map. On each turn:
5
+ * - `beforeTurn`: loads prior messages and prepends them to the turn context
6
+ * - `afterTurn`: saves the full conversation (including this turn) back
7
+ *
8
+ * Low priority so it loads after mutators (emoji, timestamp) — this means
9
+ * `afterTurn` saves the final decorated response, and `beforeTurn` prepends
10
+ * history after other extensions have processed the raw input.
11
+ *
12
+ * The returned extension has extra methods (`getMessages`, `clear`,
13
+ * `clearAll`) on the object for host-side inspection. These are not part
14
+ * of the `Extension` interface — the host can access them by finding the
15
+ * extension in the loaded array and casting.
16
+ */
17
+ export default function createMemSessionExtension() {
18
+ const store = new Map();
19
+ return {
20
+ name: 'mem-session',
21
+ priority: -100,
22
+ install(agent) {
23
+ agent.hook('beforeTurn', 'mem-session', async (ctx) => {
24
+ const sessionId = ctx.turn.request.metadata?.sessionId ?? 'default';
25
+ const history = store.get(sessionId);
26
+ if (history && history.length > 0) {
27
+ ctx.turn.messages = [...history, ...ctx.turn.messages];
28
+ }
29
+ });
30
+ agent.hook('afterTurn', 'mem-session', async (ctx) => {
31
+ const sessionId = ctx.turn.request.metadata?.sessionId ?? 'default';
32
+ store.set(sessionId, [...ctx.turn.messages]);
33
+ });
34
+ },
35
+ /** Get the messages for a session. */
36
+ getMessages(sessionId = 'default') {
37
+ return store.get(sessionId) ?? [];
38
+ },
39
+ /** Clear a single session. */
40
+ clear(sessionId = 'default') {
41
+ store.delete(sessionId);
42
+ },
43
+ /** Clear all sessions. */
44
+ clearAll() {
45
+ store.clear();
46
+ },
47
+ };
48
+ }
49
+ //# sourceMappingURL=extension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.js","sourceRoot":"","sources":["../../../../src/extras/extensions/mem-session/extension.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,OAAO,UAAU,yBAAyB;IAK/C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;IAE3C,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,QAAQ,EAAE,CAAC,GAAG;QACd,OAAO,CAAC,KAAK;YACX,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,aAAa,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;gBACpD,MAAM,SAAS,GAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAoB,IAAI,SAAS,CAAC;gBAChF,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBACrC,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAClC,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,GAAG,OAAO,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACzD,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;gBACnD,MAAM,SAAS,GAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAoB,IAAI,SAAS,CAAC;gBAChF,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC/C,CAAC,CAAC,CAAC;QACL,CAAC;QACD,sCAAsC;QACtC,WAAW,CAAC,SAAS,GAAW,SAAS;YACvC,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QACpC,CAAC;QACD,8BAA8B;QAC9B,KAAK,CAAC,SAAS,GAAW,SAAS;YACjC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC;QACD,0BAA0B;QAC1B,QAAQ;YACN,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "mem-session",
3
+ "description": "In-memory session extension. Stores conversation history per session ID. Low priority so afterTurn saves the final response after mutators have decorated it.",
4
+ "enabled": true,
5
+ "priority": -100
6
+ }
@@ -0,0 +1,2 @@
1
+ export { default as createMemSessionExtension } from './extension.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/mem-session/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { default as createMemSessionExtension } from './extension.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/extras/extensions/mem-session/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,54 @@
1
+ import type { Extension } from '../../../extension.js';
2
+ import type { MemoryExtensionConfig } from './types.js';
3
+ /**
4
+ * Memory extension — persistent, session-scoped knowledge across turns.
5
+ *
6
+ * The agent does not manage memory explicitly. Memories are:
7
+ * - **Retrieved** automatically in `beforeContext` and injected as a
8
+ * system message before the LLM loop.
9
+ * - **Extracted** automatically in `afterTurn` and persisted to the store.
10
+ *
11
+ * Both paths are non-fatal: retrieval or extraction failures are logged
12
+ * and the turn proceeds normally. Memory is convenience infrastructure,
13
+ * not a correctness requirement.
14
+ *
15
+ * ## Hook footprint
16
+ *
17
+ * Only two hooks:
18
+ * - `beforeContext` — retrieve and inject memories
19
+ * - `afterTurn` — extract and persist memories
20
+ *
21
+ * This avoids conflicts with session extensions (which use `beforeTurn`)
22
+ * and observability extensions (which use `afterLLM`/`afterTurn`).
23
+ *
24
+ * ## Ordering
25
+ *
26
+ * Priority defaults to -95 (between session at -100 and mutators at 0).
27
+ * In `beforeContext`, the memory system message is unshifted to index 0,
28
+ * ahead of session history loaded in `beforeTurn`:
29
+ *
30
+ * ```
31
+ * [memory system msg] [session history...] [user message]
32
+ * ```
33
+ *
34
+ * In `afterTurn`, memory reads the final `turn.messages` and
35
+ * `turn.response` — both are set by the core before `afterTurn` fires.
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const store = new MyVectorStore();
40
+ * const extractor = createLlmExtractor(model);
41
+ * const memoryExt = createMemoryExtension({ store, extractor });
42
+ *
43
+ * const agent = new Agent({ model });
44
+ * agent.use(memoryExt);
45
+ *
46
+ * await agent.run({
47
+ * message: "My name is Kristi",
48
+ * metadata: { sessionId: 'slack_C123' },
49
+ * });
50
+ * // Next turn in the same session: the agent remembers "Kristi".
51
+ * ```
52
+ */
53
+ export default function createMemoryExtension(config: MemoryExtensionConfig): Extension;
54
+ //# sourceMappingURL=extension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../../src/extras/extensions/memory/extension.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,KAAK,EACV,qBAAqB,EAItB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAC3C,MAAM,EAAE,qBAAqB,GAC5B,SAAS,CAsGX"}
@@ -0,0 +1,143 @@
1
+ import { messageContentToText } from '../../../types.js';
2
+ /**
3
+ * Memory extension — persistent, session-scoped knowledge across turns.
4
+ *
5
+ * The agent does not manage memory explicitly. Memories are:
6
+ * - **Retrieved** automatically in `beforeContext` and injected as a
7
+ * system message before the LLM loop.
8
+ * - **Extracted** automatically in `afterTurn` and persisted to the store.
9
+ *
10
+ * Both paths are non-fatal: retrieval or extraction failures are logged
11
+ * and the turn proceeds normally. Memory is convenience infrastructure,
12
+ * not a correctness requirement.
13
+ *
14
+ * ## Hook footprint
15
+ *
16
+ * Only two hooks:
17
+ * - `beforeContext` — retrieve and inject memories
18
+ * - `afterTurn` — extract and persist memories
19
+ *
20
+ * This avoids conflicts with session extensions (which use `beforeTurn`)
21
+ * and observability extensions (which use `afterLLM`/`afterTurn`).
22
+ *
23
+ * ## Ordering
24
+ *
25
+ * Priority defaults to -95 (between session at -100 and mutators at 0).
26
+ * In `beforeContext`, the memory system message is unshifted to index 0,
27
+ * ahead of session history loaded in `beforeTurn`:
28
+ *
29
+ * ```
30
+ * [memory system msg] [session history...] [user message]
31
+ * ```
32
+ *
33
+ * In `afterTurn`, memory reads the final `turn.messages` and
34
+ * `turn.response` — both are set by the core before `afterTurn` fires.
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * const store = new MyVectorStore();
39
+ * const extractor = createLlmExtractor(model);
40
+ * const memoryExt = createMemoryExtension({ store, extractor });
41
+ *
42
+ * const agent = new Agent({ model });
43
+ * agent.use(memoryExt);
44
+ *
45
+ * await agent.run({
46
+ * message: "My name is Kristi",
47
+ * metadata: { sessionId: 'slack_C123' },
48
+ * });
49
+ * // Next turn in the same session: the agent remembers "Kristi".
50
+ * ```
51
+ */
52
+ export default function createMemoryExtension(config) {
53
+ const { store, extractor, maxRecall = 10, scopeKey = 'sessionId', priority = -95, } = config;
54
+ // Default retriever: pass-through to store.search.
55
+ const retriever = config.retriever ?? {
56
+ async retrieve({ scope, text }) {
57
+ return store.search({ scope, text, maxResults: maxRecall });
58
+ },
59
+ };
60
+ return {
61
+ name: 'memory',
62
+ priority,
63
+ install(agent) {
64
+ // ── beforeContext: retrieve and inject ────────────────────
65
+ agent.hook('beforeContext', 'memory', async (ctx) => {
66
+ const scope = ctx.turn.request.metadata?.[scopeKey] ?? 'default';
67
+ const text = messageContentToText(ctx.turn.request.message);
68
+ let memories;
69
+ try {
70
+ memories = await retriever.retrieve({ scope, text, store });
71
+ }
72
+ catch (err) {
73
+ console.error('[memory] retrieval failed:', err);
74
+ return; // proceed without memories
75
+ }
76
+ if (memories.length === 0)
77
+ return;
78
+ const memoryText = memories
79
+ .map((m, i) => `${i + 1}. ${m.content}`)
80
+ .join('\n');
81
+ ctx.turn.messages.unshift({
82
+ role: 'system',
83
+ content: `Relevant memories from prior conversations:\n${memoryText}`,
84
+ });
85
+ });
86
+ // ── afterTurn: extract and persist ─────────────────────────
87
+ agent.hook('afterTurn', 'memory', async (ctx) => {
88
+ const scope = ctx.turn.request.metadata?.[scopeKey] ?? 'default';
89
+ // Load existing memories so the extractor can dedup/update/delete.
90
+ let existing;
91
+ try {
92
+ existing = await store.listByScope(scope);
93
+ }
94
+ catch (err) {
95
+ console.error('[memory] failed to load existing memories:', err);
96
+ return; // skip extraction — can't dedup without existing context
97
+ }
98
+ let extractions;
99
+ try {
100
+ const result = await extractor.extract({
101
+ scope,
102
+ messages: ctx.turn.messages,
103
+ response: ctx.turn.response,
104
+ existingMemories: existing,
105
+ });
106
+ // Guard against malformed extractor output — a non-array
107
+ // would throw during iteration, escaping the try/catch.
108
+ extractions = Array.isArray(result) ? result : [];
109
+ }
110
+ catch (err) {
111
+ console.error('[memory] extraction failed:', err);
112
+ return;
113
+ }
114
+ // Apply each operation. Individual failures are logged and
115
+ // skipped — partial persistence is acceptable.
116
+ for (const ext of extractions) {
117
+ try {
118
+ if (ext.action === 'create') {
119
+ await store.save({
120
+ content: ext.content,
121
+ scope,
122
+ metadata: ext.metadata,
123
+ });
124
+ }
125
+ else if (ext.action === 'update' && ext.targetId) {
126
+ await store.update(ext.targetId, {
127
+ content: ext.content,
128
+ metadata: ext.metadata,
129
+ });
130
+ }
131
+ else if (ext.action === 'delete' && ext.targetId) {
132
+ await store.delete(ext.targetId);
133
+ }
134
+ }
135
+ catch (err) {
136
+ console.error(`[memory] failed to ${ext.action} memory:`, err);
137
+ }
138
+ }
139
+ });
140
+ },
141
+ };
142
+ }
143
+ //# sourceMappingURL=extension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.js","sourceRoot":"","sources":["../../../../src/extras/extensions/memory/extension.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "memory",
3
+ "description": "Session-scoped memory extension. Automatically retrieves relevant memories in beforeContext and extracts new memories in afterTurn. Requires a MemoryStore and MemoryExtractor (provided via config). Non-fatal: memory failures never crash a turn.",
4
+ "enabled": false,
5
+ "priority": -95,
6
+ "configKeys": ["store", "extractor", "retriever", "maxRecall", "scopeKey"]
7
+ }