@opensearch-project/agent-health 0.3.0 → 0.5.2

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 (518) hide show
  1. package/README.md +77 -6
  2. package/cli/dist/index.js +10072 -4502
  3. package/deployment/cloudformation/agent-health-observability.yaml +762 -0
  4. package/dist/assets/index-CCQRDlO0.js +243 -0
  5. package/dist/assets/index-CNHQVbcj.css +1 -0
  6. package/dist/index.html +2 -2
  7. package/docs/ARCHITECTURE.md +450 -0
  8. package/docs/BACKEND_JOB_QUEUE.md +405 -0
  9. package/docs/CLAUDE_CODE_TELEMETRY.md +283 -0
  10. package/docs/CLI.md +431 -0
  11. package/docs/CODING_AGENT_ANALYTICS.md +298 -0
  12. package/docs/CONFIGURATION.md +388 -0
  13. package/docs/CONNECTORS.md +536 -0
  14. package/docs/INSTRUMENT_WITH_OTEL.md +390 -0
  15. package/docs/ML-COMMONS-SETUP.md +289 -0
  16. package/docs/NPX_PACKAGING.md +195 -0
  17. package/docs/PERFORMANCE-MONITORING.md +200 -0
  18. package/docs/PERFORMANCE.md +390 -0
  19. package/docs/PI_PROFILING.md +169 -0
  20. package/docs/PLAN-non-agui-agent-support.md +525 -0
  21. package/docs/SDK.md +577 -0
  22. package/docs/SKILLS.md +264 -0
  23. package/docs/blogs/2026-02-28-opensearch-agent-health.md +200 -0
  24. package/docs/blogs/getting-started-blog.md +608 -0
  25. package/docs/diagrams/Agent-health.excalidraw +5656 -0
  26. package/docs/diagrams/architecture.png +0 -0
  27. package/docs/plans/field-redesign.md +468 -0
  28. package/docs/rfcs/001-coding-agent-analytics.md +374 -0
  29. package/docs/rfcs/002-enterprise-leaderboard.md +267 -0
  30. package/docs/rfcs/003-remote-aggregation.md +146 -0
  31. package/docs/rfcs/004-test-sdk-v2.md +599 -0
  32. package/docs/skills/AGENT_HEALTH.md +598 -0
  33. package/docs/skills/AGENT_PROFILE.md +191 -0
  34. package/docs/skills/add-connector/SKILL.md +68 -0
  35. package/docs/skills/agent-health-profile/SKILL.md +40 -0
  36. package/docs/skills/config-auth/SKILL.md +194 -0
  37. package/docs/skills/config-auth/evals/evals.json +35 -0
  38. package/docs/skills/create-pr/SKILL.md +73 -0
  39. package/docs/skills/instrument-otel/SKILL.md +84 -0
  40. package/docs/skills/write-test/SKILL.md +124 -0
  41. package/docs/ui prd.md +376 -0
  42. package/examples/README.md +53 -0
  43. package/examples/config/agent-health.config.example.ts +155 -0
  44. package/examples/connectors/echo-connector.ts +131 -0
  45. package/examples/eval-files/demo.eval.js +128 -0
  46. package/examples/eval-files/sdk-hooks-demo.eval.js +99 -0
  47. package/examples/pi-profiling/README.md +77 -0
  48. package/examples/pi-profiling/agent-health-profile.ts +417 -0
  49. package/lib/dist/lib/agentUtils.d.ts +29 -0
  50. package/lib/dist/lib/agentUtils.d.ts.map +1 -0
  51. package/lib/dist/lib/agentUtils.js +43 -0
  52. package/lib/dist/lib/agentUtils.js.map +1 -0
  53. package/lib/dist/lib/benchmarkExport.d.ts +14 -0
  54. package/lib/dist/lib/benchmarkExport.d.ts.map +1 -0
  55. package/lib/dist/lib/benchmarkExport.js +41 -0
  56. package/lib/dist/lib/benchmarkExport.js.map +1 -0
  57. package/lib/dist/lib/benchmarkVersionUtils.d.ts +37 -0
  58. package/lib/dist/lib/benchmarkVersionUtils.d.ts.map +1 -0
  59. package/lib/dist/lib/benchmarkVersionUtils.js +68 -0
  60. package/lib/dist/lib/benchmarkVersionUtils.js.map +1 -0
  61. package/lib/dist/lib/config/defineConfig.d.ts +27 -0
  62. package/lib/dist/lib/config/defineConfig.d.ts.map +1 -0
  63. package/lib/dist/lib/config/defineConfig.js +28 -0
  64. package/lib/dist/lib/config/defineConfig.js.map +1 -0
  65. package/lib/dist/lib/config/index.d.ts +9 -0
  66. package/lib/dist/lib/config/index.d.ts.map +1 -0
  67. package/lib/dist/lib/config/index.js +8 -0
  68. package/lib/dist/lib/config/index.js.map +1 -0
  69. package/lib/dist/lib/config/loader.d.ts +39 -0
  70. package/lib/dist/lib/config/loader.d.ts.map +1 -0
  71. package/lib/dist/lib/config/loader.js +258 -0
  72. package/lib/dist/lib/config/loader.js.map +1 -0
  73. package/lib/dist/lib/config/statePaths.d.ts +61 -0
  74. package/lib/dist/lib/config/statePaths.d.ts.map +1 -0
  75. package/lib/dist/lib/config/statePaths.js +188 -0
  76. package/lib/dist/lib/config/statePaths.js.map +1 -0
  77. package/lib/dist/lib/config/types.d.ts +231 -0
  78. package/lib/dist/lib/config/types.d.ts.map +1 -0
  79. package/lib/dist/lib/config/types.js +6 -0
  80. package/lib/dist/lib/config/types.js.map +1 -0
  81. package/lib/dist/lib/config.d.ts +39 -0
  82. package/lib/dist/lib/config.d.ts.map +1 -0
  83. package/lib/dist/lib/config.js +118 -0
  84. package/lib/dist/lib/config.js.map +1 -0
  85. package/lib/dist/lib/constants.d.ts +70 -0
  86. package/lib/dist/lib/constants.d.ts.map +1 -0
  87. package/lib/dist/lib/constants.js +365 -0
  88. package/lib/dist/lib/constants.js.map +1 -0
  89. package/lib/dist/lib/contextUtilization.d.ts +23 -0
  90. package/lib/dist/lib/contextUtilization.d.ts.map +1 -0
  91. package/lib/dist/lib/contextUtilization.js +72 -0
  92. package/lib/dist/lib/contextUtilization.js.map +1 -0
  93. package/lib/dist/lib/dashboardMetrics.d.ts +87 -0
  94. package/lib/dist/lib/dashboardMetrics.d.ts.map +1 -0
  95. package/lib/dist/lib/dashboardMetrics.js +242 -0
  96. package/lib/dist/lib/dashboardMetrics.js.map +1 -0
  97. package/lib/dist/lib/dataSourceConfig.d.ts +108 -0
  98. package/lib/dist/lib/dataSourceConfig.d.ts.map +1 -0
  99. package/lib/dist/lib/dataSourceConfig.js +166 -0
  100. package/lib/dist/lib/dataSourceConfig.js.map +1 -0
  101. package/lib/dist/lib/debug.d.ts +26 -0
  102. package/lib/dist/lib/debug.d.ts.map +1 -0
  103. package/lib/dist/lib/debug.js +132 -0
  104. package/lib/dist/lib/debug.js.map +1 -0
  105. package/lib/dist/lib/diagnostics.d.ts +28 -0
  106. package/lib/dist/lib/diagnostics.d.ts.map +1 -0
  107. package/lib/dist/lib/diagnostics.js +65 -0
  108. package/lib/dist/lib/diagnostics.js.map +1 -0
  109. package/lib/dist/lib/envCompat.d.ts +27 -0
  110. package/lib/dist/lib/envCompat.d.ts.map +1 -0
  111. package/lib/dist/lib/envCompat.js +73 -0
  112. package/lib/dist/lib/envCompat.js.map +1 -0
  113. package/lib/dist/lib/findPackageRoot.d.ts +7 -0
  114. package/lib/dist/lib/findPackageRoot.d.ts.map +1 -0
  115. package/lib/dist/lib/findPackageRoot.js +57 -0
  116. package/lib/dist/lib/findPackageRoot.js.map +1 -0
  117. package/lib/dist/lib/hooks.d.ts +36 -0
  118. package/lib/dist/lib/hooks.d.ts.map +1 -0
  119. package/lib/dist/lib/hooks.js +112 -0
  120. package/lib/dist/lib/hooks.js.map +1 -0
  121. package/lib/dist/lib/index.d.ts +47 -0
  122. package/lib/dist/lib/index.d.ts.map +1 -0
  123. package/lib/dist/lib/index.js +62 -0
  124. package/lib/dist/lib/index.js.map +1 -0
  125. package/lib/dist/lib/labels.d.ts +90 -0
  126. package/lib/dist/lib/labels.d.ts.map +1 -0
  127. package/lib/dist/lib/labels.js +158 -0
  128. package/lib/dist/lib/labels.js.map +1 -0
  129. package/lib/dist/lib/markdown.d.ts +16 -0
  130. package/lib/dist/lib/markdown.d.ts.map +1 -0
  131. package/lib/dist/lib/markdown.js +42 -0
  132. package/lib/dist/lib/markdown.js.map +1 -0
  133. package/lib/dist/lib/matchers/expect.d.ts +3 -0
  134. package/lib/dist/lib/matchers/expect.d.ts.map +1 -0
  135. package/lib/dist/lib/matchers/expect.js +225 -0
  136. package/lib/dist/lib/matchers/expect.js.map +1 -0
  137. package/lib/dist/lib/matchers/index.d.ts +8 -0
  138. package/lib/dist/lib/matchers/index.d.ts.map +1 -0
  139. package/lib/dist/lib/matchers/index.js +9 -0
  140. package/lib/dist/lib/matchers/index.js.map +1 -0
  141. package/lib/dist/lib/matchers/judgeAccessor.d.ts +113 -0
  142. package/lib/dist/lib/matchers/judgeAccessor.d.ts.map +1 -0
  143. package/lib/dist/lib/matchers/judgeAccessor.js +183 -0
  144. package/lib/dist/lib/matchers/judgeAccessor.js.map +1 -0
  145. package/lib/dist/lib/matchers/session.d.ts +39 -0
  146. package/lib/dist/lib/matchers/session.d.ts.map +1 -0
  147. package/lib/dist/lib/matchers/session.js +116 -0
  148. package/lib/dist/lib/matchers/session.js.map +1 -0
  149. package/lib/dist/lib/matchers/traces.d.ts +55 -0
  150. package/lib/dist/lib/matchers/traces.d.ts.map +1 -0
  151. package/lib/dist/lib/matchers/traces.js +116 -0
  152. package/lib/dist/lib/matchers/traces.js.map +1 -0
  153. package/lib/dist/lib/matchers/types.d.ts +75 -0
  154. package/lib/dist/lib/matchers/types.d.ts.map +1 -0
  155. package/lib/dist/lib/matchers/types.js +6 -0
  156. package/lib/dist/lib/matchers/types.js.map +1 -0
  157. package/lib/dist/lib/packagePaths.d.ts +29 -0
  158. package/lib/dist/lib/packagePaths.d.ts.map +1 -0
  159. package/lib/dist/lib/packagePaths.js +63 -0
  160. package/lib/dist/lib/packagePaths.js.map +1 -0
  161. package/lib/dist/lib/performance.d.ts +51 -0
  162. package/lib/dist/lib/performance.d.ts.map +1 -0
  163. package/lib/dist/lib/performance.js +159 -0
  164. package/lib/dist/lib/performance.js.map +1 -0
  165. package/lib/dist/lib/portConfig.d.ts +29 -0
  166. package/lib/dist/lib/portConfig.d.ts.map +1 -0
  167. package/lib/dist/lib/portConfig.js +64 -0
  168. package/lib/dist/lib/portConfig.js.map +1 -0
  169. package/lib/dist/lib/preferences.d.ts +63 -0
  170. package/lib/dist/lib/preferences.d.ts.map +1 -0
  171. package/lib/dist/lib/preferences.js +117 -0
  172. package/lib/dist/lib/preferences.js.map +1 -0
  173. package/lib/dist/lib/resolveAgentModel.d.ts +22 -0
  174. package/lib/dist/lib/resolveAgentModel.d.ts.map +1 -0
  175. package/lib/dist/lib/resolveAgentModel.js +37 -0
  176. package/lib/dist/lib/resolveAgentModel.js.map +1 -0
  177. package/lib/dist/lib/runStats.d.ts +92 -0
  178. package/lib/dist/lib/runStats.d.ts.map +1 -0
  179. package/lib/dist/lib/runStats.js +160 -0
  180. package/lib/dist/lib/runStats.js.map +1 -0
  181. package/lib/dist/lib/telemetry/constants.d.ts +60 -0
  182. package/lib/dist/lib/telemetry/constants.d.ts.map +1 -0
  183. package/lib/dist/lib/telemetry/constants.js +87 -0
  184. package/lib/dist/lib/telemetry/constants.js.map +1 -0
  185. package/lib/dist/lib/telemetry/evalSpans.d.ts +61 -0
  186. package/lib/dist/lib/telemetry/evalSpans.d.ts.map +1 -0
  187. package/lib/dist/lib/telemetry/evalSpans.js +254 -0
  188. package/lib/dist/lib/telemetry/evalSpans.js.map +1 -0
  189. package/lib/dist/lib/telemetry/index.d.ts +11 -0
  190. package/lib/dist/lib/telemetry/index.d.ts.map +1 -0
  191. package/lib/dist/lib/telemetry/index.js +15 -0
  192. package/lib/dist/lib/telemetry/index.js.map +1 -0
  193. package/lib/dist/lib/telemetry/opensearchExporter.d.ts +43 -0
  194. package/lib/dist/lib/telemetry/opensearchExporter.d.ts.map +1 -0
  195. package/lib/dist/lib/telemetry/opensearchExporter.js +217 -0
  196. package/lib/dist/lib/telemetry/opensearchExporter.js.map +1 -0
  197. package/lib/dist/lib/telemetry/provider.d.ts +55 -0
  198. package/lib/dist/lib/telemetry/provider.d.ts.map +1 -0
  199. package/lib/dist/lib/telemetry/provider.js +140 -0
  200. package/lib/dist/lib/telemetry/provider.js.map +1 -0
  201. package/lib/dist/lib/testCaseLabels.d.ts +34 -0
  202. package/lib/dist/lib/testCaseLabels.d.ts.map +1 -0
  203. package/lib/dist/lib/testCaseLabels.js +88 -0
  204. package/lib/dist/lib/testCaseLabels.js.map +1 -0
  205. package/lib/dist/lib/testCaseValidation.d.ts +140 -0
  206. package/lib/dist/lib/testCaseValidation.d.ts.map +1 -0
  207. package/lib/dist/lib/testCaseValidation.js +162 -0
  208. package/lib/dist/lib/testCaseValidation.js.map +1 -0
  209. package/lib/dist/lib/testCases/agentFixture.d.ts +80 -0
  210. package/lib/dist/lib/testCases/agentFixture.d.ts.map +1 -0
  211. package/lib/dist/lib/testCases/agentFixture.js +43 -0
  212. package/lib/dist/lib/testCases/agentFixture.js.map +1 -0
  213. package/lib/dist/lib/testCases/authoringSurface.d.ts +10 -0
  214. package/lib/dist/lib/testCases/authoringSurface.d.ts.map +1 -0
  215. package/lib/dist/lib/testCases/authoringSurface.js +54 -0
  216. package/lib/dist/lib/testCases/authoringSurface.js.map +1 -0
  217. package/lib/dist/lib/testCases/codemod.d.ts +13 -0
  218. package/lib/dist/lib/testCases/codemod.d.ts.map +1 -0
  219. package/lib/dist/lib/testCases/codemod.js +169 -0
  220. package/lib/dist/lib/testCases/codemod.js.map +1 -0
  221. package/lib/dist/lib/testCases/define.d.ts +114 -0
  222. package/lib/dist/lib/testCases/define.d.ts.map +1 -0
  223. package/lib/dist/lib/testCases/define.js +253 -0
  224. package/lib/dist/lib/testCases/define.js.map +1 -0
  225. package/lib/dist/lib/testCases/evaluators.d.ts +80 -0
  226. package/lib/dist/lib/testCases/evaluators.d.ts.map +1 -0
  227. package/lib/dist/lib/testCases/evaluators.js +105 -0
  228. package/lib/dist/lib/testCases/evaluators.js.map +1 -0
  229. package/lib/dist/lib/testCases/index.d.ts +14 -0
  230. package/lib/dist/lib/testCases/index.d.ts.map +1 -0
  231. package/lib/dist/lib/testCases/index.js +12 -0
  232. package/lib/dist/lib/testCases/index.js.map +1 -0
  233. package/lib/dist/lib/testCases/judge.d.ts +165 -0
  234. package/lib/dist/lib/testCases/judge.d.ts.map +1 -0
  235. package/lib/dist/lib/testCases/judge.js +359 -0
  236. package/lib/dist/lib/testCases/judge.js.map +1 -0
  237. package/lib/dist/lib/testCases/loader.d.ts +26 -0
  238. package/lib/dist/lib/testCases/loader.d.ts.map +1 -0
  239. package/lib/dist/lib/testCases/loader.js +149 -0
  240. package/lib/dist/lib/testCases/loader.js.map +1 -0
  241. package/lib/dist/lib/testCases/types.d.ts +242 -0
  242. package/lib/dist/lib/testCases/types.d.ts.map +1 -0
  243. package/lib/dist/lib/testCases/types.js +6 -0
  244. package/lib/dist/lib/testCases/types.js.map +1 -0
  245. package/lib/dist/lib/theme.d.ts +6 -0
  246. package/lib/dist/lib/theme.d.ts.map +1 -0
  247. package/lib/dist/lib/theme.js +36 -0
  248. package/lib/dist/lib/theme.js.map +1 -0
  249. package/lib/dist/lib/uiTelemetry.d.ts +7 -0
  250. package/lib/dist/lib/uiTelemetry.d.ts.map +1 -0
  251. package/lib/dist/lib/uiTelemetry.js +25 -0
  252. package/lib/dist/lib/uiTelemetry.js.map +1 -0
  253. package/lib/dist/lib/utils.d.ts +96 -0
  254. package/lib/dist/lib/utils.d.ts.map +1 -0
  255. package/lib/dist/lib/utils.js +232 -0
  256. package/lib/dist/lib/utils.js.map +1 -0
  257. package/lib/dist/lib/workflow/consolidate.d.ts +12 -0
  258. package/lib/dist/lib/workflow/consolidate.d.ts.map +1 -0
  259. package/lib/dist/lib/workflow/consolidate.js +33 -0
  260. package/lib/dist/lib/workflow/consolidate.js.map +1 -0
  261. package/lib/dist/lib/workflow/index.d.ts +13 -0
  262. package/lib/dist/lib/workflow/index.d.ts.map +1 -0
  263. package/lib/dist/lib/workflow/index.js +12 -0
  264. package/lib/dist/lib/workflow/index.js.map +1 -0
  265. package/lib/dist/lib/workflow/ledger.d.ts +30 -0
  266. package/lib/dist/lib/workflow/ledger.d.ts.map +1 -0
  267. package/lib/dist/lib/workflow/ledger.js +41 -0
  268. package/lib/dist/lib/workflow/ledger.js.map +1 -0
  269. package/lib/dist/lib/workflow/pool.d.ts +13 -0
  270. package/lib/dist/lib/workflow/pool.d.ts.map +1 -0
  271. package/lib/dist/lib/workflow/pool.js +44 -0
  272. package/lib/dist/lib/workflow/pool.js.map +1 -0
  273. package/lib/dist/lib/workflow/source.d.ts +22 -0
  274. package/lib/dist/lib/workflow/source.d.ts.map +1 -0
  275. package/lib/dist/lib/workflow/source.js +29 -0
  276. package/lib/dist/lib/workflow/source.js.map +1 -0
  277. package/lib/dist/lib/workflow/stepB.d.ts +71 -0
  278. package/lib/dist/lib/workflow/stepB.d.ts.map +1 -0
  279. package/lib/dist/lib/workflow/stepB.js +99 -0
  280. package/lib/dist/lib/workflow/stepB.js.map +1 -0
  281. package/lib/dist/lib/workflow/types.d.ts +86 -0
  282. package/lib/dist/lib/workflow/types.d.ts.map +1 -0
  283. package/lib/dist/lib/workflow/types.js +6 -0
  284. package/lib/dist/lib/workflow/types.js.map +1 -0
  285. package/lib/dist/lib/workflow/workflow.d.ts +119 -0
  286. package/lib/dist/lib/workflow/workflow.d.ts.map +1 -0
  287. package/lib/dist/lib/workflow/workflow.js +195 -0
  288. package/lib/dist/lib/workflow/workflow.js.map +1 -0
  289. package/lib/dist/services/agent/aguiConverter.d.ts +50 -0
  290. package/lib/dist/services/agent/aguiConverter.d.ts.map +1 -0
  291. package/lib/dist/services/agent/aguiConverter.js +449 -0
  292. package/lib/dist/services/agent/aguiConverter.js.map +1 -0
  293. package/lib/dist/services/agent/index.d.ts +10 -0
  294. package/lib/dist/services/agent/index.d.ts.map +1 -0
  295. package/lib/dist/services/agent/index.js +12 -0
  296. package/lib/dist/services/agent/index.js.map +1 -0
  297. package/lib/dist/services/agent/payloadBuilder.d.ts +33 -0
  298. package/lib/dist/services/agent/payloadBuilder.d.ts.map +1 -0
  299. package/lib/dist/services/agent/payloadBuilder.js +75 -0
  300. package/lib/dist/services/agent/payloadBuilder.js.map +1 -0
  301. package/lib/dist/services/agent/sseStream.d.ts +43 -0
  302. package/lib/dist/services/agent/sseStream.d.ts.map +1 -0
  303. package/lib/dist/services/agent/sseStream.js +223 -0
  304. package/lib/dist/services/agent/sseStream.js.map +1 -0
  305. package/lib/dist/services/connectors/agui/AGUIStreamingConnector.d.ts +44 -0
  306. package/lib/dist/services/connectors/agui/AGUIStreamingConnector.d.ts.map +1 -0
  307. package/lib/dist/services/connectors/agui/AGUIStreamingConnector.js +95 -0
  308. package/lib/dist/services/connectors/agui/AGUIStreamingConnector.js.map +1 -0
  309. package/lib/dist/services/connectors/base/BaseConnector.d.ts +81 -0
  310. package/lib/dist/services/connectors/base/BaseConnector.d.ts.map +1 -0
  311. package/lib/dist/services/connectors/base/BaseConnector.js +170 -0
  312. package/lib/dist/services/connectors/base/BaseConnector.js.map +1 -0
  313. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.d.ts +116 -0
  314. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.d.ts.map +1 -0
  315. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.js +403 -0
  316. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.js.map +1 -0
  317. package/lib/dist/services/connectors/index.d.ts +13 -0
  318. package/lib/dist/services/connectors/index.d.ts.map +1 -0
  319. package/lib/dist/services/connectors/index.js +32 -0
  320. package/lib/dist/services/connectors/index.js.map +1 -0
  321. package/lib/dist/services/connectors/kiro/KiroConnector.d.ts +48 -0
  322. package/lib/dist/services/connectors/kiro/KiroConnector.d.ts.map +1 -0
  323. package/lib/dist/services/connectors/kiro/KiroConnector.js +158 -0
  324. package/lib/dist/services/connectors/kiro/KiroConnector.js.map +1 -0
  325. package/lib/dist/services/connectors/langgraph/LangGraphConnector.d.ts +36 -0
  326. package/lib/dist/services/connectors/langgraph/LangGraphConnector.d.ts.map +1 -0
  327. package/lib/dist/services/connectors/langgraph/LangGraphConnector.js +175 -0
  328. package/lib/dist/services/connectors/langgraph/LangGraphConnector.js.map +1 -0
  329. package/lib/dist/services/connectors/mock/MockConnector.d.ts +37 -0
  330. package/lib/dist/services/connectors/mock/MockConnector.d.ts.map +1 -0
  331. package/lib/dist/services/connectors/mock/MockConnector.js +120 -0
  332. package/lib/dist/services/connectors/mock/MockConnector.js.map +1 -0
  333. package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.d.ts +42 -0
  334. package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.d.ts.map +1 -0
  335. package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.js +133 -0
  336. package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.js.map +1 -0
  337. package/lib/dist/services/connectors/pi/PiConnector.d.ts +87 -0
  338. package/lib/dist/services/connectors/pi/PiConnector.d.ts.map +1 -0
  339. package/lib/dist/services/connectors/pi/PiConnector.js +274 -0
  340. package/lib/dist/services/connectors/pi/PiConnector.js.map +1 -0
  341. package/lib/dist/services/connectors/registry.d.ts +57 -0
  342. package/lib/dist/services/connectors/registry.d.ts.map +1 -0
  343. package/lib/dist/services/connectors/registry.js +106 -0
  344. package/lib/dist/services/connectors/registry.js.map +1 -0
  345. package/lib/dist/services/connectors/rest/RESTConnector.d.ts +38 -0
  346. package/lib/dist/services/connectors/rest/RESTConnector.d.ts.map +1 -0
  347. package/lib/dist/services/connectors/rest/RESTConnector.js +117 -0
  348. package/lib/dist/services/connectors/rest/RESTConnector.js.map +1 -0
  349. package/lib/dist/services/connectors/server.d.ts +13 -0
  350. package/lib/dist/services/connectors/server.d.ts.map +1 -0
  351. package/lib/dist/services/connectors/server.js +34 -0
  352. package/lib/dist/services/connectors/server.js.map +1 -0
  353. package/lib/dist/services/connectors/strands/StrandsConnector.d.ts +48 -0
  354. package/lib/dist/services/connectors/strands/StrandsConnector.d.ts.map +1 -0
  355. package/lib/dist/services/connectors/strands/StrandsConnector.js +221 -0
  356. package/lib/dist/services/connectors/strands/StrandsConnector.js.map +1 -0
  357. package/lib/dist/services/connectors/subprocess/SubprocessConnector.d.ts +88 -0
  358. package/lib/dist/services/connectors/subprocess/SubprocessConnector.d.ts.map +1 -0
  359. package/lib/dist/services/connectors/subprocess/SubprocessConnector.js +418 -0
  360. package/lib/dist/services/connectors/subprocess/SubprocessConnector.js.map +1 -0
  361. package/lib/dist/services/connectors/types.d.ts +213 -0
  362. package/lib/dist/services/connectors/types.d.ts.map +1 -0
  363. package/lib/dist/services/connectors/types.js +6 -0
  364. package/lib/dist/services/connectors/types.js.map +1 -0
  365. package/lib/dist/services/evaluation/bedrockJudge.d.ts +64 -0
  366. package/lib/dist/services/evaluation/bedrockJudge.d.ts.map +1 -0
  367. package/lib/dist/services/evaluation/bedrockJudge.js +167 -0
  368. package/lib/dist/services/evaluation/bedrockJudge.js.map +1 -0
  369. package/lib/dist/services/evaluation/evaluatorError.d.ts +56 -0
  370. package/lib/dist/services/evaluation/evaluatorError.d.ts.map +1 -0
  371. package/lib/dist/services/evaluation/evaluatorError.js +56 -0
  372. package/lib/dist/services/evaluation/evaluatorError.js.map +1 -0
  373. package/lib/dist/services/evaluation/index.d.ts +106 -0
  374. package/lib/dist/services/evaluation/index.d.ts.map +1 -0
  375. package/lib/dist/services/evaluation/index.js +684 -0
  376. package/lib/dist/services/evaluation/index.js.map +1 -0
  377. package/lib/dist/services/evaluation/mockTrajectory.d.ts +3 -0
  378. package/lib/dist/services/evaluation/mockTrajectory.d.ts.map +1 -0
  379. package/lib/dist/services/evaluation/mockTrajectory.js +72 -0
  380. package/lib/dist/services/evaluation/mockTrajectory.js.map +1 -0
  381. package/lib/dist/services/opensearch/client.d.ts +26 -0
  382. package/lib/dist/services/opensearch/client.d.ts.map +1 -0
  383. package/lib/dist/services/opensearch/client.js +131 -0
  384. package/lib/dist/services/opensearch/client.js.map +1 -0
  385. package/lib/dist/services/opensearch/index.d.ts +16 -0
  386. package/lib/dist/services/opensearch/index.d.ts.map +1 -0
  387. package/lib/dist/services/opensearch/index.js +25 -0
  388. package/lib/dist/services/opensearch/index.js.map +1 -0
  389. package/lib/dist/services/storage/asyncBenchmarkStorage.d.ts +123 -0
  390. package/lib/dist/services/storage/asyncBenchmarkStorage.d.ts.map +1 -0
  391. package/lib/dist/services/storage/asyncBenchmarkStorage.js +429 -0
  392. package/lib/dist/services/storage/asyncBenchmarkStorage.js.map +1 -0
  393. package/lib/dist/services/storage/asyncRunStorage.d.ts +127 -0
  394. package/lib/dist/services/storage/asyncRunStorage.d.ts.map +1 -0
  395. package/lib/dist/services/storage/asyncRunStorage.js +448 -0
  396. package/lib/dist/services/storage/asyncRunStorage.js.map +1 -0
  397. package/lib/dist/services/storage/asyncTestCaseStorage.d.ts +156 -0
  398. package/lib/dist/services/storage/asyncTestCaseStorage.d.ts.map +1 -0
  399. package/lib/dist/services/storage/asyncTestCaseStorage.js +285 -0
  400. package/lib/dist/services/storage/asyncTestCaseStorage.js.map +1 -0
  401. package/lib/dist/services/storage/index.d.ts +17 -0
  402. package/lib/dist/services/storage/index.d.ts.map +1 -0
  403. package/lib/dist/services/storage/index.js +20 -0
  404. package/lib/dist/services/storage/index.js.map +1 -0
  405. package/lib/dist/services/storage/migration.d.ts +54 -0
  406. package/lib/dist/services/storage/migration.d.ts.map +1 -0
  407. package/lib/dist/services/storage/migration.js +296 -0
  408. package/lib/dist/services/storage/migration.js.map +1 -0
  409. package/lib/dist/services/storage/opensearchClient.d.ts +924 -0
  410. package/lib/dist/services/storage/opensearchClient.d.ts.map +1 -0
  411. package/lib/dist/services/storage/opensearchClient.js +435 -0
  412. package/lib/dist/services/storage/opensearchClient.js.map +1 -0
  413. package/lib/dist/services/traces/browserRecovery.d.ts +26 -0
  414. package/lib/dist/services/traces/browserRecovery.d.ts.map +1 -0
  415. package/lib/dist/services/traces/browserRecovery.js +81 -0
  416. package/lib/dist/services/traces/browserRecovery.js.map +1 -0
  417. package/lib/dist/services/traces/categoryStyles.d.ts +21 -0
  418. package/lib/dist/services/traces/categoryStyles.d.ts.map +1 -0
  419. package/lib/dist/services/traces/categoryStyles.js +56 -0
  420. package/lib/dist/services/traces/categoryStyles.js.map +1 -0
  421. package/lib/dist/services/traces/executionOrderTransform.d.ts +35 -0
  422. package/lib/dist/services/traces/executionOrderTransform.d.ts.map +1 -0
  423. package/lib/dist/services/traces/executionOrderTransform.js +313 -0
  424. package/lib/dist/services/traces/executionOrderTransform.js.map +1 -0
  425. package/lib/dist/services/traces/fetchSpansForRun.d.ts +86 -0
  426. package/lib/dist/services/traces/fetchSpansForRun.d.ts.map +1 -0
  427. package/lib/dist/services/traces/fetchSpansForRun.js +69 -0
  428. package/lib/dist/services/traces/fetchSpansForRun.js.map +1 -0
  429. package/lib/dist/services/traces/flowTransform.d.ts +24 -0
  430. package/lib/dist/services/traces/flowTransform.d.ts.map +1 -0
  431. package/lib/dist/services/traces/flowTransform.js +228 -0
  432. package/lib/dist/services/traces/flowTransform.js.map +1 -0
  433. package/lib/dist/services/traces/index.d.ts +121 -0
  434. package/lib/dist/services/traces/index.d.ts.map +1 -0
  435. package/lib/dist/services/traces/index.js +255 -0
  436. package/lib/dist/services/traces/index.js.map +1 -0
  437. package/lib/dist/services/traces/intentTransform.d.ts +20 -0
  438. package/lib/dist/services/traces/intentTransform.d.ts.map +1 -0
  439. package/lib/dist/services/traces/intentTransform.js +131 -0
  440. package/lib/dist/services/traces/intentTransform.js.map +1 -0
  441. package/lib/dist/services/traces/judgeAgentsHints.d.ts +63 -0
  442. package/lib/dist/services/traces/judgeAgentsHints.d.ts.map +1 -0
  443. package/lib/dist/services/traces/judgeAgentsHints.js +89 -0
  444. package/lib/dist/services/traces/judgeAgentsHints.js.map +1 -0
  445. package/lib/dist/services/traces/messageExtraction.d.ts +15 -0
  446. package/lib/dist/services/traces/messageExtraction.d.ts.map +1 -0
  447. package/lib/dist/services/traces/messageExtraction.js +251 -0
  448. package/lib/dist/services/traces/messageExtraction.js.map +1 -0
  449. package/lib/dist/services/traces/spanCategorization.d.ts +63 -0
  450. package/lib/dist/services/traces/spanCategorization.d.ts.map +1 -0
  451. package/lib/dist/services/traces/spanCategorization.js +276 -0
  452. package/lib/dist/services/traces/spanCategorization.js.map +1 -0
  453. package/lib/dist/services/traces/spanPreprocessing.d.ts +37 -0
  454. package/lib/dist/services/traces/spanPreprocessing.d.ts.map +1 -0
  455. package/lib/dist/services/traces/spanPreprocessing.js +102 -0
  456. package/lib/dist/services/traces/spanPreprocessing.js.map +1 -0
  457. package/lib/dist/services/traces/spansToTrajectory.d.ts +36 -0
  458. package/lib/dist/services/traces/spansToTrajectory.d.ts.map +1 -0
  459. package/lib/dist/services/traces/spansToTrajectory.js +387 -0
  460. package/lib/dist/services/traces/spansToTrajectory.js.map +1 -0
  461. package/lib/dist/services/traces/toolSimilarity.d.ts +35 -0
  462. package/lib/dist/services/traces/toolSimilarity.d.ts.map +1 -0
  463. package/lib/dist/services/traces/toolSimilarity.js +203 -0
  464. package/lib/dist/services/traces/toolSimilarity.js.map +1 -0
  465. package/lib/dist/services/traces/traceComparison.d.ts +31 -0
  466. package/lib/dist/services/traces/traceComparison.d.ts.map +1 -0
  467. package/lib/dist/services/traces/traceComparison.js +318 -0
  468. package/lib/dist/services/traces/traceComparison.js.map +1 -0
  469. package/lib/dist/services/traces/traceGrouping.d.ts +19 -0
  470. package/lib/dist/services/traces/traceGrouping.d.ts.map +1 -0
  471. package/lib/dist/services/traces/traceGrouping.js +107 -0
  472. package/lib/dist/services/traces/traceGrouping.js.map +1 -0
  473. package/lib/dist/services/traces/tracePoller.d.ts +84 -0
  474. package/lib/dist/services/traces/tracePoller.d.ts.map +1 -0
  475. package/lib/dist/services/traces/tracePoller.js +309 -0
  476. package/lib/dist/services/traces/tracePoller.js.map +1 -0
  477. package/lib/dist/services/traces/traceStats.d.ts +45 -0
  478. package/lib/dist/services/traces/traceStats.d.ts.map +1 -0
  479. package/lib/dist/services/traces/traceStats.js +114 -0
  480. package/lib/dist/services/traces/traceStats.js.map +1 -0
  481. package/lib/dist/services/traces/traceSummary.d.ts +47 -0
  482. package/lib/dist/services/traces/traceSummary.d.ts.map +1 -0
  483. package/lib/dist/services/traces/traceSummary.js +68 -0
  484. package/lib/dist/services/traces/traceSummary.js.map +1 -0
  485. package/lib/dist/services/traces/utils.d.ts +33 -0
  486. package/lib/dist/services/traces/utils.d.ts.map +1 -0
  487. package/lib/dist/services/traces/utils.js +114 -0
  488. package/lib/dist/services/traces/utils.js.map +1 -0
  489. package/lib/dist/types/agui.d.ts +13 -0
  490. package/lib/dist/types/agui.d.ts.map +1 -0
  491. package/lib/dist/types/agui.js +16 -0
  492. package/lib/dist/types/agui.js.map +1 -0
  493. package/lib/dist/types/index.d.ts +1175 -0
  494. package/lib/dist/types/index.d.ts.map +1 -0
  495. package/lib/dist/types/index.js +12 -0
  496. package/lib/dist/types/index.js.map +1 -0
  497. package/lib/dist/types/skills.d.ts +146 -0
  498. package/lib/dist/types/skills.d.ts.map +1 -0
  499. package/lib/dist/types/skills.js +6 -0
  500. package/lib/dist/types/skills.js.map +1 -0
  501. package/observio-sample-agent/pi-package/README.md +112 -0
  502. package/observio-sample-agent/pi-package/extensions/agent-health.ts +373 -0
  503. package/observio-sample-agent/pi-package/package.json +17 -0
  504. package/observio-sample-agent/pi-package/prompts/agent-health.md +37 -0
  505. package/observio-sample-agent/pi-package/skills/create-pr/SKILL.md +88 -0
  506. package/observio-sample-agent/pi-package/skills/fix-bug/SKILL.md +71 -0
  507. package/observio-sample-agent/pi-package/skills/implement-feature/SKILL.md +156 -0
  508. package/observio-sample-agent/pi-package/skills/instrument-otel/SKILL.md +208 -0
  509. package/observio-sample-agent/pi-package/skills/setup-collector/SKILL.md +146 -0
  510. package/observio-sample-agent/pi-package/skills/write-test/SKILL.md +115 -0
  511. package/package.json +64 -13
  512. package/server/dist/app.js +32651 -17637
  513. package/server/dist/index.js +29875 -14638
  514. package/tsconfig.lib.json +71 -0
  515. package/dist/assets/index-EvPLSTAS.js +0 -267
  516. package/dist/assets/index-RXasQKUs.css +0 -1
  517. package/lib/dist/config/index.js +0 -404
  518. package/lib/dist/index.js +0 -1665
