dd-trace 6.15.0 → 6.17.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 (378) hide show
  1. package/README.md +15 -0
  2. package/ci/diagnose.js +0 -23
  3. package/ci/test-optimization-validation/approval-artifacts.js +0 -3
  4. package/ci/test-optimization-validation/approval.js +0 -6
  5. package/ci/test-optimization-validation/artifact-id.js +0 -1
  6. package/ci/test-optimization-validation/bounded-json.js +0 -1
  7. package/ci/test-optimization-validation/cli.js +0 -12
  8. package/ci/test-optimization-validation/command-output-policy.js +0 -1
  9. package/ci/test-optimization-validation/command-runner.js +0 -3
  10. package/ci/test-optimization-validation/environment.js +0 -4
  11. package/ci/test-optimization-validation/executable-approval.js +0 -1
  12. package/ci/test-optimization-validation/executable.js +0 -5
  13. package/ci/test-optimization-validation/framework-adapters/cucumber.js +4 -8
  14. package/ci/test-optimization-validation/framework-adapters/cypress.js +0 -3
  15. package/ci/test-optimization-validation/framework-adapters/playwright.js +0 -6
  16. package/ci/test-optimization-validation/framework-adapters/vitest.js +0 -4
  17. package/ci/test-optimization-validation/generated-test-contract.js +0 -5
  18. package/ci/test-optimization-validation/generated-verifier.js +0 -1
  19. package/ci/test-optimization-validation/literal-environment.js +0 -1
  20. package/ci/test-optimization-validation/manifest-scaffold.js +0 -17
  21. package/ci/test-optimization-validation/manifest-schema.js +0 -21
  22. package/ci/test-optimization-validation/offline-fixtures.js +0 -4
  23. package/ci/test-optimization-validation/package-check.js +4 -1
  24. package/ci/test-optimization-validation/plan-writer.js +0 -11
  25. package/ci/test-optimization-validation/preflight-runner.js +0 -1
  26. package/ci/test-optimization-validation/redaction.js +0 -4
  27. package/ci/test-optimization-validation/report-writer.js +0 -16
  28. package/ci/test-optimization-validation/runner-command.js +0 -3
  29. package/ci/test-optimization-validation/runner-contract.js +0 -4
  30. package/ci/test-optimization-validation/safe-files.js +0 -1
  31. package/ci/test-optimization-validation/scenarios/basic-reporting.js +0 -1
  32. package/ci/test-optimization-validation/scenarios/ci-wiring.js +1 -2
  33. package/ci/test-optimization-validation/source-text.js +0 -3
  34. package/ci/vitest-no-worker-init-setup.mjs +41 -16
  35. package/index.d.ts +169 -0
  36. package/next.d.ts +27 -0
  37. package/next.js +3 -0
  38. package/package.json +28 -23
  39. package/packages/datadog-esbuild/index.js +14 -1
  40. package/packages/datadog-esbuild/src/resolver.js +284 -0
  41. package/packages/datadog-esbuild/src/utils.js +162 -120
  42. package/packages/datadog-instrumentations/src/aerospike.js +28 -6
  43. package/packages/datadog-instrumentations/src/ai.js +39 -97
  44. package/packages/datadog-instrumentations/src/anthropic.js +76 -134
  45. package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +1 -3
  46. package/packages/datadog-instrumentations/src/aws-sdk.js +0 -2
  47. package/packages/datadog-instrumentations/src/azure-cosmos.js +1 -1
  48. package/packages/datadog-instrumentations/src/azure-durable-functions.js +23 -9
  49. package/packages/datadog-instrumentations/src/azure-functions.js +48 -0
  50. package/packages/datadog-instrumentations/src/bullmq.js +1 -1
  51. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -3
  52. package/packages/datadog-instrumentations/src/console.js +97 -0
  53. package/packages/datadog-instrumentations/src/cucumber.js +72 -12
  54. package/packages/datadog-instrumentations/src/cypress-config.js +0 -23
  55. package/packages/datadog-instrumentations/src/dd-trace-api.js +2 -2
  56. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  57. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +39 -14
  58. package/packages/datadog-instrumentations/src/helpers/channel.js +0 -2
  59. package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +0 -5
  60. package/packages/datadog-instrumentations/src/helpers/hooks.js +8 -0
  61. package/packages/datadog-instrumentations/src/helpers/instrument.js +25 -8
  62. package/packages/datadog-instrumentations/src/helpers/instrumentation-utils.js +69 -0
  63. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +0 -6
  64. package/packages/datadog-instrumentations/src/helpers/register.js +13 -64
  65. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +109 -29
  66. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +39 -0
  67. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-durable-functions.js +17 -0
  68. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +3 -16
  69. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +12 -0
  70. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +36 -0
  71. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/supabase.js +128 -0
  72. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +6 -7
  73. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +17 -0
  74. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +388 -0
  75. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +99 -75
  76. package/packages/datadog-instrumentations/src/helpers/router-helper.js +0 -1
  77. package/packages/datadog-instrumentations/src/jest.js +141 -51
  78. package/packages/datadog-instrumentations/src/knex.js +0 -1
  79. package/packages/datadog-instrumentations/src/langchain.js +1 -1
  80. package/packages/datadog-instrumentations/src/langgraph.js +1 -1
  81. package/packages/datadog-instrumentations/src/mariadb-bundle.js +0 -24
  82. package/packages/datadog-instrumentations/src/mariadb.js +0 -2
  83. package/packages/datadog-instrumentations/src/mercurius.js +1 -1
  84. package/packages/datadog-instrumentations/src/mocha/common.js +0 -1
  85. package/packages/datadog-instrumentations/src/mocha/main.js +22 -25
  86. package/packages/datadog-instrumentations/src/mocha/utils.js +119 -49
  87. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +0 -6
  88. package/packages/datadog-instrumentations/src/mocha/worker.js +14 -17
  89. package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +1 -1
  90. package/packages/datadog-instrumentations/src/mysql2.js +0 -2
  91. package/packages/datadog-instrumentations/src/openai-agents.js +1 -1
  92. package/packages/datadog-instrumentations/src/openai-realtime/audio-accumulator.js +241 -0
  93. package/packages/datadog-instrumentations/src/openai-realtime/events.js +76 -0
  94. package/packages/datadog-instrumentations/src/openai-realtime/index.js +301 -0
  95. package/packages/datadog-instrumentations/src/openai-realtime/session.js +998 -0
  96. package/packages/datadog-instrumentations/src/openai-realtime/turns.js +211 -0
  97. package/packages/datadog-instrumentations/src/openai.js +97 -80
  98. package/packages/datadog-instrumentations/src/oracledb.js +9 -3
  99. package/packages/datadog-instrumentations/src/playwright-reporter.js +3 -16
  100. package/packages/datadog-instrumentations/src/playwright.js +238 -55
  101. package/packages/datadog-instrumentations/src/postgres.js +7 -0
  102. package/packages/datadog-instrumentations/src/router.js +0 -2
  103. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +0 -2
  104. package/packages/datadog-instrumentations/src/sequelize.js +0 -1
  105. package/packages/datadog-instrumentations/src/supabase.js +15 -0
  106. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +18 -18
  107. package/packages/datadog-instrumentations/src/vitest-main.js +37 -17
  108. package/packages/datadog-instrumentations/src/vitest-util.js +7 -1
  109. package/packages/datadog-instrumentations/src/vitest-worker.js +56 -23
  110. package/packages/datadog-instrumentations/src/webdriverio.js +23 -42
  111. package/packages/datadog-instrumentations/src/ws.js +0 -1
  112. package/packages/datadog-plugin-ai/src/utils.js +0 -2
  113. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +0 -1
  114. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +0 -2
  115. package/packages/datadog-plugin-aws-sdk/src/base.js +0 -1
  116. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +7 -2
  117. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +0 -1
  118. package/packages/datadog-plugin-aws-sdk/src/util.js +0 -1
  119. package/packages/datadog-plugin-azure-cosmos/src/index.js +1 -1
  120. package/packages/datadog-plugin-azure-durable-functions/src/index.js +95 -1
  121. package/packages/datadog-plugin-cucumber/src/index.js +10 -0
  122. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +171 -75
  123. package/packages/datadog-plugin-cypress/src/finalization.js +0 -3
  124. package/packages/datadog-plugin-cypress/src/source-map-utils.js +0 -4
  125. package/packages/datadog-plugin-cypress/src/support.js +52 -7
  126. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -24
  127. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -36
  128. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-request-context.js +31 -0
  129. package/packages/datadog-plugin-graphql/src/resolve-error.js +32 -11
  130. package/packages/datadog-plugin-graphql/src/utils.js +0 -5
  131. package/packages/datadog-plugin-jest/src/index.js +13 -0
  132. package/packages/datadog-plugin-kafkajs/src/producer.js +0 -1
  133. package/packages/datadog-plugin-mocha/src/index.js +39 -11
  134. package/packages/datadog-plugin-mongodb-core/src/query.js +0 -1
  135. package/packages/datadog-plugin-openai/src/index.js +16 -1
  136. package/packages/datadog-plugin-openai/src/realtime.js +144 -0
  137. package/packages/datadog-plugin-openai-agents/src/integration.js +0 -4
  138. package/packages/datadog-plugin-openai-agents/src/util.js +0 -1
  139. package/packages/datadog-plugin-playwright/src/index.js +76 -9
  140. package/packages/datadog-plugin-postgres/src/index.js +167 -0
  141. package/packages/datadog-plugin-prisma/src/datadog-tracing-helper.js +0 -1
  142. package/packages/datadog-plugin-redis/src/index.js +15 -1
  143. package/packages/datadog-plugin-supabase/src/error.js +18 -0
  144. package/packages/datadog-plugin-supabase/src/index.js +21 -0
  145. package/packages/datadog-plugin-supabase/src/supabase-auth-js-gotrueclient-getuser.js +69 -0
  146. package/packages/datadog-plugin-supabase/src/supabase-functions-js-functionsclient-invoke.js +70 -0
  147. package/packages/datadog-plugin-supabase/src/supabase-postgrest-js-postgrestbuilder-then.js +122 -0
  148. package/packages/datadog-plugin-supabase/src/supabase-realtime-js-realtimechannel-send.js +66 -0
  149. package/packages/datadog-plugin-supabase/src/supabase-storage-js-handle-request.js +93 -0
  150. package/packages/datadog-plugin-supabase/src/url.js +17 -0
  151. package/packages/datadog-plugin-vitest/src/index.js +10 -0
  152. package/packages/datadog-plugin-ws/src/util.js +0 -4
  153. package/packages/datadog-turbopack/index.js +206 -0
  154. package/packages/datadog-turbopack/src/constants.js +5 -0
  155. package/packages/datadog-turbopack/src/loader.js +484 -0
  156. package/packages/datadog-webpack/src/loader.js +0 -1
  157. package/packages/dd-trace/src/aiguard/client.js +2 -3
  158. package/packages/dd-trace/src/aiguard/evaluation.js +6 -12
  159. package/packages/dd-trace/src/aiguard/index.js +3 -2
  160. package/packages/dd-trace/src/aiguard/integrations/anthropic.js +53 -25
  161. package/packages/dd-trace/src/aiguard/integrations/evaluate.js +49 -25
  162. package/packages/dd-trace/src/aiguard/integrations/index.js +4 -3
  163. package/packages/dd-trace/src/aiguard/integrations/openai.js +132 -29
  164. package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +116 -42
  165. package/packages/dd-trace/src/aiguard/messages/anthropic.js +0 -2
  166. package/packages/dd-trace/src/aiguard/messages/openai.js +64 -1
  167. package/packages/dd-trace/src/aiguard/messages/utils.js +29 -2
  168. package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +25 -0
  169. package/packages/dd-trace/src/aiguard/redaction.js +0 -1
  170. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  171. package/packages/dd-trace/src/appsec/activation.js +1 -1
  172. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +0 -5
  173. package/packages/dd-trace/src/appsec/api_security/sampler.js +0 -4
  174. package/packages/dd-trace/src/appsec/blocking/index.js +3 -3
  175. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -4
  176. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  177. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +5 -5
  178. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +1 -1
  179. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
  180. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +3 -3
  181. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +8 -10
  182. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +2 -2
  183. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -2
  184. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +4 -1
  185. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +7 -7
  186. package/packages/dd-trace/src/appsec/index.js +2 -2
  187. package/packages/dd-trace/src/appsec/lambda.js +71 -2
  188. package/packages/dd-trace/src/appsec/rasp/utils.js +5 -1
  189. package/packages/dd-trace/src/appsec/remote_config.js +8 -6
  190. package/packages/dd-trace/src/appsec/reporter.js +10 -6
  191. package/packages/dd-trace/src/appsec/rule_manager.js +3 -3
  192. package/packages/dd-trace/src/appsec/sdk/track_event.js +0 -2
  193. package/packages/dd-trace/src/appsec/telemetry/api_security.js +1 -3
  194. package/packages/dd-trace/src/appsec/telemetry/common.js +4 -0
  195. package/packages/dd-trace/src/appsec/telemetry/index.js +23 -5
  196. package/packages/dd-trace/src/appsec/telemetry/rasp.js +1 -20
  197. package/packages/dd-trace/src/appsec/telemetry/user.js +1 -3
  198. package/packages/dd-trace/src/appsec/telemetry/waf.js +1 -20
  199. package/packages/dd-trace/src/appsec/waf/index.js +2 -2
  200. package/packages/dd-trace/src/appsec/waf/waf_manager.js +8 -5
  201. package/packages/dd-trace/src/carrier.js +0 -5
  202. package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +104 -0
  203. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +0 -2
  204. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +34 -3
  205. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +0 -1
  206. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +0 -1
  207. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +0 -1
  208. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +0 -4
  209. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +0 -1
  210. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +0 -2
  211. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +37 -15
  212. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +0 -3
  213. package/packages/dd-trace/src/ci-visibility/exporters/request.js +0 -11
  214. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +0 -1
  215. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +0 -1
  216. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +0 -6
  217. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -2
  218. package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +0 -1
  219. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +0 -5
  220. package/packages/dd-trace/src/ci-visibility/requests/video-request.js +0 -1
  221. package/packages/dd-trace/src/ci-visibility/telemetry.js +13 -0
  222. package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +0 -1
  223. package/packages/dd-trace/src/ci-visibility/test-screenshot.js +0 -2
  224. package/packages/dd-trace/src/ci-visibility/test-video.js +0 -1
  225. package/packages/dd-trace/src/config/defaults.js +3 -2
  226. package/packages/dd-trace/src/config/generated-config-types.d.ts +74 -66
  227. package/packages/dd-trace/src/config/helper.js +9 -2
  228. package/packages/dd-trace/src/config/index.js +44 -29
  229. package/packages/dd-trace/src/config/parsers.js +34 -6
  230. package/packages/dd-trace/src/config/remote_config.js +25 -109
  231. package/packages/dd-trace/src/config/supported-configurations.json +146 -9
  232. package/packages/dd-trace/src/datastreams/encoding.js +0 -1
  233. package/packages/dd-trace/src/datastreams/pathway.js +0 -1
  234. package/packages/dd-trace/src/debugger/constants.js +10 -0
  235. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +76 -17
  236. package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
  237. package/packages/dd-trace/src/debugger/devtools_client/guardrail-metrics.js +15 -0
  238. package/packages/dd-trace/src/debugger/devtools_client/index.js +103 -27
  239. package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +50 -7
  240. package/packages/dd-trace/src/debugger/devtools_client/log.js +3 -1
  241. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +34 -8
  242. package/packages/dd-trace/src/debugger/devtools_client/send.js +40 -14
  243. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +53 -13
  244. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +118 -71
  245. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +0 -3
  246. package/packages/dd-trace/src/debugger/devtools_client/status.js +20 -6
  247. package/packages/dd-trace/src/debugger/guardrail-metrics.js +167 -0
  248. package/packages/dd-trace/src/debugger/index.js +50 -2
  249. package/packages/dd-trace/src/debugger/inspect-segment.js +0 -3
  250. package/packages/dd-trace/src/debugger/probe_sampler.js +133 -9
  251. package/packages/dd-trace/src/debugger/probe_sampler_constants.js +31 -1
  252. package/packages/dd-trace/src/dogstatsd.js +0 -23
  253. package/packages/dd-trace/src/encode/0.4-cross-payload.js +0 -3
  254. package/packages/dd-trace/src/encode/0.4.js +0 -7
  255. package/packages/dd-trace/src/encode/0.5.js +0 -2
  256. package/packages/dd-trace/src/encode/tags-processors.js +0 -1
  257. package/packages/dd-trace/src/evp_proxy/discovery.js +3 -5
  258. package/packages/dd-trace/src/evp_proxy/path.js +11 -4
  259. package/packages/dd-trace/src/exporters/agent/writer.js +0 -1
  260. package/packages/dd-trace/src/exporters/agentless/index.js +0 -1
  261. package/packages/dd-trace/src/exporters/agentless/intake.js +0 -1
  262. package/packages/dd-trace/src/exporters/agentless/writer.js +0 -3
  263. package/packages/dd-trace/src/exporters/common/docker.js +4 -1
  264. package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +0 -6
  265. package/packages/dd-trace/src/exporters/common/proxy.js +3 -0
  266. package/packages/dd-trace/src/exporters/common/request.js +1 -0
  267. package/packages/dd-trace/src/exporters/common/url.js +0 -2
  268. package/packages/dd-trace/src/exporters/common/writer.js +0 -2
  269. package/packages/dd-trace/src/id.js +0 -11
  270. package/packages/dd-trace/src/llmobs/audio-codec.js +192 -0
  271. package/packages/dd-trace/src/llmobs/audio-utils.js +121 -0
  272. package/packages/dd-trace/src/llmobs/constants/audio.js +35 -0
  273. package/packages/dd-trace/src/llmobs/constants/prompts.js +14 -0
  274. package/packages/dd-trace/src/llmobs/constants/tags.js +17 -0
  275. package/packages/dd-trace/src/llmobs/eval-metric.js +0 -6
  276. package/packages/dd-trace/src/llmobs/experiments/dataset.js +0 -4
  277. package/packages/dd-trace/src/llmobs/experiments/experiment.js +0 -3
  278. package/packages/dd-trace/src/llmobs/experiments/index.js +7 -6
  279. package/packages/dd-trace/src/llmobs/experiments/util.js +1 -11
  280. package/packages/dd-trace/src/llmobs/index.js +1 -3
  281. package/packages/dd-trace/src/llmobs/noop.js +10 -0
  282. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +0 -4
  283. package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +0 -1
  284. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +0 -4
  285. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +0 -2
  286. package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +0 -2
  287. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +4 -6
  288. package/packages/dd-trace/src/llmobs/plugins/openai/realtime.js +285 -0
  289. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +16 -3
  290. package/packages/dd-trace/src/llmobs/prompts/cache.js +272 -0
  291. package/packages/dd-trace/src/llmobs/prompts/manager.js +639 -0
  292. package/packages/dd-trace/src/llmobs/prompts/noop.js +29 -0
  293. package/packages/dd-trace/src/llmobs/prompts/prompt.js +92 -0
  294. package/packages/dd-trace/src/llmobs/sdk.js +21 -6
  295. package/packages/dd-trace/src/llmobs/span_processor.js +81 -2
  296. package/packages/dd-trace/src/llmobs/tagger.js +30 -7
  297. package/packages/dd-trace/src/llmobs/telemetry.js +36 -4
  298. package/packages/dd-trace/src/llmobs/util.js +0 -34
  299. package/packages/dd-trace/src/llmobs/writers/base.js +0 -1
  300. package/packages/dd-trace/src/llmobs/writers/util.js +1 -2
  301. package/packages/dd-trace/src/log/channels.js +3 -0
  302. package/packages/dd-trace/src/log/index.js +23 -5
  303. package/packages/dd-trace/src/log-submission/log-submission-plugin.js +74 -6
  304. package/packages/dd-trace/src/msgpack/chunk.js +0 -1
  305. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +0 -12
  306. package/packages/dd-trace/src/openfeature/encoding.js +0 -2
  307. package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +0 -1
  308. package/packages/dd-trace/src/openfeature/index.js +0 -4
  309. package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +0 -1
  310. package/packages/dd-trace/src/openfeature/span-enrichment.js +0 -4
  311. package/packages/dd-trace/src/openfeature/writers/base.js +0 -6
  312. package/packages/dd-trace/src/openfeature/writers/exposures.js +0 -5
  313. package/packages/dd-trace/src/openfeature/writers/util.js +0 -4
  314. package/packages/dd-trace/src/opentelemetry/logs/logger.js +0 -1
  315. package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +0 -1
  316. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +0 -1
  317. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +0 -2
  318. package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
  319. package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +4 -4
  320. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +0 -1
  321. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +0 -1
  322. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +103 -35
  323. package/packages/dd-trace/src/opentelemetry/metrics/time.js +0 -1
  324. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +36 -13
  325. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +0 -1
  326. package/packages/dd-trace/src/opentelemetry/span-helpers.js +0 -1
  327. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +0 -1
  328. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +0 -3
  329. package/packages/dd-trace/src/opentracing/propagation/text_map.js +0 -6
  330. package/packages/dd-trace/src/opentracing/span_context.js +0 -1
  331. package/packages/dd-trace/src/otel-thread-ctx.js +38 -11
  332. package/packages/dd-trace/src/payload-tagging/tagging.js +15 -3
  333. package/packages/dd-trace/src/plugin_manager.js +9 -3
  334. package/packages/dd-trace/src/plugins/ci_plugin.js +0 -1
  335. package/packages/dd-trace/src/plugins/database.js +2 -6
  336. package/packages/dd-trace/src/plugins/index.js +8 -0
  337. package/packages/dd-trace/src/plugins/plugin.js +0 -4
  338. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  339. package/packages/dd-trace/src/plugins/util/git.js +1 -3
  340. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +0 -1
  341. package/packages/dd-trace/src/plugins/util/llm.js +0 -2
  342. package/packages/dd-trace/src/plugins/util/status-validator.js +0 -1
  343. package/packages/dd-trace/src/plugins/util/test.js +25 -21
  344. package/packages/dd-trace/src/plugins/util/url.js +0 -5
  345. package/packages/dd-trace/src/priority_sampler.js +0 -6
  346. package/packages/dd-trace/src/process-tags/index.js +0 -1
  347. package/packages/dd-trace/src/profiler.js +132 -35
  348. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +0 -1
  349. package/packages/dd-trace/src/profiling/profiler.js +101 -41
  350. package/packages/dd-trace/src/profiling/ssi-heuristics.js +29 -15
  351. package/packages/dd-trace/src/propagation-hash/index.js +0 -1
  352. package/packages/dd-trace/src/proxy.js +21 -45
  353. package/packages/dd-trace/src/random_sampler.js +0 -4
  354. package/packages/dd-trace/src/rate_limiter.js +0 -4
  355. package/packages/dd-trace/src/remote_config/capabilities.js +1 -9
  356. package/packages/dd-trace/src/remote_config/index.js +0 -1
  357. package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +0 -3
  358. package/packages/dd-trace/src/sampler.js +0 -4
  359. package/packages/dd-trace/src/sampling_rule.js +0 -7
  360. package/packages/dd-trace/src/serverless/vercel.js +0 -1
  361. package/packages/dd-trace/src/serverless.js +0 -1
  362. package/packages/dd-trace/src/service-naming/index.js +0 -1
  363. package/packages/dd-trace/src/service-naming/schemas/util.js +0 -1
  364. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +7 -0
  365. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +5 -0
  366. package/packages/dd-trace/src/span_processor.js +2 -2
  367. package/packages/dd-trace/src/span_sampler.js +0 -1
  368. package/packages/dd-trace/src/standalone/product.js +2 -2
  369. package/packages/dd-trace/src/standalone/tracesource.js +0 -1
  370. package/packages/dd-trace/src/startup-log.js +1 -1
  371. package/packages/dd-trace/src/telemetry/endpoints.js +0 -8
  372. package/packages/dd-trace/src/telemetry/logs/index.js +16 -5
  373. package/packages/dd-trace/src/telemetry/logs/log-collector.js +16 -6
  374. package/packages/dd-trace/src/telemetry/metrics.js +0 -2
  375. package/packages/dd-trace/src/telemetry/telemetry.js +4 -1
  376. package/packages/dd-trace/src/util.js +13 -1
  377. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
  378. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/utils.js +0 -10
