@opensearch-project/agent-health 0.4.0 → 0.6.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 (551) hide show
  1. package/README.md +36 -5
  2. package/cli/dist/index.js +8292 -2938
  3. package/deployment/cloudformation/agent-health-observability.yaml +223 -32
  4. package/dist/assets/index-BfxtxmKc.css +1 -0
  5. package/dist/assets/index-CrjAfDHu.js +243 -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 +474 -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 +397 -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 +626 -0
  22. package/docs/SKILLS.md +264 -0
  23. package/docs/STORAGE_INDEX_FIELD_LIMITS.md +216 -0
  24. package/docs/blogs/2026-02-28-opensearch-agent-health.md +200 -0
  25. package/docs/blogs/getting-started-blog.md +608 -0
  26. package/docs/diagrams/Agent-health.excalidraw +5656 -0
  27. package/docs/diagrams/architecture.png +0 -0
  28. package/docs/plans/field-redesign.md +468 -0
  29. package/docs/rfcs/001-coding-agent-analytics.md +374 -0
  30. package/docs/rfcs/002-enterprise-leaderboard.md +267 -0
  31. package/docs/rfcs/003-remote-aggregation.md +146 -0
  32. package/docs/rfcs/004-test-sdk-v2.md +599 -0
  33. package/docs/skills/AGENT_HEALTH.md +652 -0
  34. package/docs/skills/AGENT_PROFILE.md +191 -0
  35. package/docs/skills/add-connector/SKILL.md +68 -0
  36. package/docs/skills/agent-health-profile/SKILL.md +40 -0
  37. package/docs/skills/config-auth/SKILL.md +194 -0
  38. package/docs/skills/config-auth/evals/evals.json +35 -0
  39. package/docs/skills/create-pr/SKILL.md +73 -0
  40. package/docs/skills/instrument-otel/SKILL.md +84 -0
  41. package/docs/skills/write-test/SKILL.md +124 -0
  42. package/docs/ui prd.md +376 -0
  43. package/examples/README.md +53 -0
  44. package/examples/config/agent-health.config.example.ts +155 -0
  45. package/examples/connectors/echo-connector.ts +131 -0
  46. package/examples/eval-files/demo.eval.js +128 -0
  47. package/examples/eval-files/ops-rca-classification.eval.js +71 -0
  48. package/examples/eval-files/ops-rca-evaluator.json +15 -0
  49. package/examples/eval-files/sdk-demo.eval.js +72 -0
  50. package/examples/eval-files/sdk-describe-demo.eval.js +50 -0
  51. package/examples/eval-files/sdk-hooks-demo.eval.js +99 -0
  52. package/examples/pi-profiling/README.md +77 -0
  53. package/examples/pi-profiling/agent-health-profile.ts +417 -0
  54. package/lib/dist/lib/agentUtils.d.ts +29 -0
  55. package/lib/dist/lib/agentUtils.d.ts.map +1 -0
  56. package/lib/dist/lib/agentUtils.js +43 -0
  57. package/lib/dist/lib/agentUtils.js.map +1 -0
  58. package/lib/dist/lib/bedrockCompat.d.ts +27 -0
  59. package/lib/dist/lib/bedrockCompat.d.ts.map +1 -0
  60. package/lib/dist/lib/bedrockCompat.js +83 -0
  61. package/lib/dist/lib/bedrockCompat.js.map +1 -0
  62. package/lib/dist/lib/benchmarkExport.d.ts +14 -0
  63. package/lib/dist/lib/benchmarkExport.d.ts.map +1 -0
  64. package/lib/dist/lib/benchmarkExport.js +41 -0
  65. package/lib/dist/lib/benchmarkExport.js.map +1 -0
  66. package/lib/dist/lib/benchmarkImage.d.ts +52 -0
  67. package/lib/dist/lib/benchmarkImage.d.ts.map +1 -0
  68. package/lib/dist/lib/benchmarkImage.js +113 -0
  69. package/lib/dist/lib/benchmarkImage.js.map +1 -0
  70. package/lib/dist/lib/benchmarkVersionUtils.d.ts +50 -0
  71. package/lib/dist/lib/benchmarkVersionUtils.d.ts.map +1 -0
  72. package/lib/dist/lib/benchmarkVersionUtils.js +89 -0
  73. package/lib/dist/lib/benchmarkVersionUtils.js.map +1 -0
  74. package/lib/dist/lib/chunkedFetch.d.ts +18 -0
  75. package/lib/dist/lib/chunkedFetch.d.ts.map +1 -0
  76. package/lib/dist/lib/chunkedFetch.js +40 -0
  77. package/lib/dist/lib/chunkedFetch.js.map +1 -0
  78. package/lib/dist/lib/comparisonInsights.d.ts +104 -0
  79. package/lib/dist/lib/comparisonInsights.d.ts.map +1 -0
  80. package/lib/dist/lib/comparisonInsights.js +212 -0
  81. package/lib/dist/lib/comparisonInsights.js.map +1 -0
  82. package/lib/dist/lib/config/defineConfig.d.ts +27 -0
  83. package/lib/dist/lib/config/defineConfig.d.ts.map +1 -0
  84. package/lib/dist/lib/config/defineConfig.js +28 -0
  85. package/lib/dist/lib/config/defineConfig.js.map +1 -0
  86. package/lib/dist/lib/config/index.d.ts +9 -0
  87. package/lib/dist/lib/config/index.d.ts.map +1 -0
  88. package/lib/dist/lib/config/index.js +8 -0
  89. package/lib/dist/lib/config/index.js.map +1 -0
  90. package/lib/dist/lib/config/loader.d.ts +39 -0
  91. package/lib/dist/lib/config/loader.d.ts.map +1 -0
  92. package/lib/dist/lib/config/loader.js +263 -0
  93. package/lib/dist/lib/config/loader.js.map +1 -0
  94. package/lib/dist/lib/config/statePaths.d.ts +61 -0
  95. package/lib/dist/lib/config/statePaths.d.ts.map +1 -0
  96. package/lib/dist/lib/config/statePaths.js +188 -0
  97. package/lib/dist/lib/config/statePaths.js.map +1 -0
  98. package/lib/dist/lib/config/types.d.ts +245 -0
  99. package/lib/dist/lib/config/types.d.ts.map +1 -0
  100. package/lib/dist/lib/config/types.js +6 -0
  101. package/lib/dist/lib/config/types.js.map +1 -0
  102. package/lib/dist/lib/config.d.ts +39 -0
  103. package/lib/dist/lib/config.d.ts.map +1 -0
  104. package/lib/dist/lib/config.js +118 -0
  105. package/lib/dist/lib/config.js.map +1 -0
  106. package/lib/dist/lib/constants.d.ts +81 -0
  107. package/lib/dist/lib/constants.d.ts.map +1 -0
  108. package/lib/dist/lib/constants.js +374 -0
  109. package/lib/dist/lib/constants.js.map +1 -0
  110. package/lib/dist/lib/contextFormat.d.ts +26 -0
  111. package/lib/dist/lib/contextFormat.d.ts.map +1 -0
  112. package/lib/dist/lib/contextFormat.js +28 -0
  113. package/lib/dist/lib/contextFormat.js.map +1 -0
  114. package/lib/dist/lib/contextUtilization.d.ts +23 -0
  115. package/lib/dist/lib/contextUtilization.d.ts.map +1 -0
  116. package/lib/dist/lib/contextUtilization.js +72 -0
  117. package/lib/dist/lib/contextUtilization.js.map +1 -0
  118. package/lib/dist/lib/dashboardMetrics.d.ts +87 -0
  119. package/lib/dist/lib/dashboardMetrics.d.ts.map +1 -0
  120. package/lib/dist/lib/dashboardMetrics.js +242 -0
  121. package/lib/dist/lib/dashboardMetrics.js.map +1 -0
  122. package/lib/dist/lib/dataSourceConfig.d.ts +108 -0
  123. package/lib/dist/lib/dataSourceConfig.d.ts.map +1 -0
  124. package/lib/dist/lib/dataSourceConfig.js +166 -0
  125. package/lib/dist/lib/dataSourceConfig.js.map +1 -0
  126. package/lib/dist/lib/debug.d.ts +26 -0
  127. package/lib/dist/lib/debug.d.ts.map +1 -0
  128. package/lib/dist/lib/debug.js +132 -0
  129. package/lib/dist/lib/debug.js.map +1 -0
  130. package/lib/dist/lib/diagnostics.d.ts +28 -0
  131. package/lib/dist/lib/diagnostics.d.ts.map +1 -0
  132. package/lib/dist/lib/diagnostics.js +65 -0
  133. package/lib/dist/lib/diagnostics.js.map +1 -0
  134. package/lib/dist/lib/envCompat.d.ts +27 -0
  135. package/lib/dist/lib/envCompat.d.ts.map +1 -0
  136. package/lib/dist/lib/envCompat.js +82 -0
  137. package/lib/dist/lib/envCompat.js.map +1 -0
  138. package/lib/dist/lib/evaluationRerun.d.ts +63 -0
  139. package/lib/dist/lib/evaluationRerun.d.ts.map +1 -0
  140. package/lib/dist/lib/evaluationRerun.js +85 -0
  141. package/lib/dist/lib/evaluationRerun.js.map +1 -0
  142. package/lib/dist/lib/findPackageRoot.d.ts +7 -0
  143. package/lib/dist/lib/findPackageRoot.d.ts.map +1 -0
  144. package/lib/dist/lib/findPackageRoot.js +57 -0
  145. package/lib/dist/lib/findPackageRoot.js.map +1 -0
  146. package/lib/dist/lib/hooks.d.ts +36 -0
  147. package/lib/dist/lib/hooks.d.ts.map +1 -0
  148. package/lib/dist/lib/hooks.js +112 -0
  149. package/lib/dist/lib/hooks.js.map +1 -0
  150. package/lib/dist/lib/index.d.ts +47 -0
  151. package/lib/dist/lib/index.d.ts.map +1 -0
  152. package/lib/dist/lib/index.js +62 -0
  153. package/lib/dist/lib/index.js.map +1 -0
  154. package/lib/dist/lib/labels.d.ts +90 -0
  155. package/lib/dist/lib/labels.d.ts.map +1 -0
  156. package/lib/dist/lib/labels.js +158 -0
  157. package/lib/dist/lib/labels.js.map +1 -0
  158. package/lib/dist/lib/markdown.d.ts +16 -0
  159. package/lib/dist/lib/markdown.d.ts.map +1 -0
  160. package/lib/dist/lib/markdown.js +42 -0
  161. package/lib/dist/lib/markdown.js.map +1 -0
  162. package/lib/dist/lib/matchers/expect.d.ts +3 -0
  163. package/lib/dist/lib/matchers/expect.d.ts.map +1 -0
  164. package/lib/dist/lib/matchers/expect.js +225 -0
  165. package/lib/dist/lib/matchers/expect.js.map +1 -0
  166. package/lib/dist/lib/matchers/index.d.ts +8 -0
  167. package/lib/dist/lib/matchers/index.d.ts.map +1 -0
  168. package/lib/dist/lib/matchers/index.js +9 -0
  169. package/lib/dist/lib/matchers/index.js.map +1 -0
  170. package/lib/dist/lib/matchers/judgeAccessor.d.ts +113 -0
  171. package/lib/dist/lib/matchers/judgeAccessor.d.ts.map +1 -0
  172. package/lib/dist/lib/matchers/judgeAccessor.js +183 -0
  173. package/lib/dist/lib/matchers/judgeAccessor.js.map +1 -0
  174. package/lib/dist/lib/matchers/session.d.ts +39 -0
  175. package/lib/dist/lib/matchers/session.d.ts.map +1 -0
  176. package/lib/dist/lib/matchers/session.js +116 -0
  177. package/lib/dist/lib/matchers/session.js.map +1 -0
  178. package/lib/dist/lib/matchers/traces.d.ts +70 -0
  179. package/lib/dist/lib/matchers/traces.d.ts.map +1 -0
  180. package/lib/dist/lib/matchers/traces.js +236 -0
  181. package/lib/dist/lib/matchers/traces.js.map +1 -0
  182. package/lib/dist/lib/matchers/tracesPricing.d.ts +38 -0
  183. package/lib/dist/lib/matchers/tracesPricing.d.ts.map +1 -0
  184. package/lib/dist/lib/matchers/tracesPricing.js +64 -0
  185. package/lib/dist/lib/matchers/tracesPricing.js.map +1 -0
  186. package/lib/dist/lib/matchers/types.d.ts +75 -0
  187. package/lib/dist/lib/matchers/types.d.ts.map +1 -0
  188. package/lib/dist/lib/matchers/types.js +6 -0
  189. package/lib/dist/lib/matchers/types.js.map +1 -0
  190. package/lib/dist/lib/packagePaths.d.ts +29 -0
  191. package/lib/dist/lib/packagePaths.d.ts.map +1 -0
  192. package/lib/dist/lib/packagePaths.js +63 -0
  193. package/lib/dist/lib/packagePaths.js.map +1 -0
  194. package/lib/dist/lib/performance.d.ts +51 -0
  195. package/lib/dist/lib/performance.d.ts.map +1 -0
  196. package/lib/dist/lib/performance.js +159 -0
  197. package/lib/dist/lib/performance.js.map +1 -0
  198. package/lib/dist/lib/portConfig.d.ts +29 -0
  199. package/lib/dist/lib/portConfig.d.ts.map +1 -0
  200. package/lib/dist/lib/portConfig.js +64 -0
  201. package/lib/dist/lib/portConfig.js.map +1 -0
  202. package/lib/dist/lib/preferences.d.ts +63 -0
  203. package/lib/dist/lib/preferences.d.ts.map +1 -0
  204. package/lib/dist/lib/preferences.js +117 -0
  205. package/lib/dist/lib/preferences.js.map +1 -0
  206. package/lib/dist/lib/resolveAgentModel.d.ts +22 -0
  207. package/lib/dist/lib/resolveAgentModel.d.ts.map +1 -0
  208. package/lib/dist/lib/resolveAgentModel.js +37 -0
  209. package/lib/dist/lib/resolveAgentModel.js.map +1 -0
  210. package/lib/dist/lib/runStats.d.ts +116 -0
  211. package/lib/dist/lib/runStats.d.ts.map +1 -0
  212. package/lib/dist/lib/runStats.js +192 -0
  213. package/lib/dist/lib/runStats.js.map +1 -0
  214. package/lib/dist/lib/telemetry/constants.d.ts +60 -0
  215. package/lib/dist/lib/telemetry/constants.d.ts.map +1 -0
  216. package/lib/dist/lib/telemetry/constants.js +87 -0
  217. package/lib/dist/lib/telemetry/constants.js.map +1 -0
  218. package/lib/dist/lib/telemetry/evalSpans.d.ts +61 -0
  219. package/lib/dist/lib/telemetry/evalSpans.d.ts.map +1 -0
  220. package/lib/dist/lib/telemetry/evalSpans.js +254 -0
  221. package/lib/dist/lib/telemetry/evalSpans.js.map +1 -0
  222. package/lib/dist/lib/telemetry/index.d.ts +11 -0
  223. package/lib/dist/lib/telemetry/index.d.ts.map +1 -0
  224. package/lib/dist/lib/telemetry/index.js +15 -0
  225. package/lib/dist/lib/telemetry/index.js.map +1 -0
  226. package/lib/dist/lib/telemetry/opensearchExporter.d.ts +43 -0
  227. package/lib/dist/lib/telemetry/opensearchExporter.d.ts.map +1 -0
  228. package/lib/dist/lib/telemetry/opensearchExporter.js +217 -0
  229. package/lib/dist/lib/telemetry/opensearchExporter.js.map +1 -0
  230. package/lib/dist/lib/telemetry/provider.d.ts +55 -0
  231. package/lib/dist/lib/telemetry/provider.d.ts.map +1 -0
  232. package/lib/dist/lib/telemetry/provider.js +140 -0
  233. package/lib/dist/lib/telemetry/provider.js.map +1 -0
  234. package/lib/dist/lib/testCaseLabels.d.ts +34 -0
  235. package/lib/dist/lib/testCaseLabels.d.ts.map +1 -0
  236. package/lib/dist/lib/testCaseLabels.js +88 -0
  237. package/lib/dist/lib/testCaseLabels.js.map +1 -0
  238. package/lib/dist/lib/testCaseValidation.d.ts +140 -0
  239. package/lib/dist/lib/testCaseValidation.d.ts.map +1 -0
  240. package/lib/dist/lib/testCaseValidation.js +162 -0
  241. package/lib/dist/lib/testCaseValidation.js.map +1 -0
  242. package/lib/dist/lib/testCases/agentFixture.d.ts +80 -0
  243. package/lib/dist/lib/testCases/agentFixture.d.ts.map +1 -0
  244. package/lib/dist/lib/testCases/agentFixture.js +43 -0
  245. package/lib/dist/lib/testCases/agentFixture.js.map +1 -0
  246. package/lib/dist/lib/testCases/authoringSurface.d.ts +10 -0
  247. package/lib/dist/lib/testCases/authoringSurface.d.ts.map +1 -0
  248. package/lib/dist/lib/testCases/authoringSurface.js +54 -0
  249. package/lib/dist/lib/testCases/authoringSurface.js.map +1 -0
  250. package/lib/dist/lib/testCases/codemod.d.ts +13 -0
  251. package/lib/dist/lib/testCases/codemod.d.ts.map +1 -0
  252. package/lib/dist/lib/testCases/codemod.js +169 -0
  253. package/lib/dist/lib/testCases/codemod.js.map +1 -0
  254. package/lib/dist/lib/testCases/define.d.ts +114 -0
  255. package/lib/dist/lib/testCases/define.d.ts.map +1 -0
  256. package/lib/dist/lib/testCases/define.js +253 -0
  257. package/lib/dist/lib/testCases/define.js.map +1 -0
  258. package/lib/dist/lib/testCases/evaluators.d.ts +80 -0
  259. package/lib/dist/lib/testCases/evaluators.d.ts.map +1 -0
  260. package/lib/dist/lib/testCases/evaluators.js +105 -0
  261. package/lib/dist/lib/testCases/evaluators.js.map +1 -0
  262. package/lib/dist/lib/testCases/index.d.ts +14 -0
  263. package/lib/dist/lib/testCases/index.d.ts.map +1 -0
  264. package/lib/dist/lib/testCases/index.js +12 -0
  265. package/lib/dist/lib/testCases/index.js.map +1 -0
  266. package/lib/dist/lib/testCases/judge.d.ts +165 -0
  267. package/lib/dist/lib/testCases/judge.d.ts.map +1 -0
  268. package/lib/dist/lib/testCases/judge.js +359 -0
  269. package/lib/dist/lib/testCases/judge.js.map +1 -0
  270. package/lib/dist/lib/testCases/loader.d.ts +36 -0
  271. package/lib/dist/lib/testCases/loader.d.ts.map +1 -0
  272. package/lib/dist/lib/testCases/loader.js +179 -0
  273. package/lib/dist/lib/testCases/loader.js.map +1 -0
  274. package/lib/dist/lib/testCases/types.d.ts +242 -0
  275. package/lib/dist/lib/testCases/types.d.ts.map +1 -0
  276. package/lib/dist/lib/testCases/types.js +6 -0
  277. package/lib/dist/lib/testCases/types.js.map +1 -0
  278. package/lib/dist/lib/theme.d.ts +6 -0
  279. package/lib/dist/lib/theme.d.ts.map +1 -0
  280. package/lib/dist/lib/theme.js +36 -0
  281. package/lib/dist/lib/theme.js.map +1 -0
  282. package/lib/dist/lib/uiTelemetry.d.ts +7 -0
  283. package/lib/dist/lib/uiTelemetry.d.ts.map +1 -0
  284. package/lib/dist/lib/uiTelemetry.js +25 -0
  285. package/lib/dist/lib/uiTelemetry.js.map +1 -0
  286. package/lib/dist/lib/utils.d.ts +111 -0
  287. package/lib/dist/lib/utils.d.ts.map +1 -0
  288. package/lib/dist/lib/utils.js +254 -0
  289. package/lib/dist/lib/utils.js.map +1 -0
  290. package/lib/dist/lib/workflow/consolidate.d.ts +12 -0
  291. package/lib/dist/lib/workflow/consolidate.d.ts.map +1 -0
  292. package/lib/dist/lib/workflow/consolidate.js +33 -0
  293. package/lib/dist/lib/workflow/consolidate.js.map +1 -0
  294. package/lib/dist/lib/workflow/index.d.ts +13 -0
  295. package/lib/dist/lib/workflow/index.d.ts.map +1 -0
  296. package/lib/dist/lib/workflow/index.js +12 -0
  297. package/lib/dist/lib/workflow/index.js.map +1 -0
  298. package/lib/dist/lib/workflow/ledger.d.ts +30 -0
  299. package/lib/dist/lib/workflow/ledger.d.ts.map +1 -0
  300. package/lib/dist/lib/workflow/ledger.js +41 -0
  301. package/lib/dist/lib/workflow/ledger.js.map +1 -0
  302. package/lib/dist/lib/workflow/pool.d.ts +13 -0
  303. package/lib/dist/lib/workflow/pool.d.ts.map +1 -0
  304. package/lib/dist/lib/workflow/pool.js +44 -0
  305. package/lib/dist/lib/workflow/pool.js.map +1 -0
  306. package/lib/dist/lib/workflow/source.d.ts +22 -0
  307. package/lib/dist/lib/workflow/source.d.ts.map +1 -0
  308. package/lib/dist/lib/workflow/source.js +29 -0
  309. package/lib/dist/lib/workflow/source.js.map +1 -0
  310. package/lib/dist/lib/workflow/stepB.d.ts +71 -0
  311. package/lib/dist/lib/workflow/stepB.d.ts.map +1 -0
  312. package/lib/dist/lib/workflow/stepB.js +99 -0
  313. package/lib/dist/lib/workflow/stepB.js.map +1 -0
  314. package/lib/dist/lib/workflow/types.d.ts +86 -0
  315. package/lib/dist/lib/workflow/types.d.ts.map +1 -0
  316. package/lib/dist/lib/workflow/types.js +6 -0
  317. package/lib/dist/lib/workflow/types.js.map +1 -0
  318. package/lib/dist/lib/workflow/workflow.d.ts +119 -0
  319. package/lib/dist/lib/workflow/workflow.d.ts.map +1 -0
  320. package/lib/dist/lib/workflow/workflow.js +195 -0
  321. package/lib/dist/lib/workflow/workflow.js.map +1 -0
  322. package/lib/dist/services/agent/aguiConverter.d.ts +50 -0
  323. package/lib/dist/services/agent/aguiConverter.d.ts.map +1 -0
  324. package/lib/dist/services/agent/aguiConverter.js +449 -0
  325. package/lib/dist/services/agent/aguiConverter.js.map +1 -0
  326. package/lib/dist/services/agent/index.d.ts +10 -0
  327. package/lib/dist/services/agent/index.d.ts.map +1 -0
  328. package/lib/dist/services/agent/index.js +12 -0
  329. package/lib/dist/services/agent/index.js.map +1 -0
  330. package/lib/dist/services/agent/payloadBuilder.d.ts +33 -0
  331. package/lib/dist/services/agent/payloadBuilder.d.ts.map +1 -0
  332. package/lib/dist/services/agent/payloadBuilder.js +75 -0
  333. package/lib/dist/services/agent/payloadBuilder.js.map +1 -0
  334. package/lib/dist/services/agent/sseStream.d.ts +43 -0
  335. package/lib/dist/services/agent/sseStream.d.ts.map +1 -0
  336. package/lib/dist/services/agent/sseStream.js +223 -0
  337. package/lib/dist/services/agent/sseStream.js.map +1 -0
  338. package/lib/dist/services/connectors/agui/AGUIStreamingConnector.d.ts +44 -0
  339. package/lib/dist/services/connectors/agui/AGUIStreamingConnector.d.ts.map +1 -0
  340. package/lib/dist/services/connectors/agui/AGUIStreamingConnector.js +95 -0
  341. package/lib/dist/services/connectors/agui/AGUIStreamingConnector.js.map +1 -0
  342. package/lib/dist/services/connectors/base/BaseConnector.d.ts +81 -0
  343. package/lib/dist/services/connectors/base/BaseConnector.d.ts.map +1 -0
  344. package/lib/dist/services/connectors/base/BaseConnector.js +170 -0
  345. package/lib/dist/services/connectors/base/BaseConnector.js.map +1 -0
  346. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.d.ts +126 -0
  347. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.d.ts.map +1 -0
  348. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.js +417 -0
  349. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.js.map +1 -0
  350. package/lib/dist/services/connectors/index.d.ts +13 -0
  351. package/lib/dist/services/connectors/index.d.ts.map +1 -0
  352. package/lib/dist/services/connectors/index.js +32 -0
  353. package/lib/dist/services/connectors/index.js.map +1 -0
  354. package/lib/dist/services/connectors/kiro/KiroConnector.d.ts +48 -0
  355. package/lib/dist/services/connectors/kiro/KiroConnector.d.ts.map +1 -0
  356. package/lib/dist/services/connectors/kiro/KiroConnector.js +158 -0
  357. package/lib/dist/services/connectors/kiro/KiroConnector.js.map +1 -0
  358. package/lib/dist/services/connectors/langgraph/LangGraphConnector.d.ts +36 -0
  359. package/lib/dist/services/connectors/langgraph/LangGraphConnector.d.ts.map +1 -0
  360. package/lib/dist/services/connectors/langgraph/LangGraphConnector.js +175 -0
  361. package/lib/dist/services/connectors/langgraph/LangGraphConnector.js.map +1 -0
  362. package/lib/dist/services/connectors/mock/MockConnector.d.ts +37 -0
  363. package/lib/dist/services/connectors/mock/MockConnector.d.ts.map +1 -0
  364. package/lib/dist/services/connectors/mock/MockConnector.js +120 -0
  365. package/lib/dist/services/connectors/mock/MockConnector.js.map +1 -0
  366. package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.d.ts +42 -0
  367. package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.d.ts.map +1 -0
  368. package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.js +133 -0
  369. package/lib/dist/services/connectors/openai-compatible/OpenAICompatibleConnector.js.map +1 -0
  370. package/lib/dist/services/connectors/pi/PiConnector.d.ts +87 -0
  371. package/lib/dist/services/connectors/pi/PiConnector.d.ts.map +1 -0
  372. package/lib/dist/services/connectors/pi/PiConnector.js +274 -0
  373. package/lib/dist/services/connectors/pi/PiConnector.js.map +1 -0
  374. package/lib/dist/services/connectors/registry.d.ts +57 -0
  375. package/lib/dist/services/connectors/registry.d.ts.map +1 -0
  376. package/lib/dist/services/connectors/registry.js +106 -0
  377. package/lib/dist/services/connectors/registry.js.map +1 -0
  378. package/lib/dist/services/connectors/rest/RESTConnector.d.ts +38 -0
  379. package/lib/dist/services/connectors/rest/RESTConnector.d.ts.map +1 -0
  380. package/lib/dist/services/connectors/rest/RESTConnector.js +117 -0
  381. package/lib/dist/services/connectors/rest/RESTConnector.js.map +1 -0
  382. package/lib/dist/services/connectors/server.d.ts +13 -0
  383. package/lib/dist/services/connectors/server.d.ts.map +1 -0
  384. package/lib/dist/services/connectors/server.js +34 -0
  385. package/lib/dist/services/connectors/server.js.map +1 -0
  386. package/lib/dist/services/connectors/strands/StrandsConnector.d.ts +48 -0
  387. package/lib/dist/services/connectors/strands/StrandsConnector.d.ts.map +1 -0
  388. package/lib/dist/services/connectors/strands/StrandsConnector.js +221 -0
  389. package/lib/dist/services/connectors/strands/StrandsConnector.js.map +1 -0
  390. package/lib/dist/services/connectors/subprocess/SubprocessConnector.d.ts +88 -0
  391. package/lib/dist/services/connectors/subprocess/SubprocessConnector.d.ts.map +1 -0
  392. package/lib/dist/services/connectors/subprocess/SubprocessConnector.js +426 -0
  393. package/lib/dist/services/connectors/subprocess/SubprocessConnector.js.map +1 -0
  394. package/lib/dist/services/connectors/types.d.ts +213 -0
  395. package/lib/dist/services/connectors/types.d.ts.map +1 -0
  396. package/lib/dist/services/connectors/types.js +6 -0
  397. package/lib/dist/services/connectors/types.js.map +1 -0
  398. package/lib/dist/services/evaluation/bedrockJudge.d.ts +71 -0
  399. package/lib/dist/services/evaluation/bedrockJudge.d.ts.map +1 -0
  400. package/lib/dist/services/evaluation/bedrockJudge.js +169 -0
  401. package/lib/dist/services/evaluation/bedrockJudge.js.map +1 -0
  402. package/lib/dist/services/evaluation/evaluatorError.d.ts +56 -0
  403. package/lib/dist/services/evaluation/evaluatorError.d.ts.map +1 -0
  404. package/lib/dist/services/evaluation/evaluatorError.js +56 -0
  405. package/lib/dist/services/evaluation/evaluatorError.js.map +1 -0
  406. package/lib/dist/services/evaluation/index.d.ts +106 -0
  407. package/lib/dist/services/evaluation/index.d.ts.map +1 -0
  408. package/lib/dist/services/evaluation/index.js +684 -0
  409. package/lib/dist/services/evaluation/index.js.map +1 -0
  410. package/lib/dist/services/evaluation/mockTrajectory.d.ts +3 -0
  411. package/lib/dist/services/evaluation/mockTrajectory.d.ts.map +1 -0
  412. package/lib/dist/services/evaluation/mockTrajectory.js +72 -0
  413. package/lib/dist/services/evaluation/mockTrajectory.js.map +1 -0
  414. package/lib/dist/services/opensearch/client.d.ts +26 -0
  415. package/lib/dist/services/opensearch/client.d.ts.map +1 -0
  416. package/lib/dist/services/opensearch/client.js +131 -0
  417. package/lib/dist/services/opensearch/client.js.map +1 -0
  418. package/lib/dist/services/opensearch/index.d.ts +16 -0
  419. package/lib/dist/services/opensearch/index.d.ts.map +1 -0
  420. package/lib/dist/services/opensearch/index.js +25 -0
  421. package/lib/dist/services/opensearch/index.js.map +1 -0
  422. package/lib/dist/services/storage/asyncBenchmarkStorage.d.ts +123 -0
  423. package/lib/dist/services/storage/asyncBenchmarkStorage.d.ts.map +1 -0
  424. package/lib/dist/services/storage/asyncBenchmarkStorage.js +440 -0
  425. package/lib/dist/services/storage/asyncBenchmarkStorage.js.map +1 -0
  426. package/lib/dist/services/storage/asyncRunStorage.d.ts +135 -0
  427. package/lib/dist/services/storage/asyncRunStorage.d.ts.map +1 -0
  428. package/lib/dist/services/storage/asyncRunStorage.js +524 -0
  429. package/lib/dist/services/storage/asyncRunStorage.js.map +1 -0
  430. package/lib/dist/services/storage/asyncTestCaseStorage.d.ts +170 -0
  431. package/lib/dist/services/storage/asyncTestCaseStorage.d.ts.map +1 -0
  432. package/lib/dist/services/storage/asyncTestCaseStorage.js +301 -0
  433. package/lib/dist/services/storage/asyncTestCaseStorage.js.map +1 -0
  434. package/lib/dist/services/storage/index.d.ts +17 -0
  435. package/lib/dist/services/storage/index.d.ts.map +1 -0
  436. package/lib/dist/services/storage/index.js +20 -0
  437. package/lib/dist/services/storage/index.js.map +1 -0
  438. package/lib/dist/services/storage/migration.d.ts +54 -0
  439. package/lib/dist/services/storage/migration.d.ts.map +1 -0
  440. package/lib/dist/services/storage/migration.js +296 -0
  441. package/lib/dist/services/storage/migration.js.map +1 -0
  442. package/lib/dist/services/storage/opensearchClient.d.ts +947 -0
  443. package/lib/dist/services/storage/opensearchClient.d.ts.map +1 -0
  444. package/lib/dist/services/storage/opensearchClient.js +442 -0
  445. package/lib/dist/services/storage/opensearchClient.js.map +1 -0
  446. package/lib/dist/services/traces/browserRecovery.d.ts +37 -0
  447. package/lib/dist/services/traces/browserRecovery.d.ts.map +1 -0
  448. package/lib/dist/services/traces/browserRecovery.js +108 -0
  449. package/lib/dist/services/traces/browserRecovery.js.map +1 -0
  450. package/lib/dist/services/traces/categoryStyles.d.ts +21 -0
  451. package/lib/dist/services/traces/categoryStyles.d.ts.map +1 -0
  452. package/lib/dist/services/traces/categoryStyles.js +56 -0
  453. package/lib/dist/services/traces/categoryStyles.js.map +1 -0
  454. package/lib/dist/services/traces/executionOrderTransform.d.ts +35 -0
  455. package/lib/dist/services/traces/executionOrderTransform.d.ts.map +1 -0
  456. package/lib/dist/services/traces/executionOrderTransform.js +313 -0
  457. package/lib/dist/services/traces/executionOrderTransform.js.map +1 -0
  458. package/lib/dist/services/traces/fetchSpansForRun.d.ts +86 -0
  459. package/lib/dist/services/traces/fetchSpansForRun.d.ts.map +1 -0
  460. package/lib/dist/services/traces/fetchSpansForRun.js +69 -0
  461. package/lib/dist/services/traces/fetchSpansForRun.js.map +1 -0
  462. package/lib/dist/services/traces/flowTransform.d.ts +24 -0
  463. package/lib/dist/services/traces/flowTransform.d.ts.map +1 -0
  464. package/lib/dist/services/traces/flowTransform.js +228 -0
  465. package/lib/dist/services/traces/flowTransform.js.map +1 -0
  466. package/lib/dist/services/traces/index.d.ts +121 -0
  467. package/lib/dist/services/traces/index.d.ts.map +1 -0
  468. package/lib/dist/services/traces/index.js +255 -0
  469. package/lib/dist/services/traces/index.js.map +1 -0
  470. package/lib/dist/services/traces/intentTransform.d.ts +20 -0
  471. package/lib/dist/services/traces/intentTransform.d.ts.map +1 -0
  472. package/lib/dist/services/traces/intentTransform.js +131 -0
  473. package/lib/dist/services/traces/intentTransform.js.map +1 -0
  474. package/lib/dist/services/traces/judgeAgentsHints.d.ts +63 -0
  475. package/lib/dist/services/traces/judgeAgentsHints.d.ts.map +1 -0
  476. package/lib/dist/services/traces/judgeAgentsHints.js +89 -0
  477. package/lib/dist/services/traces/judgeAgentsHints.js.map +1 -0
  478. package/lib/dist/services/traces/messageExtraction.d.ts +15 -0
  479. package/lib/dist/services/traces/messageExtraction.d.ts.map +1 -0
  480. package/lib/dist/services/traces/messageExtraction.js +313 -0
  481. package/lib/dist/services/traces/messageExtraction.js.map +1 -0
  482. package/lib/dist/services/traces/spanCategorization.d.ts +63 -0
  483. package/lib/dist/services/traces/spanCategorization.d.ts.map +1 -0
  484. package/lib/dist/services/traces/spanCategorization.js +276 -0
  485. package/lib/dist/services/traces/spanCategorization.js.map +1 -0
  486. package/lib/dist/services/traces/spanPreprocessing.d.ts +37 -0
  487. package/lib/dist/services/traces/spanPreprocessing.d.ts.map +1 -0
  488. package/lib/dist/services/traces/spanPreprocessing.js +102 -0
  489. package/lib/dist/services/traces/spanPreprocessing.js.map +1 -0
  490. package/lib/dist/services/traces/spansToTrajectory.d.ts +36 -0
  491. package/lib/dist/services/traces/spansToTrajectory.d.ts.map +1 -0
  492. package/lib/dist/services/traces/spansToTrajectory.js +425 -0
  493. package/lib/dist/services/traces/spansToTrajectory.js.map +1 -0
  494. package/lib/dist/services/traces/toolSimilarity.d.ts +35 -0
  495. package/lib/dist/services/traces/toolSimilarity.d.ts.map +1 -0
  496. package/lib/dist/services/traces/toolSimilarity.js +203 -0
  497. package/lib/dist/services/traces/toolSimilarity.js.map +1 -0
  498. package/lib/dist/services/traces/traceComparison.d.ts +31 -0
  499. package/lib/dist/services/traces/traceComparison.d.ts.map +1 -0
  500. package/lib/dist/services/traces/traceComparison.js +318 -0
  501. package/lib/dist/services/traces/traceComparison.js.map +1 -0
  502. package/lib/dist/services/traces/traceGrouping.d.ts +19 -0
  503. package/lib/dist/services/traces/traceGrouping.d.ts.map +1 -0
  504. package/lib/dist/services/traces/traceGrouping.js +107 -0
  505. package/lib/dist/services/traces/traceGrouping.js.map +1 -0
  506. package/lib/dist/services/traces/tracePoller.d.ts +108 -0
  507. package/lib/dist/services/traces/tracePoller.d.ts.map +1 -0
  508. package/lib/dist/services/traces/tracePoller.js +475 -0
  509. package/lib/dist/services/traces/tracePoller.js.map +1 -0
  510. package/lib/dist/services/traces/traceStats.d.ts +45 -0
  511. package/lib/dist/services/traces/traceStats.d.ts.map +1 -0
  512. package/lib/dist/services/traces/traceStats.js +114 -0
  513. package/lib/dist/services/traces/traceStats.js.map +1 -0
  514. package/lib/dist/services/traces/traceSummary.d.ts +47 -0
  515. package/lib/dist/services/traces/traceSummary.d.ts.map +1 -0
  516. package/lib/dist/services/traces/traceSummary.js +68 -0
  517. package/lib/dist/services/traces/traceSummary.js.map +1 -0
  518. package/lib/dist/services/traces/utils.d.ts +33 -0
  519. package/lib/dist/services/traces/utils.d.ts.map +1 -0
  520. package/lib/dist/services/traces/utils.js +114 -0
  521. package/lib/dist/services/traces/utils.js.map +1 -0
  522. package/lib/dist/types/agui.d.ts +13 -0
  523. package/lib/dist/types/agui.d.ts.map +1 -0
  524. package/lib/dist/types/agui.js +16 -0
  525. package/lib/dist/types/agui.js.map +1 -0
  526. package/lib/dist/types/index.d.ts +1229 -0
  527. package/lib/dist/types/index.d.ts.map +1 -0
  528. package/lib/dist/types/index.js +12 -0
  529. package/lib/dist/types/index.js.map +1 -0
  530. package/lib/dist/types/skills.d.ts +146 -0
  531. package/lib/dist/types/skills.d.ts.map +1 -0
  532. package/lib/dist/types/skills.js +6 -0
  533. package/lib/dist/types/skills.js.map +1 -0
  534. package/observio-sample-agent/pi-package/README.md +112 -0
  535. package/observio-sample-agent/pi-package/extensions/agent-health.ts +373 -0
  536. package/observio-sample-agent/pi-package/package.json +17 -0
  537. package/observio-sample-agent/pi-package/prompts/agent-health.md +37 -0
  538. package/observio-sample-agent/pi-package/skills/create-pr/SKILL.md +88 -0
  539. package/observio-sample-agent/pi-package/skills/fix-bug/SKILL.md +71 -0
  540. package/observio-sample-agent/pi-package/skills/implement-feature/SKILL.md +156 -0
  541. package/observio-sample-agent/pi-package/skills/instrument-otel/SKILL.md +208 -0
  542. package/observio-sample-agent/pi-package/skills/setup-collector/SKILL.md +146 -0
  543. package/observio-sample-agent/pi-package/skills/write-test/SKILL.md +115 -0
  544. package/package.json +45 -9
  545. package/server/dist/app.js +34031 -18731
  546. package/server/dist/index.js +30737 -15338
  547. package/tsconfig.lib.json +71 -0
  548. package/dist/assets/index-BOIP5L7h.js +0 -246
  549. package/dist/assets/index-CU9YKpAL.css +0 -1
  550. package/lib/dist/config/index.js +0 -452
  551. package/lib/dist/index.js +0 -1725