@@ -0,0 +1,450 @@
1
+ # Architecture Guide
2
+
3
+ This document describes the core architecture patterns in Agent Health. It serves as a reference to ensure architectural consistency across the codebase.
4
+
5
+ ## System Architecture
6
+
7
+ ### Component Diagram
8
+
9
+ ```
10
+ ┌─────────────────────────────────────────────────────────────────────┐
11
+ │ Agent Health │
12
+ ├─────────────────────────────────────────────────────────────────────┤
13
+ │ │
14
+ │ ┌──────────┐ HTTP API ┌──────────────┐ ┌────────────┐ │
15
+ │ │ CLI │ ─────────────────▶│ Server │───▶│ OpenSearch │ │
16
+ │ └──────────┘ │ (port 4001) │ │ Storage │ │
17
+ │ └──────────────┘ └────────────┘ │
18
+ │ ▲ │
19
+ │ │ │
20
+ │ ┌──────────┐ HTTP API │ │
21
+ │ │ Browser │ ─────────────────────────┘ │
22
+ │ │ (UI) │ │
23
+ │ └──────────┘ │
24
+ │ │
25
+ └─────────────────────────────────────────────────────────────────────┘
26
+ ```
27
+
28
+ ### Key Principle: Server-Mediated Access
29
+
30
+ **All clients (CLI, UI) access OpenSearch through the server HTTP API.**
31
+
32
+ This pattern ensures:
33
+ 1. **Single source of truth** - All business logic lives in server routes
34
+ 2. **Consistent behavior** - CLI and UI always produce identical results
35
+ 3. **Maintainability** - Add features once, both consumers get them
36
+ 4. **Security** - Credentials never exposed to CLI or browser
37
+
38
+ **Never do this:**
39
+ ```
40
+ CLI ──────────────────▶ OpenSearch (WRONG: bypasses server)
41
+ ```
42
+
43
+ **Always do this:**
44
+ ```
45
+ CLI ────── HTTP ──────▶ Server ──────▶ OpenSearch (CORRECT)
46
+ ```
47
+
48
+ ## Server Lifecycle (Playwright Pattern)
49
+
50
+ The CLI manages server lifecycle using a Playwright-inspired config pattern.
51
+
52
+ ### Default Behavior (No Config File)
53
+
54
+ | Environment | Server Running? | Behavior |
55
+ |-------------|-----------------|----------|
56
+ | Development | Yes | Reuse existing server |
57
+ | Development | No | Start server, keep running after CLI exits |
58
+ | CI (`CI=true`) | Yes | Error (explicit failure) |
59
+ | CI (`CI=true`) | No | Start server, stop after CLI exits |
60
+
61
+ ### Optional Config File
62
+
63
+ Create `agent-health.config.ts` only if you need to customize defaults:
64
+
65
+ ```typescript
66
+ import { defineConfig } from '@opensearch-project/agent-health';
67
+
68
+ export default defineConfig({
69
+ server: {
70
+ port: 4001, // Default: 4001
71
+ reuseExistingServer: true, // Default: !process.env.CI
72
+ startTimeout: 30000, // Default: 30000 (30s)
73
+ },
74
+
75
+ // Other config sections...
76
+ agents: [/* ... */],
77
+ models: [/* ... */],
78
+ });
79
+ ```
80
+
81
+ ### Port Auto-Increment
82
+
83
+ When starting, both the standalone server (`npm run dev:server`) and the CLI (`npx @opensearch-project/agent-health`) automatically handle port conflicts. If the configured port (default 4001) is already in use, the server tries the next port (4002, 4003, etc.) up to 10 consecutive attempts before failing. The actual port is:
84
+
85
+ - Printed to the console: `Backend Server running on http://0.0.0.0:<port>`
86
+ - Propagated to `VITE_BACKEND_PORT` so the frontend connects to the correct backend
87
+ - Returned by `ensureServer()` so CLI subcommands use the correct `baseUrl`
88
+
89
+ ### Implementation Details
90
+
91
+ The server lifecycle is implemented in `cli/utils/serverLifecycle.ts`:
92
+
93
+ - `isServerRunning(port)` - Check if server is listening on port
94
+ - `startServer(port, timeout)` - Spawn server process, parse stdout for actual port, wait for ready
95
+ - `stopServer(process)` - Gracefully terminate server
96
+ - `ensureServer(config)` - Main entry point, handles all scenarios including port auto-increment
97
+ - `createServerCleanup(result, isCI)` - Returns cleanup function for CI mode
98
+
99
+ The port retry logic uses a recursive `tryListen()` pattern in both `server/index.ts` and `cli/utils/startServer.ts`:
100
+
101
+ ```typescript
102
+ const tryListen = (port: number): Promise<number> => {
103
+ return new Promise((resolve, reject) => {
104
+ const server = app.listen(port, '0.0.0.0');
105
+ server.on('listening', () => resolve(port));
106
+ server.on('error', (err: NodeJS.ErrnoException) => {
107
+ server.close();
108
+ if (err.code === 'EADDRINUSE' && port <= startPort + MAX_PORT_ATTEMPTS) {
109
+ resolve(tryListen(port + 1));
110
+ } else {
111
+ reject(err);
112
+ }
113
+ });
114
+ });
115
+ };
116
+ ```
117
+
118
+ ## API Client Pattern
119
+
120
+ The CLI uses `cli/utils/apiClient.ts` to communicate with the server:
121
+
122
+ ```typescript
123
+ const api = new ApiClient('http://localhost:4001');
124
+
125
+ // Find benchmark by name or ID
126
+ const benchmark = await api.findBenchmark('My Benchmark');
127
+
128
+ // Execute benchmark with progress streaming
129
+ const run = await api.executeBenchmark(benchmark.id, runConfig, (event) => {
130
+ if (event.type === 'progress') {
131
+ console.log(`Progress: ${event.currentTestCaseIndex}/${event.totalTestCases}`);
132
+ }
133
+ });
134
+
135
+ // Get detailed reports
136
+ const reports = await api.getRunReports(benchmark.id, run.id);
137
+ ```
138
+
139
+ ### SSE Streaming
140
+
141
+ Long-running operations (benchmark execution) use Server-Sent Events:
142
+
143
+ ```typescript
144
+ // Server side (Express route)
145
+ res.setHeader('Content-Type', 'text/event-stream');
146
+ res.setHeader('Cache-Control', 'no-cache');
147
+ res.setHeader('Connection', 'keep-alive');
148
+ res.flushHeaders();
149
+
150
+ res.write(`data: ${JSON.stringify({ type: 'progress', ... })}\n\n`);
151
+
152
+ // Client side (API client)
153
+ const reader = res.body.getReader();
154
+ while (true) {
155
+ const { done, value } = await reader.read();
156
+ if (done) break;
157
+ // Parse SSE events from buffer
158
+ }
159
+ ```
160
+
161
+ ## Directory Structure
162
+
163
+ ```
164
+ .
165
+ ├── cli/
166
+ │ ├── commands/ # CLI commands (benchmark, serve, etc.)
167
+ │ ├── utils/
168
+ │ │ ├── apiClient.ts # HTTP client for server API
169
+ │ │ └── serverLifecycle.ts # Server start/stop utilities
170
+ │ └── demo/ # Sample data generators
171
+ ├── server/
172
+ │ ├── routes/ # Express route handlers
173
+ │ │ └── storage/ # Storage API routes
174
+ │ ├── services/ # Backend-only services
175
+ │ └── middleware/ # Express middleware
176
+ ├── lib/
177
+ │ └── config/ # Configuration loading
178
+ │ ├── types.ts # ServerConfig, UserConfig, etc.
179
+ │ ├── loader.ts # Config file loading
180
+ │ └── defineConfig.ts # Type-safe config helper
181
+ └── services/ # Shared services (used by server)
182
+ ```
183
+
184
+ ## Adding New CLI Commands
185
+
186
+ When adding a new CLI command that needs server functionality:
187
+
188
+ 1. **Use the API client** - Never import server internals or OpenSearch client directly
189
+ 2. **Handle server lifecycle** - Call `ensureServer()` at the start
190
+ 3. **Clean up in CI** - Call the cleanup function in a finally block
191
+
192
+ ```typescript
193
+ import { ensureServer, createServerCleanup } from '@/cli/utils/serverLifecycle.js';
194
+ import { ApiClient } from '@/cli/utils/apiClient.js';
195
+ import { loadConfig, DEFAULT_SERVER_CONFIG } from '@/lib/config/index.js';
196
+
197
+ export async function myCommand() {
198
+ const config = await loadConfig();
199
+ const serverConfig = { ...DEFAULT_SERVER_CONFIG, ...config.server };
200
+ const isCI = !!process.env.CI;
201
+
202
+ const serverResult = await ensureServer(serverConfig);
203
+ const cleanup = createServerCleanup(serverResult, isCI);
204
+
205
+ try {
206
+ const api = new ApiClient(serverResult.baseUrl);
207
+ // Use api.* methods to interact with server
208
+ } finally {
209
+ cleanup();
210
+ }
211
+ }
212
+ ```
213
+
214
+ ## Server API Endpoints
215
+
216
+ Key endpoints used by CLI:
217
+
218
+ | Endpoint | Method | Description |
219
+ |----------|--------|-------------|
220
+ | `/health` | GET | Health check |
221
+ | `/api/debug` | GET | Get current debug logging state |
222
+ | `/api/debug` | POST | Toggle debug logging (`{ enabled: boolean }`) |
223
+ | `/api/storage/benchmarks` | GET | List benchmarks |
224
+ | `/api/storage/benchmarks/:id` | GET | Get benchmark by ID |
225
+ | `/api/storage/benchmarks/:id/execute` | POST | Execute benchmark (SSE) |
226
+ | `/api/storage/benchmarks/:id/cancel` | POST | Cancel running benchmark |
227
+ | `/api/storage/runs/by-benchmark-run/:benchmarkId/:runId` | GET | Get reports for a run |
228
+
229
+ ## Why This Architecture?
230
+
231
+ ### Before (Direct OpenSearch Access)
232
+
233
+ ```typescript
234
+ // CLI command
235
+ import { getOpenSearchClient } from '@/server/services/opensearchClient';
236
+
237
+ const client = getOpenSearchClient();
238
+ const result = await client.search({ index: 'benchmarks', ... });
239
+ // Duplicate logic from server routes
240
+ ```
241
+
242
+ **Problems:**
243
+ - Duplicated business logic between CLI and server routes
244
+ - CLI needs OpenSearch credentials
245
+ - Inconsistent behavior possible
246
+ - Hard to maintain two code paths
247
+
248
+ ### After (Server-Mediated)
249
+
250
+ ```typescript
251
+ // CLI command
252
+ import { ApiClient } from '@/cli/utils/apiClient';
253
+
254
+ const api = new ApiClient('http://localhost:4001');
255
+ const benchmarks = await api.listBenchmarks();
256
+ // Server handles all logic
257
+ ```
258
+
259
+ **Benefits:**
260
+ - Single source of truth (server routes)
261
+ - CLI is a thin HTTP wrapper (~200 lines vs ~550 lines)
262
+ - No credential exposure
263
+ - Guaranteed consistent behavior
264
+ - Easier testing and maintenance
265
+
266
+ ## Storage Adapter Pattern
267
+
268
+ The storage layer uses an adapter pattern to support multiple backends without changing route or service code.
269
+
270
+ ### IStorageModule Interface
271
+
272
+ All storage backends implement the `IStorageModule` interface, which exposes sub-modules for each entity type:
273
+
274
+ ```typescript
275
+ interface IStorageModule {
276
+ testCases: ITestCaseStorage;
277
+ benchmarks: IBenchmarkStorage;
278
+ runs: IRunStorage;
279
+ isConfigured: boolean;
280
+ }
281
+ ```
282
+
283
+ Each sub-module (`ITestCaseStorage`, `IBenchmarkStorage`, `IRunStorage`) provides standard CRUD operations: `getAll()`, `getById()`, `create()`, `update()`, `delete()`.
284
+
285
+ ### Built-in Adapters
286
+
287
+ | Adapter | Backend | Config Required | Use Case |
288
+ |---------|---------|-----------------|----------|
289
+ | `FileStorageModule` | Local filesystem (`.agent-health/data/`) | None (default) | Zero-config local development, demos |
290
+ | `OpenSearchStorageModule` | OpenSearch cluster | `OPENSEARCH_STORAGE_*` env vars | Production, shared teams |
291
+
292
+ **FileStorageModule** is the default adapter. It stores data as JSON files in a `.agent-health/data/` directory relative to the working directory. No external services are needed - the application works out of the box.
293
+
294
+ **OpenSearchStorageModule** connects to an OpenSearch cluster for persistent, shared storage. It is activated when `OPENSEARCH_STORAGE_ENDPOINT` is configured. Supports both basic auth (username/password) and AWS SigV4 authentication for managed OpenSearch domains and OpenSearch Serverless. The `opensearchClientFactory.ts` handles client creation with the appropriate auth strategy based on `authType` in the cluster config.
295
+
296
+ ### Adapter Factory Singleton
297
+
298
+ The active storage module is managed via a singleton factory:
299
+
300
+ ```typescript
301
+ import { getStorageModule, setStorageModule } from '@/server/services/storage';
302
+
303
+ // Get the current storage module (creates FileStorageModule by default)
304
+ const storage = getStorageModule();
305
+
306
+ // Override with a different adapter (e.g., during server startup)
307
+ setStorageModule(new OpenSearchStorageModule(config));
308
+ ```
309
+
310
+ ### Usage in Routes
311
+
312
+ Routes use the `getStorageModule()` singleton and never reference a specific backend directly:
313
+
314
+ ```typescript
315
+ // In a route handler
316
+ import { getStorageModule } from '@/server/services/storage';
317
+
318
+ router.get('/api/storage/test-cases', async (req, res) => {
319
+ const storage = getStorageModule();
320
+ const testCases = await storage.testCases.getAll();
321
+ res.json(testCases);
322
+ });
323
+
324
+ router.get('/api/storage/benchmarks/:id', async (req, res) => {
325
+ const storage = getStorageModule();
326
+ const benchmark = await storage.benchmarks.getById(req.params.id);
327
+ if (!benchmark) return res.status(404).json({ error: 'Not found' });
328
+ res.json(benchmark);
329
+ });
330
+ ```
331
+
332
+ This pattern means:
333
+ - **Routes are backend-agnostic** - the same route code works with file storage or OpenSearch
334
+ - **Swapping backends is a one-line change** at startup via `setStorageModule()`
335
+ - **Testing is simple** - inject a mock `IStorageModule` for unit tests
336
+
337
+ ## Claude Code Judge
338
+
339
+ The Claude Code judge is an alternative evaluation provider that spawns the `claude` CLI to evaluate agent trajectories, giving the judge access to full tool use and the AGENT_HEALTH.md skill context.
340
+
341
+ ### How It Works
342
+
343
+ ```
344
+ ┌──────────┐ spawn ┌──────────────┐ stdout ┌──────────┐
345
+ │ Server │ ───────────────▶│ claude CLI │ ─────────────▶ │ JSON │
346
+ │ judge.ts │ --print │ (subprocess) │ JudgeResponse │ parse │
347
+ └──────────┘ --output-format │ │ └──────────┘
348
+ json └──────────────┘
349
+ ```
350
+
351
+ - **Provider key**: `'claude-code'` in the `JudgeProvider` union type
352
+ - **Model ID**: `claude-code-judge` in `DEFAULT_CONFIG.models`
353
+ - **Service**: `server/services/claudeCodeJudgeService.ts`
354
+ - **Route branch**: `server/routes/judge.ts` — `if (provider === 'claude-code')`
355
+
356
+ ### Key Details
357
+
358
+ - Spawns `claude --print --output-format json --dangerously-skip-permissions --append-system-prompt <system-prompt>`
359
+ - System prompt combines `JUDGE_SYSTEM_PROMPT` from `server/prompts/judgePrompt.ts` with AGENT_HEALTH.md skill content
360
+ - Pipes `buildEvaluationPrompt()` output (same as Bedrock) to stdin
361
+ - Parses JSON from stdout into `JudgeResponse` shape (handles bare JSON and markdown-wrapped)
362
+ - Inherits `AWS_PROFILE` and `AWS_REGION` from process environment
363
+ - 3-minute timeout per evaluation
364
+
365
+ ## AI Assistant
366
+
367
+ The AI Assistant provides conversational help powered by Claude Code CLI (with Bedrock/LiteLLM fallback). Two UI interfaces share one backend.
368
+
369
+ ### Architecture
370
+
371
+ ```
372
+ ┌─────────────────────────────────────────────────────────────────────────┐
373
+ │ Frontend (React) │
374
+ │ │
375
+ │ ┌───────────────────┐ ┌──────────────────────┐ │
376
+ │ │ AssistantModal │ │ AssistantChat │ │
377
+ │ │ (floating "?") │ │ (/assistant route) │ │
378
+ │ └────────┬──────────┘ └──────────┬───────────┘ │
379
+ │ │ │ │
380
+ │ └──────────┬───────────────┘ │
381
+ │ ▼ │
382
+ │ ┌──────────────────┐ │
383
+ │ │ AssistantProvider │ │
384
+ │ │ (runtime context) │ │
385
+ │ └────────┬─────────┘ │
386
+ │ ▼ │
387
+ │ ┌──────────────────┐ │
388
+ │ │useAssistantRuntime│ │
389
+ │ │ (ChatModelAdapter)│ │
390
+ │ └────────┬─────────┘ │
391
+ │ ▼ │
392
+ │ ┌──────────────────┐ │
393
+ │ │ assistantApi.ts │ ← ReadableStream SSE consumption │
394
+ │ └────────┬─────────┘ │
395
+ └────────────────────┼───────────────────────────────────────────────────┘
396
+ │ POST /api/assistant/chat (SSE)
397
+
398
+ ┌────────────────────────────────────────────────────────────────────────┐
399
+ │ Backend (Express) │
400
+ │ │
401
+ │ ┌──────────────────┐ ┌──────────────────────────┐ │
402
+ │ │ assistant.ts │───▶│ assistantService.ts │ │
403
+ │ │ (SSE route) │ │ (session mgmt + streaming)│ │
404
+ │ └──────────────────┘ └────────────┬─────────────┘ │
405
+ │ │ │
406
+ │ ┌────────────┼────────────┐ │
407
+ │ ▼ ▼ ▼ │
408
+ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
409
+ │ │claude CLI│ │ Bedrock │ │ LiteLLM │ │
410
+ │ │(primary) │ │(fallback)│ │(fallback)│ │
411
+ │ └──────────┘ └──────────┘ └──────────┘ │
412
+ └────────────────────────────────────────────────────────────────────────┘
413
+ ```
414
+
415
+ ### Streaming Pipeline
416
+
417
+ The end-to-end streaming pipeline converts Claude CLI NDJSON output to real-time UI updates:
418
+
419
+ 1. **Claude CLI** outputs NDJSON lines: `{"type":"assistant","subtype":"text","content":"Hello"}`
420
+ 2. **assistantService.ts** parses NDJSON → calls `onDelta(content)` callback
421
+ 3. **assistant.ts route** converts to SSE: `data: {"type":"delta","content":"Hello"}\n\n`
422
+ 4. **assistantApi.ts** reads SSE via `ReadableStream` → buffers on `\n\n` → calls `onChunk(content)`
423
+ 5. **ChatModelAdapter** (in `useAssistantRuntime.ts`) accumulates text → yields `{ content: [{ type: "text", text }] }`
424
+ 6. **assistant-ui Thread** renders incrementally with auto-scroll and typing indicator
425
+
426
+ ### Session Management
427
+
428
+ - In-memory `Map<sessionId, Session>` with 30-minute TTL
429
+ - Periodic cleanup every 5 minutes (timer uses `unref()` to not block process exit)
430
+ - Sessions persist across page navigation within the same browser session
431
+
432
+ ### API Endpoints
433
+
434
+ | Endpoint | Method | Description |
435
+ |----------|--------|-------------|
436
+ | `/api/assistant/chat` | POST | Stream assistant response (SSE) |
437
+ | `/api/assistant/session/:sessionId` | DELETE | Clear session history |
438
+ | `/api/assistant/health` | GET | Check Claude CLI availability |
439
+
440
+ ### UI Components
441
+
442
+ | Component | Location | Library Primitive |
443
+ |-----------|----------|-------------------|
444
+ | `AssistantModal` | `components/assistant-ui/AssistantModal.tsx` | `AssistantModalPrimitive` |
445
+ | `AssistantChat` | `components/assistant-ui/AssistantChat.tsx` | `ThreadPrimitive` |
446
+ | `AssistantProvider` | `components/assistant-ui/AssistantProvider.tsx` | `AssistantRuntimeProvider` |
447
+
448
+ - **AssistantModal**: Floating "?" button fixed bottom-right, opens 500x400 popup. Mobile-responsive (full viewport on small screens).
449
+ - **AssistantChat**: Full-page chat at `/assistant` route with welcome screen and suggested prompts.
450
+ - **AssistantProvider**: Mounted once in `Layout.tsx`, provides shared runtime context to both interfaces.