@fraziym/axoniz 0.1.0

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 (512) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +76 -0
  3. package/dist/agents/definition.d.ts +15 -0
  4. package/dist/agents/definition.d.ts.map +1 -0
  5. package/dist/agents/definition.js +41 -0
  6. package/dist/agents/definition.js.map +1 -0
  7. package/dist/agents/index.d.ts +12 -0
  8. package/dist/agents/index.d.ts.map +1 -0
  9. package/dist/agents/index.js +11 -0
  10. package/dist/agents/index.js.map +1 -0
  11. package/dist/agents/registry.d.ts +17 -0
  12. package/dist/agents/registry.d.ts.map +1 -0
  13. package/dist/agents/registry.js +23 -0
  14. package/dist/agents/registry.js.map +1 -0
  15. package/dist/agents/specialized.d.ts +31 -0
  16. package/dist/agents/specialized.d.ts.map +1 -0
  17. package/dist/agents/specialized.js +75 -0
  18. package/dist/agents/specialized.js.map +1 -0
  19. package/dist/awareness/index.d.ts +14 -0
  20. package/dist/awareness/index.d.ts.map +1 -0
  21. package/dist/awareness/index.js +22 -0
  22. package/dist/awareness/index.js.map +1 -0
  23. package/dist/awareness/service.d.ts +180 -0
  24. package/dist/awareness/service.d.ts.map +1 -0
  25. package/dist/awareness/service.js +789 -0
  26. package/dist/awareness/service.js.map +1 -0
  27. package/dist/cli/entry.d.ts +13 -0
  28. package/dist/cli/entry.d.ts.map +1 -0
  29. package/dist/cli/entry.js +35 -0
  30. package/dist/cli/entry.js.map +1 -0
  31. package/dist/comms/telegram.d.ts +41 -0
  32. package/dist/comms/telegram.d.ts.map +1 -0
  33. package/dist/comms/telegram.js +332 -0
  34. package/dist/comms/telegram.js.map +1 -0
  35. package/dist/core/agent.d.ts +252 -0
  36. package/dist/core/agent.d.ts.map +1 -0
  37. package/dist/core/agent.js +1399 -0
  38. package/dist/core/agent.js.map +1 -0
  39. package/dist/core/auth.d.ts +23 -0
  40. package/dist/core/auth.d.ts.map +1 -0
  41. package/dist/core/auth.js +113 -0
  42. package/dist/core/auth.js.map +1 -0
  43. package/dist/core/authority.d.ts +118 -0
  44. package/dist/core/authority.d.ts.map +1 -0
  45. package/dist/core/authority.js +402 -0
  46. package/dist/core/authority.js.map +1 -0
  47. package/dist/core/backend/async_queue.d.ts +17 -0
  48. package/dist/core/backend/async_queue.d.ts.map +1 -0
  49. package/dist/core/backend/async_queue.js +66 -0
  50. package/dist/core/backend/async_queue.js.map +1 -0
  51. package/dist/core/backend/index.d.ts +24 -0
  52. package/dist/core/backend/index.d.ts.map +1 -0
  53. package/dist/core/backend/index.js +128 -0
  54. package/dist/core/backend/index.js.map +1 -0
  55. package/dist/core/backend/llama_server.d.ts +39 -0
  56. package/dist/core/backend/llama_server.d.ts.map +1 -0
  57. package/dist/core/backend/llama_server.js +182 -0
  58. package/dist/core/backend/llama_server.js.map +1 -0
  59. package/dist/core/backend/llamacpp.d.ts +40 -0
  60. package/dist/core/backend/llamacpp.d.ts.map +1 -0
  61. package/dist/core/backend/llamacpp.js +200 -0
  62. package/dist/core/backend/llamacpp.js.map +1 -0
  63. package/dist/core/backend/lmstudio.d.ts +53 -0
  64. package/dist/core/backend/lmstudio.d.ts.map +1 -0
  65. package/dist/core/backend/lmstudio.js +274 -0
  66. package/dist/core/backend/lmstudio.js.map +1 -0
  67. package/dist/core/backend/ollama.d.ts +25 -0
  68. package/dist/core/backend/ollama.d.ts.map +1 -0
  69. package/dist/core/backend/ollama.js +86 -0
  70. package/dist/core/backend/ollama.js.map +1 -0
  71. package/dist/core/backend/openai.d.ts +27 -0
  72. package/dist/core/backend/openai.d.ts.map +1 -0
  73. package/dist/core/backend/openai.js +84 -0
  74. package/dist/core/backend/openai.js.map +1 -0
  75. package/dist/core/backend/types.d.ts +73 -0
  76. package/dist/core/backend/types.d.ts.map +1 -0
  77. package/dist/core/backend/types.js +137 -0
  78. package/dist/core/backend/types.js.map +1 -0
  79. package/dist/core/chat_store.d.ts +77 -0
  80. package/dist/core/chat_store.d.ts.map +1 -0
  81. package/dist/core/chat_store.js +332 -0
  82. package/dist/core/chat_store.js.map +1 -0
  83. package/dist/core/cli.d.ts +82 -0
  84. package/dist/core/cli.d.ts.map +1 -0
  85. package/dist/core/cli.js +602 -0
  86. package/dist/core/cli.js.map +1 -0
  87. package/dist/core/config.d.ts +127 -0
  88. package/dist/core/config.d.ts.map +1 -0
  89. package/dist/core/config.js +295 -0
  90. package/dist/core/config.js.map +1 -0
  91. package/dist/core/debug.d.ts +8 -0
  92. package/dist/core/debug.d.ts.map +1 -0
  93. package/dist/core/debug.js +8 -0
  94. package/dist/core/debug.js.map +1 -0
  95. package/dist/core/downloader.d.ts +31 -0
  96. package/dist/core/downloader.d.ts.map +1 -0
  97. package/dist/core/downloader.js +180 -0
  98. package/dist/core/downloader.js.map +1 -0
  99. package/dist/core/errors.d.ts +80 -0
  100. package/dist/core/errors.d.ts.map +1 -0
  101. package/dist/core/errors.js +134 -0
  102. package/dist/core/errors.js.map +1 -0
  103. package/dist/core/extras.d.ts +160 -0
  104. package/dist/core/extras.d.ts.map +1 -0
  105. package/dist/core/extras.js +553 -0
  106. package/dist/core/extras.js.map +1 -0
  107. package/dist/core/health.d.ts +27 -0
  108. package/dist/core/health.d.ts.map +1 -0
  109. package/dist/core/health.js +96 -0
  110. package/dist/core/health.js.map +1 -0
  111. package/dist/core/history.d.ts +50 -0
  112. package/dist/core/history.d.ts.map +1 -0
  113. package/dist/core/history.js +276 -0
  114. package/dist/core/history.js.map +1 -0
  115. package/dist/core/index.d.ts +6 -0
  116. package/dist/core/index.d.ts.map +1 -0
  117. package/dist/core/index.js +6 -0
  118. package/dist/core/index.js.map +1 -0
  119. package/dist/core/intelligence/ast_index.d.ts +255 -0
  120. package/dist/core/intelligence/ast_index.d.ts.map +1 -0
  121. package/dist/core/intelligence/ast_index.js +1369 -0
  122. package/dist/core/intelligence/ast_index.js.map +1 -0
  123. package/dist/core/intelligence/confidence.d.ts +113 -0
  124. package/dist/core/intelligence/confidence.d.ts.map +1 -0
  125. package/dist/core/intelligence/confidence.js +298 -0
  126. package/dist/core/intelligence/confidence.js.map +1 -0
  127. package/dist/core/intelligence/context_compressor.d.ts +80 -0
  128. package/dist/core/intelligence/context_compressor.d.ts.map +1 -0
  129. package/dist/core/intelligence/context_compressor.js +245 -0
  130. package/dist/core/intelligence/context_compressor.js.map +1 -0
  131. package/dist/core/intelligence/daemon.d.ts +247 -0
  132. package/dist/core/intelligence/daemon.d.ts.map +1 -0
  133. package/dist/core/intelligence/daemon.js +842 -0
  134. package/dist/core/intelligence/daemon.js.map +1 -0
  135. package/dist/core/intelligence/index.d.ts +60 -0
  136. package/dist/core/intelligence/index.d.ts.map +1 -0
  137. package/dist/core/intelligence/index.js +101 -0
  138. package/dist/core/intelligence/index.js.map +1 -0
  139. package/dist/core/intelligence/predictor.d.ts +246 -0
  140. package/dist/core/intelligence/predictor.d.ts.map +1 -0
  141. package/dist/core/intelligence/predictor.js +590 -0
  142. package/dist/core/intelligence/predictor.js.map +1 -0
  143. package/dist/core/intelligence/reflex.d.ts +84 -0
  144. package/dist/core/intelligence/reflex.d.ts.map +1 -0
  145. package/dist/core/intelligence/reflex.js +344 -0
  146. package/dist/core/intelligence/reflex.js.map +1 -0
  147. package/dist/core/intelligence/self_correction.d.ts +121 -0
  148. package/dist/core/intelligence/self_correction.d.ts.map +1 -0
  149. package/dist/core/intelligence/self_correction.js +327 -0
  150. package/dist/core/intelligence/self_correction.js.map +1 -0
  151. package/dist/core/intelligence/skill_distiller.d.ts +100 -0
  152. package/dist/core/intelligence/skill_distiller.d.ts.map +1 -0
  153. package/dist/core/intelligence/skill_distiller.js +246 -0
  154. package/dist/core/intelligence/skill_distiller.js.map +1 -0
  155. package/dist/core/intelligence/swarm.d.ts +330 -0
  156. package/dist/core/intelligence/swarm.d.ts.map +1 -0
  157. package/dist/core/intelligence/swarm.js +1064 -0
  158. package/dist/core/intelligence/swarm.js.map +1 -0
  159. package/dist/core/intelligence/trajectory.d.ts +107 -0
  160. package/dist/core/intelligence/trajectory.d.ts.map +1 -0
  161. package/dist/core/intelligence/trajectory.js +330 -0
  162. package/dist/core/intelligence/trajectory.js.map +1 -0
  163. package/dist/core/logger.d.ts +111 -0
  164. package/dist/core/logger.d.ts.map +1 -0
  165. package/dist/core/logger.js +640 -0
  166. package/dist/core/logger.js.map +1 -0
  167. package/dist/core/loop.d.ts +123 -0
  168. package/dist/core/loop.d.ts.map +1 -0
  169. package/dist/core/loop.js +423 -0
  170. package/dist/core/loop.js.map +1 -0
  171. package/dist/core/memory.d.ts +81 -0
  172. package/dist/core/memory.d.ts.map +1 -0
  173. package/dist/core/memory.js +328 -0
  174. package/dist/core/memory.js.map +1 -0
  175. package/dist/core/metrics.d.ts +29 -0
  176. package/dist/core/metrics.d.ts.map +1 -0
  177. package/dist/core/metrics.js +109 -0
  178. package/dist/core/metrics.js.map +1 -0
  179. package/dist/core/models.d.ts +51 -0
  180. package/dist/core/models.d.ts.map +1 -0
  181. package/dist/core/models.js +146 -0
  182. package/dist/core/models.js.map +1 -0
  183. package/dist/core/optimizer.d.ts +34 -0
  184. package/dist/core/optimizer.d.ts.map +1 -0
  185. package/dist/core/optimizer.js +131 -0
  186. package/dist/core/optimizer.js.map +1 -0
  187. package/dist/core/persona.d.ts +35 -0
  188. package/dist/core/persona.d.ts.map +1 -0
  189. package/dist/core/persona.js +126 -0
  190. package/dist/core/persona.js.map +1 -0
  191. package/dist/core/rate_limit.d.ts +23 -0
  192. package/dist/core/rate_limit.d.ts.map +1 -0
  193. package/dist/core/rate_limit.js +62 -0
  194. package/dist/core/rate_limit.js.map +1 -0
  195. package/dist/core/runner.d.ts +63 -0
  196. package/dist/core/runner.d.ts.map +1 -0
  197. package/dist/core/runner.js +671 -0
  198. package/dist/core/runner.js.map +1 -0
  199. package/dist/core/stream_parser.d.ts +43 -0
  200. package/dist/core/stream_parser.d.ts.map +1 -0
  201. package/dist/core/stream_parser.js +140 -0
  202. package/dist/core/stream_parser.js.map +1 -0
  203. package/dist/core/tool_schemas.d.ts +26 -0
  204. package/dist/core/tool_schemas.d.ts.map +1 -0
  205. package/dist/core/tool_schemas.js +124 -0
  206. package/dist/core/tool_schemas.js.map +1 -0
  207. package/dist/core/which.d.ts +2 -0
  208. package/dist/core/which.d.ts.map +1 -0
  209. package/dist/core/which.js +35 -0
  210. package/dist/core/which.js.map +1 -0
  211. package/dist/goals/index.d.ts +9 -0
  212. package/dist/goals/index.d.ts.map +1 -0
  213. package/dist/goals/index.js +17 -0
  214. package/dist/goals/index.js.map +1 -0
  215. package/dist/goals/service.d.ts +115 -0
  216. package/dist/goals/service.d.ts.map +1 -0
  217. package/dist/goals/service.js +415 -0
  218. package/dist/goals/service.js.map +1 -0
  219. package/dist/goals/types.d.ts +47 -0
  220. package/dist/goals/types.d.ts.map +1 -0
  221. package/dist/goals/types.js +66 -0
  222. package/dist/goals/types.js.map +1 -0
  223. package/dist/index.d.ts +22 -0
  224. package/dist/index.d.ts.map +1 -0
  225. package/dist/index.js +22 -0
  226. package/dist/index.js.map +1 -0
  227. package/dist/integrations/autonomous_startup.d.ts +51 -0
  228. package/dist/integrations/autonomous_startup.d.ts.map +1 -0
  229. package/dist/integrations/autonomous_startup.js +419 -0
  230. package/dist/integrations/autonomous_startup.js.map +1 -0
  231. package/dist/integrations/goose.d.ts +105 -0
  232. package/dist/integrations/goose.d.ts.map +1 -0
  233. package/dist/integrations/goose.js +408 -0
  234. package/dist/integrations/goose.js.map +1 -0
  235. package/dist/integrations/index.d.ts +21 -0
  236. package/dist/integrations/index.d.ts.map +1 -0
  237. package/dist/integrations/index.js +17 -0
  238. package/dist/integrations/index.js.map +1 -0
  239. package/dist/integrations/mcp.d.ts +73 -0
  240. package/dist/integrations/mcp.d.ts.map +1 -0
  241. package/dist/integrations/mcp.js +307 -0
  242. package/dist/integrations/mcp.js.map +1 -0
  243. package/dist/integrations/mempalace.d.ts +18 -0
  244. package/dist/integrations/mempalace.d.ts.map +1 -0
  245. package/dist/integrations/mempalace.js +25 -0
  246. package/dist/integrations/mempalace.js.map +1 -0
  247. package/dist/integrations/multi_agent.d.ts +82 -0
  248. package/dist/integrations/multi_agent.d.ts.map +1 -0
  249. package/dist/integrations/multi_agent.js +280 -0
  250. package/dist/integrations/multi_agent.js.map +1 -0
  251. package/dist/integrations/unified_memory.d.ts +415 -0
  252. package/dist/integrations/unified_memory.d.ts.map +1 -0
  253. package/dist/integrations/unified_memory.js +1489 -0
  254. package/dist/integrations/unified_memory.js.map +1 -0
  255. package/dist/roles/beru.yaml +48 -0
  256. package/dist/sidecar/client.d.ts +63 -0
  257. package/dist/sidecar/client.d.ts.map +1 -0
  258. package/dist/sidecar/client.js +222 -0
  259. package/dist/sidecar/client.js.map +1 -0
  260. package/dist/sidecar/index.d.ts +7 -0
  261. package/dist/sidecar/index.d.ts.map +1 -0
  262. package/dist/sidecar/index.js +6 -0
  263. package/dist/sidecar/index.js.map +1 -0
  264. package/dist/startup.d.ts +22 -0
  265. package/dist/startup.d.ts.map +1 -0
  266. package/dist/startup.js +194 -0
  267. package/dist/startup.js.map +1 -0
  268. package/dist/tools/_internal.d.ts +90 -0
  269. package/dist/tools/_internal.d.ts.map +1 -0
  270. package/dist/tools/_internal.js +375 -0
  271. package/dist/tools/_internal.js.map +1 -0
  272. package/dist/tools/_smoke.d.ts +2 -0
  273. package/dist/tools/_smoke.d.ts.map +1 -0
  274. package/dist/tools/_smoke.js +203 -0
  275. package/dist/tools/_smoke.js.map +1 -0
  276. package/dist/tools/axodex_tools.d.ts +51 -0
  277. package/dist/tools/axodex_tools.d.ts.map +1 -0
  278. package/dist/tools/axodex_tools.js +181 -0
  279. package/dist/tools/axodex_tools.js.map +1 -0
  280. package/dist/tools/code_tools.d.ts +33 -0
  281. package/dist/tools/code_tools.d.ts.map +1 -0
  282. package/dist/tools/code_tools.js +191 -0
  283. package/dist/tools/code_tools.js.map +1 -0
  284. package/dist/tools/computer_tools.d.ts +59 -0
  285. package/dist/tools/computer_tools.d.ts.map +1 -0
  286. package/dist/tools/computer_tools.js +348 -0
  287. package/dist/tools/computer_tools.js.map +1 -0
  288. package/dist/tools/file_tools.d.ts +51 -0
  289. package/dist/tools/file_tools.d.ts.map +1 -0
  290. package/dist/tools/file_tools.js +424 -0
  291. package/dist/tools/file_tools.js.map +1 -0
  292. package/dist/tools/index.d.ts +13 -0
  293. package/dist/tools/index.d.ts.map +1 -0
  294. package/dist/tools/index.js +13 -0
  295. package/dist/tools/index.js.map +1 -0
  296. package/dist/tools/shell_tools.d.ts +39 -0
  297. package/dist/tools/shell_tools.d.ts.map +1 -0
  298. package/dist/tools/shell_tools.js +163 -0
  299. package/dist/tools/shell_tools.js.map +1 -0
  300. package/dist/tools/web_tools.d.ts +31 -0
  301. package/dist/tools/web_tools.d.ts.map +1 -0
  302. package/dist/tools/web_tools.js +117 -0
  303. package/dist/tools/web_tools.js.map +1 -0
  304. package/dist/voice/index.d.ts +41 -0
  305. package/dist/voice/index.d.ts.map +1 -0
  306. package/dist/voice/index.js +58 -0
  307. package/dist/voice/index.js.map +1 -0
  308. package/dist/voice/light_daemon.d.ts +197 -0
  309. package/dist/voice/light_daemon.d.ts.map +1 -0
  310. package/dist/voice/light_daemon.js +746 -0
  311. package/dist/voice/light_daemon.js.map +1 -0
  312. package/dist/voice/setup.d.ts +63 -0
  313. package/dist/voice/setup.d.ts.map +1 -0
  314. package/dist/voice/setup.js +443 -0
  315. package/dist/voice/setup.js.map +1 -0
  316. package/dist/voice/stt.d.ts +148 -0
  317. package/dist/voice/stt.d.ts.map +1 -0
  318. package/dist/voice/stt.js +361 -0
  319. package/dist/voice/stt.js.map +1 -0
  320. package/dist/voice/tts.d.ts +168 -0
  321. package/dist/voice/tts.d.ts.map +1 -0
  322. package/dist/voice/tts.js +698 -0
  323. package/dist/voice/tts.js.map +1 -0
  324. package/dist/voice/voice_loop.d.ts +101 -0
  325. package/dist/voice/voice_loop.d.ts.map +1 -0
  326. package/dist/voice/voice_loop.js +463 -0
  327. package/dist/voice/voice_loop.js.map +1 -0
  328. package/dist/voice/wake_word.d.ts +153 -0
  329. package/dist/voice/wake_word.d.ts.map +1 -0
  330. package/dist/voice/wake_word.js +458 -0
  331. package/dist/voice/wake_word.js.map +1 -0
  332. package/dist/voice/wav.d.ts +99 -0
  333. package/dist/voice/wav.d.ts.map +1 -0
  334. package/dist/voice/wav.js +306 -0
  335. package/dist/voice/wav.js.map +1 -0
  336. package/dist/web/broker.d.ts +33 -0
  337. package/dist/web/broker.d.ts.map +1 -0
  338. package/dist/web/broker.js +58 -0
  339. package/dist/web/broker.js.map +1 -0
  340. package/dist/web/open_browser.d.ts +2 -0
  341. package/dist/web/open_browser.d.ts.map +1 -0
  342. package/dist/web/open_browser.js +42 -0
  343. package/dist/web/open_browser.js.map +1 -0
  344. package/dist/web/server.d.ts +54 -0
  345. package/dist/web/server.d.ts.map +1 -0
  346. package/dist/web/server.js +831 -0
  347. package/dist/web/server.js.map +1 -0
  348. package/dist/web/static/app.js +4121 -0
  349. package/dist/web/static/index.html +2281 -0
  350. package/dist/web/static/js/MODULE_SUMMARY.md +124 -0
  351. package/dist/web/static/js/a11y.js +165 -0
  352. package/dist/web/static/js/admin.js +2145 -0
  353. package/dist/web/static/js/assistant.js +475 -0
  354. package/dist/web/static/js/calendar/reminders.js +114 -0
  355. package/dist/web/static/js/calendar/utils.js +166 -0
  356. package/dist/web/static/js/calendar.js +3348 -0
  357. package/dist/web/static/js/censor.js +356 -0
  358. package/dist/web/static/js/chat.js +4546 -0
  359. package/dist/web/static/js/chatRenderer.js +2294 -0
  360. package/dist/web/static/js/chatStream.js +276 -0
  361. package/dist/web/static/js/codeRunner.js +398 -0
  362. package/dist/web/static/js/color/hex.js +14 -0
  363. package/dist/web/static/js/colorPicker.js +453 -0
  364. package/dist/web/static/js/compare/icons.js +77 -0
  365. package/dist/web/static/js/compare/index.js +1482 -0
  366. package/dist/web/static/js/compare/models.js +104 -0
  367. package/dist/web/static/js/compare/panes.js +817 -0
  368. package/dist/web/static/js/compare/probe.js +78 -0
  369. package/dist/web/static/js/compare/scoreboard.js +223 -0
  370. package/dist/web/static/js/compare/selector.js +1335 -0
  371. package/dist/web/static/js/compare/state.js +58 -0
  372. package/dist/web/static/js/compare/stream.js +695 -0
  373. package/dist/web/static/js/compare/vote.js +254 -0
  374. package/dist/web/static/js/cookbook-diagnosis.js +694 -0
  375. package/dist/web/static/js/cookbook-hwfit.js +1888 -0
  376. package/dist/web/static/js/cookbook.js +2093 -0
  377. package/dist/web/static/js/cookbookDownload.js +633 -0
  378. package/dist/web/static/js/cookbookProgressSignal.js +29 -0
  379. package/dist/web/static/js/cookbookRunning.js +3506 -0
  380. package/dist/web/static/js/cookbookServe.js +2128 -0
  381. package/dist/web/static/js/document.js +9731 -0
  382. package/dist/web/static/js/documentLibrary.js +3376 -0
  383. package/dist/web/static/js/dragSort.js +265 -0
  384. package/dist/web/static/js/editor/ai-inpaint.js +374 -0
  385. package/dist/web/static/js/editor/ai-models.js +273 -0
  386. package/dist/web/static/js/editor/ai-rembg.js +230 -0
  387. package/dist/web/static/js/editor/ai-tool-runner.js +147 -0
  388. package/dist/web/static/js/editor/ai-tools-misc.js +216 -0
  389. package/dist/web/static/js/editor/build/controls.js +366 -0
  390. package/dist/web/static/js/editor/build/popups.js +112 -0
  391. package/dist/web/static/js/editor/build/right-panel.js +200 -0
  392. package/dist/web/static/js/editor/build/toolbar.js +73 -0
  393. package/dist/web/static/js/editor/build/topbar.js +131 -0
  394. package/dist/web/static/js/editor/build/transform-popup.js +109 -0
  395. package/dist/web/static/js/editor/canvas-coords.js +21 -0
  396. package/dist/web/static/js/editor/canvas-events.js +197 -0
  397. package/dist/web/static/js/editor/canvas-transforms.js +132 -0
  398. package/dist/web/static/js/editor/checkerboard.js +24 -0
  399. package/dist/web/static/js/editor/clipboard-and-drop.js +133 -0
  400. package/dist/web/static/js/editor/composite-helpers.js +83 -0
  401. package/dist/web/static/js/editor/filters/blur.js +118 -0
  402. package/dist/web/static/js/editor/filters/edge-feather.js +70 -0
  403. package/dist/web/static/js/editor/fx/adj-popup.js +677 -0
  404. package/dist/web/static/js/editor/fx/filter-string.js +38 -0
  405. package/dist/web/static/js/editor/fx/histogram.js +67 -0
  406. package/dist/web/static/js/editor/fx/pixel-pass.js +249 -0
  407. package/dist/web/static/js/editor/harmonize-masks.js +116 -0
  408. package/dist/web/static/js/editor/history-panel.js +176 -0
  409. package/dist/web/static/js/editor/keyboard-shortcuts.js +271 -0
  410. package/dist/web/static/js/editor/layer-helpers.js +131 -0
  411. package/dist/web/static/js/editor/layer-panel.js +600 -0
  412. package/dist/web/static/js/editor/mask-utils.js +91 -0
  413. package/dist/web/static/js/editor/shortcuts-popover.js +149 -0
  414. package/dist/web/static/js/editor/slider-ux.js +191 -0
  415. package/dist/web/static/js/editor/snap.js +107 -0
  416. package/dist/web/static/js/editor/state.js +257 -0
  417. package/dist/web/static/js/editor/stroke-pipeline.js +162 -0
  418. package/dist/web/static/js/editor/stroke-tool-sliders.js +64 -0
  419. package/dist/web/static/js/editor/tools/clone.js +81 -0
  420. package/dist/web/static/js/editor/tools/crop.js +137 -0
  421. package/dist/web/static/js/editor/tools/flood-fill.js +72 -0
  422. package/dist/web/static/js/editor/tools/lasso-mask.js +171 -0
  423. package/dist/web/static/js/editor/tools/lasso.js +65 -0
  424. package/dist/web/static/js/editor/tools/move.js +79 -0
  425. package/dist/web/static/js/editor/tools/stroke.js +123 -0
  426. package/dist/web/static/js/editor/tools/transform-drag.js +174 -0
  427. package/dist/web/static/js/editor/tools/transform-handles.js +271 -0
  428. package/dist/web/static/js/editor/tools/transform-session.js +381 -0
  429. package/dist/web/static/js/editor/tools/wand.js +46 -0
  430. package/dist/web/static/js/editor/wire-import.js +148 -0
  431. package/dist/web/static/js/editor/wire-inpaint-controls.js +164 -0
  432. package/dist/web/static/js/editor/wire-merge-buttons.js +103 -0
  433. package/dist/web/static/js/editor/wire-selection-controls.js +170 -0
  434. package/dist/web/static/js/editor/wire-topbar-menus.js +174 -0
  435. package/dist/web/static/js/editor/wire-topbar-overflow.js +49 -0
  436. package/dist/web/static/js/editor/wire-topbar.js +188 -0
  437. package/dist/web/static/js/emailInbox.js +1245 -0
  438. package/dist/web/static/js/emailLibrary/replyRecipients.js +27 -0
  439. package/dist/web/static/js/emailLibrary/signatureFold.js +339 -0
  440. package/dist/web/static/js/emailLibrary/state.js +34 -0
  441. package/dist/web/static/js/emailLibrary/utils.js +202 -0
  442. package/dist/web/static/js/emailLibrary.js +5217 -0
  443. package/dist/web/static/js/emojiPicker.js +311 -0
  444. package/dist/web/static/js/escMenuStack.js +102 -0
  445. package/dist/web/static/js/fileHandler.js +295 -0
  446. package/dist/web/static/js/gallery.js +2835 -0
  447. package/dist/web/static/js/galleryEditor.js +3798 -0
  448. package/dist/web/static/js/group.js +955 -0
  449. package/dist/web/static/js/init.js +405 -0
  450. package/dist/web/static/js/keyboard-shortcuts.js +292 -0
  451. package/dist/web/static/js/langIcons.js +187 -0
  452. package/dist/web/static/js/markdown/tableRow.js +19 -0
  453. package/dist/web/static/js/markdown.js +806 -0
  454. package/dist/web/static/js/memory.js +1418 -0
  455. package/dist/web/static/js/modalManager.js +1552 -0
  456. package/dist/web/static/js/modalSnap.js +782 -0
  457. package/dist/web/static/js/model/matchKey.js +19 -0
  458. package/dist/web/static/js/modelPicker.js +695 -0
  459. package/dist/web/static/js/modelSort.js +33 -0
  460. package/dist/web/static/js/models.js +642 -0
  461. package/dist/web/static/js/notes.js +5054 -0
  462. package/dist/web/static/js/package.json +1 -0
  463. package/dist/web/static/js/platform.js +47 -0
  464. package/dist/web/static/js/presets.js +1110 -0
  465. package/dist/web/static/js/providers.js +93 -0
  466. package/dist/web/static/js/rag.js +177 -0
  467. package/dist/web/static/js/research/jobs.js +335 -0
  468. package/dist/web/static/js/research/panel.js +1233 -0
  469. package/dist/web/static/js/researchSynapse.js +225 -0
  470. package/dist/web/static/js/search-chat.js +201 -0
  471. package/dist/web/static/js/search.js +52 -0
  472. package/dist/web/static/js/section-management.js +260 -0
  473. package/dist/web/static/js/sessions.js +3108 -0
  474. package/dist/web/static/js/settings.js +4991 -0
  475. package/dist/web/static/js/sidebar-layout.js +573 -0
  476. package/dist/web/static/js/signature.js +504 -0
  477. package/dist/web/static/js/skills.js +1908 -0
  478. package/dist/web/static/js/slashAutocomplete.js +267 -0
  479. package/dist/web/static/js/slashCommands.js +6099 -0
  480. package/dist/web/static/js/spinner.js +406 -0
  481. package/dist/web/static/js/storage.js +123 -0
  482. package/dist/web/static/js/tasks.js +2699 -0
  483. package/dist/web/static/js/theme.js +2086 -0
  484. package/dist/web/static/js/tileManager.js +386 -0
  485. package/dist/web/static/js/tourAutoplay.js +133 -0
  486. package/dist/web/static/js/tourHints.js +179 -0
  487. package/dist/web/static/js/tts-ai.js +521 -0
  488. package/dist/web/static/js/ui.js +1288 -0
  489. package/dist/web/static/js/util/ordinal.js +13 -0
  490. package/dist/web/static/js/voiceRecorder.js +283 -0
  491. package/dist/web/static/js/windowDrag.js +326 -0
  492. package/dist/web/static/js/windowResize.js +233 -0
  493. package/dist/web/static/landing.html +824 -0
  494. package/dist/web/static/lib/docx.umd.min.js +20116 -0
  495. package/dist/web/static/lib/highlight.min.js +1213 -0
  496. package/dist/web/static/lib/html2pdf.bundle.min.js +3 -0
  497. package/dist/web/static/lib/mammoth.browser.min.js +21 -0
  498. package/dist/web/static/lib/qrcode.min.js +8 -0
  499. package/dist/web/static/lib/xlsx.full.min.js +24 -0
  500. package/dist/web/static/login.html +582 -0
  501. package/dist/web/static/manifest.json +15 -0
  502. package/dist/web/static/style.css +35733 -0
  503. package/dist/web/static/sw.js +144 -0
  504. package/dist/workflows/engine.d.ts +162 -0
  505. package/dist/workflows/engine.d.ts.map +1 -0
  506. package/dist/workflows/engine.js +625 -0
  507. package/dist/workflows/engine.js.map +1 -0
  508. package/dist/workflows/index.d.ts +8 -0
  509. package/dist/workflows/index.d.ts.map +1 -0
  510. package/dist/workflows/index.js +14 -0
  511. package/dist/workflows/index.js.map +1 -0
  512. package/package.json +112 -0