@@ -0,0 +1,211 @@
1
+ 'use strict'
2
+
3
+ const AudioAccumulator = require('./audio-accumulator')
4
+
5
+ /**
6
+ * @typedef {{ name?: string, arguments?: unknown, toolId?: string, type?: string }} ToolCall
7
+ * @typedef {{ name?: string, result?: string, toolId?: string, type?: string }} ToolResult
8
+ */
9
+
10
+ /**
11
+ * One response's text or transcript, accumulated across the output items it arrives in.
12
+ *
13
+ * Deltas stream per output item, and each item ends with a `.done` carrying that item's
14
+ * authoritative final value. A single response can hold several output items — a server-side MCP
15
+ * call sits between a preamble message and the answer — so a `.done` replaces only the span its own
16
+ * item contributed rather than the whole response, which would drop every item before it.
17
+ *
18
+ * Events that carry no item id are treated as one continuous item, which is how a response with a
19
+ * single output item behaves anyway.
20
+ */
21
+ class ItemText {
22
+ /** @type {string} */
23
+ value = ''
24
+
25
+ /** @type {string | undefined} */
26
+ #itemId = undefined
27
+
28
+ /** Offset into `value` at which the current item's span begins. */
29
+ #itemStart = 0
30
+
31
+ /**
32
+ * @param {unknown} itemId
33
+ * @param {string} delta
34
+ */
35
+ appendDelta (itemId, delta) {
36
+ this.#openItem(itemId)
37
+ this.value += delta
38
+ }
39
+
40
+ /**
41
+ * Replace the current item's span with the final value the server reported for it.
42
+ *
43
+ * @param {unknown} itemId
44
+ * @param {string} final
45
+ */
46
+ complete (itemId, final) {
47
+ this.#openItem(itemId)
48
+ this.value = this.value.slice(0, this.#itemStart) + final
49
+ }
50
+
51
+ /**
52
+ * Begin a new item's span, leaving everything earlier items contributed in place.
53
+ *
54
+ * @param {unknown} itemId
55
+ */
56
+ #openItem (itemId) {
57
+ const item = itemId == null ? undefined : String(itemId)
58
+ if (item === this.#itemId) return
59
+
60
+ this.#itemId = item
61
+ this.#itemStart = this.value.length
62
+ }
63
+ }
64
+
65
+ /** Accumulated user input — audio plus transcript or text — for a single turn. */
66
+ class InputTurn {
67
+ /**
68
+ * @param {(() => boolean) | boolean} [retainAudio] - Whether anything consumes the bytes, so only
69
+ * their count is kept when not. Resolved when the segment opens. See `AudioAccumulator`.
70
+ */
71
+ constructor (retainAudio = true) {
72
+ this.audio = new AudioAccumulator(retainAudio)
73
+ }
74
+
75
+ text = ''
76
+
77
+ transcript = ''
78
+
79
+ /** @type {string | undefined} */
80
+ itemId = undefined
81
+
82
+ /**
83
+ * Wall clock (epoch ms) when the user actually started speaking, from the VAD speech-onset event.
84
+ * This is the start of the user-speech window; the first buffered frame is not, because a
85
+ * server-VAD client streams the microphone continuously.
86
+ *
87
+ * @type {number | undefined}
88
+ */
89
+ speechStartTime = undefined
90
+
91
+ /**
92
+ * Wall clock (epoch ms) when the input audio was committed (roughly the end of user speech). Lets
93
+ * response latency be measured from real speech-end rather than the padded buffer end.
94
+ *
95
+ * @type {number | undefined}
96
+ */
97
+ speechEndTime = undefined
98
+
99
+ /**
100
+ * Offset (ms) on the session's input-audio-buffer timeline of the first frame buffered for this
101
+ * turn, so a VAD offset can be converted into a byte offset into `audio`.
102
+ *
103
+ * @type {number | undefined}
104
+ */
105
+ audioBaseMs = undefined
106
+
107
+ /**
108
+ * Tool results the app fed back (`function_call_output`) before the next response.
109
+ *
110
+ * @type {ToolResult[]}
111
+ */
112
+ toolResults = []
113
+
114
+ /**
115
+ * The input audio buffer was cleared: drop the buffered audio and the speech onset derived from
116
+ * it, so neither can be attributed to the next response. A commit that already happened is left
117
+ * alone — a client that clears the buffer after committing has still ended that speech.
118
+ */
119
+ discardAudio () {
120
+ this.audio.clear()
121
+ this.speechStartTime = undefined
122
+ this.audioBaseMs = undefined
123
+ }
124
+ }
125
+
126
+ /** Accumulated assistant output for a single `response.*` lifecycle. */
127
+ class ResponseTurn {
128
+ /**
129
+ * @param {InputTurn} input
130
+ * @param {number} createdTime - Epoch ms at which `response.created` arrived. The fallback start
131
+ * for the turn root and llm spans when the turn produced no user speech to back-date to.
132
+ * @param {(() => boolean) | boolean} [retainAudio] - Whether anything consumes the bytes, so only
133
+ * their count is kept when not. Resolved when the segment opens. See `AudioAccumulator`.
134
+ */
135
+ constructor (input, createdTime, retainAudio = true) {
136
+ this.input = input
137
+ this.createdTime = createdTime
138
+ this.audio = new AudioAccumulator(retainAudio)
139
+ }
140
+
141
+ transcript = new ItemText()
142
+
143
+ text = new ItemText()
144
+
145
+ /** @type {{ input_tokens?: number, output_tokens?: number, total_tokens?: number } | undefined} */
146
+ usage = undefined
147
+
148
+ /** @type {string | undefined} */
149
+ model = undefined
150
+
151
+ /** @type {string | undefined} */
152
+ status = undefined
153
+
154
+ /**
155
+ * The provider's own account of a failure, from `response.done`'s `status_details.error`. Carried
156
+ * separately from `status` because `failed` alone leaves a span with no way to say what went wrong.
157
+ *
158
+ * @type {{ type?: string, code?: string, message?: string } | undefined}
159
+ */
160
+ error = undefined
161
+
162
+ /**
163
+ * Wall clock (epoch ms) when `response.done` arrived. The llm span ends here — generation
164
+ * complete — not when the agent finishes speaking.
165
+ *
166
+ * @type {number | undefined}
167
+ */
168
+ responseDoneTime = undefined
169
+
170
+ /**
171
+ * Byte offset into `audio` at which each output item's audio begins, so a truncation — which is
172
+ * reported per item — maps onto this turn's segment.
173
+ *
174
+ * @type {Map<string, number>}
175
+ */
176
+ audioItemStarts = new Map()
177
+
178
+ /**
179
+ * Wall clock (epoch ms) at which the agent's audio would finish playing. Set while the turn is
180
+ * held open waiting for playback to end.
181
+ *
182
+ * @type {number | undefined}
183
+ */
184
+ playbackEndTime = undefined
185
+
186
+ /**
187
+ * Runs a callback inside the async context that was active when this turn started, so the span
188
+ * tree replayed at finalize nests under the caller's own APM and LLM Observability context.
189
+ * Composed by the tracing and LLM Observability plugins off the capture-context channel; absent
190
+ * when neither is subscribed.
191
+ *
192
+ * @type {((fn: () => void) => void) | undefined}
193
+ */
194
+ runInContext = undefined
195
+
196
+ /**
197
+ * Function and MCP calls the model made this turn.
198
+ *
199
+ * @type {ToolCall[]}
200
+ */
201
+ toolCalls = []
202
+
203
+ /**
204
+ * Inline MCP results for the calls above.
205
+ *
206
+ * @type {ToolResult[]}
207
+ */
208
+ toolResults = []
209
+ }
210
+
211
+ module.exports = { InputTurn, ItemText, ResponseTurn }
@@ -3,51 +3,34 @@
3
3
  const dc = require('dc-polyfill')
4
4
  const shimmer = require('../../datadog-shimmer')
5
5
  const { addHook } = require('./helpers/instrument')
6
+ const { patchRealtimeEmitter, patchRealtimeTransport, realtimeEnabled } = require('./openai-realtime')
6
7
 
7
8
  const ch = dc.tracingChannel('apm:openai:request')
8
9
  const onStreamedChunkCh = dc.channel('apm:openai:request:chunk')
9
10
  const responsePromiseContexts = new WeakMap()
10
11
 
11
- // Provider lifecycle channels. Payloads stay OpenAI-native:
12
- // before { args, parentSpan, abortController, pending }
13
- // after { args, body, parentSpan, abortController, pending }
14
- const chatCompletionsBeforeChannel = dc.channel('dd-trace:openai:chat.completions:before')
15
- const chatCompletionsAfterChannel = dc.channel('dd-trace:openai:chat.completions:after')
16
- const responsesBeforeChannel = dc.channel('dd-trace:openai:responses:before')
17
- const responsesAfterChannel = dc.channel('dd-trace:openai:responses:after')
18
-
19
- const LIFECYCLE_CHANNELS = {
20
- 'chat.completions': {
21
- before: chatCompletionsBeforeChannel,
22
- after: chatCompletionsAfterChannel,
23
- },
24
- responses: {
25
- before: responsesBeforeChannel,
26
- after: responsesAfterChannel,
27
- },
28
- }
12
+ // Published synchronously with the native call data. A subscriber may set either callback and
13
+ // this instrumentation applies it, so the wrapping stays here and only the policy lives outside:
14
+ // beforeResult () => Promise<void>|undefined holds the result back until it settles
15
+ // onResult (body) => unknown|Promise<unknown> inspects or replaces the delivered body
16
+ const chatCompletionsInterceptChannel = dc.channel('dd-trace:openai:chat.completions:intercept')
17
+ const responsesInterceptChannel = dc.channel('dd-trace:openai:responses:intercept')
29
18
 
30
19
  /**
31
- * Publishes a provider-native lifecycle payload to a cancelable lifecycle channel.
32
- *
33
- * Subscribers push async work into `pending` synchronously during publication and
34
- * abort `abortController` with an error before the pushed promise resolves to block.
20
+ * Returns `promise`, but not before `settled` settles, so a rejection from an interceptor
21
+ * reaches the caller instead of the SDK's value.
35
22
  *
36
- * @param {object} channel
37
- * @param {object} payload
38
- * @returns {Promise<void>}
23
+ * @template T
24
+ * @param {Promise<T>} promise
25
+ * @param {Promise<void>|undefined} settled
26
+ * @returns {Promise<T>}
39
27
  */
40
- function publishLifecycle (channel, payload) {
41
- const abortController = new AbortController()
42
- const ctx = { ...payload, abortController, pending: [] }
28
+ function heldUntil (promise, settled) {
29
+ if (!settled) return promise
43
30
 
44
- channel.publish(ctx)
45
-
46
- return Promise.all(ctx.pending).then(() => {
47
- if (abortController.signal.aborted) {
48
- throw abortController.signal.reason
49
- }
50
- })
31
+ // The interceptor's rejection wins over an earlier SDK rejection, so keep that one handled.
32
+ promise.catch(() => {})
33
+ return settled.then(() => promise)
51
34
  }
52
35
 
53
36
  const V4_PACKAGE_SHIMS = [
@@ -57,6 +40,7 @@ const V4_PACKAGE_SHIMS = [
57
40
  baseResource: 'chat.completions',
58
41
  methods: ['create'],
59
42
  streamedResponse: true,
43
+ interceptChannel: chatCompletionsInterceptChannel,
60
44
  },
61
45
  {
62
46
  file: 'resources/completions',
@@ -72,6 +56,7 @@ const V4_PACKAGE_SHIMS = [
72
56
  methods: ['create'], // implicitly covers `parse` as well which calls `create` under the hood
73
57
  streamedResponse: true,
74
58
  versions: ['>=4.87.0'],
59
+ interceptChannel: responsesInterceptChannel,
75
60
  },
76
61
  {
77
62
  file: 'resources/embeddings',
@@ -185,6 +170,7 @@ const V4_PACKAGE_SHIMS = [
185
170
  methods: ['create'],
186
171
  streamedResponse: true,
187
172
  versions: ['>=4.85.0'],
173
+ interceptChannel: chatCompletionsInterceptChannel,
188
174
  },
189
175
  ]
190
176
 
@@ -287,13 +273,11 @@ for (const extension of extensions) {
287
273
  return handleUnwrappedAPIPromise(parsedPromise, state)
288
274
  })
289
275
 
276
+ // Raw-response callers bypass `parse`, so run the interceptor here too.
290
277
  shimmer.wrap(prototype, 'asResponse', asResponse => function (...args) {
291
278
  const state = responsePromiseContexts.get(this.responsePromise)
292
- const responsePromise = asResponse.apply(this, args)
293
-
294
- if (!state?.getBeforeVerdict) return responsePromise
295
279
 
296
- return Promise.all([state.getBeforeVerdict(), responsePromise]).then(([, response]) => response)
280
+ return heldUntil(asResponse.apply(this, args), state?.interceptCtx?.beforeResult?.())
297
281
  })
298
282
 
299
283
  return exports
@@ -303,7 +287,7 @@ for (const extension of extensions) {
303
287
 
304
288
  for (const extension of extensions) {
305
289
  for (const shim of V4_PACKAGE_SHIMS) {
306
- const { file, targetClass, baseResource, methods, versions, streamedResponse } = shim
290
+ const { file, targetClass, baseResource, methods, versions, streamedResponse, interceptChannel } = shim
307
291
  addHook({ name: 'openai', file: file + extension, versions: versions || ['>=4'] }, exports => {
308
292
  const targetPrototype = exports[targetClass].prototype
309
293
 
@@ -314,10 +298,10 @@ for (const extension of extensions) {
314
298
  // chat.completions and completions
315
299
  const stream = streamedResponse && getOption(args, 'stream', false)
316
300
 
317
- const channels = stream ? null : LIFECYCLE_CHANNELS[baseResource]
318
- const hasLifecycle = !!channels && (channels.before.hasSubscribers || channels.after.hasSubscribers)
301
+ const tracing = ch.start.hasSubscribers
302
+ const intercepted = interceptChannel?.hasSubscribers
319
303
 
320
- if (!ch.start.hasSubscribers && !hasLifecycle) {
304
+ if (!tracing && !intercepted) {
321
305
  return methodFn.apply(this, args)
322
306
  }
323
307
 
@@ -330,24 +314,21 @@ for (const extension of extensions) {
330
314
  }
331
315
 
332
316
  return ch.start.runStores(ctx, () => {
333
- // Capture the parent span explicitly: the _thenUnwrap/parse path decouples
334
- // the lazy evaluation from the active scope at call time.
335
- const parentSpan = hasLifecycle ? ctx.currentStore?.span : undefined
336
-
337
317
  const apiProm = methodFn.apply(this, args)
338
318
 
339
- const beforeChannel = hasLifecycle && channels.before.hasSubscribers ? channels.before : null
340
- const afterChannel = hasLifecycle && channels.after.hasSubscribers ? channels.after : null
341
- let beforeVerdict
342
- const getBeforeVerdict = beforeChannel
343
- ? function getBeforeVerdict () {
344
- beforeVerdict ??= publishLifecycle(beforeChannel, { args, parentSpan })
345
- return beforeVerdict
346
- }
347
- : null
319
+ let interceptCtx
320
+ if (intercepted) {
321
+ interceptCtx = { arguments: args, tracingContext: ctx }
322
+ interceptChannel.publish(interceptCtx)
323
+ }
348
324
 
349
- const state = { ctx, stream, getBeforeVerdict, afterChannel, parentSpan }
350
- responsePromiseContexts.set(apiProm.responsePromise, state)
325
+ // Keyed by the response promise rather than the APIPromise: `_thenUnwrap` builds a new
326
+ // APIPromise around the same response, which is how `responses.parse` and the
327
+ // pagination page types reach the prototype wrappers above. A method that resolves to
328
+ // a plain value has none, and a WeakMap rejects a non-object key.
329
+ if (apiProm?.responsePromise) {
330
+ responsePromiseContexts.set(apiProm.responsePromise, { ctx, stream, interceptCtx, tracing })
331
+ }
351
332
 
352
333
  ch.end.publish(ctx)
353
334
 
@@ -360,23 +341,57 @@ for (const extension of extensions) {
360
341
  }
361
342
  }
362
343
 
344
+ // The Realtime API is a bidirectional WebSocket event stream, not request/response, so it can't
345
+ // reuse the resource shims above. Every server event funnels through the emitter's `_emit`, and
346
+ // every client event through the transport's `send`.
347
+ //
348
+ // Realtime ships at two paths: the current `realtime/*` (openai >=5.17.0) and the older
349
+ // `beta/realtime/*`, which is a fully duplicated implementation with its own emitter and transport
350
+ // classes — not a re-export — and still ships alongside it. Both are hooked, so an app that has not
351
+ // moved off the beta import path is still instrumented. `addHook` on a file a given version doesn't
352
+ // have is a no-op, so the ranges only need to be loose enough.
353
+ const REALTIME_SHIMS = [
354
+ { file: 'realtime/internal-base', targetClass: 'OpenAIRealtimeEmitter', versions: ['>=5.17.0'] },
355
+ { file: 'realtime/ws', targetClass: 'OpenAIRealtimeWS', versions: ['>=5.17.0'] },
356
+ { file: 'realtime/websocket', targetClass: 'OpenAIRealtimeWebSocket', versions: ['>=5.17.0'] },
357
+ { file: 'beta/realtime/internal-base', targetClass: 'OpenAIRealtimeEmitter', versions: ['>=4'] },
358
+ { file: 'beta/realtime/ws', targetClass: 'OpenAIRealtimeWS', versions: ['>=4'] },
359
+ { file: 'beta/realtime/websocket', targetClass: 'OpenAIRealtimeWebSocket', versions: ['>=4'] },
360
+ ]
361
+
362
+ if (realtimeEnabled()) {
363
+ for (const extension of extensions) {
364
+ for (const { file, targetClass, versions } of REALTIME_SHIMS) {
365
+ addHook({ name: 'openai', file: file + extension, versions }, exports => {
366
+ const prototype = exports[targetClass]?.prototype
367
+ if (targetClass === 'OpenAIRealtimeEmitter') {
368
+ patchRealtimeEmitter(prototype)
369
+ } else {
370
+ patchRealtimeTransport(prototype)
371
+ }
372
+ return exports
373
+ })
374
+ }
375
+ }
376
+ }
377
+
363
378
  function handleUnwrappedAPIPromise (apiProm, state) {
364
- const { ctx, stream, getBeforeVerdict, afterChannel, parentSpan } = state
365
- const gatedApiProm = getBeforeVerdict
366
- ? Promise.all([getBeforeVerdict(), apiProm]).then(([, result]) => result)
367
- : apiProm
379
+ const { ctx, stream, interceptCtx, tracing } = state
368
380
 
369
- return gatedApiProm
381
+ return heldUntil(apiProm, interceptCtx?.beforeResult?.())
370
382
  .then(([{ response, options }, body]) => {
371
383
  if (stream) {
372
- if (body.iterator) {
373
- shimmer.wrap(body, 'iterator', wrapStreamIterator(response, options, ctx))
374
- } else {
375
- shimmer.wrap(
376
- body.response.body, Symbol.asyncIterator, wrapStreamIterator(response, options, ctx)
377
- )
378
- }
379
- return body
384
+ return Promise.resolve(interceptCtx?.onResult ? interceptCtx.onResult(body) : body).then(streamBody => {
385
+ if (!tracing) return streamBody
386
+
387
+ const wrapIterator = wrapStreamIterator(response, options, ctx)
388
+ if (streamBody.iterator) {
389
+ shimmer.wrap(streamBody, 'iterator', wrapIterator)
390
+ } else {
391
+ shimmer.wrap(streamBody.response.body, Symbol.asyncIterator, wrapIterator)
392
+ }
393
+ return streamBody
394
+ })
380
395
  }
381
396
 
382
397
  const responseData = {
@@ -388,28 +403,29 @@ function handleUnwrappedAPIPromise (apiProm, state) {
388
403
  },
389
404
  }
390
405
 
391
- if (!afterChannel) {
406
+ if (!interceptCtx?.onResult) {
392
407
  finish(ctx, responseData)
393
408
  return body
394
409
  }
395
410
 
396
- // Finish after evaluation so a block propagates the error to openai.request
397
- // and the span wraps its child instead of closing before it.
398
- return publishLifecycle(afterChannel, { args: ctx.args, body, parentSpan }).then(() => {
411
+ // Finish after the callback settles so a rejection propagates to openai.request and the
412
+ // span wraps its child instead of closing before it.
413
+ return Promise.resolve(interceptCtx.onResult(body)).then(deliveredBody => {
399
414
  finish(ctx, responseData)
400
- return body
415
+ return deliveredBody
401
416
  })
402
417
  })
403
418
  .catch(error => {
404
- // ctx.result is set inside finish(); if absent, finish never ran (sync throw in the success
405
- // branch, Before Model block, After Model block, or openai error) — record the error now so
406
- // the openai.request span is marked errored. If finish already ran, don't double-publish.
407
- if (!ctx.result) finish(ctx, undefined, error)
419
+ finish(ctx, undefined, error)
408
420
  throw error
409
421
  })
410
422
  }
411
423
 
412
424
  function finish (ctx, response, error) {
425
+ // `parse` is re-entered on every await of the same APIPromise, and a stream may be iterated
426
+ // more than once, so the span must only close once.
427
+ if (ctx.finished) return
428
+
413
429
  if (error) {
414
430
  ctx.error = error
415
431
  ch.error.publish(ctx)
@@ -419,6 +435,7 @@ function finish (ctx, response, error) {
419
435
  // so we don't want to override it here
420
436
  ctx.result ??= {}
421
437
  Object.assign(ctx.result, response)
438
+ ctx.finished = true
422
439
 
423
440
  ch.asyncEnd.publish(ctx)
424
441
  }
@@ -105,9 +105,13 @@ addHook({ name: 'oracledb', versions: ['>=5'], file: 'lib/oracledb.js' }, oracle
105
105
  })
106
106
  shimmer.wrap(oracledb, 'getConnection', getConnection => {
107
107
  return function wrappedGetConnection (connAttrs, callback) {
108
+ if (typeof connAttrs === 'function') {
109
+ callback = connAttrs
110
+ connAttrs = undefined
111
+ }
108
112
  if (callback) {
109
- arguments[1] = shimmer.wrapFunction(callback, callback => (err, connection) => {
110
- if (connection) {
113
+ arguments[arguments.length - 1] = shimmer.wrapFunction(callback, callback => (err, connection) => {
114
+ if (connection && !connectionAttributes.has(connection)) {
111
115
  connectionAttributes.set(connection, connAttrs)
112
116
  }
113
117
  callback(err, connection)
@@ -116,7 +120,9 @@ addHook({ name: 'oracledb', versions: ['>=5'], file: 'lib/oracledb.js' }, oracle
116
120
  getConnection.apply(this, arguments)
117
121
  } else {
118
122
  return getConnection.apply(this, arguments).then((connection) => {
119
- connectionAttributes.set(connection, connAttrs)
123
+ if (!connectionAttributes.has(connection)) {
124
+ connectionAttributes.set(connection, connAttrs)
125
+ }
120
126
  return connection
121
127
  })
122
128
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  const { channel } = require('dc-polyfill')
4
4
 
5
+ const libraryConfigurationCh = channel('ci:playwright:library-configuration')
5
6
  const reporterErrorCh = channel('ci:playwright:reporter:error')
6
7
  const reporterRunSummaryCh = channel('ci:playwright:reporter:run-summary')
7
8
  const reporterSuiteHookErrorCh = channel('ci:playwright:reporter:suite-hook-error')
@@ -15,7 +16,6 @@ const PLAYWRIGHT_REPORTER_ERROR_CALLER_RE =
15
16
  * interpreting identical user console output as a framework error.
16
17
  *
17
18
  * @param {unknown} message - First console.error argument
18
- * @returns {boolean}
19
19
  */
20
20
  function isPlaywrightReporterError (message) {
21
21
  if (message !== PLAYWRIGHT_REPORTER_ERROR_MESSAGE) return false
@@ -34,7 +34,6 @@ function isPlaywrightReporterError (message) {
34
34
  * Returns whether a finalized Playwright result contains a failed suite hook.
35
35
  *
36
36
  * @param {Array<object>} steps
37
- * @returns {boolean}
38
37
  */
39
38
  function hasFailedSuiteHook (steps) {
40
39
  if (!steps) return false
@@ -71,7 +70,6 @@ class DatadogPlaywrightReporter {
71
70
  * Implements the reporter v2 lifecycle hook required by older Playwright versions.
72
71
  *
73
72
  * @param {object} config
74
- * @returns {void}
75
73
  */
76
74
  onConfigure (config) {
77
75
  this.failOnFlakyTests = config.failOnFlakyTests
@@ -80,7 +78,6 @@ class DatadogPlaywrightReporter {
80
78
  /**
81
79
  * Restores console error after Playwright completes the reporter lifecycle.
82
80
  *
83
- * @returns {void}
84
81
  */
85
82
  static restoreConsoleError () {
86
83
  // eslint-disable-next-line no-console
@@ -99,7 +96,6 @@ class DatadogPlaywrightReporter {
99
96
  *
100
97
  * @param {object} configOrSuite
101
98
  * @param {object} [suite]
102
- * @returns {void}
103
99
  */
104
100
  onBegin (configOrSuite, suite) {
105
101
  this.suite = suite || configOrSuite
@@ -110,49 +106,42 @@ class DatadogPlaywrightReporter {
110
106
  /**
111
107
  * Implements the reporter v2 lifecycle hook required by older Playwright versions.
112
108
  *
113
- * @returns {void}
114
109
  */
115
110
  onTestBegin () {}
116
111
 
117
112
  /**
118
113
  * Implements the reporter v2 lifecycle hook required by older Playwright versions.
119
114
  *
120
- * @returns {void}
121
115
  */
122
116
  onStdOut () {}
123
117
 
124
118
  /**
125
119
  * Implements the reporter v2 lifecycle hook required by older Playwright versions.
126
120
  *
127
- * @returns {void}
128
121
  */
129
122
  onStdErr () {}
130
123
 
131
124
  /**
132
125
  * Implements the reporter v2 lifecycle hook required by older Playwright versions.
133
126
  *
134
- * @returns {void}
135
127
  */
136
128
  onTestEnd () {}
137
129
 
138
130
  /**
139
131
  * Implements the reporter v2 lifecycle hook required by older Playwright versions.
140
132
  *
141
- * @returns {void}
142
133
  */
143
134
  onStepBegin () {}
144
135
 
145
136
  /**
146
137
  * Implements the reporter v2 lifecycle hook required by older Playwright versions.
147
138
  *
148
- * @returns {void}
149
139
  */
150
140
  onStepEnd () {}
151
141
 
152
142
  /**
153
143
  * Marks the beginning of reporter finalization so later reporter errors can be identified.
154
144
  *
155
- * @returns {void}
156
145
  */
157
146
  onEnd () {
158
147
  let failureCount = this.fatalErrorCount
@@ -182,7 +171,8 @@ class DatadogPlaywrightReporter {
182
171
  reporterRunSummaryCh.publish({ failureCount, quarantinedFailureCount, hasIncompleteTests })
183
172
  suitesWithHookErrors.clear()
184
173
 
185
- if (!this.captureReporterErrors) return
174
+ // A reused config can retain this reporter after the plugin is disabled.
175
+ if (!this.captureReporterErrors || !libraryConfigurationCh.hasSubscribers) return
186
176
 
187
177
  this.isFinalizing = true
188
178
  // Playwright 1.60 and 1.61 only expose reporter errors through this exact console call.
@@ -212,7 +202,6 @@ class DatadogPlaywrightReporter {
212
202
  /**
213
203
  * Implements the reporter v2 lifecycle hook required by older Playwright versions.
214
204
  *
215
- * @returns {void}
216
205
  */
217
206
  onExit () {}
218
207
 
@@ -220,7 +209,6 @@ class DatadogPlaywrightReporter {
220
209
  * Reports errors emitted by Playwright while later reporters are finalizing.
221
210
  *
222
211
  * @param {unknown} error
223
- * @returns {void}
224
212
  */
225
213
  onError (error) {
226
214
  if (this.isFinalizing) {
@@ -233,7 +221,6 @@ class DatadogPlaywrightReporter {
233
221
  /**
234
222
  * Keeps the internal reporter from affecting Playwright's output reporter selection.
235
223
  *
236
- * @returns {boolean}
237
224
  */
238
225
  printsToStdio () {
239
226
  return false