elasticdash-sdk 0.2.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 (349) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +775 -0
  3. package/dist/browser-ui.d.ts +43 -0
  4. package/dist/browser-ui.d.ts.map +1 -0
  5. package/dist/browser-ui.js +246 -0
  6. package/dist/browser-ui.js.map +1 -0
  7. package/dist/capture/event.d.ts +33 -0
  8. package/dist/capture/event.d.ts.map +1 -0
  9. package/dist/capture/event.js +2 -0
  10. package/dist/capture/event.js.map +1 -0
  11. package/dist/capture/index.d.ts +4 -0
  12. package/dist/capture/index.d.ts.map +1 -0
  13. package/dist/capture/index.js +4 -0
  14. package/dist/capture/index.js.map +1 -0
  15. package/dist/capture/recorder.d.ts +24 -0
  16. package/dist/capture/recorder.d.ts.map +1 -0
  17. package/dist/capture/recorder.js +46 -0
  18. package/dist/capture/recorder.js.map +1 -0
  19. package/dist/capture/replay.d.ts +20 -0
  20. package/dist/capture/replay.d.ts.map +1 -0
  21. package/dist/capture/replay.js +47 -0
  22. package/dist/capture/replay.js.map +1 -0
  23. package/dist/ci/api-client.d.ts +38 -0
  24. package/dist/ci/api-client.d.ts.map +1 -0
  25. package/dist/ci/api-client.js +96 -0
  26. package/dist/ci/api-client.js.map +1 -0
  27. package/dist/ci/benchmark.d.ts +33 -0
  28. package/dist/ci/benchmark.d.ts.map +1 -0
  29. package/dist/ci/benchmark.js +213 -0
  30. package/dist/ci/benchmark.js.map +1 -0
  31. package/dist/ci/ed-runner.d.ts +48 -0
  32. package/dist/ci/ed-runner.d.ts.map +1 -0
  33. package/dist/ci/ed-runner.js +260 -0
  34. package/dist/ci/ed-runner.js.map +1 -0
  35. package/dist/ci/executor.d.ts +13 -0
  36. package/dist/ci/executor.d.ts.map +1 -0
  37. package/dist/ci/executor.js +542 -0
  38. package/dist/ci/executor.js.map +1 -0
  39. package/dist/ci/git-info.d.ts +17 -0
  40. package/dist/ci/git-info.d.ts.map +1 -0
  41. package/dist/ci/git-info.js +102 -0
  42. package/dist/ci/git-info.js.map +1 -0
  43. package/dist/ci/index.d.ts +6 -0
  44. package/dist/ci/index.d.ts.map +1 -0
  45. package/dist/ci/index.js +4 -0
  46. package/dist/ci/index.js.map +1 -0
  47. package/dist/ci/measurement.d.ts +9 -0
  48. package/dist/ci/measurement.d.ts.map +1 -0
  49. package/dist/ci/measurement.js +15 -0
  50. package/dist/ci/measurement.js.map +1 -0
  51. package/dist/ci/replay.d.ts +31 -0
  52. package/dist/ci/replay.d.ts.map +1 -0
  53. package/dist/ci/replay.js +96 -0
  54. package/dist/ci/replay.js.map +1 -0
  55. package/dist/ci/reporters/default.d.ts +8 -0
  56. package/dist/ci/reporters/default.d.ts.map +1 -0
  57. package/dist/ci/reporters/default.js +46 -0
  58. package/dist/ci/reporters/default.js.map +1 -0
  59. package/dist/ci/reporters/index.d.ts +8 -0
  60. package/dist/ci/reporters/index.d.ts.map +1 -0
  61. package/dist/ci/reporters/index.js +14 -0
  62. package/dist/ci/reporters/index.js.map +1 -0
  63. package/dist/ci/reporters/json.d.ts +8 -0
  64. package/dist/ci/reporters/json.d.ts.map +1 -0
  65. package/dist/ci/reporters/json.js +14 -0
  66. package/dist/ci/reporters/json.js.map +1 -0
  67. package/dist/ci/reporters/junit.d.ts +8 -0
  68. package/dist/ci/reporters/junit.d.ts.map +1 -0
  69. package/dist/ci/reporters/junit.js +48 -0
  70. package/dist/ci/reporters/junit.js.map +1 -0
  71. package/dist/ci/runner.d.ts +3 -0
  72. package/dist/ci/runner.d.ts.map +1 -0
  73. package/dist/ci/runner.js +187 -0
  74. package/dist/ci/runner.js.map +1 -0
  75. package/dist/ci/test-discovery.d.ts +5 -0
  76. package/dist/ci/test-discovery.d.ts.map +1 -0
  77. package/dist/ci/test-discovery.js +11 -0
  78. package/dist/ci/test-discovery.js.map +1 -0
  79. package/dist/ci/test-loader.d.ts +19 -0
  80. package/dist/ci/test-loader.d.ts.map +1 -0
  81. package/dist/ci/test-loader.js +149 -0
  82. package/dist/ci/test-loader.js.map +1 -0
  83. package/dist/ci/test-registry.d.ts +42 -0
  84. package/dist/ci/test-registry.d.ts.map +1 -0
  85. package/dist/ci/test-registry.js +18 -0
  86. package/dist/ci/test-registry.js.map +1 -0
  87. package/dist/ci/trace-schema.d.ts +30 -0
  88. package/dist/ci/trace-schema.d.ts.map +1 -0
  89. package/dist/ci/trace-schema.js +66 -0
  90. package/dist/ci/trace-schema.js.map +1 -0
  91. package/dist/ci/trace-writer.d.ts +16 -0
  92. package/dist/ci/trace-writer.d.ts.map +1 -0
  93. package/dist/ci/trace-writer.js +108 -0
  94. package/dist/ci/trace-writer.js.map +1 -0
  95. package/dist/ci/types.d.ts +108 -0
  96. package/dist/ci/types.d.ts.map +1 -0
  97. package/dist/ci/types.js +3 -0
  98. package/dist/ci/types.js.map +1 -0
  99. package/dist/ci/upload-client.d.ts +74 -0
  100. package/dist/ci/upload-client.d.ts.map +1 -0
  101. package/dist/ci/upload-client.js +195 -0
  102. package/dist/ci/upload-client.js.map +1 -0
  103. package/dist/cli.d.ts +3 -0
  104. package/dist/cli.d.ts.map +1 -0
  105. package/dist/cli.js +716 -0
  106. package/dist/cli.js.map +1 -0
  107. package/dist/core/agent-state.d.ts +47 -0
  108. package/dist/core/agent-state.d.ts.map +1 -0
  109. package/dist/core/agent-state.js +137 -0
  110. package/dist/core/agent-state.js.map +1 -0
  111. package/dist/core/judge-utils.d.ts +22 -0
  112. package/dist/core/judge-utils.d.ts.map +1 -0
  113. package/dist/core/judge-utils.js +211 -0
  114. package/dist/core/judge-utils.js.map +1 -0
  115. package/dist/core/registry.d.ts +28 -0
  116. package/dist/core/registry.d.ts.map +1 -0
  117. package/dist/core/registry.js +52 -0
  118. package/dist/core/registry.js.map +1 -0
  119. package/dist/dashboard-server.d.ts +65 -0
  120. package/dist/dashboard-server.d.ts.map +1 -0
  121. package/dist/dashboard-server.js +3940 -0
  122. package/dist/dashboard-server.js.map +1 -0
  123. package/dist/execution/tool-runner.d.ts +26 -0
  124. package/dist/execution/tool-runner.d.ts.map +1 -0
  125. package/dist/execution/tool-runner.js +316 -0
  126. package/dist/execution/tool-runner.js.map +1 -0
  127. package/dist/html/dashboard.html +2218 -0
  128. package/dist/http.d.ts +14 -0
  129. package/dist/http.d.ts.map +1 -0
  130. package/dist/http.js +13 -0
  131. package/dist/http.js.map +1 -0
  132. package/dist/index.cjs +8102 -0
  133. package/dist/index.d.ts +61 -0
  134. package/dist/index.d.ts.map +1 -0
  135. package/dist/index.js +67 -0
  136. package/dist/index.js.map +1 -0
  137. package/dist/interceptors/ai-interceptor.d.ts +26 -0
  138. package/dist/interceptors/ai-interceptor.d.ts.map +1 -0
  139. package/dist/interceptors/ai-interceptor.js +756 -0
  140. package/dist/interceptors/ai-interceptor.js.map +1 -0
  141. package/dist/interceptors/db-auto.d.ts +8 -0
  142. package/dist/interceptors/db-auto.d.ts.map +1 -0
  143. package/dist/interceptors/db-auto.js +217 -0
  144. package/dist/interceptors/db-auto.js.map +1 -0
  145. package/dist/interceptors/db.d.ts +23 -0
  146. package/dist/interceptors/db.d.ts.map +1 -0
  147. package/dist/interceptors/db.js +137 -0
  148. package/dist/interceptors/db.js.map +1 -0
  149. package/dist/interceptors/http.d.ts +28 -0
  150. package/dist/interceptors/http.d.ts.map +1 -0
  151. package/dist/interceptors/http.js +356 -0
  152. package/dist/interceptors/http.js.map +1 -0
  153. package/dist/interceptors/side-effects.d.ts +7 -0
  154. package/dist/interceptors/side-effects.d.ts.map +1 -0
  155. package/dist/interceptors/side-effects.js +72 -0
  156. package/dist/interceptors/side-effects.js.map +1 -0
  157. package/dist/interceptors/telemetry-push.d.ts +142 -0
  158. package/dist/interceptors/telemetry-push.d.ts.map +1 -0
  159. package/dist/interceptors/telemetry-push.js +463 -0
  160. package/dist/interceptors/telemetry-push.js.map +1 -0
  161. package/dist/interceptors/tool.d.ts +2 -0
  162. package/dist/interceptors/tool.d.ts.map +1 -0
  163. package/dist/interceptors/tool.js +274 -0
  164. package/dist/interceptors/tool.js.map +1 -0
  165. package/dist/interceptors/workflow-ai.d.ts +5 -0
  166. package/dist/interceptors/workflow-ai.d.ts.map +1 -0
  167. package/dist/interceptors/workflow-ai.js +382 -0
  168. package/dist/interceptors/workflow-ai.js.map +1 -0
  169. package/dist/internals/conditional-recorder.d.ts +21 -0
  170. package/dist/internals/conditional-recorder.d.ts.map +1 -0
  171. package/dist/internals/conditional-recorder.js +54 -0
  172. package/dist/internals/conditional-recorder.js.map +1 -0
  173. package/dist/internals/mock-resolver.d.ts +146 -0
  174. package/dist/internals/mock-resolver.d.ts.map +1 -0
  175. package/dist/internals/mock-resolver.js +427 -0
  176. package/dist/internals/mock-resolver.js.map +1 -0
  177. package/dist/matchers/index.d.ts +96 -0
  178. package/dist/matchers/index.d.ts.map +1 -0
  179. package/dist/matchers/index.js +668 -0
  180. package/dist/matchers/index.js.map +1 -0
  181. package/dist/observability.d.ts +82 -0
  182. package/dist/observability.d.ts.map +1 -0
  183. package/dist/observability.js +471 -0
  184. package/dist/observability.js.map +1 -0
  185. package/dist/portal-executor.d.ts +30 -0
  186. package/dist/portal-executor.d.ts.map +1 -0
  187. package/dist/portal-executor.js +324 -0
  188. package/dist/portal-executor.js.map +1 -0
  189. package/dist/portal-server.d.ts +3 -0
  190. package/dist/portal-server.d.ts.map +1 -0
  191. package/dist/portal-server.js +279 -0
  192. package/dist/portal-server.js.map +1 -0
  193. package/dist/proxy/llm-capture.d.ts +14 -0
  194. package/dist/proxy/llm-capture.d.ts.map +1 -0
  195. package/dist/proxy/llm-capture.js +264 -0
  196. package/dist/proxy/llm-capture.js.map +1 -0
  197. package/dist/reporter.d.ts +3 -0
  198. package/dist/reporter.d.ts.map +1 -0
  199. package/dist/reporter.js +72 -0
  200. package/dist/reporter.js.map +1 -0
  201. package/dist/runWorkflowSubprocess.d.ts +14 -0
  202. package/dist/runWorkflowSubprocess.d.ts.map +1 -0
  203. package/dist/runWorkflowSubprocess.js +66 -0
  204. package/dist/runWorkflowSubprocess.js.map +1 -0
  205. package/dist/runner.d.ts +16 -0
  206. package/dist/runner.d.ts.map +1 -0
  207. package/dist/runner.js +138 -0
  208. package/dist/runner.js.map +1 -0
  209. package/dist/socket-connector.d.ts +22 -0
  210. package/dist/socket-connector.d.ts.map +1 -0
  211. package/dist/socket-connector.js +104 -0
  212. package/dist/socket-connector.js.map +1 -0
  213. package/dist/telemetry-batcher.d.ts +56 -0
  214. package/dist/telemetry-batcher.d.ts.map +1 -0
  215. package/dist/telemetry-batcher.js +143 -0
  216. package/dist/telemetry-batcher.js.map +1 -0
  217. package/dist/test-setup.d.ts +12 -0
  218. package/dist/test-setup.d.ts.map +1 -0
  219. package/dist/test-setup.js +13 -0
  220. package/dist/test-setup.js.map +1 -0
  221. package/dist/tool-registry.d.ts +31 -0
  222. package/dist/tool-registry.d.ts.map +1 -0
  223. package/dist/tool-registry.js +73 -0
  224. package/dist/tool-registry.js.map +1 -0
  225. package/dist/tool-runner-worker.d.ts +2 -0
  226. package/dist/tool-runner-worker.d.ts.map +1 -0
  227. package/dist/tool-runner-worker.js +215 -0
  228. package/dist/tool-runner-worker.js.map +1 -0
  229. package/dist/trace-adapter/context.d.ts +72 -0
  230. package/dist/trace-adapter/context.d.ts.map +1 -0
  231. package/dist/trace-adapter/context.js +80 -0
  232. package/dist/trace-adapter/context.js.map +1 -0
  233. package/dist/tracing.d.ts +2 -0
  234. package/dist/tracing.d.ts.map +1 -0
  235. package/dist/tracing.js +59 -0
  236. package/dist/tracing.js.map +1 -0
  237. package/dist/trigger-executor.d.ts +12 -0
  238. package/dist/trigger-executor.d.ts.map +1 -0
  239. package/dist/trigger-executor.js +130 -0
  240. package/dist/trigger-executor.js.map +1 -0
  241. package/dist/types/portal.d.ts +76 -0
  242. package/dist/types/portal.d.ts.map +1 -0
  243. package/dist/types/portal.js +2 -0
  244. package/dist/types/portal.js.map +1 -0
  245. package/dist/utils/debug.d.ts +3 -0
  246. package/dist/utils/debug.d.ts.map +1 -0
  247. package/dist/utils/debug.js +8 -0
  248. package/dist/utils/debug.js.map +1 -0
  249. package/dist/utils/license-error.d.ts +23 -0
  250. package/dist/utils/license-error.d.ts.map +1 -0
  251. package/dist/utils/license-error.js +42 -0
  252. package/dist/utils/license-error.js.map +1 -0
  253. package/dist/utils/redact.d.ts +7 -0
  254. package/dist/utils/redact.d.ts.map +1 -0
  255. package/dist/utils/redact.js +26 -0
  256. package/dist/utils/redact.js.map +1 -0
  257. package/dist/workflow-runner-worker.d.ts +2 -0
  258. package/dist/workflow-runner-worker.d.ts.map +1 -0
  259. package/dist/workflow-runner-worker.js +329 -0
  260. package/dist/workflow-runner-worker.js.map +1 -0
  261. package/dist/workflow-runner.d.ts +14 -0
  262. package/dist/workflow-runner.d.ts.map +1 -0
  263. package/dist/workflow-runner.js +34 -0
  264. package/dist/workflow-runner.js.map +1 -0
  265. package/docs/agent-coding-instructions.md +138 -0
  266. package/docs/agent-integration-guide.md +564 -0
  267. package/docs/agents.md +140 -0
  268. package/docs/dashboard.md +394 -0
  269. package/docs/deno.md +69 -0
  270. package/docs/instrumentation.md +424 -0
  271. package/docs/langfuse-trace-structure.md +145 -0
  272. package/docs/matchers.md +173 -0
  273. package/docs/observability_contract.md +192 -0
  274. package/docs/observability_mode.md +195 -0
  275. package/docs/quickstart.md +621 -0
  276. package/docs/security-compliance.md +566 -0
  277. package/docs/test-writing-guidelines.md +444 -0
  278. package/docs/tools.md +165 -0
  279. package/docs/workflow-modes.md +253 -0
  280. package/package.json +76 -0
  281. package/src/browser-ui.ts +281 -0
  282. package/src/capture/event.ts +30 -0
  283. package/src/capture/index.ts +3 -0
  284. package/src/capture/recorder.ts +62 -0
  285. package/src/capture/replay.ts +55 -0
  286. package/src/ci/api-client.ts +136 -0
  287. package/src/ci/benchmark.ts +257 -0
  288. package/src/ci/ed-runner.ts +351 -0
  289. package/src/ci/executor.ts +671 -0
  290. package/src/ci/git-info.ts +127 -0
  291. package/src/ci/index.ts +5 -0
  292. package/src/ci/measurement.ts +25 -0
  293. package/src/ci/replay.ts +127 -0
  294. package/src/ci/reporters/default.ts +50 -0
  295. package/src/ci/reporters/index.ts +21 -0
  296. package/src/ci/reporters/json.ts +18 -0
  297. package/src/ci/reporters/junit.ts +61 -0
  298. package/src/ci/runner.ts +208 -0
  299. package/src/ci/test-discovery.ts +16 -0
  300. package/src/ci/test-loader.ts +187 -0
  301. package/src/ci/test-registry.ts +62 -0
  302. package/src/ci/trace-schema.ts +96 -0
  303. package/src/ci/trace-writer.ts +107 -0
  304. package/src/ci/types.ts +115 -0
  305. package/src/ci/upload-client.ts +300 -0
  306. package/src/cli.ts +811 -0
  307. package/src/core/agent-state.ts +162 -0
  308. package/src/core/judge-utils.ts +232 -0
  309. package/src/core/registry.ts +92 -0
  310. package/src/dashboard-server.ts +2047 -0
  311. package/src/execution/tool-runner.ts +352 -0
  312. package/src/html/dashboard.html +2218 -0
  313. package/src/http.ts +13 -0
  314. package/src/index.ts +138 -0
  315. package/src/interceptors/ai-interceptor.ts +798 -0
  316. package/src/interceptors/db-auto.ts +243 -0
  317. package/src/interceptors/db.ts +156 -0
  318. package/src/interceptors/http.ts +393 -0
  319. package/src/interceptors/side-effects.ts +83 -0
  320. package/src/interceptors/telemetry-push.ts +537 -0
  321. package/src/interceptors/tool.ts +287 -0
  322. package/src/interceptors/workflow-ai.ts +419 -0
  323. package/src/internals/conditional-recorder.ts +63 -0
  324. package/src/internals/mock-resolver.ts +492 -0
  325. package/src/matchers/index.ts +824 -0
  326. package/src/observability.ts +501 -0
  327. package/src/portal-executor.ts +355 -0
  328. package/src/portal-server.ts +304 -0
  329. package/src/proxy/llm-capture.ts +301 -0
  330. package/src/reporter.ts +81 -0
  331. package/src/runWorkflowSubprocess.ts +74 -0
  332. package/src/runner.ts +178 -0
  333. package/src/socket-connector.ts +117 -0
  334. package/src/telemetry-batcher.ts +191 -0
  335. package/src/test-setup.ts +16 -0
  336. package/src/tool-registry.ts +94 -0
  337. package/src/tool-runner-worker.ts +244 -0
  338. package/src/trace-adapter/context.ts +156 -0
  339. package/src/tracing.ts +62 -0
  340. package/src/trigger-executor.ts +171 -0
  341. package/src/types/agent.d.ts +63 -0
  342. package/src/types/expect.d.ts +81 -0
  343. package/src/types/modules.d.ts +2 -0
  344. package/src/types/portal.ts +69 -0
  345. package/src/utils/debug.ts +8 -0
  346. package/src/utils/license-error.ts +43 -0
  347. package/src/utils/redact.ts +25 -0
  348. package/src/workflow-runner-worker.ts +386 -0
  349. package/src/workflow-runner.ts +58 -0