@@ -0,0 +1,99 @@
1
+ /*
2
+ * Copyright OpenSearch Contributors
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ /**
7
+ * SDK lifecycle hooks demo — shows beforeEach/afterEach, beforeAll/afterAll,
8
+ * and the `provide()` mechanism for surfacing per-test provisioned values
9
+ * to the body and the teardown hook.
10
+ *
11
+ * The example uses a temp directory as the "out-of-band resource" — the
12
+ * exact thing connectors can't do today (no lifecycle, no teardown). Each
13
+ * test gets its own directory; concurrent runs are isolated automatically.
14
+ *
15
+ * Run with:
16
+ * AH_PORT=4002 npx @opensearch-project/agent-health benchmark \
17
+ * -f examples/eval-files/sdk-hooks-demo.eval.js -a demo
18
+ */
19
+
20
+ const fs = require('fs');
21
+ const os = require('os');
22
+ const path = require('path');
23
+
24
+ const {
25
+ test,
26
+ beforeAll,
27
+ afterAll,
28
+ beforeEach,
29
+ afterEach,
30
+ expect,
31
+ } = require('@opensearch-project/agent-health');
32
+
33
+ // ─────────────────────────────────────────────────────────────────────────────
34
+ // Suite-scoped: runs once before any test, once after them all.
35
+ // ─────────────────────────────────────────────────────────────────────────────
36
+
37
+ let suiteRoot;
38
+
39
+ beforeAll(() => {
40
+ suiteRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ah-hooks-demo-'));
41
+ });
42
+
43
+ afterAll(() => {
44
+ if (suiteRoot && fs.existsSync(suiteRoot)) {
45
+ fs.rmSync(suiteRoot, { recursive: true, force: true });
46
+ }
47
+ });
48
+
49
+ // ─────────────────────────────────────────────────────────────────────────────
50
+ // Per-test: each test gets its own subdirectory, surfaced via `provide()`.
51
+ // `afterEach` reads the same key from `provisioned` to clean up, even when
52
+ // the body throws.
53
+ // ─────────────────────────────────────────────────────────────────────────────
54
+
55
+ beforeEach(({ provide, testInfo }) => {
56
+ const safe = testInfo.name.replace(/[^a-z0-9-]+/gi, '_');
57
+ const dir = fs.mkdtempSync(path.join(suiteRoot, `${safe}-`));
58
+ provide('workspaceDir', dir);
59
+ });
60
+
61
+ afterEach(({ provisioned }) => {
62
+ const dir = provisioned.workspaceDir;
63
+ if (typeof dir === 'string' && fs.existsSync(dir)) {
64
+ fs.rmSync(dir, { recursive: true, force: true });
65
+ }
66
+ });
67
+
68
+ // ─────────────────────────────────────────────────────────────────────────────
69
+ // Tests — read the provisioned value via `fixtures.provisioned`. No prompt
70
+ // is set so the runner skips the agent and runs the body directly; the
71
+ // hooks still run because they don't depend on the agent step.
72
+ // ─────────────────────────────────────────────────────────────────────────────
73
+
74
+ test('hook-demo-uses-workspace', {
75
+ description: 'beforeEach provisioned a fresh temp dir for this test',
76
+ labels: ['category:Smoke', 'feature:hooks'],
77
+ }, ({ provisioned, testInfo }) => {
78
+ expect(provisioned.workspaceDir).to.be.a('string');
79
+ expect(fs.existsSync(provisioned.workspaceDir)).to.equal(true);
80
+
81
+ // The dir's basename must include the test name, proving testInfo flowed
82
+ // through `provide()` correctly.
83
+ expect(path.basename(provisioned.workspaceDir)).to.include(
84
+ testInfo.name.replace(/[^a-z0-9-]+/gi, '_')
85
+ );
86
+
87
+ // Write a file inside, just to show it's a real, writable workspace.
88
+ fs.writeFileSync(path.join(provisioned.workspaceDir, 'marker'), 'hello');
89
+ });
90
+
91
+ test('hook-demo-isolation', {
92
+ description: 'A second test gets its own isolated workspace',
93
+ labels: ['category:Smoke', 'feature:hooks'],
94
+ }, ({ provisioned }) => {
95
+ expect(provisioned.workspaceDir).to.be.a('string');
96
+ // Concurrent tests would each see their own dir; this one in particular
97
+ // must NOT see the marker file from the other test.
98
+ expect(fs.existsSync(path.join(provisioned.workspaceDir, 'marker'))).to.equal(false);
99
+ });
@@ -0,0 +1,77 @@
1
+ <!--
2
+ * Copyright OpenSearch Contributors
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ -->
5
+
6
+ # Pi session profiling — drop-in extension
7
+
8
+ Profile your **pi.dev** coding sessions with Agent Health, the way a CPU profiler
9
+ profiles a running process: instrument a real session, then get back what to fix
10
+ (scored against an evaluator rubric) to improve the agent and your own
11
+ productivity.
12
+
13
+ pi has **no native OpenTelemetry telemetry**, so `agent-health profile` has
14
+ nothing to read for a live pi session. This single file supplies that missing
15
+ half: it instruments the running session (emitting OTel spans) **and** registers
16
+ the `/agent-health-profile` command. It is **zero-dependency** — it speaks OTLP
17
+ over the built-in `fetch`, so there is nothing to `npm install`.
18
+
19
+ ## Install (out of the box)
20
+
21
+ ```bash
22
+ # 1. Drop the extension in (global = every pi session; or .pi/extensions/ per project)
23
+ mkdir -p ~/.pi/agent/extensions
24
+ cp agent-health-profile.ts ~/.pi/agent/extensions/
25
+
26
+ # 2. Point telemetry at a trace store BEFORE starting pi.
27
+ # Simplest: Agent Health in FILE mode (no OpenSearch) — its embedded receiver
28
+ # persists spans and matches sessions out of the box:
29
+ agent-health serve # or any command that boots the server on :4001
30
+ export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4001 # /v1/traces is appended
31
+ ```
32
+
33
+ That's it. Use pi normally, then run `/agent-health-profile` (or
34
+ `/agent-health-profile -e <evaluator-id> -f "focus on X"`).
35
+
36
+ ## How it routes (important for OpenSearch users)
37
+
38
+ The extension exports OTLP/JSON to `OTEL_EXPORTER_OTLP_ENDPOINT`:
39
+
40
+ - **File mode (recommended for getting started):** point it at Agent Health's
41
+ embedded `:4001/v1/traces`. Spans persist to disk and `profile` matches them by
42
+ `session.id` directly. Zero infra.
43
+ - **OpenSearch-backed Agent Health:** the embedded `:4001` receiver *drops*
44
+ payloads when a cluster is configured (no split-brain). Point the extension at
45
+ the **same OTLP ingest the cluster reads from** (your OTel Collector / OSIS
46
+ pipeline). The extension emits a standard OTLP `session.id` attribute — it is
47
+ schema-agnostic; what matters is that your ingest and `agent-health profile`'s
48
+ session query agree on where `session.id` lands. Agent Health is standardizing
49
+ on the plain/nested schema (`attributes.session.id`; OSIS
50
+ `trace-analytics-plain-raw`), moving off the legacy `@`-flattened
51
+ `span.attributes.session@id` layout.
52
+
53
+ ## Config (env)
54
+
55
+ | Var | Default | Meaning |
56
+ |-----|---------|---------|
57
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://localhost:4001` | OTLP traces target (`/v1/traces` appended) |
58
+ | `OTEL_SERVICE_NAME` | `pi-agent` | service.name on spans (keep `pi-agent` for `--service` defaults) |
59
+ | `OTEL_ENABLED` | `true` | set `false` to disable telemetry |
60
+ | `AGENT_HEALTH_REDACT` | unset | `1` → redact prompt / tool I/O |
61
+ | `AGENT_HEALTH_CLI` | `npx @opensearch-project/agent-health` | how the command invokes the CLI |
62
+
63
+ ## What it emits
64
+
65
+ | Span | `gen_ai.operation.name` | Notes |
66
+ |------|-------------------------|-------|
67
+ | `invoke_agent pi` (root) | `invoke_agent` | one per session; carries `session.id` |
68
+ | `chat <model>` (per turn) | `chat` | token usage + `llm.request`/`llm.response` events |
69
+ | `execute_tool <name>` | `execute_tool` | `gen_ai.tool.input`/`output`; ERROR status on failure |
70
+
71
+ Every span carries `session.id`; the resource carries `service.name=pi-agent`.
72
+
73
+ ## Caveat
74
+
75
+ Profiling only sees sessions that ran **while the extension was loaded and
76
+ telemetry was on** — you can't profile a session retroactively. Run a session,
77
+ then `/agent-health-profile`.
@@ -0,0 +1,417 @@
1
+ /*
2
+ * Copyright OpenSearch Contributors
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ /**
7
+ * Agent Health — pi session profiling extension (single-file, zero-dependency).
8
+ *
9
+ * Drop this one file into `~/.pi/agent/extensions/` (global) or
10
+ * `.pi/extensions/` (project) and pi will auto-load it. No `npm install` — it
11
+ * speaks OTLP/HTTP JSON over the built-in `fetch`, so there are no
12
+ * `@opentelemetry/*` dependencies to resolve.
13
+ *
14
+ * Why it exists: pi has no native OpenTelemetry telemetry (unlike Claude Code's
15
+ * CLAUDE_CODE_ENABLE_TELEMETRY), so `agent-health profile` has nothing to read
16
+ * for a live pi session. This extension supplies that missing half — it
17
+ * instruments the running session and registers the profiling command.
18
+ *
19
+ * What it does:
20
+ * 1. Emits OTel spans for the session (root `invoke_agent pi`, one
21
+ * `chat <model>` span per turn with token usage + prompt/completion, and an
22
+ * `execute_tool <name>` span per tool call). Every span carries
23
+ * `session.id`; the resource carries `service.name=pi-agent`.
24
+ * 2. Records the session id to `.pi/agent-health/current-session` so
25
+ * `agent-health profile` resolves it deterministically.
26
+ * 3. Registers `/agent-health-profile -e <id> [-f "<feedback>"]`, which runs
27
+ * the CLI and feeds the rubric + trajectory + signals back into the chat.
28
+ *
29
+ * Config (env):
30
+ * - OTEL_EXPORTER_OTLP_ENDPOINT where to export (default http://localhost:4001;
31
+ * `/v1/traces` is appended if missing). Point at
32
+ * Agent Health's embedded receiver (file mode),
33
+ * an OTel Collector, or an OSIS pipeline.
34
+ * - OTEL_SERVICE_NAME default `pi-agent`.
35
+ * - OTEL_ENABLED=false disable telemetry (command still explains how).
36
+ * - AGENT_HEALTH_REDACT=1 stamp redaction placeholders instead of capturing
37
+ * prompt / tool I/O.
38
+ * - AGENT_HEALTH_CLI CLI invocation (default `npx @opensearch-project/agent-health`).
39
+ *
40
+ * See docs/skills/AGENT_PROFILE.md.
41
+ */
42
+
43
+ import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
44
+ import { randomBytes } from 'node:crypto';
45
+ import { mkdirSync, writeFileSync } from 'node:fs';
46
+ import { join } from 'node:path';
47
+
48
+ // ─── Pure, exported helpers (unit-tested; no pi/OTel imports) ────────────────
49
+
50
+ export const PI_SERVICE_NAME = 'pi-agent';
51
+ export const PI_SCOPE_NAME = 'agent-health-pi';
52
+ export const DEFAULT_ENDPOINT = 'http://localhost:4001';
53
+ export const DEFAULT_CLI = 'npx @opensearch-project/agent-health';
54
+ export const DEFAULT_EVALUATOR = 'system-rca-default';
55
+ export const REDACTED = '[redacted]';
56
+
57
+ export type OtlpValue = { stringValue: string } | { intValue: string } | { boolValue: boolean };
58
+ export interface OtlpKeyValue { key: string; value: OtlpValue; }
59
+ export interface OtlpEvent { name: string; timeUnixNano: string; attributes: OtlpKeyValue[]; }
60
+ export interface OtlpSpan {
61
+ traceId: string;
62
+ spanId: string;
63
+ parentSpanId?: string;
64
+ name: string;
65
+ kind: number;
66
+ startTimeUnixNano: string;
67
+ endTimeUnixNano: string;
68
+ attributes: OtlpKeyValue[];
69
+ events: OtlpEvent[];
70
+ status: { code: number };
71
+ }
72
+
73
+ export function randomHex(bytes: number): string {
74
+ return randomBytes(bytes).toString('hex');
75
+ }
76
+ export const genTraceId = () => randomHex(16); // 32 hex chars
77
+ export const genSpanId = () => randomHex(8); // 16 hex chars
78
+
79
+ /** Parse a W3C `traceparent` (`00-<trace>-<span>-<flags>`). */
80
+ export function parseTraceparent(tp?: string): { traceId: string; spanId: string } | null {
81
+ if (!tp) return null;
82
+ const m = tp.trim().match(/^[0-9a-f]{2}-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/i);
83
+ return m ? { traceId: m[1].toLowerCase(), spanId: m[2].toLowerCase() } : null;
84
+ }
85
+
86
+ /** Resolve the full OTLP traces URL from a base endpoint. */
87
+ export function resolveEndpoint(base?: string): string {
88
+ const b = (base || DEFAULT_ENDPOINT).replace(/\/$/, '');
89
+ return b.endsWith('/v1/traces') ? b : `${b}/v1/traces`;
90
+ }
91
+
92
+ /** Stable session id from pi's session file path (basename minus extension). */
93
+ export function sessionIdFromFile(file?: string | null): string | undefined {
94
+ if (!file) return undefined;
95
+ const base = file.split(/[\\/]/).pop() ?? file;
96
+ const stem = base.replace(/\.[^.]+$/, '').trim();
97
+ return stem || undefined;
98
+ }
99
+
100
+ export function numOrUndef(v: unknown): number | undefined {
101
+ const n = Number(v);
102
+ return Number.isFinite(n) ? n : undefined;
103
+ }
104
+
105
+ export function truncate(s: unknown, max = 5000): string {
106
+ const str = typeof s === 'string' ? s : safeStringify(s);
107
+ return str.length > max ? `${str.slice(0, max)}…` : str;
108
+ }
109
+
110
+ export function safeStringify(v: unknown): string {
111
+ if (v == null) return '';
112
+ if (typeof v === 'string') return v;
113
+ try { return JSON.stringify(v); } catch { return String(v); }
114
+ }
115
+
116
+ /** Pull plain text out of a pi assistant message `content` (string or blocks). */
117
+ export function extractText(content: unknown): string | undefined {
118
+ if (typeof content === 'string') return content || undefined;
119
+ if (!Array.isArray(content)) return undefined;
120
+ const parts = content
121
+ .filter((b): b is { type: string; text: string } =>
122
+ !!b && (b as any).type === 'text' && typeof (b as any).text === 'string')
123
+ .map((b) => b.text);
124
+ return parts.length ? parts.join('\n') : undefined;
125
+ }
126
+
127
+ /** Parse `<flag> <value>` (quoted or bare) from a raw command arg string. */
128
+ export function parseFlag(args: string, flags: string[]): string | undefined {
129
+ const names = flags.map((f) => f.replace(/^-+/, '')).join('|');
130
+ const re = new RegExp(`(?:^|\\s)(?:-{1,2})(?:${names})\\s+("([^"]*)"|'([^']*)'|(\\S+))`);
131
+ const m = (args || '').match(re);
132
+ return m ? (m[2] ?? m[3] ?? m[4]) : undefined;
133
+ }
134
+
135
+ /** Build the `agent-health profile …` argv (binary + args) for a pi session. */
136
+ export function buildProfileInvocation(opts: {
137
+ cli?: string; sessionId: string; evaluator?: string; feedback?: string; service?: string;
138
+ }): { bin: string; args: string[] } {
139
+ const [bin, ...binArgs] = (opts.cli || DEFAULT_CLI).trim().split(/\s+/);
140
+ const args = [
141
+ ...binArgs, 'profile',
142
+ '-e', opts.evaluator || DEFAULT_EVALUATOR,
143
+ '--session', opts.sessionId,
144
+ '--service', opts.service || PI_SERVICE_NAME,
145
+ '--output', 'json',
146
+ ];
147
+ if (opts.feedback) args.push('--feedback', opts.feedback);
148
+ return { bin, args };
149
+ }
150
+
151
+ /** Extract the JSON object from CLI stdout (tolerant of leading log lines). */
152
+ export function extractJson(stdout: string): unknown | null {
153
+ if (!stdout) return null;
154
+ const start = stdout.indexOf('{');
155
+ const end = stdout.lastIndexOf('}');
156
+ if (start === -1 || end === -1 || end < start) return null;
157
+ try { return JSON.parse(stdout.slice(start, end + 1)); } catch { return null; }
158
+ }
159
+
160
+ function kv(attributes: Record<string, string | number | boolean>): OtlpKeyValue[] {
161
+ return Object.entries(attributes).map(([key, value]) => ({
162
+ key,
163
+ value: typeof value === 'number'
164
+ ? { intValue: String(value) }
165
+ : typeof value === 'boolean'
166
+ ? { boolValue: value }
167
+ : { stringValue: String(value) },
168
+ }));
169
+ }
170
+
171
+ /** Wrap finished spans into an OTLP/JSON ExportTraceServiceRequest. */
172
+ export function buildOtlpPayload(serviceName: string, spans: OtlpSpan[]) {
173
+ return {
174
+ resourceSpans: [{
175
+ resource: { attributes: kv({ 'service.name': serviceName }) },
176
+ scopeSpans: [{ scope: { name: PI_SCOPE_NAME }, spans }],
177
+ }],
178
+ };
179
+ }
180
+
181
+ const SPAN_KIND_SERVER = 2;
182
+ const SPAN_KIND_CLIENT = 3;
183
+ const STATUS_OK = 1;
184
+ const STATUS_ERROR = 2;
185
+
186
+ export interface SpanTimes { startNs: string; endNs: string; }
187
+ export function msToNanos(ms: number): string { return `${Math.round(ms)}000000`; }
188
+
189
+ /** Root session span (`invoke_agent pi`). */
190
+ export function buildRootSpan(p: { traceId: string; spanId: string; parentSpanId?: string; sessionId: string; times: SpanTimes }): OtlpSpan {
191
+ return {
192
+ traceId: p.traceId, spanId: p.spanId, ...(p.parentSpanId ? { parentSpanId: p.parentSpanId } : {}),
193
+ name: 'invoke_agent pi', kind: SPAN_KIND_SERVER,
194
+ startTimeUnixNano: p.times.startNs, endTimeUnixNano: p.times.endNs,
195
+ attributes: kv({ 'gen_ai.operation.name': 'invoke_agent', 'gen_ai.system': 'pi', 'gen_ai.agent.name': 'pi', 'session.id': p.sessionId }),
196
+ events: [], status: { code: STATUS_OK },
197
+ };
198
+ }
199
+
200
+ /** Chat (LLM) span for one turn. */
201
+ export function buildChatSpan(p: {
202
+ traceId: string; spanId: string; parentSpanId: string; sessionId: string; times: SpanTimes;
203
+ model: string; inputTokens?: number; outputTokens?: number; userPrompt?: string; completion?: string; redact?: boolean;
204
+ }): OtlpSpan {
205
+ const attrs: Record<string, string | number | boolean> = {
206
+ 'gen_ai.operation.name': 'chat', 'gen_ai.system': 'pi', 'gen_ai.request.model': p.model || 'unknown', 'session.id': p.sessionId,
207
+ };
208
+ if (typeof p.inputTokens === 'number') attrs['gen_ai.usage.input_tokens'] = p.inputTokens;
209
+ if (typeof p.outputTokens === 'number') attrs['gen_ai.usage.output_tokens'] = p.outputTokens;
210
+ const events: OtlpEvent[] = [];
211
+ if (p.userPrompt != null) {
212
+ events.push({ name: 'llm.request', timeUnixNano: p.times.startNs, attributes: kv({ 'gen_ai.prompt': p.redact ? REDACTED : truncate(p.userPrompt) }) });
213
+ }
214
+ if (p.completion != null) {
215
+ events.push({ name: 'llm.response', timeUnixNano: p.times.endNs, attributes: kv({ 'llm.completion': p.redact ? REDACTED : truncate(p.completion) }) });
216
+ }
217
+ return {
218
+ traceId: p.traceId, spanId: p.spanId, parentSpanId: p.parentSpanId,
219
+ name: `chat ${p.model || 'pi'}`, kind: SPAN_KIND_CLIENT,
220
+ startTimeUnixNano: p.times.startNs, endTimeUnixNano: p.times.endNs,
221
+ attributes: kv(attrs), events, status: { code: STATUS_OK },
222
+ };
223
+ }
224
+
225
+ /** Tool execution span (`execute_tool <name>`). */
226
+ export function buildToolSpan(p: {
227
+ traceId: string; spanId: string; parentSpanId: string; sessionId: string; times: SpanTimes;
228
+ toolName: string; input?: unknown; output?: unknown; isError?: boolean; redact?: boolean;
229
+ }): OtlpSpan {
230
+ const attrs: Record<string, string | number | boolean> = {
231
+ 'gen_ai.operation.name': 'execute_tool', 'gen_ai.tool.name': p.toolName, 'session.id': p.sessionId,
232
+ };
233
+ if (p.input != null) attrs['gen_ai.tool.input'] = p.redact ? REDACTED : truncate(p.input, 3000);
234
+ if (p.output != null) attrs['gen_ai.tool.output'] = p.redact ? REDACTED : truncate(p.output, 3000);
235
+ return {
236
+ traceId: p.traceId, spanId: p.spanId, parentSpanId: p.parentSpanId,
237
+ name: `execute_tool ${p.toolName}`, kind: SPAN_KIND_CLIENT,
238
+ startTimeUnixNano: p.times.startNs, endTimeUnixNano: p.times.endNs,
239
+ attributes: kv(attrs), events: [], status: { code: p.isError ? STATUS_ERROR : STATUS_OK },
240
+ };
241
+ }
242
+
243
+ // ─── The extension (I/O wiring; not unit-tested) ─────────────────────────────
244
+
245
+ const SESSION_DIR = join('.pi', 'agent-health');
246
+ const SESSION_FILE = join(SESSION_DIR, 'current-session');
247
+
248
+ export default function (pi: ExtensionAPI) {
249
+ let sessionId: string | null = null;
250
+ let traceId: string | null = null;
251
+ let rootSpanId: string | null = null;
252
+ let rootStartNs: string | null = null;
253
+ const buffer: OtlpSpan[] = [];
254
+
255
+ // Per-turn / per-tool scratch state.
256
+ let turnStartMs = 0;
257
+ let pendingUserPrompt: string | undefined;
258
+ let firstTurnOfInvocation = false;
259
+ let lastUsage: { inputTokens?: number; outputTokens?: number } = {};
260
+ let lastCompletion: string | undefined;
261
+ let lastModel = 'unknown';
262
+ const toolStart = new Map<string, { startMs: number; toolName: string; input: unknown }>();
263
+
264
+ const redact = process.env.AGENT_HEALTH_REDACT === '1';
265
+ const endpoint = resolveEndpoint(process.env.OTEL_EXPORTER_OTLP_ENDPOINT);
266
+ const serviceName = process.env.OTEL_SERVICE_NAME || PI_SERVICE_NAME;
267
+ // Opt-in: only emit when an endpoint is explicitly configured, so a
268
+ // globally-installed copy never POSTs unexpectedly for unconfigured sessions.
269
+ const telemetryEnabled = (): boolean =>
270
+ process.env.OTEL_ENABLED !== 'false' && !!process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
271
+
272
+ async function flush(): Promise<void> {
273
+ if (!telemetryEnabled() || buffer.length === 0) return;
274
+ const batch = buffer.splice(0, buffer.length);
275
+ try {
276
+ await fetch(endpoint, {
277
+ method: 'POST',
278
+ headers: { 'Content-Type': 'application/json' },
279
+ body: JSON.stringify(buildOtlpPayload(serviceName, batch)),
280
+ });
281
+ } catch {
282
+ // Best-effort: drop the batch rather than block the session.
283
+ }
284
+ }
285
+
286
+ function recordSessionId(id: string): void {
287
+ try { mkdirSync(SESSION_DIR, { recursive: true }); writeFileSync(SESSION_FILE, id); } catch { /* best-effort */ }
288
+ }
289
+
290
+ pi.on('session_start', async (_e, ctx) => {
291
+ sessionId = sessionIdFromFile(ctx.sessionManager.getSessionFile()) ?? null;
292
+ if (!sessionId) return; // ephemeral session
293
+ recordSessionId(sessionId);
294
+ if (!telemetryEnabled()) return;
295
+
296
+ const parent = parseTraceparent(process.env.TRACEPARENT);
297
+ traceId = parent?.traceId ?? genTraceId();
298
+ rootSpanId = genSpanId();
299
+ rootStartNs = msToNanos(Date.now());
300
+ // Root span is finalized at shutdown; record start now.
301
+ });
302
+
303
+ pi.on('model_select', async (event) => {
304
+ const id = (event as { model?: { id?: string } }).model?.id;
305
+ if (id) lastModel = String(id);
306
+ });
307
+
308
+ pi.on('before_agent_start', async (event) => {
309
+ const prompt = (event as { prompt?: unknown }).prompt;
310
+ pendingUserPrompt = typeof prompt === 'string' ? prompt : undefined;
311
+ firstTurnOfInvocation = true;
312
+ });
313
+
314
+ pi.on('turn_start', async () => {
315
+ turnStartMs = Date.now();
316
+ lastUsage = {};
317
+ lastCompletion = undefined;
318
+ });
319
+
320
+ pi.on('message_end', async (event) => {
321
+ const msg = (event as { message?: any }).message;
322
+ if (!msg || msg.role !== 'assistant') return;
323
+ const usage = msg.usage || {};
324
+ lastUsage = {
325
+ inputTokens: numOrUndef(usage.inputTokens ?? usage.input_tokens ?? usage.promptTokens),
326
+ outputTokens: numOrUndef(usage.outputTokens ?? usage.output_tokens ?? usage.completionTokens),
327
+ };
328
+ lastCompletion = extractText(msg.content);
329
+ if (msg.model) lastModel = String(msg.model);
330
+ });
331
+
332
+ pi.on('turn_end', async () => {
333
+ if (!traceId || !rootSpanId || !sessionId) return;
334
+ buffer.push(buildChatSpan({
335
+ traceId, spanId: genSpanId(), parentSpanId: rootSpanId, sessionId,
336
+ times: { startNs: msToNanos(turnStartMs || Date.now()), endNs: msToNanos(Date.now()) },
337
+ model: lastModel, inputTokens: lastUsage.inputTokens, outputTokens: lastUsage.outputTokens,
338
+ userPrompt: firstTurnOfInvocation ? pendingUserPrompt : undefined, completion: lastCompletion, redact,
339
+ }));
340
+ firstTurnOfInvocation = false;
341
+ await flush();
342
+ });
343
+
344
+ pi.on('tool_execution_start', async (event) => {
345
+ const e = event as { toolCallId?: string; toolName?: string; args?: unknown };
346
+ toolStart.set(String(e.toolCallId), { startMs: Date.now(), toolName: String(e.toolName ?? 'tool'), input: e.args });
347
+ });
348
+
349
+ pi.on('tool_execution_end', async (event) => {
350
+ if (!traceId || !rootSpanId || !sessionId) return;
351
+ const e = event as { toolCallId?: string; result?: unknown; isError?: boolean };
352
+ const started = toolStart.get(String(e.toolCallId));
353
+ toolStart.delete(String(e.toolCallId));
354
+ buffer.push(buildToolSpan({
355
+ traceId, spanId: genSpanId(), parentSpanId: rootSpanId, sessionId,
356
+ times: { startNs: msToNanos(started?.startMs ?? Date.now()), endNs: msToNanos(Date.now()) },
357
+ toolName: started?.toolName ?? 'tool', input: started?.input, output: e.result, isError: !!e.isError, redact,
358
+ }));
359
+ await flush();
360
+ });
361
+
362
+ pi.on('session_shutdown', async () => {
363
+ if (traceId && rootSpanId && sessionId && rootStartNs) {
364
+ buffer.push(buildRootSpan({ traceId, spanId: rootSpanId, parentSpanId: parseTraceparent(process.env.TRACEPARENT)?.spanId, sessionId, times: { startNs: rootStartNs, endNs: msToNanos(Date.now()) } }));
365
+ }
366
+ await flush();
367
+ });
368
+
369
+ pi.registerCommand('agent-health-profile', {
370
+ description: 'Profile this pi session against an evaluator rubric and propose fixes',
371
+ handler: async (args, ctx) => {
372
+ const id = sessionId ?? sessionIdFromFile(ctx.sessionManager.getSessionFile());
373
+ if (!id) {
374
+ ctx.ui.notify('No session id (ephemeral session) — start pi without --no-session to profile.', 'warning');
375
+ return;
376
+ }
377
+ if (!telemetryEnabled()) {
378
+ ctx.ui.notify('Telemetry is off — set OTEL_EXPORTER_OTLP_ENDPOINT (e.g. http://localhost:4001 for file-mode Agent Health) and re-run the session so its traces are captured.', 'warning');
379
+ return;
380
+ }
381
+ await flush(); // ensure the just-finished turns are queryable
382
+
383
+ const { bin, args: cmdArgs } = buildProfileInvocation({
384
+ cli: process.env.AGENT_HEALTH_CLI || DEFAULT_CLI,
385
+ sessionId: id,
386
+ evaluator: parseFlag(args, ['-e', '--evaluator']),
387
+ feedback: parseFlag(args, ['-f', '--feedback']),
388
+ service: serviceName,
389
+ });
390
+ ctx.ui.notify(`Profiling pi session ${id}…`, 'info');
391
+ const result = await pi.exec(bin, cmdArgs, { timeout: 120_000 });
392
+ if (result.code !== 0) {
393
+ ctx.ui.notify(`profile failed (exit ${result.code}): ${truncate(result.stderr || result.stdout, 400)}`, 'error');
394
+ return;
395
+ }
396
+ const profile = extractJson(result.stdout);
397
+ if (!profile) {
398
+ ctx.ui.notify('profile produced no JSON — is telemetry reaching the trace store?', 'error');
399
+ return;
400
+ }
401
+ pi.sendUserMessage([
402
+ 'I ran `agent-health profile` on THIS pi session. Below is the JSON profile:',
403
+ 'the evaluator rubric (`evaluator.systemPrompt`), the reconstructed `trajectory`,',
404
+ 'deterministic `signals`, and my `userFeedback` (if any).',
405
+ '',
406
+ 'Using `evaluator.systemPrompt` as the rubric, review the trajectory + signals',
407
+ '+ THIS conversation (including any corrections I made) + the codebase here.',
408
+ 'Produce a prioritized list of concrete edits (file, change, why — cite the',
409
+ 'signal/`traceIds`, priority) and apply them on a NEW branch for review.',
410
+ '',
411
+ '```json',
412
+ truncate(JSON.stringify(profile), 60_000),
413
+ '```',
414
+ ].join('\n'));
415
+ },
416
+ });
417
+ }
@@ -0,0 +1,29 @@
1
+ import { AgentConfig } from '../types/index.js';
2
+ /**
3
+ * Determines if an agent can be run from the browser UI.
4
+ *
5
+ * Some agents (like Claude Code) require CLI execution because they:
6
+ * - Spawn local processes via child_process.spawn() (Node.js only)
7
+ * - Access local filesystem or environment variables
8
+ * - Cannot operate within browser sandbox security constraints
9
+ *
10
+ * @param agent - The agent configuration to check
11
+ * @returns true if the agent can be run from the browser, false if CLI-only
12
+ */
13
+ export declare function isBrowserCompatible(agent: AgentConfig): boolean;
14
+ /**
15
+ * Gets a user-friendly explanation for why an agent cannot run from the UI.
16
+ *
17
+ * @param agent - The agent configuration to check
18
+ * @returns Error message if agent requires CLI, null if browser-compatible
19
+ */
20
+ export declare function getAgentUnavailableReason(agent: AgentConfig): string | null;
21
+ /**
22
+ * Gets the first browser-compatible agent from a list.
23
+ * Useful for setting default selection in UI components.
24
+ *
25
+ * @param agents - List of agent configurations
26
+ * @returns The first browser-compatible agent, or undefined if none found
27
+ */
28
+ export declare function getFirstBrowserCompatibleAgent(agents: AgentConfig[]): AgentConfig | undefined;
29
+ //# sourceMappingURL=agentUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentUtils.d.ts","sourceRoot":"","sources":["../../agentUtils.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGtC;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAG/D;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAM3E;AAED;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,WAAW,GAAG,SAAS,CAE7F"}
@@ -0,0 +1,43 @@
1
+ /*
2
+ * Copyright OpenSearch Contributors
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { BROWSER_SAFE_CONNECTORS } from '../lib/constants.js';
6
+ /**
7
+ * Determines if an agent can be run from the browser UI.
8
+ *
9
+ * Some agents (like Claude Code) require CLI execution because they:
10
+ * - Spawn local processes via child_process.spawn() (Node.js only)
11
+ * - Access local filesystem or environment variables
12
+ * - Cannot operate within browser sandbox security constraints
13
+ *
14
+ * @param agent - The agent configuration to check
15
+ * @returns true if the agent can be run from the browser, false if CLI-only
16
+ */
17
+ export function isBrowserCompatible(agent) {
18
+ const connectorType = agent.connectorType || 'agui-streaming';
19
+ return BROWSER_SAFE_CONNECTORS.includes(connectorType);
20
+ }
21
+ /**
22
+ * Gets a user-friendly explanation for why an agent cannot run from the UI.
23
+ *
24
+ * @param agent - The agent configuration to check
25
+ * @returns Error message if agent requires CLI, null if browser-compatible
26
+ */
27
+ export function getAgentUnavailableReason(agent) {
28
+ if (isBrowserCompatible(agent)) {
29
+ return null;
30
+ }
31
+ return `This agent requires the CLI. Run with: npx @opensearch-project/agent-health run -t <test-case> -a ${agent.key}`;
32
+ }
33
+ /**
34
+ * Gets the first browser-compatible agent from a list.
35
+ * Useful for setting default selection in UI components.
36
+ *
37
+ * @param agents - List of agent configurations
38
+ * @returns The first browser-compatible agent, or undefined if none found
39
+ */
40
+ export function getFirstBrowserCompatibleAgent(agents) {
41
+ return agents.find(agent => isBrowserCompatible(agent));
42
+ }
43
+ //# sourceMappingURL=agentUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentUtils.js","sourceRoot":"","sources":["../../agentUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAkB;IACpD,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,IAAI,gBAAgB,CAAC;IAC9D,OAAO,uBAAuB,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAAkB;IAC1D,IAAI,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,qGAAqG,KAAK,CAAC,GAAG,EAAE,CAAC;AAC1H,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,8BAA8B,CAAC,MAAqB;IAClE,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1D,CAAC"}