@@ -0,0 +1,1489 @@
1
+ /**
2
+ * axoniz/integrations/unified_memory.ts
3
+ * ======================================
4
+ * Merges Hermes MemoryManager + MemPalace palace + axoniz SemanticMemory
5
+ * into one object used directly by axoniz.core.agent.Agent.
6
+ *
7
+ * Port of axoniz/integrations/unified_memory.py
8
+ *
9
+ * ── STORAGE (port decision) ──────────────────────────────────────────────────
10
+ * The Python palace is a ChromaDB vector store provided by the `mempalace`
11
+ * package. Neither `mempalace` nor `chromadb` has an installable npm equivalent
12
+ * on this machine (the chromadb npm install repeatedly failed against the
13
+ * degraded registry), so the palace is backed by a **local SQLite store using
14
+ * Node's built-in `node:sqlite` (`DatabaseSync`)** — zero dependencies, fully
15
+ * local. Verified working on Node v24.21.0 (including recursive CTEs and FTS5).
16
+ *
17
+ * Because there are no embeddings, "semantic" palace search is performed with
18
+ * the already-ported TF-IDF scorer from `src/core/memory.ts`
19
+ * (`tokenize` + `tfidfScore` over the stored documents). This is a genuine
20
+ * capability downgrade vs. ChromaDB embeddings:
21
+ * - ranking is lexical (TF-IDF cosine), not semantic — paraphrases that share
22
+ * no vocabulary are not retrieved, and drawers with zero vocabulary overlap
23
+ * are dropped entirely (a lexical ranker cannot order them);
24
+ * - there is no ANN index, so search is a linear scan over the filtered
25
+ * drawer set (fine for the local-first scale this targets).
26
+ *
27
+ * The seam for a real embedding backend is `registerEmbeddingBackend()`: pass an
28
+ * object with `name` + `embed(texts)` (sync OR async, e.g. a local
29
+ * node-llama-cpp embedding model) and `PalaceLayer.search()` /
30
+ * `PalaceLayer.searchAsync()` will rank by cosine similarity over those vectors
31
+ * instead of TF-IDF. `VectorBackend` keeps the ChromaDB-shaped surface
32
+ * (add/search/delete/status/get), so a Chroma-backed implementation can be
33
+ * dropped in via the `PalaceLayer` constructor's second argument.
34
+ *
35
+ * ── Other degradations ──────────────────────────────────────────────────────
36
+ * - `mempalace.palace_graph` (traverse / find_tunnels / graph_stats) is not in
37
+ * the Python reference tree, so it is re-implemented over the drawer
38
+ * wing/room metadata (see PalaceLayer.traverse_graph for the graph model).
39
+ * - `mempalace.knowledge_graph.KnowledgeGraph` is replaced by
40
+ * `SqliteKnowledgeGraph`, which is the Python `_MinimalKG` fallback plus
41
+ * real `as_of` temporal filtering (the fallback ignored `as_of`, the original
42
+ * mempalace class honoured it). Return shapes are unchanged.
43
+ * - `chromadb`-specific status strings became backend-neutral.
44
+ * - `threading.Thread(daemon=True)` in `prefetch`/`sync_turn` became
45
+ * fire-and-forget async tasks (both are now awaitable and never reject).
46
+ * - `threading.Lock` in `_prefetch_lock` is dropped: the JS event loop is
47
+ * single-threaded and the field is a plain string assignment.
48
+ */
49
+ import fs from "node:fs";
50
+ import path from "node:path";
51
+ import { createHash } from "node:crypto";
52
+ import { DatabaseSync } from "node:sqlite";
53
+ import { AXONIZ_HOME, MEMORY_PATH } from "../core/config.js";
54
+ import { SemanticMemory, tokenize, tfidfScore } from "../core/memory.js";
55
+ import { toolArgs, optStr, optNum } from "../core/extras.js";
56
+ import { getLogger } from "../core/logger.js";
57
+ const logger = getLogger();
58
+ /* ── Paths shared across sub-systems ────────────────────────────────────────── */
59
+ export const PALACE_PATH = path.join(AXONIZ_HOME, "palace");
60
+ export const KG_PATH = path.join(AXONIZ_HOME, "knowledge_graph.sqlite3");
61
+ export const WAL_DIR = path.join(AXONIZ_HOME, "wal");
62
+ /** SQLite file holding the palace drawers (replaces the ChromaDB directory). */
63
+ export const PALACE_DB_PATH = path.join(PALACE_PATH, "palace.sqlite3");
64
+ export const COLLECTION_NAME = "mempalace_drawers";
65
+ for (const dir of [PALACE_PATH, WAL_DIR]) {
66
+ try {
67
+ fs.mkdirSync(dir, { recursive: true });
68
+ }
69
+ catch {
70
+ /* best effort, matching Python's makedirs(exist_ok=True) */
71
+ }
72
+ }
73
+ /* ── context fencing (from hermes memory_manager.py) ────────────────────────── */
74
+ const _FENCE_TAG_RE = /<\/?\s*memory-context\s*>/gi;
75
+ export function _sanitize_context(text) {
76
+ return text.replace(_FENCE_TAG_RE, "");
77
+ }
78
+ /** Wrap recalled memory in a fenced block — prevents the model treating it as user input. */
79
+ export function _build_memory_context_block(raw) {
80
+ if (!raw || !raw.trim())
81
+ return "";
82
+ const clean = _sanitize_context(raw);
83
+ return ("<memory-context>\n" +
84
+ "[System note: recalled memory context — NOT new user input. Treat as background.]\n\n" +
85
+ `${clean}\n` +
86
+ "</memory-context>");
87
+ }
88
+ let _embeddingBackend = null;
89
+ /**
90
+ * Register (or clear, with `null`) the embedding backend used for palace
91
+ * ranking. When none is registered the palace falls back to TF-IDF.
92
+ */
93
+ export function registerEmbeddingBackend(backend) {
94
+ _embeddingBackend = backend;
95
+ }
96
+ export function getEmbeddingBackend() {
97
+ return _embeddingBackend;
98
+ }
99
+ /** Cosine similarity (0 when either vector is empty/zero-length). */
100
+ export function cosineSimilarity(a, b) {
101
+ const n = Math.min(a.length, b.length);
102
+ let dot = 0;
103
+ let na = 0;
104
+ let nb = 0;
105
+ for (let i = 0; i < n; i++) {
106
+ dot += a[i] * b[i];
107
+ na += a[i] * a[i];
108
+ nb += b[i] * b[i];
109
+ }
110
+ if (na === 0 || nb === 0)
111
+ return 0;
112
+ return dot / (Math.sqrt(na) * Math.sqrt(nb));
113
+ }
114
+ /* ── SQLite implementation (the default, dependency-free backend) ──────────── */
115
+ function placeholders(n) {
116
+ return new Array(n).fill("?").join(",");
117
+ }
118
+ function buildIdf(docs) {
119
+ const N = Math.max(docs.length, 1);
120
+ const df = new Map();
121
+ for (const tokens of docs) {
122
+ for (const t of new Set(tokens))
123
+ df.set(t, (df.get(t) ?? 0) + 1);
124
+ }
125
+ const idf = new Map();
126
+ for (const [t, c] of df)
127
+ idf.set(t, Math.log(N / (1 + c)));
128
+ return idf;
129
+ }
130
+ /** TF-IDF weight map matching `tfidfScore`'s tf = count/total convention. */
131
+ function tfidfVector(tokens, idf) {
132
+ const vec = new Map();
133
+ if (tokens.length === 0)
134
+ return vec;
135
+ const tf = new Map();
136
+ for (const t of tokens)
137
+ tf.set(t, (tf.get(t) ?? 0) + 1);
138
+ for (const [t, c] of tf)
139
+ vec.set(t, (c / tokens.length) * (idf.get(t) ?? Math.log(10)));
140
+ return vec;
141
+ }
142
+ function cosineMaps(a, b) {
143
+ if (a.size === 0 || b.size === 0)
144
+ return 0;
145
+ const [small, large] = a.size <= b.size ? [a, b] : [b, a];
146
+ let dot = 0;
147
+ for (const [t, w] of small) {
148
+ const other = large.get(t);
149
+ if (other !== undefined)
150
+ dot += w * other;
151
+ }
152
+ let na = 0;
153
+ for (const w of a.values())
154
+ na += w * w;
155
+ let nb = 0;
156
+ for (const w of b.values())
157
+ nb += w * w;
158
+ if (na === 0 || nb === 0)
159
+ return 0;
160
+ return dot / (Math.sqrt(na) * Math.sqrt(nb));
161
+ }
162
+ export function round3(x) {
163
+ return Math.round(x * 1000) / 1000;
164
+ }
165
+ /**
166
+ * Drawer store on `node:sqlite`. Documents + wing/room metadata live in a plain
167
+ * table; similarity is TF-IDF (see the module header) unless an embedding
168
+ * backend is registered.
169
+ */
170
+ export class SqliteVectorBackend {
171
+ name = "sqlite-tfidf";
172
+ dbPath;
173
+ db = null;
174
+ openError = null;
175
+ constructor(dbPath = PALACE_DB_PATH) {
176
+ this.dbPath = dbPath;
177
+ try {
178
+ fs.mkdirSync(path.dirname(dbPath), { recursive: true });
179
+ const db = new DatabaseSync(dbPath);
180
+ db.exec("PRAGMA journal_mode=WAL");
181
+ db.exec(`CREATE TABLE IF NOT EXISTS drawers (
182
+ id TEXT PRIMARY KEY,
183
+ document TEXT NOT NULL,
184
+ wing TEXT,
185
+ room TEXT,
186
+ added_by TEXT,
187
+ filed_at TEXT
188
+ )`);
189
+ db.exec("CREATE INDEX IF NOT EXISTS idx_drawers_wing ON drawers(wing)");
190
+ db.exec("CREATE INDEX IF NOT EXISTS idx_drawers_room ON drawers(room)");
191
+ this.db = db;
192
+ }
193
+ catch (e) {
194
+ this.openError = e instanceof Error ? e.message : String(e);
195
+ this.db = null;
196
+ }
197
+ }
198
+ get available() {
199
+ return this.db !== null;
200
+ }
201
+ rowToRecord(row) {
202
+ return {
203
+ id: String(row["id"] ?? ""),
204
+ document: String(row["document"] ?? ""),
205
+ metadata: {
206
+ wing: String(row["wing"] ?? "unknown"),
207
+ room: String(row["room"] ?? "unknown"),
208
+ added_by: String(row["added_by"] ?? ""),
209
+ filed_at: String(row["filed_at"] ?? ""),
210
+ },
211
+ };
212
+ }
213
+ add(records) {
214
+ const db = this.db;
215
+ if (!db || records.length === 0)
216
+ return;
217
+ const stmt = db.prepare(`INSERT INTO drawers (id, document, wing, room, added_by, filed_at)
218
+ VALUES (?, ?, ?, ?, ?, ?)
219
+ ON CONFLICT(id) DO UPDATE SET
220
+ document = excluded.document,
221
+ wing = excluded.wing,
222
+ room = excluded.room,
223
+ added_by = excluded.added_by,
224
+ filed_at = excluded.filed_at`);
225
+ for (const rec of records) {
226
+ stmt.run(rec.id, rec.document, String(rec.metadata["wing"] ?? "unknown"), String(rec.metadata["room"] ?? "unknown"), String(rec.metadata["added_by"] ?? ""), String(rec.metadata["filed_at"] ?? ""));
227
+ }
228
+ }
229
+ get(ids, filter) {
230
+ const db = this.db;
231
+ if (!db)
232
+ return [];
233
+ const where = [];
234
+ const params = [];
235
+ if (ids && ids.length > 0) {
236
+ where.push(`id IN (${placeholders(ids.length)})`);
237
+ params.push(...ids);
238
+ }
239
+ if (filter?.wing) {
240
+ where.push("wing = ?");
241
+ params.push(filter.wing);
242
+ }
243
+ if (filter?.room) {
244
+ where.push("room = ?");
245
+ params.push(filter.room);
246
+ }
247
+ const sql = `SELECT id, document, wing, room, added_by, filed_at FROM drawers${where.length > 0 ? ` WHERE ${where.join(" AND ")}` : ""}`;
248
+ const rows = db.prepare(sql).all(...params);
249
+ return rows.map((r) => this.rowToRecord(r));
250
+ }
251
+ delete(ids) {
252
+ const db = this.db;
253
+ if (!db || ids.length === 0)
254
+ return 0;
255
+ const stmt = db.prepare(`DELETE FROM drawers WHERE id IN (${placeholders(ids.length)})`);
256
+ const res = stmt.run(...ids);
257
+ return Number(res.changes ?? 0);
258
+ }
259
+ count(filter) {
260
+ const db = this.db;
261
+ if (!db)
262
+ return 0;
263
+ const where = [];
264
+ const params = [];
265
+ if (filter?.wing) {
266
+ where.push("wing = ?");
267
+ params.push(filter.wing);
268
+ }
269
+ if (filter?.room) {
270
+ where.push("room = ?");
271
+ params.push(filter.room);
272
+ }
273
+ const sql = `SELECT COUNT(*) AS n FROM drawers${where.length > 0 ? ` WHERE ${where.join(" AND ")}` : ""}`;
274
+ const row = db.prepare(sql).get(...params);
275
+ return Number(row?.["n"] ?? 0);
276
+ }
277
+ /**
278
+ * TF-IDF ranked search over the filtered drawer set.
279
+ * `similarity` is TF-IDF cosine in [0,1]; `distance` is 1 - similarity.
280
+ *
281
+ * Lexical ranker caveat: a drawer that shares no vocabulary with the query
282
+ * scores 0 and is dropped (a lexical ranker cannot order it, and returning it
283
+ * would put unrelated text in the context block). ChromaDB embeddings would
284
+ * still return such drawers at a high distance.
285
+ */
286
+ search(query, options = {}) {
287
+ const limit = options.limit ?? 5;
288
+ const maxDistance = options.maxDistance ?? 1.5;
289
+ const candidates = this.get(null, { wing: options.wing ?? null, room: options.room ?? null });
290
+ if (candidates.length === 0)
291
+ return [];
292
+ const qTokens = tokenize(query);
293
+ const docTokens = candidates.map((c) => tokenize(c.document));
294
+ const idf = buildIdf(docTokens);
295
+ const qVec = tfidfVector(qTokens, idf);
296
+ const hits = [];
297
+ for (let i = 0; i < candidates.length; i++) {
298
+ const tokens = docTokens[i];
299
+ const score = tfidfScore(qTokens, tokens, idf);
300
+ if (score <= 0)
301
+ continue; // no shared vocabulary — not retrievable lexically
302
+ const similarity = round3(cosineMaps(qVec, tfidfVector(tokens, idf)));
303
+ const distance = round3(1 - similarity);
304
+ if (distance > maxDistance)
305
+ continue;
306
+ hits.push({
307
+ id: candidates[i].id,
308
+ document: candidates[i].document,
309
+ metadata: candidates[i].metadata,
310
+ distance,
311
+ similarity,
312
+ score,
313
+ });
314
+ }
315
+ hits.sort((a, b) => b.score - a.score || b.similarity - a.similarity);
316
+ return hits.slice(0, limit);
317
+ }
318
+ status() {
319
+ if (!this.db) {
320
+ return { backend: this.name, total: 0, available: false, error: this.openError ?? "SQLite palace unavailable" };
321
+ }
322
+ try {
323
+ return { backend: this.name, total: this.count(), available: true };
324
+ }
325
+ catch (e) {
326
+ return { backend: this.name, total: 0, available: false, error: errMsg(e) };
327
+ }
328
+ }
329
+ close() {
330
+ try {
331
+ this.db?.close();
332
+ }
333
+ catch {
334
+ /* ignore */
335
+ }
336
+ this.db = null;
337
+ }
338
+ }
339
+ function errMsg(e) {
340
+ return e instanceof Error ? e.message : String(e);
341
+ }
342
+ export class PalaceLayer {
343
+ palace_path;
344
+ backend;
345
+ _available = null;
346
+ _wal;
347
+ /** ChromaDB-shaped compat shim — `agent.marshal_scan()` calls `_db.get()`. */
348
+ _db;
349
+ constructor(palacePath = PALACE_PATH, backend) {
350
+ this.palace_path = palacePath;
351
+ this.backend = backend ?? new SqliteVectorBackend(path.join(palacePath, "palace.sqlite3"));
352
+ this._wal = path.join(WAL_DIR, "palace_writes.jsonl");
353
+ try {
354
+ if (!fs.existsSync(this._wal)) {
355
+ fs.writeFileSync(this._wal, "", { encoding: "utf-8", mode: 0o600 });
356
+ }
357
+ }
358
+ catch {
359
+ /* best effort */
360
+ }
361
+ this._db = {
362
+ get: (ids) => {
363
+ const records = this.backend.get(ids ?? null);
364
+ return {
365
+ ids: records.map((r) => r.id),
366
+ documents: records.map((r) => r.document),
367
+ metadatas: records.map((r) => r.metadata),
368
+ };
369
+ },
370
+ };
371
+ }
372
+ is_available() {
373
+ if (this._available === null) {
374
+ this._available = this.backend.status().available;
375
+ if (!this._available) {
376
+ logger.warning("[Palace] local SQLite palace backend unavailable — palace disabled. " +
377
+ "Check write access to " +
378
+ this.palace_path);
379
+ }
380
+ }
381
+ return this._available;
382
+ }
383
+ /** Backend-neutral reason string used by search()/store() when disabled. */
384
+ _unavailableReason() {
385
+ return this.backend.status().error ?? "Palace backend unavailable";
386
+ }
387
+ /** Compat shim for the removed ChromaDB collection handle. */
388
+ _get_col(create = true) {
389
+ void create;
390
+ if (!this.is_available())
391
+ return null;
392
+ return this.backend;
393
+ }
394
+ _wal_log(op, info) {
395
+ const entry = { ts: new Date().toISOString(), op, ...info };
396
+ try {
397
+ fs.appendFileSync(this._wal, `${JSON.stringify(entry)}\n`, "utf-8");
398
+ }
399
+ catch {
400
+ /* best effort */
401
+ }
402
+ }
403
+ search(query, wingOrOptions, room, limit = 5, maxDistance = 1.5) {
404
+ let wing = null;
405
+ let rm = room ?? null;
406
+ let lim = limit;
407
+ let maxD = maxDistance;
408
+ if (wingOrOptions !== null && typeof wingOrOptions === "object") {
409
+ const o = wingOrOptions;
410
+ wing = o.wing ?? null;
411
+ rm = o.room ?? null;
412
+ lim = o.limit ?? o.top_k ?? 5;
413
+ maxD = o.max_distance ?? o.maxDistance ?? 1.5;
414
+ }
415
+ else {
416
+ wing = wingOrOptions ?? null;
417
+ }
418
+ if (!this.is_available()) {
419
+ return { results: [], error: this._unavailableReason() };
420
+ }
421
+ try {
422
+ const hits = this.backend.search(query, { wing, room: rm, limit: lim, maxDistance: maxD });
423
+ return {
424
+ results: hits.map((h) => ({
425
+ id: h.id,
426
+ text: h.document,
427
+ wing: String(h.metadata["wing"] ?? "unknown"),
428
+ room: String(h.metadata["room"] ?? "unknown"),
429
+ distance: h.distance,
430
+ similarity: h.similarity,
431
+ metadata: h.metadata,
432
+ })),
433
+ };
434
+ }
435
+ catch (e) {
436
+ return { results: [], error: errMsg(e) };
437
+ }
438
+ }
439
+ /**
440
+ * Additive async search: uses the registered embedding backend (awaiting it)
441
+ * when present, otherwise behaves exactly like `search()`.
442
+ */
443
+ async searchAsync(query, options = {}) {
444
+ const backend = getEmbeddingBackend();
445
+ if (!backend || !this.is_available()) {
446
+ return this.search(query, options);
447
+ }
448
+ try {
449
+ const lim = options.limit ?? options.top_k ?? 5;
450
+ const maxD = options.max_distance ?? options.maxDistance ?? 1.5;
451
+ const candidates = this.backend.get(null, { wing: options.wing ?? null, room: options.room ?? null });
452
+ if (candidates.length === 0)
453
+ return { results: [] };
454
+ const [qVec] = await Promise.resolve(backend.embed([query]));
455
+ const docVecs = await Promise.resolve(backend.embed(candidates.map((c) => c.document)));
456
+ const sim = backend.similarity ?? cosineSimilarity;
457
+ const results = [];
458
+ for (let i = 0; i < candidates.length; i++) {
459
+ const similarity = round3(sim(qVec ?? [], docVecs[i] ?? []));
460
+ const distance = round3(1 - similarity);
461
+ if (distance > maxD)
462
+ continue;
463
+ results.push({
464
+ id: candidates[i].id,
465
+ text: candidates[i].document,
466
+ wing: String(candidates[i].metadata["wing"] ?? "unknown"),
467
+ room: String(candidates[i].metadata["room"] ?? "unknown"),
468
+ distance,
469
+ similarity,
470
+ metadata: candidates[i].metadata,
471
+ });
472
+ }
473
+ results.sort((a, b) => b.similarity - a.similarity);
474
+ return { results: results.slice(0, lim) };
475
+ }
476
+ catch (e) {
477
+ return { results: [], error: errMsg(e) };
478
+ }
479
+ }
480
+ status() {
481
+ const st = this.backend.status();
482
+ if (!st.available) {
483
+ return { error: st.error ?? "Palace backend unavailable", total_drawers: 0, wings: {} };
484
+ }
485
+ try {
486
+ const count = st.total;
487
+ const wings = {};
488
+ if (count > 0) {
489
+ for (const rec of this.backend.get()) {
490
+ const w = String(rec.metadata["wing"] ?? "unknown");
491
+ wings[w] = (wings[w] ?? 0) + 1;
492
+ }
493
+ }
494
+ return {
495
+ total_drawers: count,
496
+ wings,
497
+ palace_path: this.palace_path,
498
+ backend: this.backend.name,
499
+ };
500
+ }
501
+ catch (e) {
502
+ return { error: errMsg(e), total_drawers: 0, wings: {} };
503
+ }
504
+ }
505
+ list_wings() {
506
+ const st = this.status();
507
+ return { wings: st.wings ?? {} };
508
+ }
509
+ list_rooms(wing) {
510
+ if (!this.is_available()) {
511
+ return { wing: wing ?? "all", rooms: {} };
512
+ }
513
+ try {
514
+ const records = this.backend.get(null, { wing: wing ?? null });
515
+ const rooms = {};
516
+ for (const rec of records) {
517
+ const r = String(rec.metadata["room"] ?? "unknown");
518
+ rooms[r] = (rooms[r] ?? 0) + 1;
519
+ }
520
+ return { wing: wing ?? "all", rooms };
521
+ }
522
+ catch (e) {
523
+ return { rooms: {}, error: errMsg(e) };
524
+ }
525
+ }
526
+ get_context() {
527
+ const st = this.status();
528
+ if (st.error !== undefined && st.total_drawers === 0) {
529
+ return "";
530
+ }
531
+ const wingStr = Object.entries(st.wings ?? {})
532
+ .slice(0, 6)
533
+ .map(([w, c]) => `${w}(${c})`)
534
+ .join(", ");
535
+ return `Palace: ${st.total_drawers} drawers | Wings: ${wingStr}`;
536
+ }
537
+ /* ── Graph helpers ──────────────────────────────────────────────────────── */
538
+ _roomCounts() {
539
+ const byWing = new Map();
540
+ const byRoom = new Map();
541
+ for (const rec of this.backend.get()) {
542
+ const w = String(rec.metadata["wing"] ?? "unknown");
543
+ const r = String(rec.metadata["room"] ?? "unknown");
544
+ if (!byWing.has(w))
545
+ byWing.set(w, new Map());
546
+ byWing.get(w).set(r, (byWing.get(w).get(r) ?? 0) + 1);
547
+ if (!byRoom.has(r))
548
+ byRoom.set(r, new Map());
549
+ byRoom.get(r).set(w, (byRoom.get(r).get(w) ?? 0) + 1);
550
+ }
551
+ return { byWing, byRoom };
552
+ }
553
+ /**
554
+ * Walk the palace graph from a room.
555
+ *
556
+ * Graph model (re-implementation — `mempalace.palace_graph` is not part of the
557
+ * Python reference tree): a node is a (wing, room) pair. Two nodes are linked
558
+ * when they live in the same wing ("wing" edges), and a room that exists in
559
+ * more than one wing links those copies ("tunnel" edges). BFS is capped at
560
+ * `max_hops` hops and at `MAX_TRAVERSE_NODES` visited nodes.
561
+ */
562
+ traverse_graph(startRoom, maxHops = 2) {
563
+ if (!this.is_available()) {
564
+ return { error: "Palace unavailable" };
565
+ }
566
+ try {
567
+ const { byWing, byRoom } = this._roomCounts();
568
+ const MAX_TRAVERSE_NODES = 200;
569
+ const key = (w, r) => `${w}\u0000${r}`;
570
+ const visited = new Map();
571
+ const edges = [];
572
+ const startWings = [...(byRoom.get(startRoom)?.keys() ?? [])];
573
+ if (startWings.length === 0) {
574
+ return { start_room: startRoom, max_hops: maxHops, nodes: [], edges: [], error: "room not found" };
575
+ }
576
+ let frontier = [];
577
+ for (const w of startWings) {
578
+ const k = key(w, startRoom);
579
+ visited.set(k, { wing: w, room: startRoom, depth: 0, drawers: byWing.get(w)?.get(startRoom) ?? 0 });
580
+ frontier.push([w, startRoom]);
581
+ }
582
+ for (let depth = 1; depth <= maxHops && frontier.length > 0; depth++) {
583
+ const next = [];
584
+ for (const [w, r] of frontier) {
585
+ // Tunnel: same room name in another wing.
586
+ for (const w2 of byRoom.get(r)?.keys() ?? []) {
587
+ if (w2 === w)
588
+ continue;
589
+ const k = key(w2, r);
590
+ if (!visited.has(k)) {
591
+ if (visited.size >= MAX_TRAVERSE_NODES)
592
+ break;
593
+ visited.set(k, { wing: w2, room: r, depth, drawers: byWing.get(w2)?.get(r) ?? 0 });
594
+ next.push([w2, r]);
595
+ }
596
+ edges.push({ from: [w, r], to: [w2, r], kind: "tunnel" });
597
+ }
598
+ // Wing: sibling rooms in the same wing.
599
+ for (const r2 of byWing.get(w)?.keys() ?? []) {
600
+ if (r2 === r)
601
+ continue;
602
+ const k = key(w, r2);
603
+ if (!visited.has(k)) {
604
+ if (visited.size >= MAX_TRAVERSE_NODES)
605
+ break;
606
+ visited.set(k, { wing: w, room: r2, depth, drawers: byWing.get(w)?.get(r2) ?? 0 });
607
+ next.push([w, r2]);
608
+ }
609
+ edges.push({ from: [w, r], to: [w, r2], kind: "wing" });
610
+ }
611
+ }
612
+ frontier = next;
613
+ }
614
+ const nodes = [...visited.values()].sort((a, b) => a.depth - b.depth || a.wing.localeCompare(b.wing) || a.room.localeCompare(b.room));
615
+ return { start_room: startRoom, max_hops: maxHops, nodes, edges };
616
+ }
617
+ catch (e) {
618
+ return { error: errMsg(e) };
619
+ }
620
+ }
621
+ /** Rooms that bridge two wings (or every room present in >1 wing). */
622
+ find_tunnels(wingA, wingB) {
623
+ if (!this.is_available()) {
624
+ return { error: "Palace unavailable" };
625
+ }
626
+ try {
627
+ const { byRoom } = this._roomCounts();
628
+ const tunnels = [];
629
+ for (const [room, wings] of byRoom) {
630
+ if (wingA && !wings.has(wingA))
631
+ continue;
632
+ if (wingB && !wings.has(wingB))
633
+ continue;
634
+ if (wings.size < 2)
635
+ continue;
636
+ let drawers = 0;
637
+ for (const c of wings.values())
638
+ drawers += c;
639
+ tunnels.push({ room, wings: [...wings.keys()], wings_count: wings.size, drawers });
640
+ }
641
+ tunnels.sort((a, b) => b.wings_count - a.wings_count || b.drawers - a.drawers || a.room.localeCompare(b.room));
642
+ return {
643
+ wing_a: wingA ?? null,
644
+ wing_b: wingB ?? null,
645
+ tunnels: tunnels.slice(0, 50),
646
+ count: tunnels.length,
647
+ };
648
+ }
649
+ catch (e) {
650
+ return { error: errMsg(e) };
651
+ }
652
+ }
653
+ /** Palace graph overview: rooms, wings, intra-wing edges, tunnels. */
654
+ graph_stats() {
655
+ if (!this.is_available()) {
656
+ return { error: "Palace unavailable" };
657
+ }
658
+ try {
659
+ const { byWing, byRoom } = this._roomCounts();
660
+ let edges = 0;
661
+ for (const rooms of byWing.values()) {
662
+ const n = rooms.size;
663
+ if (n > 1)
664
+ edges += (n * (n - 1)) / 2;
665
+ }
666
+ let tunnels = 0;
667
+ for (const wings of byRoom.values()) {
668
+ if (wings.size >= 2)
669
+ tunnels += 1;
670
+ }
671
+ return {
672
+ rooms: byRoom.size,
673
+ wings: byWing.size,
674
+ nodes: [...byWing.values()].reduce((acc, m) => acc + m.size, 0),
675
+ edges,
676
+ tunnels,
677
+ total_drawers: this.backend.count(),
678
+ };
679
+ }
680
+ catch (e) {
681
+ return { error: errMsg(e) };
682
+ }
683
+ }
684
+ /**
685
+ * Duplicate check. ChromaDB reported `similarity = 1 - distance`; the SQLite
686
+ * backend reports TF-IDF cosine directly, so `similarity` is comparable —
687
+ * but lexical rather than semantic (see the module header).
688
+ */
689
+ check_duplicate(content, threshold = 0.9) {
690
+ if (!this.is_available()) {
691
+ return { is_duplicate: false };
692
+ }
693
+ try {
694
+ const hits = this.backend.search(content, { limit: 3 });
695
+ const dups = [];
696
+ for (const h of hits) {
697
+ const sim = round3(h.similarity);
698
+ if (sim >= threshold) {
699
+ dups.push({ id: h.id, similarity: sim, content: h.document.slice(0, 200) });
700
+ }
701
+ }
702
+ return { is_duplicate: dups.length > 0, matches: dups };
703
+ }
704
+ catch (e) {
705
+ return { is_duplicate: false, error: errMsg(e) };
706
+ }
707
+ }
708
+ store(wingOrOptions, room, content, addedBy = "axoniz") {
709
+ let wing;
710
+ let rm;
711
+ let body;
712
+ let by = addedBy;
713
+ if (wingOrOptions !== null && typeof wingOrOptions === "object") {
714
+ wing = wingOrOptions.wing;
715
+ rm = wingOrOptions.room;
716
+ body = wingOrOptions.content;
717
+ by = wingOrOptions.added_by ?? wingOrOptions.addedBy ?? addedBy;
718
+ }
719
+ else {
720
+ wing = wingOrOptions;
721
+ rm = room ?? "";
722
+ body = content ?? "";
723
+ }
724
+ if (!this.is_available()) {
725
+ return { success: false, error: this._unavailableReason() };
726
+ }
727
+ const w = wing.toLowerCase().replace(/[^a-z0-9_-]/g, "-").slice(0, 40);
728
+ const r = rm.toLowerCase().replace(/[^a-z0-9_-]/g, "-").slice(0, 40);
729
+ const digest = createHash("sha256").update(`${w}${r}${body.slice(0, 100)}`).digest("hex").slice(0, 20);
730
+ const drawerId = `drawer_${w}_${r}_${digest}`;
731
+ this._wal_log("store", { wing: w, room: r, id: drawerId, added_by: by });
732
+ try {
733
+ if (this.backend.get([drawerId]).length > 0) {
734
+ return { success: true, reason: "already_exists", id: drawerId };
735
+ }
736
+ }
737
+ catch {
738
+ /* ignore lookup failure and try the upsert, as Python does */
739
+ }
740
+ try {
741
+ this.backend.add([
742
+ {
743
+ id: drawerId,
744
+ document: body,
745
+ metadata: { wing: w, room: r, added_by: by, filed_at: new Date().toISOString() },
746
+ },
747
+ ]);
748
+ return { success: true, id: drawerId, wing: w, room: r };
749
+ }
750
+ catch (e) {
751
+ return { success: false, error: errMsg(e) };
752
+ }
753
+ }
754
+ delete(drawerId) {
755
+ if (!this.is_available()) {
756
+ return { success: false, error: "Palace unavailable" };
757
+ }
758
+ try {
759
+ this._wal_log("delete", { id: drawerId });
760
+ this.backend.delete([drawerId]);
761
+ return { success: true, id: drawerId };
762
+ }
763
+ catch (e) {
764
+ return { success: false, error: errMsg(e) };
765
+ }
766
+ }
767
+ /** camelCase aliases (additive). */
768
+ isAvailable() {
769
+ return this.is_available();
770
+ }
771
+ listWings() {
772
+ return this.list_wings();
773
+ }
774
+ listRooms(wing) {
775
+ return this.list_rooms(wing);
776
+ }
777
+ getContext() {
778
+ return this.get_context();
779
+ }
780
+ traverseGraph(startRoom, maxHops = 2) {
781
+ return this.traverse_graph(startRoom, maxHops);
782
+ }
783
+ findTunnels(wingA, wingB) {
784
+ return this.find_tunnels(wingA, wingB);
785
+ }
786
+ graphStats() {
787
+ return this.graph_stats();
788
+ }
789
+ checkDuplicate(content, threshold = 0.9) {
790
+ return this.check_duplicate(content, threshold);
791
+ }
792
+ }
793
+ /**
794
+ * SQLite temporal knowledge graph — this is the Python `_MinimalKG` schema and
795
+ * SQL, promoted to the only implementation because the mempalace
796
+ * `KnowledgeGraph` source is not in the reference tree.
797
+ * `as_of` filtering is honoured (documented deviation from `_MinimalKG`, which
798
+ * accepted but ignored it; the real mempalace class honoured it).
799
+ */
800
+ export class SqliteKnowledgeGraph {
801
+ db_path;
802
+ _conn;
803
+ constructor(dbPath = KG_PATH) {
804
+ this.db_path = dbPath;
805
+ fs.mkdirSync(path.dirname(dbPath), { recursive: true });
806
+ this._conn = new DatabaseSync(dbPath);
807
+ this._conn.exec("PRAGMA journal_mode=WAL");
808
+ this._conn.exec(`CREATE TABLE IF NOT EXISTS triples (
809
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
810
+ subject TEXT, predicate TEXT, object TEXT,
811
+ valid_from TEXT, valid_until TEXT, source TEXT,
812
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP
813
+ )`);
814
+ this._conn.exec("CREATE INDEX IF NOT EXISTS idx_s ON triples(subject)");
815
+ }
816
+ add_triple(subject, predicate, obj, validFrom = null, sourceCloset = null) {
817
+ const res = this._conn
818
+ .prepare("INSERT INTO triples(subject,predicate,object,valid_from,source) VALUES(?,?,?,?,?)")
819
+ .run(subject, predicate, obj, validFrom, sourceCloset);
820
+ return String(res.lastInsertRowid);
821
+ }
822
+ query_entity(name, asOf = null, direction = "both") {
823
+ const rows = [];
824
+ const temporal = asOf
825
+ ? " AND (valid_from IS NULL OR valid_from <= ?) AND (valid_until IS NULL OR valid_until > ?)"
826
+ : "";
827
+ const sqlFor = (column) => `SELECT subject, predicate, object, valid_from, valid_until,
828
+ CASE WHEN valid_until IS NULL THEN 1 ELSE 0 END AS current
829
+ FROM triples WHERE ${column} = ?${temporal}`;
830
+ if (direction === "outgoing" || direction === "both") {
831
+ const params = [name];
832
+ if (asOf)
833
+ params.push(asOf, asOf);
834
+ rows.push(...this._conn.prepare(sqlFor("subject")).all(...params).map(normalizeTriple));
835
+ }
836
+ if (direction === "incoming" || direction === "both") {
837
+ const params = [name];
838
+ if (asOf)
839
+ params.push(asOf, asOf);
840
+ rows.push(...this._conn.prepare(sqlFor("object")).all(...params).map(normalizeTriple));
841
+ }
842
+ return rows;
843
+ }
844
+ invalidate(subject, predicate, obj, ended = null) {
845
+ const end = ended ?? formatDate(new Date());
846
+ this._conn
847
+ .prepare("UPDATE triples SET valid_until=? WHERE subject=? AND predicate=? AND object=? AND valid_until IS NULL")
848
+ .run(end, subject, predicate, obj);
849
+ }
850
+ timeline(entityName = null) {
851
+ const sql = "SELECT subject,predicate,object,valid_from,valid_until FROM triples" +
852
+ (entityName ? " WHERE subject=? OR object=?" : "") +
853
+ " ORDER BY created_at";
854
+ const rows = (entityName
855
+ ? this._conn.prepare(sql).all(entityName, entityName)
856
+ : this._conn.prepare(sql).all());
857
+ return rows.map((r) => ({
858
+ subject: String(r["subject"] ?? ""),
859
+ predicate: String(r["predicate"] ?? ""),
860
+ object: String(r["object"] ?? ""),
861
+ valid_from: r["valid_from"] === null || r["valid_from"] === undefined ? null : String(r["valid_from"]),
862
+ valid_to: r["valid_until"] === null || r["valid_until"] === undefined ? null : String(r["valid_until"]),
863
+ }));
864
+ }
865
+ stats() {
866
+ const total = Number(this._conn.prepare("SELECT COUNT(*) AS n FROM triples").get()["n"] ?? 0);
867
+ const active = Number(this._conn.prepare("SELECT COUNT(*) AS n FROM triples WHERE valid_until IS NULL").get()["n"] ?? 0);
868
+ return { total_triples: total, active_triples: active };
869
+ }
870
+ close() {
871
+ try {
872
+ this._conn.close();
873
+ }
874
+ catch {
875
+ /* ignore */
876
+ }
877
+ }
878
+ }
879
+ function normalizeTriple(row) {
880
+ const r = row;
881
+ return {
882
+ subject: String(r["subject"] ?? ""),
883
+ predicate: String(r["predicate"] ?? ""),
884
+ object: String(r["object"] ?? ""),
885
+ valid_from: r["valid_from"] === null || r["valid_from"] === undefined ? null : String(r["valid_from"]),
886
+ valid_to: r["valid_until"] === null || r["valid_until"] === undefined ? null : String(r["valid_until"]),
887
+ current: Number(r["current"] ?? 0),
888
+ };
889
+ }
890
+ /** `datetime.now().strftime("%Y-%m-%d")` in local time. */
891
+ export function formatDate(d) {
892
+ const p = (x) => String(x).padStart(2, "0");
893
+ return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
894
+ }
895
+ /**
896
+ * Wraps the temporal knowledge graph stored at AXONIZ_HOME.
897
+ * Keeps the Python method names/return shapes (`add`, `query`, `invalidate`,
898
+ * `timeline`, `stats`); the tuple-style keyword arguments are also accepted as
899
+ * an options object.
900
+ */
901
+ export class KnowledgeGraphLayer {
902
+ _kg_path;
903
+ _kg = null;
904
+ constructor(kgPath = KG_PATH) {
905
+ this._kg_path = kgPath;
906
+ }
907
+ _get() {
908
+ if (this._kg === null) {
909
+ this._kg = new SqliteKnowledgeGraph(this._kg_path);
910
+ }
911
+ return this._kg;
912
+ }
913
+ add(subject, predicate, obj, validFromOrOptions, source) {
914
+ let validFrom = null;
915
+ let src = null;
916
+ if (validFromOrOptions !== null && typeof validFromOrOptions === "object") {
917
+ validFrom = validFromOrOptions.valid_from ?? null;
918
+ src = validFromOrOptions.source ?? null;
919
+ }
920
+ else {
921
+ validFrom = validFromOrOptions ?? null;
922
+ src = source ?? null;
923
+ }
924
+ try {
925
+ return this._get().add_triple(subject, predicate, obj, validFrom, src);
926
+ }
927
+ catch (e) {
928
+ return `[KG error] ${errMsg(e)}`;
929
+ }
930
+ }
931
+ query(entity, asOfOrOptions, direction = "both") {
932
+ let asOf = null;
933
+ let dir = direction;
934
+ if (asOfOrOptions !== null && typeof asOfOrOptions === "object") {
935
+ asOf = asOfOrOptions.as_of ?? null;
936
+ dir = asOfOrOptions.direction ?? "both";
937
+ }
938
+ else {
939
+ asOf = asOfOrOptions ?? null;
940
+ }
941
+ try {
942
+ return this._get().query_entity(entity, asOf, dir);
943
+ }
944
+ catch (e) {
945
+ return [{ error: errMsg(e) }];
946
+ }
947
+ }
948
+ invalidate(subject, predicate, obj, ended) {
949
+ const end = ended !== null && typeof ended === "object" ? (ended.ended ?? null) : (ended ?? null);
950
+ try {
951
+ this._get().invalidate(subject, predicate, obj, end);
952
+ }
953
+ catch {
954
+ /* Python swallows invalidate errors */
955
+ }
956
+ }
957
+ timeline(entity) {
958
+ const name = entity !== null && typeof entity === "object" ? (entity.entity ?? null) : (entity ?? null);
959
+ try {
960
+ return this._get().timeline(name);
961
+ }
962
+ catch (e) {
963
+ return [{ error: errMsg(e) }];
964
+ }
965
+ }
966
+ stats() {
967
+ try {
968
+ return this._get().stats();
969
+ }
970
+ catch (e) {
971
+ return { error: errMsg(e) };
972
+ }
973
+ }
974
+ close() {
975
+ try {
976
+ this._kg?.close();
977
+ }
978
+ catch {
979
+ /* ignore */
980
+ }
981
+ this._kg = null;
982
+ }
983
+ }
984
+ /* ════════════════════════════════════════════════════════════════════════════
985
+ * AgentDiary — AAAK diary stored in the palace
986
+ * ════════════════════════════════════════════════════════════════════════════ */
987
+ /**
988
+ * The agent's personal journal, stored in the palace.
989
+ * Each agent gets wing_<name>/diary, with AAAK-compressed entries.
990
+ */
991
+ export class AgentDiary {
992
+ static AAAK_SPEC = "AAAK: compressed memory dialect. " +
993
+ "ENTITIES: 3-letter codes. EMOTIONS: *warm* *fierce* *raw* *bloom*. " +
994
+ "STRUCTURE: SESSION:DATE|TOPIC:tag|entry. ★ to ★★★★★. " +
995
+ "HALLS: hall_facts hall_events hall_decisions hall_diary. " +
996
+ "WINGS: wing_user wing_agent wing_code wing_project. " +
997
+ "ROOMS: hyphenated-slugs.";
998
+ palace;
999
+ agent_name;
1000
+ _wing;
1001
+ _room = "diary";
1002
+ constructor(palace, agentName = "axoniz-zero") {
1003
+ this.palace = palace;
1004
+ this.agent_name = agentName.toLowerCase().replace(/[^a-z0-9_]/g, "_");
1005
+ this._wing = `wing_${this.agent_name}`;
1006
+ }
1007
+ write(entry, topic = "general") {
1008
+ const now = formatDate(new Date());
1009
+ const content = `SESSION:${now}|TOPIC:${topic}|${entry}`;
1010
+ return this.palace.store(this._wing, this._room, content, this.agent_name);
1011
+ }
1012
+ read(lastN = 10) {
1013
+ return this.palace.search("SESSION TOPIC diary", this._wing, this._room, lastN);
1014
+ }
1015
+ }
1016
+ /**
1017
+ * Drop-in replacement for `axoniz.core.memory.SemanticMemory` used by Agent.
1018
+ *
1019
+ * Combines:
1020
+ * 1. SemanticMemory — TF-IDF, always-on, no deps (from src/core/memory.ts)
1021
+ * 2. PalaceLayer — local SQLite palace (wings/rooms/drawers)
1022
+ * 3. KnowledgeGraphLayer — temporal KG (SQLite)
1023
+ * 4. AgentDiary — AAAK journal stored in the palace
1024
+ *
1025
+ * Hermes MemoryManager patterns used:
1026
+ * - context fencing (_build_memory_context_block)
1027
+ * - prefetch/sync_turn lifecycle
1028
+ * - single provider limit enforced (palace replaces mempalace_bridge)
1029
+ */
1030
+ export class UnifiedMemory {
1031
+ builtin;
1032
+ palace;
1033
+ kg;
1034
+ diary;
1035
+ _prefetch_cache = "";
1036
+ constructor(config = {}) {
1037
+ const agentName = String(config["agent_name"] ?? "axoniz-zero");
1038
+ const palacePath = String(config["palace_path"] ?? PALACE_PATH);
1039
+ const kgPath = String(config["kg_path"] ?? KG_PATH);
1040
+ // 1. Always-on local memory (TF-IDF, zero deps)
1041
+ this.builtin = new SemanticMemory(MEMORY_PATH);
1042
+ // 2. Palace (local SQLite backend; embeddings pluggable)
1043
+ this.palace = new PalaceLayer(palacePath);
1044
+ // 3. Knowledge graph
1045
+ this.kg = new KnowledgeGraphLayer(kgPath);
1046
+ // 4. Diary
1047
+ this.diary = new AgentDiary(this.palace, agentName);
1048
+ // Hermes: prefetch cache for the next turn
1049
+ logger.info(`[UnifiedMemory] ready | palace=${palacePath} | kg=${kgPath} | palace_enabled=${this.palace.is_available()}`);
1050
+ }
1051
+ /* ── SemanticMemory drop-in interface ───────────────────────────────────── */
1052
+ save(key, value, tags, importance = 0.5) {
1053
+ const result = this.builtin.save(key, value, tags ?? undefined, importance);
1054
+ if (this.palace.is_available()) {
1055
+ const wing = tags && tags.length > 0 ? tags[0] : "general";
1056
+ this.palace.store(wing, "memory", `${key}: ${value}`, "axoniz");
1057
+ }
1058
+ return result;
1059
+ }
1060
+ get(key) {
1061
+ const local = this.builtin.get(key);
1062
+ if (!local.includes("not found in memory.")) {
1063
+ return local;
1064
+ }
1065
+ if (this.palace.is_available()) {
1066
+ const r = this.palace.search(key, null, null, 1);
1067
+ const items = r.results;
1068
+ if (items.length > 0) {
1069
+ return items[0].text;
1070
+ }
1071
+ }
1072
+ return local;
1073
+ }
1074
+ delete(key) {
1075
+ return this.builtin.delete(key);
1076
+ }
1077
+ clear() {
1078
+ this.builtin.clear();
1079
+ }
1080
+ all() {
1081
+ return this.builtin.all();
1082
+ }
1083
+ all_rich() {
1084
+ return this.builtin.allRich();
1085
+ }
1086
+ allRich() {
1087
+ return this.all_rich();
1088
+ }
1089
+ list_keys() {
1090
+ const local = this.builtin.listKeys();
1091
+ if (this.palace.is_available()) {
1092
+ const wings = this.palace.list_wings().wings;
1093
+ const entries = Object.entries(wings);
1094
+ if (entries.length > 0) {
1095
+ const wingStr = entries.map(([w, c]) => `${w}(${c})`).join(", ");
1096
+ return `${local}\n\n[Palace wings]: ${wingStr}`;
1097
+ }
1098
+ }
1099
+ return local;
1100
+ }
1101
+ listKeys() {
1102
+ return this.list_keys();
1103
+ }
1104
+ search(query, topK = 5) {
1105
+ return this.builtin.search(query, topK);
1106
+ }
1107
+ /**
1108
+ * Build the context block injected into the system prompt.
1109
+ * Hermes pattern: fenced block, prefetch from the palace.
1110
+ */
1111
+ get_relevant_context(query, maxTokens = 800) {
1112
+ const parts = [];
1113
+ // Prefetch cache from the previous turn (Hermes pattern)
1114
+ const cached = this._prefetch_cache;
1115
+ if (cached) {
1116
+ parts.push(cached);
1117
+ }
1118
+ else if (this.palace.is_available()) {
1119
+ // Live fetch when there is no cache yet
1120
+ const ctx = this.palace.get_context();
1121
+ if (ctx) {
1122
+ parts.push(ctx);
1123
+ }
1124
+ const r = this.palace.search(query, null, null, 3);
1125
+ const hits = r.results;
1126
+ if (hits.length > 0) {
1127
+ const lines = ["[PALACE SEARCH]"];
1128
+ for (const h of hits) {
1129
+ lines.push(` [${h.wing}/${h.room}] ${h.text.slice(0, 200)}`);
1130
+ }
1131
+ parts.push(lines.join("\n"));
1132
+ }
1133
+ }
1134
+ // Always include TF-IDF local memory too
1135
+ const localCtx = this.builtin.getRelevantContext(query, Math.floor(maxTokens / 2));
1136
+ if (localCtx) {
1137
+ parts.push(localCtx);
1138
+ }
1139
+ if (parts.length === 0) {
1140
+ return "";
1141
+ }
1142
+ return _build_memory_context_block(parts.join("\n\n"));
1143
+ }
1144
+ getRelevantContext(query, maxTokens = 800) {
1145
+ return this.get_relevant_context(query, maxTokens);
1146
+ }
1147
+ auto_extract_and_save(text, source = "conversation") {
1148
+ this.builtin.autoExtractAndSave(text, source);
1149
+ if (this.palace.is_available() && text.length > 50) {
1150
+ this.palace.store("wing_axoniz", "conversations", text.slice(0, 600), "auto");
1151
+ }
1152
+ }
1153
+ autoExtractAndSave(text, source = "conversation") {
1154
+ this.auto_extract_and_save(text, source);
1155
+ }
1156
+ /* ── Hermes lifecycle hooks ─────────────────────────────────────────────── */
1157
+ /**
1158
+ * Called before each agent turn — refreshes the cached palace context.
1159
+ * Python used a daemon thread; this is a fire-and-forget async task that is
1160
+ * also awaitable and never rejects.
1161
+ */
1162
+ async prefetch(query) {
1163
+ if (!this.palace.is_available()) {
1164
+ return;
1165
+ }
1166
+ try {
1167
+ const parts = [];
1168
+ const ctx = this.palace.get_context();
1169
+ if (ctx) {
1170
+ parts.push(ctx);
1171
+ }
1172
+ const r = this.palace.search(query, null, null, 4);
1173
+ const hits = r.results;
1174
+ if (hits.length > 0) {
1175
+ const lines = ["[PALACE]"];
1176
+ for (const h of hits) {
1177
+ lines.push(` [${h.wing}/${h.room}] ${h.text.slice(0, 150)}`);
1178
+ }
1179
+ parts.push(lines.join("\n"));
1180
+ }
1181
+ this._prefetch_cache = parts.join("\n\n");
1182
+ }
1183
+ catch (e) {
1184
+ logger.debug(`[UnifiedMemory] prefetch failed: ${errMsg(e)}`);
1185
+ }
1186
+ }
1187
+ /** Called after each turn — saves the conversation to the palace. */
1188
+ async sync_turn(userContent, assistantContent) {
1189
+ if (!this.palace.is_available()) {
1190
+ return;
1191
+ }
1192
+ try {
1193
+ this.palace.store("wing_axoniz", "conversation-log", `USR: ${userContent.slice(0, 300)}\nAGT: ${assistantContent.slice(0, 300)}`, "sync");
1194
+ }
1195
+ catch (e) {
1196
+ logger.debug(`[UnifiedMemory] sync_turn failed: ${errMsg(e)}`);
1197
+ }
1198
+ }
1199
+ syncTurn(userContent, assistantContent) {
1200
+ return this.sync_turn(userContent, assistantContent);
1201
+ }
1202
+ /* ── Tool map — injected into Agent._tool_map ───────────────────────────── */
1203
+ /**
1204
+ * Callable tools to merge into the agent tool map.
1205
+ * Overrides memory_save/get/list with the unified versions and adds
1206
+ * palace/kg/diary tools. Key names match the Python exactly, and each callable
1207
+ * accepts the Python kwargs object the agent dispatches (`fn(args)`) as well
1208
+ * as plain positional arguments.
1209
+ */
1210
+ as_tool_map() {
1211
+ return {
1212
+ // ── Override existing axoniz memory tools ──
1213
+ memory_save: (...args) => {
1214
+ const a = toolArgs(args, ["key", "value", "tags", "importance"]);
1215
+ return this.save(String(a["key"] ?? ""), String(a["value"] ?? ""), a["tags"], optNum(a["importance"]) ?? 0.5);
1216
+ },
1217
+ memory_get: (...args) => {
1218
+ const a = toolArgs(args, ["key"]);
1219
+ return this.get(String(a["key"] ?? ""));
1220
+ },
1221
+ memory_list: () => this.list_keys(),
1222
+ // ── Palace read tools ──
1223
+ palace_search: (...args) => {
1224
+ const a = toolArgs(args, ["query", "wing", "room", "limit"]);
1225
+ return this._t_palace_search(String(a["query"] ?? ""), optStr(a["wing"]), optStr(a["room"]), optNum(a["limit"]));
1226
+ },
1227
+ palace_context: () => this._t_palace_context(),
1228
+ palace_status: () => this._t_palace_status(),
1229
+ palace_wings: () => this._t_palace_wings(),
1230
+ palace_rooms: (...args) => {
1231
+ const a = toolArgs(args, ["wing"]);
1232
+ return this._t_palace_rooms(optStr(a["wing"]));
1233
+ },
1234
+ palace_check_dup: (...args) => {
1235
+ const a = toolArgs(args, ["content", "threshold"]);
1236
+ return this._t_palace_check_dup(String(a["content"] ?? ""), optNum(a["threshold"]) ?? 0.9);
1237
+ },
1238
+ palace_graph_traverse: (...args) => {
1239
+ const a = toolArgs(args, ["start_room", "max_hops"]);
1240
+ return this._t_palace_traverse(String(a["start_room"] ?? ""), optNum(a["max_hops"]) ?? 2);
1241
+ },
1242
+ palace_find_tunnels: (...args) => {
1243
+ const a = toolArgs(args, ["wing_a", "wing_b"]);
1244
+ return this._t_palace_tunnels(optStr(a["wing_a"]), optStr(a["wing_b"]));
1245
+ },
1246
+ palace_graph_stats: () => this._t_palace_graph_stats(),
1247
+ // ── Palace write tools ──
1248
+ palace_store: (...args) => {
1249
+ const a = toolArgs(args, ["wing", "room", "content"]);
1250
+ return this._t_palace_store(String(a["wing"] ?? ""), String(a["room"] ?? ""), String(a["content"] ?? ""));
1251
+ },
1252
+ palace_delete: (...args) => {
1253
+ const a = toolArgs(args, ["drawer_id"]);
1254
+ return this._t_palace_delete(String(a["drawer_id"] ?? ""));
1255
+ },
1256
+ // ── Knowledge graph ──
1257
+ kg_add: (...args) => {
1258
+ const a = toolArgs(args, ["subject", "predicate", "obj", "valid_from", "source"]);
1259
+ return this._t_kg_add(String(a["subject"] ?? ""), String(a["predicate"] ?? ""), String(a["obj"] ?? ""), optStr(a["valid_from"]), optStr(a["source"]));
1260
+ },
1261
+ kg_query: (...args) => {
1262
+ const a = toolArgs(args, ["entity", "as_of", "direction"]);
1263
+ return this._t_kg_query(String(a["entity"] ?? ""), optStr(a["as_of"]), optStr(a["direction"]) ?? "both");
1264
+ },
1265
+ kg_invalidate: (...args) => {
1266
+ const a = toolArgs(args, ["subject", "predicate", "obj", "ended"]);
1267
+ return this._t_kg_invalidate(String(a["subject"] ?? ""), String(a["predicate"] ?? ""), String(a["obj"] ?? ""), optStr(a["ended"]));
1268
+ },
1269
+ kg_timeline: (...args) => {
1270
+ const a = toolArgs(args, ["entity"]);
1271
+ return this._t_kg_timeline(optStr(a["entity"]));
1272
+ },
1273
+ kg_stats: () => this._t_kg_stats(),
1274
+ // ── Agent diary ──
1275
+ diary_write: (...args) => {
1276
+ const a = toolArgs(args, ["entry", "topic"]);
1277
+ return this._t_diary_write(String(a["entry"] ?? ""), optStr(a["topic"]) ?? "general");
1278
+ },
1279
+ diary_read: (...args) => {
1280
+ const a = toolArgs(args, ["last_n"]);
1281
+ return this._t_diary_read(optNum(a["last_n"]) ?? 10);
1282
+ },
1283
+ };
1284
+ }
1285
+ asToolMap() {
1286
+ return this.as_tool_map();
1287
+ }
1288
+ /** OpenAI-format schemas for all memory tools — used in TOOL_SCHEMAS. */
1289
+ as_tool_schemas() {
1290
+ return [
1291
+ _fn("palace_search", "Semantic search across the palace. Use before answering questions about past decisions, projects, or context. Returns verbatim stored content.", {
1292
+ query: ["string", "Search query"],
1293
+ wing: ["string", "Wing filter (optional)"],
1294
+ room: ["string", "Room filter (optional)"],
1295
+ limit: ["integer", "Max results (default 5)"],
1296
+ }, ["query"]),
1297
+ _fn("palace_store", "Save verbatim content into the palace. wing=domain (project/person/topic), room=sub-topic.", {
1298
+ wing: ["string", "Domain (e.g. project name)"],
1299
+ room: ["string", "Sub-topic"],
1300
+ content: ["string", "Verbatim content to store"],
1301
+ }, ["wing", "room", "content"]),
1302
+ _fn("palace_context", "Load palace wake-up context: total drawers, wings overview. Call at start of session.", {}, []),
1303
+ _fn("palace_wings", "List all palace wings and drawer counts.", {}, []),
1304
+ _fn("palace_rooms", "List rooms in a wing.", { wing: ["string", "Wing name"] }, []),
1305
+ _fn("palace_check_dup", "Check if content already exists before storing.", {
1306
+ content: ["string", "Content to check"],
1307
+ threshold: ["number", "Similarity threshold 0-1 (default 0.9)"],
1308
+ }, ["content"]),
1309
+ _fn("palace_delete", "Delete a palace drawer by ID.", { drawer_id: ["string", "Drawer ID"] }, ["drawer_id"]),
1310
+ _fn("palace_graph_traverse", "Walk palace graph from a room — find connected ideas across wings.", {
1311
+ start_room: ["string", "Room to start from"],
1312
+ max_hops: ["integer", "Hops to follow (default 2)"],
1313
+ }, ["start_room"]),
1314
+ _fn("palace_find_tunnels", "Find rooms that bridge two wings.", { wing_a: ["string", "First wing"], wing_b: ["string", "Second wing"] }, []),
1315
+ _fn("palace_graph_stats", "Palace graph overview: rooms, tunnels, edges.", {}, []),
1316
+ _fn("kg_add", "Add a temporal fact: subject → predicate → object. E.g. ('Max','loves','chess',valid_from='2025-01-01')", {
1317
+ subject: ["string", "Entity"],
1318
+ predicate: ["string", "Relationship"],
1319
+ obj: ["string", "Connected entity"],
1320
+ valid_from: ["string", "When true (YYYY-MM-DD)"],
1321
+ source: ["string", "Source reference"],
1322
+ }, ["subject", "predicate", "obj"]),
1323
+ _fn("kg_query", "Query knowledge graph for an entity's facts. direction: outgoing/incoming/both.", {
1324
+ entity: ["string", "Entity name"],
1325
+ as_of: ["string", "Date filter YYYY-MM-DD"],
1326
+ direction: ["string", "outgoing/incoming/both"],
1327
+ }, ["entity"]),
1328
+ _fn("kg_invalidate", "Mark a fact as no longer true.", {
1329
+ subject: ["string", ""],
1330
+ predicate: ["string", ""],
1331
+ obj: ["string", ""],
1332
+ ended: ["string", "When it ended YYYY-MM-DD"],
1333
+ }, ["subject", "predicate", "obj"]),
1334
+ _fn("kg_timeline", "Chronological timeline of facts.", { entity: ["string", "Entity name (optional)"] }, []),
1335
+ _fn("kg_stats", "Knowledge graph statistics.", {}, []),
1336
+ _fn("diary_write", "Write a diary entry in AAAK format. Your personal journal across sessions.", { entry: ["string", "AAAK-format diary entry"], topic: ["string", "Topic tag (optional)"] }, ["entry"]),
1337
+ _fn("diary_read", "Read your recent diary entries.", { last_n: ["integer", "Number of entries (default 10)"] }, []),
1338
+ ];
1339
+ }
1340
+ asToolSchemas() {
1341
+ return this.as_tool_schemas();
1342
+ }
1343
+ /* ── Tool implementations ───────────────────────────────────────────────── */
1344
+ _t_palace_search(query, wing, room, limit = 5) {
1345
+ const r = this.palace.search(query, wing ?? null, room ?? null, limit);
1346
+ if (r.error !== undefined && r.results.length === 0) {
1347
+ return `[Palace error] ${r.error}`;
1348
+ }
1349
+ const hits = r.results;
1350
+ if (hits.length === 0) {
1351
+ return `No palace results for: ${query}`;
1352
+ }
1353
+ const lines = [`Palace search: '${query}' (${hits.length} results)`];
1354
+ for (const h of hits) {
1355
+ lines.push(` [${h.wing}/${h.room}] sim=${h.similarity} | ${h.text.slice(0, 200)}`);
1356
+ }
1357
+ return lines.join("\n");
1358
+ }
1359
+ _t_palace_store(wing, room, content) {
1360
+ return JSON.stringify(this.palace.store(wing, room, content, "agent"));
1361
+ }
1362
+ _t_palace_context() {
1363
+ const st = this.palace.status();
1364
+ if (st.error !== undefined && st.total_drawers === 0) {
1365
+ return "[Palace empty or unavailable. Local SQLite palace backend is not initialized.]";
1366
+ }
1367
+ const lines = [
1368
+ `Palace status: ${st.total_drawers} drawers`,
1369
+ "Wings: " +
1370
+ Object.entries(st.wings ?? {})
1371
+ .slice(0, 8)
1372
+ .map(([w, c]) => `${w}(${c})`)
1373
+ .join(", "),
1374
+ ];
1375
+ return lines.join("\n");
1376
+ }
1377
+ _t_palace_status() {
1378
+ return JSON.stringify(this.palace.status(), null, 2);
1379
+ }
1380
+ _t_palace_wings() {
1381
+ return JSON.stringify(this.palace.list_wings(), null, 2);
1382
+ }
1383
+ _t_palace_rooms(wing) {
1384
+ return JSON.stringify(this.palace.list_rooms(wing ?? null), null, 2);
1385
+ }
1386
+ _t_palace_check_dup(content, threshold = 0.9) {
1387
+ return JSON.stringify(this.palace.check_duplicate(content, threshold), null, 2);
1388
+ }
1389
+ _t_palace_delete(drawerId) {
1390
+ return JSON.stringify(this.palace.delete(drawerId), null, 2);
1391
+ }
1392
+ _t_palace_traverse(startRoom, maxHops = 2) {
1393
+ return JSON.stringify(this.palace.traverse_graph(startRoom, maxHops), null, 2);
1394
+ }
1395
+ _t_palace_tunnels(wingA, wingB) {
1396
+ return JSON.stringify(this.palace.find_tunnels(wingA ?? null, wingB ?? null), null, 2);
1397
+ }
1398
+ _t_palace_graph_stats() {
1399
+ return JSON.stringify(this.palace.graph_stats(), null, 2);
1400
+ }
1401
+ _t_kg_add(subject, predicate, obj, validFrom, source) {
1402
+ const result = this.kg.add(subject, predicate, obj, validFrom ?? null, source ?? null);
1403
+ return `Added: ${subject} → ${predicate} → ${obj} | id=${result}`;
1404
+ }
1405
+ _t_kg_query(entity, asOf, direction = "both") {
1406
+ const facts = this.kg.query(entity, asOf ?? null, direction);
1407
+ if (facts.length === 0) {
1408
+ return `No facts found for: ${entity}`;
1409
+ }
1410
+ const lines = [`KG facts for '${entity}':`];
1411
+ for (const f of facts.slice(0, 20)) {
1412
+ const status = f.current ? "✓" : "✗";
1413
+ lines.push(` ${status} ${f.subject} → ${f.predicate} → ${f.object} [${f.valid_from ?? ""}→${f.valid_to ?? ""}]`);
1414
+ }
1415
+ return lines.join("\n");
1416
+ }
1417
+ _t_kg_invalidate(subject, predicate, obj, ended) {
1418
+ this.kg.invalidate(subject, predicate, obj, ended ?? null);
1419
+ return `Invalidated: ${subject} → ${predicate} → ${obj} (ended: ${ended ?? "today"})`;
1420
+ }
1421
+ _t_kg_timeline(entity) {
1422
+ const facts = this.kg.timeline(entity ?? null);
1423
+ if (facts.length === 0) {
1424
+ return "No timeline entries.";
1425
+ }
1426
+ const lines = [`Timeline${entity ? ` for ${entity}` : ""}:`];
1427
+ for (const f of facts.slice(0, 20)) {
1428
+ lines.push(` ${f["valid_from"] ?? "?"} | ${f["subject"] ?? ""} → ${f["predicate"] ?? ""} → ${f["object"] ?? ""} ` +
1429
+ `${f["valid_to"] ? "(expired)" : ""}`);
1430
+ }
1431
+ return lines.join("\n");
1432
+ }
1433
+ _t_kg_stats() {
1434
+ return JSON.stringify(this.kg.stats(), null, 2);
1435
+ }
1436
+ _t_diary_write(entry, topic = "general") {
1437
+ const r = this.diary.write(entry, topic);
1438
+ return `Diary entry saved: ${r.id ?? JSON.stringify(r)}`;
1439
+ }
1440
+ /**
1441
+ * `last_n` may be passed positionally (tool map) or as `{ last_n }` — the
1442
+ * Python CLI calls it as `memory._t_diary_read(last_n=1)`.
1443
+ */
1444
+ _t_diary_read(lastN = 10) {
1445
+ const n = typeof lastN === "object" && lastN !== null ? (lastN.last_n ?? 10) : lastN;
1446
+ const r = this.diary.read(n);
1447
+ const hits = r.results;
1448
+ if (hits.length === 0) {
1449
+ return "No diary entries yet.";
1450
+ }
1451
+ const lines = ["Recent diary entries:"];
1452
+ for (const h of hits) {
1453
+ lines.push(` ${h.text.slice(0, 300)}`);
1454
+ }
1455
+ return lines.join("\n");
1456
+ }
1457
+ /** Close the underlying SQLite handles (additive; Python had no explicit close). */
1458
+ close() {
1459
+ this.palace.backend.close();
1460
+ this.kg.close();
1461
+ }
1462
+ }
1463
+ export function _fn(name, description, props, required) {
1464
+ const properties = {};
1465
+ for (const [k, v] of Object.entries(props)) {
1466
+ if (Array.isArray(v)) {
1467
+ const prop = { type: v[0] };
1468
+ if (v[1])
1469
+ prop["description"] = v[1];
1470
+ properties[k] = prop;
1471
+ }
1472
+ else {
1473
+ properties[k] = v;
1474
+ }
1475
+ }
1476
+ return {
1477
+ type: "function",
1478
+ function: {
1479
+ name,
1480
+ description,
1481
+ parameters: {
1482
+ type: "object",
1483
+ properties,
1484
+ required,
1485
+ },
1486
+ },
1487
+ };
1488
+ }
1489
+ //# sourceMappingURL=unified_memory.js.map