universal-agent-protocol 0.5.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 (415) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +462 -0
  3. package/dist/analyzers/index.d.ts +3 -0
  4. package/dist/analyzers/index.d.ts.map +1 -0
  5. package/dist/analyzers/index.js +656 -0
  6. package/dist/analyzers/index.js.map +1 -0
  7. package/dist/bin/cli.d.ts +3 -0
  8. package/dist/bin/cli.d.ts.map +1 -0
  9. package/dist/bin/cli.js +506 -0
  10. package/dist/bin/cli.js.map +1 -0
  11. package/dist/bin/tool-calls.d.ts +3 -0
  12. package/dist/bin/tool-calls.d.ts.map +1 -0
  13. package/dist/bin/tool-calls.js +4 -0
  14. package/dist/bin/tool-calls.js.map +1 -0
  15. package/dist/cli/agent.d.ts +20 -0
  16. package/dist/cli/agent.d.ts.map +1 -0
  17. package/dist/cli/agent.js +434 -0
  18. package/dist/cli/agent.js.map +1 -0
  19. package/dist/cli/analyze.d.ts +7 -0
  20. package/dist/cli/analyze.d.ts.map +1 -0
  21. package/dist/cli/analyze.js +103 -0
  22. package/dist/cli/analyze.js.map +1 -0
  23. package/dist/cli/coord.d.ts +7 -0
  24. package/dist/cli/coord.d.ts.map +1 -0
  25. package/dist/cli/coord.js +138 -0
  26. package/dist/cli/coord.js.map +1 -0
  27. package/dist/cli/dashboard.d.ts +8 -0
  28. package/dist/cli/dashboard.d.ts.map +1 -0
  29. package/dist/cli/dashboard.js +704 -0
  30. package/dist/cli/dashboard.js.map +1 -0
  31. package/dist/cli/deploy.d.ts +19 -0
  32. package/dist/cli/deploy.d.ts.map +1 -0
  33. package/dist/cli/deploy.js +267 -0
  34. package/dist/cli/deploy.js.map +1 -0
  35. package/dist/cli/droids.d.ts +9 -0
  36. package/dist/cli/droids.d.ts.map +1 -0
  37. package/dist/cli/droids.js +227 -0
  38. package/dist/cli/droids.js.map +1 -0
  39. package/dist/cli/generate.d.ts +17 -0
  40. package/dist/cli/generate.d.ts.map +1 -0
  41. package/dist/cli/generate.js +432 -0
  42. package/dist/cli/generate.js.map +1 -0
  43. package/dist/cli/hooks.d.ts +9 -0
  44. package/dist/cli/hooks.d.ts.map +1 -0
  45. package/dist/cli/hooks.js +374 -0
  46. package/dist/cli/hooks.js.map +1 -0
  47. package/dist/cli/init.d.ts +11 -0
  48. package/dist/cli/init.d.ts.map +1 -0
  49. package/dist/cli/init.js +316 -0
  50. package/dist/cli/init.js.map +1 -0
  51. package/dist/cli/mcp-router.d.ts +16 -0
  52. package/dist/cli/mcp-router.d.ts.map +1 -0
  53. package/dist/cli/mcp-router.js +143 -0
  54. package/dist/cli/mcp-router.js.map +1 -0
  55. package/dist/cli/memory.d.ts +24 -0
  56. package/dist/cli/memory.d.ts.map +1 -0
  57. package/dist/cli/memory.js +877 -0
  58. package/dist/cli/memory.js.map +1 -0
  59. package/dist/cli/model.d.ts +15 -0
  60. package/dist/cli/model.d.ts.map +1 -0
  61. package/dist/cli/model.js +270 -0
  62. package/dist/cli/model.js.map +1 -0
  63. package/dist/cli/patterns.d.ts +26 -0
  64. package/dist/cli/patterns.d.ts.map +1 -0
  65. package/dist/cli/patterns.js +587 -0
  66. package/dist/cli/patterns.js.map +1 -0
  67. package/dist/cli/setup-mcp-router.d.ts +8 -0
  68. package/dist/cli/setup-mcp-router.d.ts.map +1 -0
  69. package/dist/cli/setup-mcp-router.js +163 -0
  70. package/dist/cli/setup-mcp-router.js.map +1 -0
  71. package/dist/cli/setup.d.ts +13 -0
  72. package/dist/cli/setup.d.ts.map +1 -0
  73. package/dist/cli/setup.js +146 -0
  74. package/dist/cli/setup.js.map +1 -0
  75. package/dist/cli/sync.d.ts +7 -0
  76. package/dist/cli/sync.d.ts.map +1 -0
  77. package/dist/cli/sync.js +26 -0
  78. package/dist/cli/sync.js.map +1 -0
  79. package/dist/cli/task.d.ts +33 -0
  80. package/dist/cli/task.d.ts.map +1 -0
  81. package/dist/cli/task.js +616 -0
  82. package/dist/cli/task.js.map +1 -0
  83. package/dist/cli/tool-calls.d.ts +8 -0
  84. package/dist/cli/tool-calls.d.ts.map +1 -0
  85. package/dist/cli/tool-calls.js +239 -0
  86. package/dist/cli/tool-calls.js.map +1 -0
  87. package/dist/cli/update.d.ts +10 -0
  88. package/dist/cli/update.d.ts.map +1 -0
  89. package/dist/cli/update.js +300 -0
  90. package/dist/cli/update.js.map +1 -0
  91. package/dist/cli/visualize.d.ts +77 -0
  92. package/dist/cli/visualize.d.ts.map +1 -0
  93. package/dist/cli/visualize.js +287 -0
  94. package/dist/cli/visualize.js.map +1 -0
  95. package/dist/cli/worktree.d.ts +9 -0
  96. package/dist/cli/worktree.d.ts.map +1 -0
  97. package/dist/cli/worktree.js +175 -0
  98. package/dist/cli/worktree.js.map +1 -0
  99. package/dist/coordination/capability-router.d.ts +79 -0
  100. package/dist/coordination/capability-router.d.ts.map +1 -0
  101. package/dist/coordination/capability-router.js +324 -0
  102. package/dist/coordination/capability-router.js.map +1 -0
  103. package/dist/coordination/database.d.ts +13 -0
  104. package/dist/coordination/database.d.ts.map +1 -0
  105. package/dist/coordination/database.js +131 -0
  106. package/dist/coordination/database.js.map +1 -0
  107. package/dist/coordination/deploy-batcher.d.ts +101 -0
  108. package/dist/coordination/deploy-batcher.d.ts.map +1 -0
  109. package/dist/coordination/deploy-batcher.js +565 -0
  110. package/dist/coordination/deploy-batcher.js.map +1 -0
  111. package/dist/coordination/index.d.ts +5 -0
  112. package/dist/coordination/index.d.ts.map +1 -0
  113. package/dist/coordination/index.js +5 -0
  114. package/dist/coordination/index.js.map +1 -0
  115. package/dist/coordination/service.d.ts +81 -0
  116. package/dist/coordination/service.d.ts.map +1 -0
  117. package/dist/coordination/service.js +603 -0
  118. package/dist/coordination/service.js.map +1 -0
  119. package/dist/generators/claude-md.d.ts +3 -0
  120. package/dist/generators/claude-md.d.ts.map +1 -0
  121. package/dist/generators/claude-md.js +977 -0
  122. package/dist/generators/claude-md.js.map +1 -0
  123. package/dist/generators/template-loader.d.ts +105 -0
  124. package/dist/generators/template-loader.d.ts.map +1 -0
  125. package/dist/generators/template-loader.js +291 -0
  126. package/dist/generators/template-loader.js.map +1 -0
  127. package/dist/index.d.ts +47 -0
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/index.js +59 -0
  130. package/dist/index.js.map +1 -0
  131. package/dist/mcp-router/config/parser.d.ts +9 -0
  132. package/dist/mcp-router/config/parser.d.ts.map +1 -0
  133. package/dist/mcp-router/config/parser.js +174 -0
  134. package/dist/mcp-router/config/parser.js.map +1 -0
  135. package/dist/mcp-router/executor/client.d.ts +31 -0
  136. package/dist/mcp-router/executor/client.d.ts.map +1 -0
  137. package/dist/mcp-router/executor/client.js +187 -0
  138. package/dist/mcp-router/executor/client.js.map +1 -0
  139. package/dist/mcp-router/index.d.ts +22 -0
  140. package/dist/mcp-router/index.d.ts.map +1 -0
  141. package/dist/mcp-router/index.js +18 -0
  142. package/dist/mcp-router/index.js.map +1 -0
  143. package/dist/mcp-router/output-compressor.d.ts +26 -0
  144. package/dist/mcp-router/output-compressor.d.ts.map +1 -0
  145. package/dist/mcp-router/output-compressor.js +236 -0
  146. package/dist/mcp-router/output-compressor.js.map +1 -0
  147. package/dist/mcp-router/search/fuzzy.d.ts +26 -0
  148. package/dist/mcp-router/search/fuzzy.d.ts.map +1 -0
  149. package/dist/mcp-router/search/fuzzy.js +94 -0
  150. package/dist/mcp-router/search/fuzzy.js.map +1 -0
  151. package/dist/mcp-router/server.d.ts +50 -0
  152. package/dist/mcp-router/server.d.ts.map +1 -0
  153. package/dist/mcp-router/server.js +229 -0
  154. package/dist/mcp-router/server.js.map +1 -0
  155. package/dist/mcp-router/session-stats.d.ts +37 -0
  156. package/dist/mcp-router/session-stats.d.ts.map +1 -0
  157. package/dist/mcp-router/session-stats.js +56 -0
  158. package/dist/mcp-router/session-stats.js.map +1 -0
  159. package/dist/mcp-router/tools/discover.d.ts +37 -0
  160. package/dist/mcp-router/tools/discover.d.ts.map +1 -0
  161. package/dist/mcp-router/tools/discover.js +65 -0
  162. package/dist/mcp-router/tools/discover.js.map +1 -0
  163. package/dist/mcp-router/tools/execute.d.ts +43 -0
  164. package/dist/mcp-router/tools/execute.d.ts.map +1 -0
  165. package/dist/mcp-router/tools/execute.js +103 -0
  166. package/dist/mcp-router/tools/execute.js.map +1 -0
  167. package/dist/mcp-router/types.d.ts +62 -0
  168. package/dist/mcp-router/types.d.ts.map +1 -0
  169. package/dist/mcp-router/types.js +6 -0
  170. package/dist/mcp-router/types.js.map +1 -0
  171. package/dist/memory/adaptive-context.d.ts +146 -0
  172. package/dist/memory/adaptive-context.d.ts.map +1 -0
  173. package/dist/memory/adaptive-context.js +1022 -0
  174. package/dist/memory/adaptive-context.js.map +1 -0
  175. package/dist/memory/agent-scoped-memory.d.ts +67 -0
  176. package/dist/memory/agent-scoped-memory.d.ts.map +1 -0
  177. package/dist/memory/agent-scoped-memory.js +126 -0
  178. package/dist/memory/agent-scoped-memory.js.map +1 -0
  179. package/dist/memory/backends/base.d.ts +18 -0
  180. package/dist/memory/backends/base.d.ts.map +1 -0
  181. package/dist/memory/backends/base.js +2 -0
  182. package/dist/memory/backends/base.js.map +1 -0
  183. package/dist/memory/backends/factory.d.ts +4 -0
  184. package/dist/memory/backends/factory.d.ts.map +1 -0
  185. package/dist/memory/backends/factory.js +53 -0
  186. package/dist/memory/backends/factory.js.map +1 -0
  187. package/dist/memory/backends/github.d.ts +22 -0
  188. package/dist/memory/backends/github.d.ts.map +1 -0
  189. package/dist/memory/backends/github.js +118 -0
  190. package/dist/memory/backends/github.js.map +1 -0
  191. package/dist/memory/backends/qdrant-cloud.d.ts +32 -0
  192. package/dist/memory/backends/qdrant-cloud.d.ts.map +1 -0
  193. package/dist/memory/backends/qdrant-cloud.js +168 -0
  194. package/dist/memory/backends/qdrant-cloud.js.map +1 -0
  195. package/dist/memory/context-compressor.d.ts +74 -0
  196. package/dist/memory/context-compressor.d.ts.map +1 -0
  197. package/dist/memory/context-compressor.js +289 -0
  198. package/dist/memory/context-compressor.js.map +1 -0
  199. package/dist/memory/correction-propagator.d.ts +44 -0
  200. package/dist/memory/correction-propagator.d.ts.map +1 -0
  201. package/dist/memory/correction-propagator.js +156 -0
  202. package/dist/memory/correction-propagator.js.map +1 -0
  203. package/dist/memory/daily-log.d.ts +67 -0
  204. package/dist/memory/daily-log.d.ts.map +1 -0
  205. package/dist/memory/daily-log.js +143 -0
  206. package/dist/memory/daily-log.js.map +1 -0
  207. package/dist/memory/dynamic-retrieval.d.ts +110 -0
  208. package/dist/memory/dynamic-retrieval.d.ts.map +1 -0
  209. package/dist/memory/dynamic-retrieval.js +688 -0
  210. package/dist/memory/dynamic-retrieval.js.map +1 -0
  211. package/dist/memory/embeddings.d.ts +116 -0
  212. package/dist/memory/embeddings.d.ts.map +1 -0
  213. package/dist/memory/embeddings.js +461 -0
  214. package/dist/memory/embeddings.js.map +1 -0
  215. package/dist/memory/hierarchical-memory.d.ts +141 -0
  216. package/dist/memory/hierarchical-memory.d.ts.map +1 -0
  217. package/dist/memory/hierarchical-memory.js +477 -0
  218. package/dist/memory/hierarchical-memory.js.map +1 -0
  219. package/dist/memory/memory-consolidator.d.ts +124 -0
  220. package/dist/memory/memory-consolidator.d.ts.map +1 -0
  221. package/dist/memory/memory-consolidator.js +514 -0
  222. package/dist/memory/memory-consolidator.js.map +1 -0
  223. package/dist/memory/memory-maintenance.d.ts +39 -0
  224. package/dist/memory/memory-maintenance.d.ts.map +1 -0
  225. package/dist/memory/memory-maintenance.js +305 -0
  226. package/dist/memory/memory-maintenance.js.map +1 -0
  227. package/dist/memory/model-router.d.ts +102 -0
  228. package/dist/memory/model-router.d.ts.map +1 -0
  229. package/dist/memory/model-router.js +448 -0
  230. package/dist/memory/model-router.js.map +1 -0
  231. package/dist/memory/multi-view-memory.d.ts +134 -0
  232. package/dist/memory/multi-view-memory.d.ts.map +1 -0
  233. package/dist/memory/multi-view-memory.js +420 -0
  234. package/dist/memory/multi-view-memory.js.map +1 -0
  235. package/dist/memory/prepopulate.d.ts +76 -0
  236. package/dist/memory/prepopulate.d.ts.map +1 -0
  237. package/dist/memory/prepopulate.js +815 -0
  238. package/dist/memory/prepopulate.js.map +1 -0
  239. package/dist/memory/semantic-compression.d.ts +77 -0
  240. package/dist/memory/semantic-compression.d.ts.map +1 -0
  241. package/dist/memory/semantic-compression.js +348 -0
  242. package/dist/memory/semantic-compression.js.map +1 -0
  243. package/dist/memory/serverless-qdrant.d.ts +102 -0
  244. package/dist/memory/serverless-qdrant.d.ts.map +1 -0
  245. package/dist/memory/serverless-qdrant.js +369 -0
  246. package/dist/memory/serverless-qdrant.js.map +1 -0
  247. package/dist/memory/short-term/factory.d.ts +26 -0
  248. package/dist/memory/short-term/factory.d.ts.map +1 -0
  249. package/dist/memory/short-term/factory.js +28 -0
  250. package/dist/memory/short-term/factory.js.map +1 -0
  251. package/dist/memory/short-term/indexeddb.d.ts +25 -0
  252. package/dist/memory/short-term/indexeddb.d.ts.map +1 -0
  253. package/dist/memory/short-term/indexeddb.js +64 -0
  254. package/dist/memory/short-term/indexeddb.js.map +1 -0
  255. package/dist/memory/short-term/schema.d.ts +6 -0
  256. package/dist/memory/short-term/schema.d.ts.map +1 -0
  257. package/dist/memory/short-term/schema.js +119 -0
  258. package/dist/memory/short-term/schema.js.map +1 -0
  259. package/dist/memory/short-term/sqlite.d.ts +50 -0
  260. package/dist/memory/short-term/sqlite.d.ts.map +1 -0
  261. package/dist/memory/short-term/sqlite.js +221 -0
  262. package/dist/memory/short-term/sqlite.js.map +1 -0
  263. package/dist/memory/speculative-cache.d.ts +111 -0
  264. package/dist/memory/speculative-cache.d.ts.map +1 -0
  265. package/dist/memory/speculative-cache.js +409 -0
  266. package/dist/memory/speculative-cache.js.map +1 -0
  267. package/dist/memory/task-classifier.d.ts +34 -0
  268. package/dist/memory/task-classifier.d.ts.map +1 -0
  269. package/dist/memory/task-classifier.js +300 -0
  270. package/dist/memory/task-classifier.js.map +1 -0
  271. package/dist/memory/terminal-bench-knowledge.d.ts +48 -0
  272. package/dist/memory/terminal-bench-knowledge.d.ts.map +1 -0
  273. package/dist/memory/terminal-bench-knowledge.js +399 -0
  274. package/dist/memory/terminal-bench-knowledge.js.map +1 -0
  275. package/dist/memory/write-gate.d.ts +39 -0
  276. package/dist/memory/write-gate.d.ts.map +1 -0
  277. package/dist/memory/write-gate.js +190 -0
  278. package/dist/memory/write-gate.js.map +1 -0
  279. package/dist/models/executor.d.ts +130 -0
  280. package/dist/models/executor.d.ts.map +1 -0
  281. package/dist/models/executor.js +383 -0
  282. package/dist/models/executor.js.map +1 -0
  283. package/dist/models/index.d.ts +15 -0
  284. package/dist/models/index.d.ts.map +1 -0
  285. package/dist/models/index.js +17 -0
  286. package/dist/models/index.js.map +1 -0
  287. package/dist/models/planner.d.ts +71 -0
  288. package/dist/models/planner.d.ts.map +1 -0
  289. package/dist/models/planner.js +344 -0
  290. package/dist/models/planner.js.map +1 -0
  291. package/dist/models/router.d.ts +75 -0
  292. package/dist/models/router.d.ts.map +1 -0
  293. package/dist/models/router.js +344 -0
  294. package/dist/models/router.js.map +1 -0
  295. package/dist/models/types.d.ts +370 -0
  296. package/dist/models/types.d.ts.map +1 -0
  297. package/dist/models/types.js +181 -0
  298. package/dist/models/types.js.map +1 -0
  299. package/dist/tasks/coordination.d.ts +74 -0
  300. package/dist/tasks/coordination.d.ts.map +1 -0
  301. package/dist/tasks/coordination.js +237 -0
  302. package/dist/tasks/coordination.js.map +1 -0
  303. package/dist/tasks/database.d.ts +14 -0
  304. package/dist/tasks/database.d.ts.map +1 -0
  305. package/dist/tasks/database.js +128 -0
  306. package/dist/tasks/database.js.map +1 -0
  307. package/dist/tasks/index.d.ts +5 -0
  308. package/dist/tasks/index.d.ts.map +1 -0
  309. package/dist/tasks/index.js +5 -0
  310. package/dist/tasks/index.js.map +1 -0
  311. package/dist/tasks/service.d.ts +39 -0
  312. package/dist/tasks/service.d.ts.map +1 -0
  313. package/dist/tasks/service.js +582 -0
  314. package/dist/tasks/service.js.map +1 -0
  315. package/dist/tasks/types.d.ts +224 -0
  316. package/dist/tasks/types.d.ts.map +1 -0
  317. package/dist/tasks/types.js +64 -0
  318. package/dist/tasks/types.js.map +1 -0
  319. package/dist/types/analysis.d.ts +82 -0
  320. package/dist/types/analysis.d.ts.map +1 -0
  321. package/dist/types/analysis.js +2 -0
  322. package/dist/types/analysis.js.map +1 -0
  323. package/dist/types/config.d.ts +3023 -0
  324. package/dist/types/config.d.ts.map +1 -0
  325. package/dist/types/config.js +292 -0
  326. package/dist/types/config.js.map +1 -0
  327. package/dist/types/coordination.d.ts +240 -0
  328. package/dist/types/coordination.d.ts.map +1 -0
  329. package/dist/types/coordination.js +43 -0
  330. package/dist/types/coordination.js.map +1 -0
  331. package/dist/types/index.d.ts +4 -0
  332. package/dist/types/index.d.ts.map +1 -0
  333. package/dist/types/index.js +4 -0
  334. package/dist/types/index.js.map +1 -0
  335. package/dist/utils/calculate-average.d.ts +15 -0
  336. package/dist/utils/calculate-average.d.ts.map +1 -0
  337. package/dist/utils/calculate-average.js +21 -0
  338. package/dist/utils/calculate-average.js.map +1 -0
  339. package/dist/utils/config-manager.d.ts +30 -0
  340. package/dist/utils/config-manager.d.ts.map +1 -0
  341. package/dist/utils/config-manager.js +41 -0
  342. package/dist/utils/config-manager.js.map +1 -0
  343. package/dist/utils/dijkstra.d.ts +17 -0
  344. package/dist/utils/dijkstra.d.ts.map +1 -0
  345. package/dist/utils/dijkstra.js +91 -0
  346. package/dist/utils/dijkstra.js.map +1 -0
  347. package/dist/utils/fetch-with-retry.d.ts +5 -0
  348. package/dist/utils/fetch-with-retry.d.ts.map +1 -0
  349. package/dist/utils/fetch-with-retry.js +61 -0
  350. package/dist/utils/fetch-with-retry.js.map +1 -0
  351. package/dist/utils/merge-claude-md.d.ts +28 -0
  352. package/dist/utils/merge-claude-md.d.ts.map +1 -0
  353. package/dist/utils/merge-claude-md.js +342 -0
  354. package/dist/utils/merge-claude-md.js.map +1 -0
  355. package/dist/utils/order-processor-refactored.d.ts +126 -0
  356. package/dist/utils/order-processor-refactored.d.ts.map +1 -0
  357. package/dist/utils/order-processor-refactored.js +165 -0
  358. package/dist/utils/order-processor-refactored.js.map +1 -0
  359. package/dist/utils/order-processor-strategy.d.ts +72 -0
  360. package/dist/utils/order-processor-strategy.d.ts.map +1 -0
  361. package/dist/utils/order-processor-strategy.js +158 -0
  362. package/dist/utils/order-processor-strategy.js.map +1 -0
  363. package/dist/utils/order-processor.d.ts +242 -0
  364. package/dist/utils/order-processor.d.ts.map +1 -0
  365. package/dist/utils/order-processor.js +370 -0
  366. package/dist/utils/order-processor.js.map +1 -0
  367. package/dist/utils/rate-limiter-simple.d.ts +58 -0
  368. package/dist/utils/rate-limiter-simple.d.ts.map +1 -0
  369. package/dist/utils/rate-limiter-simple.js +100 -0
  370. package/dist/utils/rate-limiter-simple.js.map +1 -0
  371. package/dist/utils/rate-limiter.d.ts +62 -0
  372. package/dist/utils/rate-limiter.d.ts.map +1 -0
  373. package/dist/utils/rate-limiter.js +150 -0
  374. package/dist/utils/rate-limiter.js.map +1 -0
  375. package/dist/utils/string-similarity.d.ts +37 -0
  376. package/dist/utils/string-similarity.d.ts.map +1 -0
  377. package/dist/utils/string-similarity.js +114 -0
  378. package/dist/utils/string-similarity.js.map +1 -0
  379. package/dist/utils/validate-json.d.ts +51 -0
  380. package/dist/utils/validate-json.d.ts.map +1 -0
  381. package/dist/utils/validate-json.js +99 -0
  382. package/dist/utils/validate-json.js.map +1 -0
  383. package/package.json +96 -0
  384. package/templates/CLAUDE.template.md +11 -0
  385. package/templates/CLAUDE_ARCHITECTURE.template.md +103 -0
  386. package/templates/CLAUDE_CODING.template.md +125 -0
  387. package/templates/CLAUDE_DROIDS.template.md +109 -0
  388. package/templates/CLAUDE_MEMORY.template.md +130 -0
  389. package/templates/CLAUDE_WORKFLOWS.template.md +136 -0
  390. package/templates/PROJECT.template.md +209 -0
  391. package/templates/SCHEMA.md +57 -0
  392. package/templates/archive/CLAUDE.template.root-v6.md +762 -0
  393. package/templates/archive/CLAUDE.template.v6.md +762 -0
  394. package/templates/hooks/pre-compact.sh +68 -0
  395. package/templates/hooks/session-start.sh +106 -0
  396. package/tools/agents/README.md +224 -0
  397. package/tools/agents/UAP/README.md +351 -0
  398. package/tools/agents/UAP/__init__.py +9 -0
  399. package/tools/agents/UAP/cli.py +675 -0
  400. package/tools/agents/UAP/version.py +2 -0
  401. package/tools/agents/benchmarks/benchmark_memory_systems.py +637 -0
  402. package/tools/agents/benchmarks/results/benchmark_20260106_064817.json +170 -0
  403. package/tools/agents/benchmarks/results/benchmark_20260106_064817.md +51 -0
  404. package/tools/agents/config/chat_template.jinja +172 -0
  405. package/tools/agents/docker-compose.qdrant.yml +24 -0
  406. package/tools/agents/migrations/apply.py +256 -0
  407. package/tools/agents/scripts/fix_qwen_chat_template.py +314 -0
  408. package/tools/agents/scripts/init_qdrant.py +151 -0
  409. package/tools/agents/scripts/memory_migration.py +518 -0
  410. package/tools/agents/scripts/migrate_memory_to_qdrant.py +113 -0
  411. package/tools/agents/scripts/query_memory.py +189 -0
  412. package/tools/agents/scripts/qwen_tool_call_test.py +419 -0
  413. package/tools/agents/scripts/qwen_tool_call_wrapper.py +517 -0
  414. package/tools/agents/scripts/start-services.sh +96 -0
  415. package/tools/agents/tests/test_uap_compliance.py +257 -0