@@ -0,0 +1,287 @@
1
+ import { getCaptureContext } from '../capture/recorder.js'
2
+ import { getCurrentTrace } from '../trace-adapter/context.js'
3
+ import { rawDateNow } from './side-effects.js'
4
+ import { getHttpRunContext, getHttpFrozenEvent, getHttpToolMock, pushTelemetryEvent, tryAutoInitHttpContext, getObservabilityContext } from './telemetry-push.js'
5
+ import { getEdReplayContext, replayCall } from '../ci/replay.js'
6
+ import { debugLog } from '../utils/debug.js'
7
+
8
+ const TOOL_WRAPPER_ACTIVE_KEY = '__elasticdash_tool_wrapper_active__'
9
+
10
+ function toTraceArgs(input: unknown): Record<string, unknown> | undefined {
11
+ if (input && typeof input === 'object' && !Array.isArray(input)) {
12
+ return input as Record<string, unknown>
13
+ }
14
+ if (input === undefined) return undefined
15
+ return { value: input }
16
+ }
17
+
18
+ function isReadableStream(v: unknown): v is ReadableStream<Uint8Array> {
19
+ return (
20
+ typeof v === 'object' &&
21
+ v !== null &&
22
+ typeof (v as ReadableStream).getReader === 'function' &&
23
+ typeof (v as ReadableStream).tee === 'function'
24
+ )
25
+ }
26
+
27
+ function isAsyncIterable(v: unknown): v is AsyncIterable<unknown> {
28
+ return typeof v === 'object' && v !== null && Symbol.asyncIterator in (v as object)
29
+ }
30
+
31
+ async function bufferReadableStream(stream: ReadableStream<Uint8Array>): Promise<string> {
32
+ const decoder = new TextDecoder()
33
+ const reader = stream.getReader()
34
+ let raw = ''
35
+ try {
36
+ for (;;) {
37
+ const { done, value } = await reader.read()
38
+ if (done) break
39
+ raw += decoder.decode(value, { stream: true })
40
+ }
41
+ } finally {
42
+ reader.releaseLock()
43
+ }
44
+ return raw
45
+ }
46
+
47
+ function reconstructStream(raw: string): ReadableStream<Uint8Array> {
48
+ const encoder = new TextEncoder()
49
+ return new ReadableStream<Uint8Array>({
50
+ start(ctrl) {
51
+ ctrl.enqueue(encoder.encode(raw))
52
+ ctrl.close()
53
+ },
54
+ })
55
+ }
56
+
57
+ /** Wraps an AsyncIterable so chunks are collected while the caller iterates */
58
+ function wrapAsyncIterable<T>(
59
+ source: AsyncIterable<T>,
60
+ onComplete: (chunks: T[]) => void,
61
+ ): AsyncIterable<T> {
62
+ return {
63
+ [Symbol.asyncIterator]() {
64
+ const iter = source[Symbol.asyncIterator]()
65
+ const collected: T[] = []
66
+ return {
67
+ async next() {
68
+ const result = await iter.next()
69
+ if (!result.done) {
70
+ collected.push(result.value)
71
+ } else {
72
+ onComplete(collected)
73
+ }
74
+ return result
75
+ },
76
+ async return(value?: unknown) {
77
+ onComplete(collected)
78
+ return iter.return ? iter.return(value) : { done: true as const, value: undefined }
79
+ },
80
+ }
81
+ },
82
+ }
83
+ }
84
+
85
+ export function wrapTool<Args extends unknown[], R>(
86
+ name: string,
87
+ fn: (...args: Args) => Promise<R>,
88
+ ): (...args: Args) => Promise<R> {
89
+ return async (...args: Args): Promise<R> => {
90
+ // Phase 3 fixture replay: short-circuit if ed-runner replay is active
91
+ const edReplay = getEdReplayContext()
92
+ if (edReplay) {
93
+ const input = args.length === 1 ? args[0] : args
94
+ const { output } = replayCall(edReplay, 'tool_call', name, input)
95
+ return output as R
96
+ }
97
+
98
+ await tryAutoInitHttpContext()
99
+ const ctx = getCaptureContext()
100
+ const httpCtx = getHttpRunContext()
101
+ const obsCtx = getObservabilityContext()
102
+ debugLog(`[elasticdash] Tool called: ${name}`, { args })
103
+ debugLog(`[elasticdash] Current capture context:`, ctx ? { hasRecorder: !!ctx.recorder, hasReplay: !!ctx.replay } : null)
104
+ debugLog(`[elasticdash] Current HTTP context:`, httpCtx ? { hasHttpContext: !!httpCtx } : null)
105
+ if (!ctx && !httpCtx && !obsCtx) return fn(...args)
106
+
107
+ // Observability-only mode: record and push, no mocks/replay
108
+ if (!ctx && !httpCtx && obsCtx) {
109
+ debugLog(`[elasticdash] wrapTool obs-only path: ${name}`)
110
+ const id = obsCtx.nextId()
111
+ const input = args.length === 1 ? args[0] : args
112
+ const start = rawDateNow()
113
+ try {
114
+ const output = await fn(...args)
115
+ const durationMs = rawDateNow() - start
116
+ if (isReadableStream(output)) {
117
+ const [streamForCaller, streamForRecorder] = output.tee()
118
+ bufferReadableStream(streamForRecorder).then((rawText) => {
119
+ const durationMs = rawDateNow() - start
120
+ pushTelemetryEvent({ id, type: 'tool', name, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs })
121
+ }).catch(() => {
122
+ const durationMs = rawDateNow() - start
123
+ pushTelemetryEvent({ id, type: 'tool', name, input, output: null, streamed: true, streamRaw: '', timestamp: start, durationMs })
124
+ })
125
+ return streamForCaller as unknown as R
126
+ }
127
+ if (isAsyncIterable(output)) {
128
+ return wrapAsyncIterable(output, (chunks) => {
129
+ const durationMs = rawDateNow() - start
130
+ const rawText = chunks.map((c) => (typeof c === 'string' ? c : JSON.stringify(c))).join('')
131
+ pushTelemetryEvent({ id, type: 'tool', name, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs })
132
+ }) as unknown as R
133
+ }
134
+ pushTelemetryEvent({ id, type: 'tool', name, input, output, timestamp: start, durationMs })
135
+ return output
136
+ } catch (e) {
137
+ const durationMs = rawDateNow() - start
138
+ pushTelemetryEvent({ id, type: 'tool', name, input, output: { error: String(e) }, timestamp: start, durationMs })
139
+ throw e
140
+ }
141
+ }
142
+
143
+ // HTTP mode only (no capture context) — execute, record timing, push telemetry
144
+ if (!ctx) {
145
+ const id = httpCtx!.nextId()
146
+ const input = args.length === 1 ? args[0] : args
147
+
148
+ // Replay frozen step: push historical event so dashboard trace stays complete
149
+ const frozen = getHttpFrozenEvent(id)
150
+ if (frozen) {
151
+ pushTelemetryEvent(frozen)
152
+ if (frozen.streamed === true) {
153
+ const raw = typeof frozen.streamRaw === 'string' ? frozen.streamRaw : ''
154
+ return reconstructStream(raw) as unknown as R
155
+ }
156
+ return frozen.output as R
157
+ }
158
+
159
+ // Check tool output mock (skip real call, return mocked result)
160
+ const toolMock = getHttpToolMock(name)
161
+ if (toolMock.mocked) {
162
+ const event = { id, type: 'tool' as const, name, input, output: toolMock.result, timestamp: rawDateNow(), durationMs: 0 }
163
+ pushTelemetryEvent(event)
164
+ return toolMock.result as R
165
+ }
166
+
167
+ const start = rawDateNow()
168
+ try {
169
+ const output = await fn(...args)
170
+ if (isReadableStream(output)) {
171
+ const [streamForCaller, streamForRecorder] = output.tee()
172
+ bufferReadableStream(streamForRecorder).then((rawText) => {
173
+ const durationMs = rawDateNow() - start
174
+ pushTelemetryEvent({ id, type: 'tool', name, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs })
175
+ }).catch(() => {
176
+ const durationMs = rawDateNow() - start
177
+ pushTelemetryEvent({ id, type: 'tool', name, input, output: null, streamed: true, streamRaw: '', timestamp: start, durationMs })
178
+ })
179
+ return streamForCaller as unknown as R
180
+ }
181
+ if (isAsyncIterable(output)) {
182
+ return wrapAsyncIterable(output, (chunks) => {
183
+ const durationMs = rawDateNow() - start
184
+ const rawText = chunks.map((c) => (typeof c === 'string' ? c : JSON.stringify(c))).join('')
185
+ pushTelemetryEvent({ id, type: 'tool', name, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs })
186
+ }) as unknown as R
187
+ }
188
+ const durationMs = rawDateNow() - start
189
+ pushTelemetryEvent({ id, type: 'tool', name, input, output, timestamp: start, durationMs })
190
+ return output
191
+ } catch (e) {
192
+ const durationMs = rawDateNow() - start
193
+ pushTelemetryEvent({ id, type: 'tool', name, input, output: { error: String(e) }, timestamp: start, durationMs })
194
+ throw e
195
+ }
196
+ }
197
+
198
+ const trace = getCurrentTrace()
199
+ const { recorder, replay } = ctx
200
+ const id = recorder.nextId()
201
+ const input = args.length === 1 ? args[0] : args
202
+
203
+ if (replay.shouldReplay(id)) {
204
+ const historical = replay.getRecordedEvent(id)
205
+ if (historical) recorder.record(historical)
206
+
207
+ if (historical?.streamed === true) {
208
+ const raw = typeof historical.streamRaw === 'string' ? historical.streamRaw : ''
209
+ const stream = reconstructStream(raw) as unknown as R
210
+ if (trace && typeof trace.recordToolCall === 'function') {
211
+ trace.recordToolCall({ name, args: toTraceArgs(input), result: stream, workflowEventId: id })
212
+ }
213
+ return stream
214
+ }
215
+
216
+ const replayed = replay.getRecordedResult(id) as R
217
+ if (trace && typeof trace.recordToolCall === 'function') {
218
+ trace.recordToolCall({ name, args: toTraceArgs(input), result: replayed, workflowEventId: id })
219
+ }
220
+ return replayed
221
+ }
222
+
223
+ const g = globalThis as Record<string, unknown>
224
+ const prev = g[TOOL_WRAPPER_ACTIVE_KEY]
225
+ g[TOOL_WRAPPER_ACTIVE_KEY] = true
226
+ const start = rawDateNow()
227
+
228
+ try {
229
+ const output = await fn(...args)
230
+
231
+ if (isReadableStream(output)) {
232
+ const [streamForCaller, streamForRecorder] = output.tee()
233
+ bufferReadableStream(streamForRecorder).then((rawText) => {
234
+ const durationMs = rawDateNow() - start
235
+ const event = { id, type: 'tool' as const, name, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs }
236
+ recorder.record(event)
237
+ if (httpCtx) pushTelemetryEvent(event)
238
+ }).catch(() => {
239
+ const durationMs = rawDateNow() - start
240
+ const event = { id, type: 'tool' as const, name, input, output: null, streamed: true, streamRaw: '', timestamp: start, durationMs }
241
+ recorder.record(event)
242
+ if (httpCtx) pushTelemetryEvent(event)
243
+ })
244
+ const result = streamForCaller as unknown as R
245
+ if (trace && typeof trace.recordToolCall === 'function') {
246
+ trace.recordToolCall({ name, args: toTraceArgs(input), result, workflowEventId: id })
247
+ }
248
+ return result
249
+ }
250
+
251
+ if (isAsyncIterable(output)) {
252
+ const wrapped = wrapAsyncIterable(output, (chunks) => {
253
+ const durationMs = rawDateNow() - start
254
+ const rawText = chunks.map((c) => (typeof c === 'string' ? c : JSON.stringify(c))).join('')
255
+ const event = { id, type: 'tool' as const, name, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs }
256
+ recorder.record(event)
257
+ if (httpCtx) pushTelemetryEvent(event)
258
+ }) as unknown as R
259
+ if (trace && typeof trace.recordToolCall === 'function') {
260
+ trace.recordToolCall({ name, args: toTraceArgs(input), result: wrapped, workflowEventId: id })
261
+ }
262
+ return wrapped
263
+ }
264
+
265
+ const durationMs = rawDateNow() - start
266
+ const successEvent = { id, type: 'tool' as const, name, input, output, timestamp: start, durationMs }
267
+ recorder.record(successEvent)
268
+ if (httpCtx) pushTelemetryEvent(successEvent)
269
+ if (trace && typeof trace.recordToolCall === 'function') {
270
+ trace.recordToolCall({ name, args: toTraceArgs(input), result: output, workflowEventId: id, durationMs })
271
+ }
272
+ return output
273
+ } catch (e) {
274
+ const durationMs = rawDateNow() - start
275
+ const errorEvent = { id, type: 'tool' as const, name, input, output: { error: String(e) }, timestamp: start, durationMs }
276
+ recorder.record(errorEvent)
277
+ if (httpCtx) pushTelemetryEvent(errorEvent)
278
+ if (trace && typeof trace.recordToolCall === 'function') {
279
+ trace.recordToolCall({ name, args: toTraceArgs(input), result: { error: String(e) }, workflowEventId: id, durationMs })
280
+ }
281
+ throw e
282
+ } finally {
283
+ if (prev === undefined) delete g[TOOL_WRAPPER_ACTIVE_KEY]
284
+ else g[TOOL_WRAPPER_ACTIVE_KEY] = prev
285
+ }
286
+ }
287
+ }