@@ -0,0 +1,637 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Memory Systems Benchmark Suite
4
+
5
+ Benchmarks the current Pay2U memory implementation and compares against
6
+ theoretical performance of alternative systems (Mem0, A-MEM, MemGPT patterns).
7
+
8
+ Usage:
9
+ tools/agents/.venv/bin/python tools/agents/benchmarks/benchmark_memory_systems.py
10
+
11
+ Outputs results to: tools/agents/benchmarks/results/
12
+ """
13
+
14
+ import json
15
+ import os
16
+ import random
17
+ import sqlite3
18
+ import statistics
19
+ import string
20
+ import time
21
+ import uuid
22
+ from dataclasses import dataclass
23
+ from datetime import datetime, timedelta
24
+ from pathlib import Path
25
+ from typing import Optional
26
+
27
+ try:
28
+ from sentence_transformers import SentenceTransformer
29
+ from qdrant_client import QdrantClient
30
+ from qdrant_client.models import PointStruct, Distance, VectorParams
31
+ QDRANT_AVAILABLE = True
32
+ except ImportError:
33
+ QDRANT_AVAILABLE = False
34
+ print("Warning: Qdrant/sentence-transformers not available. Some benchmarks skipped.")
35
+
36
+
37
+ @dataclass
38
+ class BenchmarkResult:
39
+ name: str
40
+ operation: str
41
+ samples: int
42
+ mean_ms: float
43
+ median_ms: float
44
+ p95_ms: float
45
+ p99_ms: float
46
+ min_ms: float
47
+ max_ms: float
48
+ ops_per_sec: float
49
+
50
+
51
+ class MemoryBenchmark:
52
+ def __init__(self, results_dir: Optional[Path] = None):
53
+ self.project_root = Path(__file__).parent.parent.parent.parent
54
+ self.results_dir = results_dir or self.project_root / "tools/agents/benchmarks/results"
55
+ self.results_dir.mkdir(parents=True, exist_ok=True)
56
+
57
+ # Test database paths (use separate test databases)
58
+ self.test_db = self.results_dir / "test_short_term.db"
59
+ self.test_collection = "benchmark_memory"
60
+
61
+ # Initialize embedding model if available
62
+ self.model = None
63
+ self.qdrant = None
64
+ if QDRANT_AVAILABLE:
65
+ try:
66
+ self.model = SentenceTransformer("all-MiniLM-L6-v2")
67
+ self.qdrant = QdrantClient(host="localhost", port=6333)
68
+ except Exception as e:
69
+ print(f"Warning: Could not initialize Qdrant: {e}")
70
+
71
+ self.results: list[BenchmarkResult] = []
72
+
73
+ def setup_test_sqlite(self):
74
+ """Create test SQLite database with same schema as production."""
75
+ if self.test_db.exists():
76
+ os.remove(self.test_db)
77
+
78
+ conn = sqlite3.connect(self.test_db)
79
+ cursor = conn.cursor()
80
+
81
+ cursor.execute("""
82
+ CREATE TABLE memories (
83
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
84
+ timestamp TEXT NOT NULL,
85
+ type TEXT NOT NULL CHECK(type IN ('action', 'observation', 'thought', 'goal')),
86
+ content TEXT NOT NULL
87
+ )
88
+ """)
89
+ cursor.execute("CREATE INDEX idx_memories_timestamp ON memories(timestamp DESC)")
90
+ cursor.execute("CREATE INDEX idx_memories_type ON memories(type)")
91
+
92
+ # Session memory table (proposed enhancement)
93
+ cursor.execute("""
94
+ CREATE TABLE session_memories (
95
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
96
+ session_id TEXT NOT NULL,
97
+ timestamp TEXT NOT NULL,
98
+ type TEXT NOT NULL CHECK(type IN ('summary', 'decision', 'entity', 'error')),
99
+ content TEXT NOT NULL,
100
+ context TEXT,
101
+ importance INTEGER DEFAULT 5
102
+ )
103
+ """)
104
+ cursor.execute("CREATE INDEX idx_session_memories_session ON session_memories(session_id)")
105
+
106
+ # Knowledge graph tables (proposed enhancement)
107
+ cursor.execute("""
108
+ CREATE TABLE entities (
109
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
110
+ type TEXT NOT NULL,
111
+ name TEXT NOT NULL,
112
+ context TEXT,
113
+ first_seen TEXT NOT NULL,
114
+ last_seen TEXT NOT NULL,
115
+ mention_count INTEGER DEFAULT 1,
116
+ UNIQUE(type, name)
117
+ )
118
+ """)
119
+ cursor.execute("""
120
+ CREATE TABLE relationships (
121
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
122
+ source_id INTEGER NOT NULL,
123
+ target_id INTEGER NOT NULL,
124
+ relation TEXT NOT NULL,
125
+ weight REAL DEFAULT 1.0,
126
+ timestamp TEXT NOT NULL,
127
+ FOREIGN KEY (source_id) REFERENCES entities(id),
128
+ FOREIGN KEY (target_id) REFERENCES entities(id)
129
+ )
130
+ """)
131
+ cursor.execute("CREATE INDEX idx_rel_source ON relationships(source_id)")
132
+ cursor.execute("CREATE INDEX idx_rel_target ON relationships(target_id)")
133
+
134
+ conn.commit()
135
+ conn.close()
136
+
137
+ def setup_test_qdrant(self):
138
+ """Create test Qdrant collection."""
139
+ if not self.qdrant:
140
+ return False
141
+
142
+ try:
143
+ # Delete if exists
144
+ try:
145
+ self.qdrant.delete_collection(self.test_collection)
146
+ except Exception:
147
+ pass
148
+
149
+ # Create fresh collection
150
+ self.qdrant.create_collection(
151
+ collection_name=self.test_collection,
152
+ vectors_config=VectorParams(size=384, distance=Distance.COSINE)
153
+ )
154
+ return True
155
+ except Exception as e:
156
+ print(f"Warning: Could not setup Qdrant test collection: {e}")
157
+ return False
158
+
159
+ def generate_test_content(self, size: int = 100) -> str:
160
+ """Generate realistic test content."""
161
+ templates = [
162
+ "Fixed bug in {file} where {issue} caused {effect}",
163
+ "Updated {component} to use {pattern} for better {benefit}",
164
+ "Deployed {service} to {environment} with {config} settings",
165
+ "Discovered that {feature} requires {requirement} to work correctly",
166
+ "Resolved {error} by {solution} in {location}",
167
+ "Created {artifact} with {specifications} for {purpose}",
168
+ ]
169
+
170
+ files = ["api.py", "main.cpp", "config.yaml", "auth.js", "database.sql"]
171
+ components = ["cache layer", "auth module", "API gateway", "frontend", "database"]
172
+ patterns = ["singleton", "factory", "observer", "decorator", "strategy"]
173
+
174
+ template = random.choice(templates)
175
+ content = template.format(
176
+ file=random.choice(files),
177
+ component=random.choice(components),
178
+ pattern=random.choice(patterns),
179
+ issue="null pointer exception",
180
+ effect="crashes",
181
+ benefit="performance",
182
+ service="products-api",
183
+ environment="production",
184
+ config="optimized",
185
+ feature="OAuth",
186
+ requirement="HTTPS",
187
+ error="timeout",
188
+ solution="increasing buffer",
189
+ location="main handler",
190
+ artifact="deployment script",
191
+ specifications="HA config",
192
+ purpose="disaster recovery"
193
+ )
194
+
195
+ # Pad to desired size
196
+ while len(content) < size:
197
+ content += " " + ''.join(random.choices(string.ascii_lowercase, k=10))
198
+
199
+ return content[:size]
200
+
201
+ def benchmark_operation(self, name: str, operation: str, func, iterations: int = 100) -> BenchmarkResult:
202
+ """Run a benchmark and collect statistics."""
203
+ times = []
204
+
205
+ for _ in range(iterations):
206
+ start = time.perf_counter()
207
+ func()
208
+ elapsed = (time.perf_counter() - start) * 1000 # Convert to ms
209
+ times.append(elapsed)
210
+
211
+ times.sort()
212
+ result = BenchmarkResult(
213
+ name=name,
214
+ operation=operation,
215
+ samples=iterations,
216
+ mean_ms=statistics.mean(times),
217
+ median_ms=statistics.median(times),
218
+ p95_ms=times[int(len(times) * 0.95)],
219
+ p99_ms=times[int(len(times) * 0.99)],
220
+ min_ms=min(times),
221
+ max_ms=max(times),
222
+ ops_per_sec=1000 / statistics.mean(times) if statistics.mean(times) > 0 else 0
223
+ )
224
+
225
+ self.results.append(result)
226
+ return result
227
+
228
+ def run_sqlite_benchmarks(self):
229
+ """Benchmark SQLite short-term memory operations."""
230
+ print("\n=== SQLite Short-term Memory Benchmarks ===\n")
231
+ self.setup_test_sqlite()
232
+
233
+ # Benchmark: Single INSERT
234
+ def insert_single():
235
+ conn = sqlite3.connect(self.test_db)
236
+ cursor = conn.cursor()
237
+ cursor.execute(
238
+ "INSERT INTO memories (timestamp, type, content) VALUES (?, ?, ?)",
239
+ (datetime.utcnow().isoformat(), "action", self.generate_test_content(200))
240
+ )
241
+ conn.commit()
242
+ conn.close()
243
+
244
+ result = self.benchmark_operation("SQLite", "INSERT (single)", insert_single, 100)
245
+ print(f"INSERT (single): {result.mean_ms:.3f}ms mean, {result.p95_ms:.3f}ms p95, {result.ops_per_sec:.0f} ops/sec")
246
+
247
+ # Pre-populate for read tests
248
+ conn = sqlite3.connect(self.test_db)
249
+ cursor = conn.cursor()
250
+ for i in range(1000):
251
+ cursor.execute(
252
+ "INSERT INTO memories (timestamp, type, content) VALUES (?, ?, ?)",
253
+ (
254
+ (datetime.utcnow() - timedelta(hours=i)).isoformat(),
255
+ random.choice(["action", "observation", "thought", "goal"]),
256
+ self.generate_test_content(200)
257
+ )
258
+ )
259
+ conn.commit()
260
+ conn.close()
261
+
262
+ # Benchmark: SELECT recent (LIMIT 50)
263
+ def select_recent():
264
+ conn = sqlite3.connect(self.test_db)
265
+ cursor = conn.cursor()
266
+ cursor.execute("SELECT * FROM memories ORDER BY id DESC LIMIT 50")
267
+ _ = cursor.fetchall()
268
+ conn.close()
269
+
270
+ result = self.benchmark_operation("SQLite", "SELECT recent (LIMIT 50)", select_recent, 100)
271
+ print(f"SELECT recent (50): {result.mean_ms:.3f}ms mean, {result.p95_ms:.3f}ms p95, {result.ops_per_sec:.0f} ops/sec")
272
+
273
+ # Benchmark: SELECT by type
274
+ def select_by_type():
275
+ conn = sqlite3.connect(self.test_db)
276
+ cursor = conn.cursor()
277
+ cursor.execute("SELECT * FROM memories WHERE type = 'action' ORDER BY id DESC LIMIT 20")
278
+ _ = cursor.fetchall()
279
+ conn.close()
280
+
281
+ result = self.benchmark_operation("SQLite", "SELECT by type", select_by_type, 100)
282
+ print(f"SELECT by type: {result.mean_ms:.3f}ms mean, {result.p95_ms:.3f}ms p95, {result.ops_per_sec:.0f} ops/sec")
283
+
284
+ # Benchmark: Full-text search (LIKE)
285
+ def fulltext_search():
286
+ conn = sqlite3.connect(self.test_db)
287
+ cursor = conn.cursor()
288
+ cursor.execute("SELECT * FROM memories WHERE content LIKE '%api%' LIMIT 10")
289
+ _ = cursor.fetchall()
290
+ conn.close()
291
+
292
+ result = self.benchmark_operation("SQLite", "LIKE search", fulltext_search, 100)
293
+ print(f"LIKE search: {result.mean_ms:.3f}ms mean, {result.p95_ms:.3f}ms p95, {result.ops_per_sec:.0f} ops/sec")
294
+
295
+ # Benchmark: Knowledge graph query (proposed enhancement)
296
+ # Pre-populate entities
297
+ conn = sqlite3.connect(self.test_db)
298
+ cursor = conn.cursor()
299
+ for i in range(100):
300
+ cursor.execute(
301
+ "INSERT OR IGNORE INTO entities (type, name, first_seen, last_seen) VALUES (?, ?, ?, ?)",
302
+ (
303
+ random.choice(["file", "function", "concept", "error"]),
304
+ f"entity_{i}",
305
+ datetime.utcnow().isoformat(),
306
+ datetime.utcnow().isoformat()
307
+ )
308
+ )
309
+ for i in range(200):
310
+ cursor.execute(
311
+ "INSERT INTO relationships (source_id, target_id, relation, timestamp) VALUES (?, ?, ?, ?)",
312
+ (
313
+ random.randint(1, 100),
314
+ random.randint(1, 100),
315
+ random.choice(["depends_on", "fixes", "causes", "related_to"]),
316
+ datetime.utcnow().isoformat()
317
+ )
318
+ )
319
+ conn.commit()
320
+ conn.close()
321
+
322
+ def graph_query():
323
+ conn = sqlite3.connect(self.test_db)
324
+ cursor = conn.cursor()
325
+ cursor.execute("""
326
+ SELECT e.*, r.relation, e2.name as related
327
+ FROM entities e
328
+ LEFT JOIN relationships r ON e.id = r.source_id
329
+ LEFT JOIN entities e2 ON r.target_id = e2.id
330
+ WHERE e.type = 'file'
331
+ LIMIT 20
332
+ """)
333
+ _ = cursor.fetchall()
334
+ conn.close()
335
+
336
+ result = self.benchmark_operation("SQLite", "Graph query (1-hop)", graph_query, 100)
337
+ print(f"Graph query (1-hop): {result.mean_ms:.3f}ms mean, {result.p95_ms:.3f}ms p95, {result.ops_per_sec:.0f} ops/sec")
338
+
339
+ def run_qdrant_benchmarks(self):
340
+ """Benchmark Qdrant long-term memory operations."""
341
+ if not self.qdrant or not self.model:
342
+ print("\n=== Qdrant Benchmarks SKIPPED (not available) ===")
343
+ return
344
+
345
+ print("\n=== Qdrant Long-term Memory Benchmarks ===\n")
346
+
347
+ if not self.setup_test_qdrant():
348
+ print("Could not setup Qdrant test collection, skipping")
349
+ return
350
+
351
+ # Pre-generate embeddings for batch insert
352
+ test_contents = [self.generate_test_content(200) for _ in range(100)]
353
+
354
+ # Benchmark: Single INSERT with embedding
355
+ idx = [0]
356
+ def insert_single():
357
+ content = test_contents[idx[0] % len(test_contents)]
358
+ embedding = self.model.encode(content).tolist()
359
+ point = PointStruct(
360
+ id=str(uuid.uuid4()),
361
+ vector=embedding,
362
+ payload={
363
+ "type": "lesson",
364
+ "content": content,
365
+ "importance": random.randint(1, 10),
366
+ "timestamp": datetime.utcnow().isoformat()
367
+ }
368
+ )
369
+ self.qdrant.upsert(collection_name=self.test_collection, points=[point])
370
+ idx[0] += 1
371
+
372
+ result = self.benchmark_operation("Qdrant", "INSERT (single + embed)", insert_single, 50)
373
+ print(f"INSERT (single + embed): {result.mean_ms:.3f}ms mean, {result.p95_ms:.3f}ms p95, {result.ops_per_sec:.0f} ops/sec")
374
+
375
+ # Pre-populate for search tests
376
+ points = []
377
+ for i in range(500):
378
+ content = self.generate_test_content(200)
379
+ embedding = self.model.encode(content).tolist()
380
+ points.append(PointStruct(
381
+ id=str(uuid.uuid4()),
382
+ vector=embedding,
383
+ payload={
384
+ "type": random.choice(["fact", "skill", "lesson", "discovery"]),
385
+ "content": content,
386
+ "tags": random.sample(["api", "database", "auth", "cache", "deploy"], 2),
387
+ "importance": random.randint(1, 10),
388
+ "timestamp": datetime.utcnow().isoformat()
389
+ }
390
+ ))
391
+
392
+ # Batch insert
393
+ self.qdrant.upsert(collection_name=self.test_collection, points=points)
394
+
395
+ # Benchmark: Semantic search (just query, no embedding)
396
+ query_embeddings = [self.model.encode(self.generate_test_content(50)).tolist() for _ in range(20)]
397
+ qidx = [0]
398
+
399
+ def semantic_search():
400
+ query_vec = query_embeddings[qidx[0] % len(query_embeddings)]
401
+ results = self.qdrant.query_points(
402
+ collection_name=self.test_collection,
403
+ query=query_vec,
404
+ limit=5
405
+ )
406
+ _ = results.points
407
+ qidx[0] += 1
408
+
409
+ result = self.benchmark_operation("Qdrant", "Semantic search (top-5)", semantic_search, 100)
410
+ print(f"Semantic search (top-5): {result.mean_ms:.3f}ms mean, {result.p95_ms:.3f}ms p95, {result.ops_per_sec:.0f} ops/sec")
411
+
412
+ # Benchmark: Search with filter
413
+ def filtered_search():
414
+ query_vec = query_embeddings[qidx[0] % len(query_embeddings)]
415
+ from qdrant_client.models import Filter, FieldCondition, MatchValue
416
+ results = self.qdrant.query_points(
417
+ collection_name=self.test_collection,
418
+ query=query_vec,
419
+ query_filter=Filter(
420
+ must=[FieldCondition(key="importance", match=MatchValue(value=8))]
421
+ ),
422
+ limit=5
423
+ )
424
+ _ = results.points
425
+ qidx[0] += 1
426
+
427
+ result = self.benchmark_operation("Qdrant", "Filtered search", filtered_search, 100)
428
+ print(f"Filtered search: {result.mean_ms:.3f}ms mean, {result.p95_ms:.3f}ms p95, {result.ops_per_sec:.0f} ops/sec")
429
+
430
+ # Benchmark: Embedding generation (major latency component)
431
+ def generate_embedding():
432
+ content = self.generate_test_content(200)
433
+ _ = self.model.encode(content)
434
+
435
+ result = self.benchmark_operation("Embedding", "Generate (all-MiniLM-L6-v2)", generate_embedding, 100)
436
+ print(f"Embedding generation: {result.mean_ms:.3f}ms mean, {result.p95_ms:.3f}ms p95, {result.ops_per_sec:.0f} ops/sec")
437
+
438
+ def run_consolidation_benchmark(self):
439
+ """Benchmark memory consolidation operations (proposed enhancement)."""
440
+ print("\n=== Memory Consolidation Benchmarks ===\n")
441
+
442
+ import hashlib
443
+
444
+ # Simulate consolidation logic
445
+ test_memories = [
446
+ {"type": "action", "content": self.generate_test_content(200)}
447
+ for _ in range(50)
448
+ ]
449
+
450
+ def consolidate_simple():
451
+ """Simple consolidation: extract key facts."""
452
+ facts = []
453
+ for mem in test_memories:
454
+ if any(kw in mem["content"].lower() for kw in ["fixed", "resolved", "created"]):
455
+ facts.append({
456
+ "type": "lesson",
457
+ "content": mem["content"][:100],
458
+ "hash": hashlib.md5(mem["content"].encode()).hexdigest()[:16]
459
+ })
460
+ # Deduplicate by hash
461
+ seen = set()
462
+ unique = []
463
+ for f in facts:
464
+ if f["hash"] not in seen:
465
+ seen.add(f["hash"])
466
+ unique.append(f)
467
+ return unique
468
+
469
+ result = self.benchmark_operation("Consolidation", "Simple extraction", consolidate_simple, 100)
470
+ print(f"Simple extraction: {result.mean_ms:.3f}ms mean, {result.p95_ms:.3f}ms p95, {result.ops_per_sec:.0f} ops/sec")
471
+
472
+ # Simulate deduplication with embedding similarity
473
+ if self.model:
474
+ def consolidate_with_similarity():
475
+ """Consolidation with semantic deduplication."""
476
+ facts = []
477
+ for mem in test_memories[:10]: # Limit for speed
478
+ embedding = self.model.encode(mem["content"])
479
+ facts.append({
480
+ "content": mem["content"],
481
+ "embedding": embedding
482
+ })
483
+
484
+ # Check pairwise similarity
485
+ import numpy as np
486
+ unique = [facts[0]]
487
+ for f in facts[1:]:
488
+ is_dup = False
489
+ for u in unique:
490
+ sim = np.dot(f["embedding"], u["embedding"]) / (
491
+ np.linalg.norm(f["embedding"]) * np.linalg.norm(u["embedding"])
492
+ )
493
+ if sim > 0.92:
494
+ is_dup = True
495
+ break
496
+ if not is_dup:
497
+ unique.append(f)
498
+ return unique
499
+
500
+ result = self.benchmark_operation("Consolidation", "Semantic dedup", consolidate_with_similarity, 20)
501
+ print(f"Semantic dedup: {result.mean_ms:.3f}ms mean, {result.p95_ms:.3f}ms p95, {result.ops_per_sec:.0f} ops/sec")
502
+
503
+ def run_scalability_test(self):
504
+ """Test performance at different scales."""
505
+ print("\n=== Scalability Tests ===\n")
506
+
507
+ scales = [100, 1000, 5000]
508
+
509
+ for scale in scales:
510
+ # Setup fresh database
511
+ self.setup_test_sqlite()
512
+
513
+ # Populate
514
+ conn = sqlite3.connect(self.test_db)
515
+ cursor = conn.cursor()
516
+ for i in range(scale):
517
+ cursor.execute(
518
+ "INSERT INTO memories (timestamp, type, content) VALUES (?, ?, ?)",
519
+ (datetime.utcnow().isoformat(), "action", self.generate_test_content(200))
520
+ )
521
+ conn.commit()
522
+ conn.close()
523
+
524
+ # Benchmark at this scale
525
+ def select_recent():
526
+ conn = sqlite3.connect(self.test_db)
527
+ cursor = conn.cursor()
528
+ cursor.execute("SELECT * FROM memories ORDER BY id DESC LIMIT 50")
529
+ _ = cursor.fetchall()
530
+ conn.close()
531
+
532
+ result = self.benchmark_operation(f"SQLite@{scale}", "SELECT recent", select_recent, 50)
533
+ print(f"SQLite @ {scale} rows: SELECT recent = {result.mean_ms:.3f}ms mean, {result.p95_ms:.3f}ms p95")
534
+
535
+ def generate_report(self) -> str:
536
+ """Generate markdown report of all benchmarks."""
537
+ report = [
538
+ "# Memory Systems Benchmark Report",
539
+ f"\n**Generated:** {datetime.utcnow().isoformat()}Z",
540
+ f"**System:** Pay2U Memory Implementation",
541
+ "",
542
+ "## Summary",
543
+ "",
544
+ "| System | Operation | Mean (ms) | P95 (ms) | Ops/sec |",
545
+ "|--------|-----------|-----------|----------|---------|"
546
+ ]
547
+
548
+ for r in self.results:
549
+ report.append(f"| {r.name} | {r.operation} | {r.mean_ms:.3f} | {r.p95_ms:.3f} | {r.ops_per_sec:.0f} |")
550
+
551
+ report.extend([
552
+ "",
553
+ "## Key Findings",
554
+ "",
555
+ "### Short-term Memory (SQLite)",
556
+ "- Single INSERT operations are extremely fast (<0.5ms)",
557
+ "- SELECT with ORDER BY and LIMIT scales well",
558
+ "- Knowledge graph queries (1-hop) add minimal overhead",
559
+ "",
560
+ "### Long-term Memory (Qdrant)",
561
+ "- Embedding generation is the main latency contributor",
562
+ "- Semantic search is fast once vectors exist (~50-100ms)",
563
+ "- Filtering adds minimal overhead",
564
+ "",
565
+ "### Consolidation",
566
+ "- Simple extraction is very fast (<1ms)",
567
+ "- Semantic deduplication adds significant latency (~100-500ms)",
568
+ "- Recommendation: Use hash-based dedup, semantic only for high-importance",
569
+ "",
570
+ "## Recommendations",
571
+ "",
572
+ "1. **Keep SQLite for short-term**: Performance is excellent",
573
+ "2. **Batch Qdrant operations**: Reduce per-operation overhead",
574
+ "3. **Cache embeddings**: Avoid regenerating for known content",
575
+ "4. **Use hybrid dedup**: Hash first, semantic for borderline cases",
576
+ "5. **Add session memory layer**: Low overhead, high value",
577
+ ])
578
+
579
+ return "\n".join(report)
580
+
581
+ def save_results(self):
582
+ """Save benchmark results to files."""
583
+ # JSON results
584
+ json_results = [
585
+ {
586
+ "name": r.name,
587
+ "operation": r.operation,
588
+ "samples": r.samples,
589
+ "mean_ms": r.mean_ms,
590
+ "median_ms": r.median_ms,
591
+ "p95_ms": r.p95_ms,
592
+ "p99_ms": r.p99_ms,
593
+ "min_ms": r.min_ms,
594
+ "max_ms": r.max_ms,
595
+ "ops_per_sec": r.ops_per_sec
596
+ }
597
+ for r in self.results
598
+ ]
599
+
600
+ timestamp = datetime.utcnow().strftime("%Y%m%d_%H%M%S")
601
+
602
+ with open(self.results_dir / f"benchmark_{timestamp}.json", "w") as f:
603
+ json.dump(json_results, f, indent=2)
604
+
605
+ # Markdown report
606
+ report = self.generate_report()
607
+ with open(self.results_dir / f"benchmark_{timestamp}.md", "w") as f:
608
+ f.write(report)
609
+
610
+ print(f"\nResults saved to: {self.results_dir}")
611
+
612
+ def run_all(self):
613
+ """Run all benchmarks."""
614
+ print("=" * 60)
615
+ print(" PAY2U MEMORY SYSTEMS BENCHMARK SUITE")
616
+ print("=" * 60)
617
+
618
+ self.run_sqlite_benchmarks()
619
+ self.run_qdrant_benchmarks()
620
+ self.run_consolidation_benchmark()
621
+ self.run_scalability_test()
622
+
623
+ print("\n" + "=" * 60)
624
+ print(" BENCHMARK COMPLETE")
625
+ print("=" * 60)
626
+
627
+ self.save_results()
628
+ print("\n" + self.generate_report())
629
+
630
+
631
+ def main():
632
+ benchmark = MemoryBenchmark()
633
+ benchmark.run_all()
634
+
635
+
636
+ if __name__ == "__main__":
637
+ main()