dd-trace 6.16.0 → 6.18.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 (356) hide show
  1. package/ci/diagnose.js +0 -23
  2. package/ci/test-optimization-validation/approval-artifacts.js +0 -3
  3. package/ci/test-optimization-validation/approval.js +0 -6
  4. package/ci/test-optimization-validation/artifact-id.js +0 -1
  5. package/ci/test-optimization-validation/bounded-json.js +0 -1
  6. package/ci/test-optimization-validation/cli.js +0 -12
  7. package/ci/test-optimization-validation/command-output-policy.js +0 -1
  8. package/ci/test-optimization-validation/command-runner.js +0 -3
  9. package/ci/test-optimization-validation/environment.js +0 -4
  10. package/ci/test-optimization-validation/executable-approval.js +0 -1
  11. package/ci/test-optimization-validation/executable.js +0 -5
  12. package/ci/test-optimization-validation/framework-adapters/cucumber.js +0 -6
  13. package/ci/test-optimization-validation/framework-adapters/cypress.js +0 -3
  14. package/ci/test-optimization-validation/framework-adapters/playwright.js +0 -6
  15. package/ci/test-optimization-validation/framework-adapters/vitest.js +0 -4
  16. package/ci/test-optimization-validation/generated-test-contract.js +0 -5
  17. package/ci/test-optimization-validation/generated-verifier.js +0 -1
  18. package/ci/test-optimization-validation/literal-environment.js +0 -1
  19. package/ci/test-optimization-validation/manifest-scaffold.js +0 -17
  20. package/ci/test-optimization-validation/manifest-schema.js +0 -21
  21. package/ci/test-optimization-validation/offline-fixtures.js +0 -4
  22. package/ci/test-optimization-validation/plan-writer.js +0 -11
  23. package/ci/test-optimization-validation/preflight-runner.js +0 -1
  24. package/ci/test-optimization-validation/redaction.js +0 -4
  25. package/ci/test-optimization-validation/report-writer.js +0 -16
  26. package/ci/test-optimization-validation/runner-command.js +0 -3
  27. package/ci/test-optimization-validation/runner-contract.js +0 -4
  28. package/ci/test-optimization-validation/safe-files.js +0 -1
  29. package/ci/test-optimization-validation/scenarios/basic-reporting.js +0 -1
  30. package/ci/test-optimization-validation/scenarios/ci-wiring.js +0 -1
  31. package/ci/test-optimization-validation/source-text.js +0 -3
  32. package/ci/vitest-no-worker-init-setup.mjs +41 -16
  33. package/index.d.ts +208 -0
  34. package/package.json +17 -16
  35. package/packages/datadog-esbuild/src/utils.js +0 -2
  36. package/packages/datadog-instrumentations/src/aerospike.js +28 -6
  37. package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +0 -2
  38. package/packages/datadog-instrumentations/src/aws-sdk.js +0 -2
  39. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +0 -2
  40. package/packages/datadog-instrumentations/src/console.js +97 -0
  41. package/packages/datadog-instrumentations/src/cucumber.js +77 -12
  42. package/packages/datadog-instrumentations/src/cypress-config.js +27 -38
  43. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +6 -0
  44. package/packages/datadog-instrumentations/src/helpers/channel.js +0 -2
  45. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +2 -1
  46. package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +0 -5
  47. package/packages/datadog-instrumentations/src/helpers/hooks.js +8 -6
  48. package/packages/datadog-instrumentations/src/helpers/instrumentation-utils.js +0 -3
  49. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +0 -6
  50. package/packages/datadog-instrumentations/src/helpers/register.js +24 -0
  51. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +111 -26
  52. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +41 -0
  53. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +3 -17
  54. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +55 -0
  55. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +36 -0
  56. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/supabase.js +128 -0
  57. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +13 -0
  58. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +28 -3
  59. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +20 -0
  60. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +388 -0
  61. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +0 -5
  62. package/packages/datadog-instrumentations/src/helpers/router-helper.js +0 -1
  63. package/packages/datadog-instrumentations/src/jest.js +165 -51
  64. package/packages/datadog-instrumentations/src/knex.js +0 -1
  65. package/packages/datadog-instrumentations/src/mariadb-bundle.js +0 -24
  66. package/packages/datadog-instrumentations/src/mariadb.js +0 -2
  67. package/packages/datadog-instrumentations/src/mocha/common.js +0 -1
  68. package/packages/datadog-instrumentations/src/mocha/main.js +25 -26
  69. package/packages/datadog-instrumentations/src/mocha/utils.js +119 -49
  70. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +0 -6
  71. package/packages/datadog-instrumentations/src/mocha/worker.js +14 -17
  72. package/packages/datadog-instrumentations/src/mysql2.js +0 -2
  73. package/packages/datadog-instrumentations/src/openai-realtime/audio-accumulator.js +241 -0
  74. package/packages/datadog-instrumentations/src/openai-realtime/events.js +76 -0
  75. package/packages/datadog-instrumentations/src/openai-realtime/index.js +301 -0
  76. package/packages/datadog-instrumentations/src/openai-realtime/session.js +998 -0
  77. package/packages/datadog-instrumentations/src/openai-realtime/turns.js +211 -0
  78. package/packages/datadog-instrumentations/src/openai.js +51 -12
  79. package/packages/datadog-instrumentations/src/oracledb.js +9 -3
  80. package/packages/datadog-instrumentations/src/playwright-reporter.js +6 -20
  81. package/packages/datadog-instrumentations/src/playwright.js +280 -56
  82. package/packages/datadog-instrumentations/src/{azure-cosmos.js → postgres.js} +1 -1
  83. package/packages/datadog-instrumentations/src/router.js +0 -2
  84. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +0 -2
  85. package/packages/datadog-instrumentations/src/sequelize.js +0 -1
  86. package/packages/datadog-instrumentations/src/supabase.js +15 -0
  87. package/packages/datadog-instrumentations/src/undici.js +7 -3
  88. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +18 -18
  89. package/packages/datadog-instrumentations/src/vitest-main.js +121 -30
  90. package/packages/datadog-instrumentations/src/vitest-util.js +7 -1
  91. package/packages/datadog-instrumentations/src/vitest-worker.js +49 -13
  92. package/packages/datadog-instrumentations/src/webdriverio.js +44 -47
  93. package/packages/datadog-instrumentations/src/ws.js +41 -2
  94. package/packages/datadog-plugin-ai/src/utils.js +0 -2
  95. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +0 -1
  96. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +0 -2
  97. package/packages/datadog-plugin-aws-sdk/src/base.js +0 -1
  98. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +0 -1
  99. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +0 -1
  100. package/packages/datadog-plugin-aws-sdk/src/util.js +0 -1
  101. package/packages/datadog-plugin-azure-durable-functions/src/index.js +0 -1
  102. package/packages/datadog-plugin-cucumber/src/index.js +9 -0
  103. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +211 -85
  104. package/packages/datadog-plugin-cypress/src/finalization.js +0 -3
  105. package/packages/datadog-plugin-cypress/src/index.js +3 -1
  106. package/packages/datadog-plugin-cypress/src/source-map-utils.js +0 -4
  107. package/packages/datadog-plugin-cypress/src/support.js +52 -7
  108. package/packages/datadog-plugin-graphql/src/resolve-error.js +1 -2
  109. package/packages/datadog-plugin-graphql/src/utils.js +0 -5
  110. package/packages/datadog-plugin-jest/src/index.js +12 -0
  111. package/packages/datadog-plugin-kafkajs/src/producer.js +0 -1
  112. package/packages/datadog-plugin-mocha/src/index.js +38 -11
  113. package/packages/datadog-plugin-mongodb-core/src/query.js +0 -1
  114. package/packages/datadog-plugin-openai/src/index.js +16 -1
  115. package/packages/datadog-plugin-openai/src/realtime.js +144 -0
  116. package/packages/datadog-plugin-openai-agents/src/integration.js +0 -4
  117. package/packages/datadog-plugin-openai-agents/src/util.js +0 -1
  118. package/packages/datadog-plugin-playwright/src/index.js +81 -9
  119. package/packages/datadog-plugin-postgres/src/index.js +167 -0
  120. package/packages/datadog-plugin-prisma/src/datadog-tracing-helper.js +0 -1
  121. package/packages/datadog-plugin-redis/src/index.js +15 -1
  122. package/packages/datadog-plugin-supabase/src/error.js +18 -0
  123. package/packages/datadog-plugin-supabase/src/index.js +21 -0
  124. package/packages/datadog-plugin-supabase/src/supabase-auth-js-gotrueclient-getuser.js +69 -0
  125. package/packages/datadog-plugin-supabase/src/supabase-functions-js-functionsclient-invoke.js +70 -0
  126. package/packages/datadog-plugin-supabase/src/supabase-postgrest-js-postgrestbuilder-then.js +122 -0
  127. package/packages/datadog-plugin-supabase/src/supabase-realtime-js-realtimechannel-send.js +66 -0
  128. package/packages/datadog-plugin-supabase/src/supabase-storage-js-handle-request.js +93 -0
  129. package/packages/datadog-plugin-supabase/src/url.js +17 -0
  130. package/packages/datadog-plugin-vitest/src/index.js +9 -0
  131. package/packages/datadog-plugin-ws/src/producer.js +1 -1
  132. package/packages/datadog-plugin-ws/src/util.js +0 -4
  133. package/packages/datadog-shimmer/src/shimmer.js +14 -10
  134. package/packages/datadog-turbopack/index.js +4 -7
  135. package/packages/datadog-turbopack/src/loader.js +6 -18
  136. package/packages/datadog-webpack/src/loader.js +0 -1
  137. package/packages/dd-trace/src/agent/info.js +5 -4
  138. package/packages/dd-trace/src/aiguard/client.js +2 -3
  139. package/packages/dd-trace/src/aiguard/evaluation.js +6 -12
  140. package/packages/dd-trace/src/aiguard/index.js +2 -2
  141. package/packages/dd-trace/src/aiguard/integrations/index.js +1 -1
  142. package/packages/dd-trace/src/aiguard/integrations/openai.js +81 -7
  143. package/packages/dd-trace/src/aiguard/messages/anthropic.js +0 -2
  144. package/packages/dd-trace/src/aiguard/messages/openai.js +64 -1
  145. package/packages/dd-trace/src/aiguard/messages/utils.js +0 -1
  146. package/packages/dd-trace/src/aiguard/redaction.js +0 -1
  147. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  148. package/packages/dd-trace/src/appsec/activation.js +1 -1
  149. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +0 -5
  150. package/packages/dd-trace/src/appsec/api_security/sampler.js +0 -4
  151. package/packages/dd-trace/src/appsec/blocking/index.js +3 -3
  152. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -4
  153. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  154. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +5 -5
  155. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +1 -1
  156. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
  157. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +3 -3
  158. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +8 -10
  159. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -2
  160. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +4 -1
  161. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +7 -7
  162. package/packages/dd-trace/src/appsec/index.js +2 -2
  163. package/packages/dd-trace/src/appsec/lambda.js +71 -2
  164. package/packages/dd-trace/src/appsec/rasp/utils.js +5 -1
  165. package/packages/dd-trace/src/appsec/remote_config.js +8 -6
  166. package/packages/dd-trace/src/appsec/reporter.js +10 -6
  167. package/packages/dd-trace/src/appsec/rule_manager.js +3 -3
  168. package/packages/dd-trace/src/appsec/sdk/track_event.js +0 -2
  169. package/packages/dd-trace/src/appsec/waf/index.js +2 -2
  170. package/packages/dd-trace/src/appsec/waf/waf_manager.js +8 -5
  171. package/packages/dd-trace/src/carrier.js +0 -5
  172. package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +104 -0
  173. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +0 -2
  174. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +34 -3
  175. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +0 -1
  176. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +0 -1
  177. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +0 -1
  178. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +0 -4
  179. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +0 -1
  180. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +0 -2
  181. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +37 -15
  182. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +0 -3
  183. package/packages/dd-trace/src/ci-visibility/exporters/request.js +0 -11
  184. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +0 -1
  185. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +0 -1
  186. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +0 -6
  187. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -2
  188. package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +0 -1
  189. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +0 -5
  190. package/packages/dd-trace/src/ci-visibility/requests/video-request.js +0 -1
  191. package/packages/dd-trace/src/ci-visibility/telemetry.js +13 -0
  192. package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +0 -1
  193. package/packages/dd-trace/src/ci-visibility/test-screenshot.js +0 -2
  194. package/packages/dd-trace/src/ci-visibility/test-video.js +0 -1
  195. package/packages/dd-trace/src/config/defaults.js +3 -2
  196. package/packages/dd-trace/src/config/generated-config-types.d.ts +88 -82
  197. package/packages/dd-trace/src/config/helper.js +0 -1
  198. package/packages/dd-trace/src/config/index.js +31 -30
  199. package/packages/dd-trace/src/config/parsers.js +34 -6
  200. package/packages/dd-trace/src/config/remote_config.js +25 -109
  201. package/packages/dd-trace/src/config/supported-configurations.json +150 -10
  202. package/packages/dd-trace/src/datastreams/encoding.js +0 -1
  203. package/packages/dd-trace/src/datastreams/pathway.js +0 -1
  204. package/packages/dd-trace/src/debugger/constants.js +10 -0
  205. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +62 -10
  206. package/packages/dd-trace/src/debugger/devtools_client/config.js +4 -1
  207. package/packages/dd-trace/src/debugger/devtools_client/guardrail-metrics.js +15 -0
  208. package/packages/dd-trace/src/debugger/devtools_client/index.js +103 -27
  209. package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +50 -7
  210. package/packages/dd-trace/src/debugger/devtools_client/log.js +3 -1
  211. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +21 -8
  212. package/packages/dd-trace/src/debugger/devtools_client/send.js +41 -15
  213. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +53 -13
  214. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +118 -71
  215. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +5 -3
  216. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +0 -3
  217. package/packages/dd-trace/src/debugger/devtools_client/status.js +21 -7
  218. package/packages/dd-trace/src/debugger/guardrail-metrics.js +167 -0
  219. package/packages/dd-trace/src/debugger/index.js +51 -3
  220. package/packages/dd-trace/src/debugger/inspect-segment.js +0 -3
  221. package/packages/dd-trace/src/debugger/probe_sampler.js +133 -9
  222. package/packages/dd-trace/src/debugger/probe_sampler_constants.js +31 -1
  223. package/packages/dd-trace/src/dogstatsd.js +0 -23
  224. package/packages/dd-trace/src/encode/0.4-cross-payload.js +0 -3
  225. package/packages/dd-trace/src/encode/0.4.js +0 -7
  226. package/packages/dd-trace/src/encode/0.5.js +0 -2
  227. package/packages/dd-trace/src/encode/tags-processors.js +0 -1
  228. package/packages/dd-trace/src/evp_proxy/constants.js +2 -0
  229. package/packages/dd-trace/src/evp_proxy/direct.js +17 -13
  230. package/packages/dd-trace/src/evp_proxy/discovery.js +14 -11
  231. package/packages/dd-trace/src/evp_proxy/path.js +21 -9
  232. package/packages/dd-trace/src/exporters/agent/writer.js +0 -1
  233. package/packages/dd-trace/src/exporters/agentless/index.js +0 -1
  234. package/packages/dd-trace/src/exporters/agentless/intake.js +0 -1
  235. package/packages/dd-trace/src/exporters/agentless/writer.js +0 -3
  236. package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +0 -6
  237. package/packages/dd-trace/src/exporters/common/request.js +1 -0
  238. package/packages/dd-trace/src/exporters/common/url.js +33 -4
  239. package/packages/dd-trace/src/exporters/common/writer.js +0 -2
  240. package/packages/dd-trace/src/id.js +0 -11
  241. package/packages/dd-trace/src/llmobs/audio-codec.js +192 -0
  242. package/packages/dd-trace/src/llmobs/audio-utils.js +121 -0
  243. package/packages/dd-trace/src/llmobs/constants/audio.js +35 -0
  244. package/packages/dd-trace/src/llmobs/constants/prompts.js +14 -0
  245. package/packages/dd-trace/src/llmobs/constants/tags.js +17 -0
  246. package/packages/dd-trace/src/llmobs/eval-metric.js +0 -6
  247. package/packages/dd-trace/src/llmobs/experiments/dataset.js +0 -4
  248. package/packages/dd-trace/src/llmobs/experiments/experiment.js +0 -3
  249. package/packages/dd-trace/src/llmobs/experiments/index.js +7 -6
  250. package/packages/dd-trace/src/llmobs/experiments/util.js +1 -11
  251. package/packages/dd-trace/src/llmobs/index.js +1 -3
  252. package/packages/dd-trace/src/llmobs/noop.js +10 -0
  253. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +0 -4
  254. package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +0 -1
  255. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +0 -4
  256. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +0 -2
  257. package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +0 -2
  258. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +4 -6
  259. package/packages/dd-trace/src/llmobs/plugins/openai/realtime.js +285 -0
  260. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +16 -3
  261. package/packages/dd-trace/src/llmobs/prompts/cache.js +272 -0
  262. package/packages/dd-trace/src/llmobs/prompts/manager.js +647 -0
  263. package/packages/dd-trace/src/llmobs/prompts/noop.js +29 -0
  264. package/packages/dd-trace/src/llmobs/prompts/prompt.js +158 -0
  265. package/packages/dd-trace/src/llmobs/sdk.js +21 -6
  266. package/packages/dd-trace/src/llmobs/span_processor.js +81 -2
  267. package/packages/dd-trace/src/llmobs/tagger.js +39 -11
  268. package/packages/dd-trace/src/llmobs/telemetry.js +36 -4
  269. package/packages/dd-trace/src/llmobs/util.js +0 -34
  270. package/packages/dd-trace/src/llmobs/writers/base.js +0 -1
  271. package/packages/dd-trace/src/llmobs/writers/util.js +1 -2
  272. package/packages/dd-trace/src/log/channels.js +3 -0
  273. package/packages/dd-trace/src/log/index.js +23 -5
  274. package/packages/dd-trace/src/log-submission/log-submission-plugin.js +74 -6
  275. package/packages/dd-trace/src/msgpack/chunk.js +0 -1
  276. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +0 -12
  277. package/packages/dd-trace/src/openfeature/configuration_source.js +4 -1
  278. package/packages/dd-trace/src/openfeature/encoding.js +0 -2
  279. package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +0 -1
  280. package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -3
  281. package/packages/dd-trace/src/openfeature/index.js +6 -6
  282. package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +0 -1
  283. package/packages/dd-trace/src/openfeature/span-enrichment.js +0 -4
  284. package/packages/dd-trace/src/openfeature/writers/base.js +90 -23
  285. package/packages/dd-trace/src/openfeature/writers/exposures.js +4 -5
  286. package/packages/dd-trace/src/openfeature/writers/util.js +104 -37
  287. package/packages/dd-trace/src/opentelemetry/logs/logger.js +0 -1
  288. package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +0 -1
  289. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +0 -1
  290. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +0 -2
  291. package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +0 -1
  292. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +0 -1
  293. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +0 -1
  294. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -14
  295. package/packages/dd-trace/src/opentelemetry/metrics/time.js +0 -1
  296. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +30 -13
  297. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +0 -1
  298. package/packages/dd-trace/src/opentelemetry/span-helpers.js +0 -1
  299. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +0 -1
  300. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +0 -3
  301. package/packages/dd-trace/src/opentracing/propagation/text_map.js +0 -6
  302. package/packages/dd-trace/src/opentracing/span_context.js +0 -1
  303. package/packages/dd-trace/src/opentracing/tracer.js +3 -3
  304. package/packages/dd-trace/src/otel-thread-ctx.js +38 -11
  305. package/packages/dd-trace/src/payload-tagging/tagging.js +15 -3
  306. package/packages/dd-trace/src/plugin_manager.js +27 -8
  307. package/packages/dd-trace/src/plugins/ci_plugin.js +1 -2
  308. package/packages/dd-trace/src/plugins/database.js +2 -6
  309. package/packages/dd-trace/src/plugins/index.js +7 -0
  310. package/packages/dd-trace/src/plugins/plugin.js +0 -4
  311. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  312. package/packages/dd-trace/src/plugins/util/git.js +1 -3
  313. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +0 -1
  314. package/packages/dd-trace/src/plugins/util/llm.js +0 -2
  315. package/packages/dd-trace/src/plugins/util/status-validator.js +0 -1
  316. package/packages/dd-trace/src/plugins/util/test.js +26 -20
  317. package/packages/dd-trace/src/plugins/util/url.js +0 -5
  318. package/packages/dd-trace/src/priority_sampler.js +0 -6
  319. package/packages/dd-trace/src/process-tags/index.js +0 -1
  320. package/packages/dd-trace/src/profiler.js +132 -35
  321. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +0 -1
  322. package/packages/dd-trace/src/profiling/profiler.js +101 -41
  323. package/packages/dd-trace/src/profiling/ssi-heuristics.js +29 -15
  324. package/packages/dd-trace/src/propagation-hash/index.js +0 -1
  325. package/packages/dd-trace/src/proxy.js +23 -47
  326. package/packages/dd-trace/src/random_sampler.js +0 -4
  327. package/packages/dd-trace/src/rate_limiter.js +0 -4
  328. package/packages/dd-trace/src/remote_config/capabilities.js +1 -9
  329. package/packages/dd-trace/src/remote_config/index.js +0 -1
  330. package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +0 -3
  331. package/packages/dd-trace/src/sampler.js +0 -4
  332. package/packages/dd-trace/src/sampling_rule.js +0 -7
  333. package/packages/dd-trace/src/serverless/vercel.js +0 -1
  334. package/packages/dd-trace/src/serverless.js +0 -1
  335. package/packages/dd-trace/src/service-naming/index.js +0 -1
  336. package/packages/dd-trace/src/service-naming/schemas/util.js +0 -1
  337. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +7 -0
  338. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +5 -0
  339. package/packages/dd-trace/src/span_processor.js +2 -2
  340. package/packages/dd-trace/src/span_sampler.js +0 -1
  341. package/packages/dd-trace/src/standalone/product.js +2 -2
  342. package/packages/dd-trace/src/standalone/tracesource.js +0 -1
  343. package/packages/dd-trace/src/startup-log.js +1 -1
  344. package/packages/dd-trace/src/telemetry/endpoints.js +0 -8
  345. package/packages/dd-trace/src/telemetry/logs/index.js +16 -5
  346. package/packages/dd-trace/src/telemetry/logs/log-collector.js +16 -6
  347. package/packages/dd-trace/src/telemetry/metrics.js +0 -2
  348. package/packages/dd-trace/src/telemetry/send-data.js +2 -1
  349. package/packages/dd-trace/src/telemetry/telemetry.js +4 -1
  350. package/packages/dd-trace/src/tracer.js +5 -4
  351. package/packages/dd-trace/src/util.js +13 -1
  352. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
  353. package/packages/datadog-instrumentations/src/bullmq.js +0 -11
  354. package/packages/datadog-instrumentations/src/langchain.js +0 -7
  355. package/packages/datadog-instrumentations/src/langgraph.js +0 -7
  356. package/packages/datadog-instrumentations/src/mercurius.js +0 -11
@@ -0,0 +1,647 @@
1
+ 'use strict'
2
+
3
+ const log = require('../../log')
4
+ const { getEnvironmentVariable } = require('../../config/helper')
5
+ const request = require('../../exporters/common/request')
6
+ const { createSiteUrl, isLoopbackHost } = require('../../exporters/common/url')
7
+ const { ERROR_NAMES, PROMPTS_PATH, SOURCE_CACHE } = require('../constants/prompts')
8
+ const telemetry = require('../telemetry')
9
+ const { HotCache, WarmCache, cacheKey, promptIdFromKey } = require('./cache')
10
+ const ManagedPrompt = require('./prompt')
11
+
12
+ /**
13
+ * @typedef {object} PromptRequest
14
+ * @property {string} promptId
15
+ * @property {number | undefined} version
16
+ * @property {string | undefined} env
17
+ * @property {string | undefined} targetingKey
18
+ * @property {Record<string, unknown>} attributes
19
+ * @property {string} key
20
+ * @property {boolean} resolve
21
+ */
22
+
23
+ /**
24
+ * @typedef {object} PromptFetchResult
25
+ * @property {ManagedPrompt} [prompt]
26
+ * @property {string} [reason]
27
+ * @property {boolean} [notFound]
28
+ * @property {boolean} [cacheable]
29
+ * @property {PromptAPIError} [error]
30
+ */
31
+
32
+ function isPlainObject (value) {
33
+ if (!value || typeof value !== 'object') return false
34
+ const prototype = Object.getPrototypeOf(value)
35
+ return prototype === Object.prototype || prototype === null
36
+ }
37
+
38
+ /**
39
+ * Build a canonical prompt selector.
40
+ * @param {string} promptId
41
+ * @param {object} [options]
42
+ * @param {number} [options.version]
43
+ * @param {string} [options.env]
44
+ * @param {string} [options.targetingKey]
45
+ * @param {Record<string, unknown>} [options.attributes]
46
+ */
47
+ function promptRequest (promptId, { version, env, targetingKey, attributes = {} } = {}) {
48
+ const requestAttributes = { ...attributes }
49
+ let selector
50
+ if (version !== undefined) {
51
+ selector = ['version', version]
52
+ } else if (env) {
53
+ const attributesSelector = Object.keys(requestAttributes).sort().map(key => [key, requestAttributes[key]])
54
+ selector = ['resolve', env, targetingKey ?? null, attributesSelector]
55
+ } else {
56
+ selector = ['latest']
57
+ }
58
+
59
+ return {
60
+ promptId,
61
+ version,
62
+ env,
63
+ targetingKey,
64
+ attributes: requestAttributes,
65
+ key: cacheKey(promptId, selector),
66
+ resolve: version === undefined && Boolean(env),
67
+ }
68
+ }
69
+
70
+ function promptFromData (data, source) {
71
+ if (!isPlainObject(data) || !data.prompt_id) return
72
+ const version = data.user_version || data.version
73
+ if (!version) return
74
+ const template = Array.isArray(data.template?.messages) ? data.template.messages : data.template
75
+ return new ManagedPrompt({
76
+ id: data.prompt_id,
77
+ version: String(version),
78
+ source,
79
+ template: template || data.chat_template || [],
80
+ config: data.config,
81
+ promptUuid: data.prompt_uuid,
82
+ promptVersionUuid: data.prompt_version_uuid || data.id || data.ID,
83
+ })
84
+ }
85
+
86
+ /**
87
+ * Copy a prompt with a different source.
88
+ * @param {ManagedPrompt} prompt
89
+ * @param {'registry'|'cache'|'fallback'|'ff'|'resolve'} source
90
+ */
91
+ function withSource (prompt, source) {
92
+ if (source === prompt.source) return prompt
93
+ return new ManagedPrompt({ ...prompt, source })
94
+ }
95
+
96
+ function detailFromBody (body) {
97
+ try {
98
+ return JSON.parse(body)?.detail ?? body
99
+ } catch {
100
+ return body
101
+ }
102
+ }
103
+
104
+ function errorName (status) {
105
+ if (status === 400) return ERROR_NAMES.VALIDATION
106
+ if (status === 401 || status === 403) return ERROR_NAMES.AUTH
107
+ if (status === 404) return ERROR_NAMES.NOT_FOUND
108
+ if (status === 409) return ERROR_NAMES.CONFLICT
109
+ if (status >= 500) return ERROR_NAMES.SERVER
110
+ return ERROR_NAMES.API
111
+ }
112
+
113
+ class PromptAPIError extends Error {
114
+ /**
115
+ * Create a typed Prompt Management API error.
116
+ * @param {number} status
117
+ * @param {string} detail
118
+ * @param {string} [name]
119
+ */
120
+ constructor (status, detail, name = errorName(status)) {
121
+ super(`Prompt API error (${status}): ${detail}`)
122
+ this.name = name
123
+ this.status = status
124
+ this.detail = detail
125
+ }
126
+ }
127
+
128
+ function normalizeItem (item) {
129
+ if (!isPlainObject(item)) return item
130
+ const { ID, labels, ...normalized } = item
131
+ if (normalized.id === undefined && ID !== undefined) normalized.id = ID
132
+ return normalized
133
+ }
134
+
135
+ function requestSignal (timeoutMs, cacheSignal) {
136
+ const timeoutSignal = AbortSignal.timeout(timeoutMs)
137
+ if (!cacheSignal) return timeoutSignal
138
+ const controller = new AbortController()
139
+ cacheSignal.addEventListener('abort', () => controller.abort(cacheSignal.reason), { once: true })
140
+ timeoutSignal.addEventListener('abort', () => controller.abort(timeoutSignal.reason), { once: true })
141
+ return controller.signal
142
+ }
143
+
144
+ function httpRequest (body, options) {
145
+ return new Promise((resolve, reject) => {
146
+ request(body || '', { ...options, retry: false, includeErrorResponseBody: true }, (error, responseBody, status) => {
147
+ if (error && status === undefined) return reject(error)
148
+ resolve({ ok: !error, status, body: error?.responseBody || responseBody || '' })
149
+ })
150
+ })
151
+ }
152
+
153
+ class PromptManager {
154
+ /**
155
+ * @param {import('../../config/config-base')} config
156
+ * @param {() => object} getProvider
157
+ */
158
+ constructor (config, getProvider) {
159
+ this.config = config
160
+ this.getProvider = getProvider
161
+ this.ttlMs = Math.round(config.DD_LLMOBS_PROMPTS_CACHE_TTL * 1000)
162
+ this.timeoutMs = Math.round(config.DD_LLMOBS_PROMPTS_TIMEOUT * 1000)
163
+ const origin = getEnvironmentVariable('_DD_LLMOBS_OVERRIDE_ORIGIN') || createSiteUrl(config.site, 'api')?.origin
164
+ this.origin = origin?.replace(/\/$/, '')
165
+ this.cacheGeneration = 0
166
+ this.fetchTokens = new Map()
167
+ this.pendingFetches = new Map()
168
+ this.hotCache = new HotCache({
169
+ ttlMs: this.ttlMs,
170
+ fetchMethod: (key, stale, { context, signal }) => this.#backgroundFetch(context, signal),
171
+ })
172
+ this.warmCache = new WarmCache({
173
+ cacheDir: config.DD_LLMOBS_PROMPTS_CACHE_DIR,
174
+ enabled: config.DD_LLMOBS_PROMPTS_FILE_CACHE_ENABLED,
175
+ ttlMs: this.ttlMs,
176
+ })
177
+ }
178
+
179
+ #requireOrigin () {
180
+ if (!this.origin) {
181
+ throw new PromptAPIError(0, 'DD_SITE is invalid for prompt operations', ERROR_NAMES.AUTH)
182
+ }
183
+ const { hostname, protocol } = new URL(this.origin)
184
+ if (protocol !== 'https:' && !(protocol === 'http:' && isLoopbackHost(hostname))) {
185
+ throw new PromptAPIError(0, 'Prompt origin must use HTTPS unless it targets a loopback host', ERROR_NAMES.AUTH)
186
+ }
187
+ return this.origin
188
+ }
189
+
190
+ /**
191
+ * Require API authentication before using an HTTP prompt path.
192
+ */
193
+ #requireApiKey () {
194
+ if (!this.config.DD_API_KEY) {
195
+ throw new PromptAPIError(0, 'DD_API_KEY is required for prompt operations', ERROR_NAMES.AUTH)
196
+ }
197
+ return this.config.DD_API_KEY
198
+ }
199
+
200
+ /**
201
+ * Evaluate a prompt through the tracer's existing OpenFeature provider.
202
+ * @param {PromptRequest} request
203
+ * @returns {Promise<ManagedPrompt | undefined>}
204
+ */
205
+ async #fetchFromProvider (request) {
206
+ try {
207
+ const context = { ...request.attributes }
208
+ if (request.targetingKey !== undefined) context.targetingKey = request.targetingKey
209
+ const details = await this.getProvider().resolveObjectEvaluation(
210
+ `__llmobs__.prompt.${request.promptId}`,
211
+ {},
212
+ context,
213
+ log
214
+ )
215
+ return promptFromData(details.value, 'ff')
216
+ } catch (error) {
217
+ log.debug('Feature Flag prompt evaluation failed for %s: %s', request.promptId, error.message)
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Fetch a prompt from the registry or resolve endpoint.
223
+ * @param {PromptRequest} request
224
+ * @param {AbortSignal} [cacheSignal]
225
+ * @returns {Promise<PromptFetchResult>}
226
+ */
227
+ async #fetchHttp (request, cacheSignal) {
228
+ let origin
229
+ let apiKey
230
+ try {
231
+ origin = this.#requireOrigin()
232
+ apiKey = this.#requireApiKey()
233
+ } catch (error) {
234
+ return { reason: error.detail, error }
235
+ }
236
+ if (request.resolve && !this.config.DD_APP_KEY) {
237
+ return { reason: 'DD_APP_KEY is required to resolve prompts for an environment' }
238
+ }
239
+
240
+ const encodedId = encodeURIComponent(request.promptId)
241
+ let method = 'GET'
242
+ let path = `${PROMPTS_PATH}/${encodedId}`
243
+ let body
244
+ const headers = {
245
+ 'DD-API-KEY': apiKey,
246
+ 'X-Datadog-SDK-Language': 'javascript',
247
+ }
248
+
249
+ if (request.resolve) {
250
+ method = 'POST'
251
+ path += '/resolve'
252
+ const attributes = { env: request.env }
253
+ if (request.targetingKey !== undefined) attributes.targeting_key = request.targetingKey
254
+ if (Object.entries(request.attributes).length > 0) attributes.context = request.attributes
255
+ body = JSON.stringify({ data: { type: 'prompt_resolve_requests', attributes } })
256
+ headers['Content-Type'] = 'application/json'
257
+ headers['DD-APPLICATION-KEY'] = this.config.DD_APP_KEY
258
+ } else if (request.version !== undefined) {
259
+ path += `/versions/${encodeURIComponent(request.version)}`
260
+ }
261
+
262
+ try {
263
+ const response = await httpRequest(body, {
264
+ url: `${origin}${path}`,
265
+ method,
266
+ headers,
267
+ timeout: this.timeoutMs,
268
+ signal: requestSignal(this.timeoutMs, cacheSignal),
269
+ })
270
+ const responseBody = response.body
271
+ if (response.ok) {
272
+ let data
273
+ try {
274
+ data = JSON.parse(responseBody)
275
+ } catch {
276
+ return { reason: 'invalid JSON in response body' }
277
+ }
278
+ const source = request.resolve ? 'resolve' : 'registry'
279
+ const prompt = promptFromData(data, source)
280
+ return prompt ? { prompt } : { reason: 'invalid prompt response' }
281
+ }
282
+
283
+ const detail = detailFromBody(responseBody)
284
+ if (response.status === 404) {
285
+ log.debug('Prompt not found: prompt_id=%s detail="%s"', request.promptId, detail)
286
+ return { reason: detail, notFound: true }
287
+ }
288
+ log.warn('Prompt fetch failed: prompt_id=%s status=%d detail="%s"', request.promptId, response.status, detail)
289
+ return { reason: detail }
290
+ } catch (error) {
291
+ if (cacheSignal?.aborted) return { reason: 'fetch cancelled' }
292
+ log.warn('Prompt fetch exception: prompt_id=%s: %s', request.promptId, error.message)
293
+ return { reason: error.message }
294
+ }
295
+ }
296
+
297
+ /**
298
+ * Fetch and cache one selector.
299
+ * @param {PromptRequest} request
300
+ * @param {{hot?: boolean, signal?: AbortSignal}} [options]
301
+ * @returns {Promise<PromptFetchResult>}
302
+ */
303
+ async #fetchAndCache (request, { hot = true, signal } = {}) {
304
+ const generationAtStart = this.cacheGeneration
305
+ const token = Symbol(request.key)
306
+ this.fetchTokens.set(request.key, token)
307
+ const result = await this.#fetchHttp(request, signal)
308
+ const latest = this.fetchTokens.get(request.key) === token
309
+ if (latest) this.fetchTokens.delete(request.key)
310
+ const cacheable = generationAtStart === this.cacheGeneration && latest
311
+ if (result.prompt) {
312
+ if (cacheable) {
313
+ const cached = withSource(result.prompt, SOURCE_CACHE)
314
+ if (hot) this.hotCache.set(request.key, cached)
315
+ if (!request.resolve) this.warmCache.set(request.key, cached)
316
+ }
317
+ return { ...result, cacheable }
318
+ }
319
+
320
+ if (signal?.aborted) return { ...result, cacheable }
321
+ telemetry.recordPromptFetchError(result.notFound ? 'NotFound' : 'FetchError')
322
+ if (result.notFound && cacheable) {
323
+ this.hotCache.delete(request.key)
324
+ this.warmCache.delete(request.key)
325
+ }
326
+ return { ...result, cacheable }
327
+ }
328
+
329
+ /**
330
+ * Refresh one stale hot-cache entry.
331
+ * @param {PromptRequest} request
332
+ * @param {AbortSignal} signal
333
+ * @returns {Promise<ManagedPrompt | undefined>}
334
+ */
335
+ async #backgroundFetch (request, signal) {
336
+ const result = await this.#fetchAndCache(request, { hot: false, signal })
337
+ if (!result.cacheable) return
338
+ if (result.prompt) return withSource(result.prompt, SOURCE_CACHE)
339
+ if (result.notFound) return
340
+ throw new Error(result.reason)
341
+ }
342
+
343
+ /**
344
+ * Resolve a prompt from caches, HTTP, or a caller fallback.
345
+ * @param {PromptRequest} request
346
+ * @param {string | object | Array<{role: string, content: string}> |
347
+ * (() => string | object | Array<{role: string, content: string}>) | undefined} fallback
348
+ * @returns {Promise<ManagedPrompt>}
349
+ */
350
+ async #getHttpPrompt (request, fallback) {
351
+ const hot = this.hotCache.get(request.key)
352
+ if (hot) {
353
+ if (hot.stale) this.hotCache.refresh(request.key, request)
354
+ telemetry.recordPromptSource('hot_cache')
355
+ return hot.prompt
356
+ }
357
+
358
+ if (!request.resolve) {
359
+ const warm = this.warmCache.get(request.key)
360
+ if (warm) {
361
+ this.hotCache.set(request.key, warm.prompt, warm.ageMs)
362
+ if (warm.stale) this.hotCache.refresh(request.key, request)
363
+ telemetry.recordPromptSource('warm_cache')
364
+ return warm.prompt
365
+ }
366
+ }
367
+
368
+ let pending = this.pendingFetches.get(request.key)
369
+ if (!pending) {
370
+ pending = this.#fetchAndCache(request)
371
+ this.pendingFetches.set(request.key, pending)
372
+ }
373
+ let result
374
+ try {
375
+ result = await pending
376
+ } finally {
377
+ if (this.pendingFetches.get(request.key) === pending) this.pendingFetches.delete(request.key)
378
+ }
379
+ if (result.prompt) {
380
+ telemetry.recordPromptSource(request.resolve ? 'resolve' : 'registry')
381
+ return result.prompt
382
+ }
383
+
384
+ if (fallback === undefined) {
385
+ if (result.error) throw result.error
386
+ const reason = result.reason ? `: ${result.reason}` : ''
387
+ throw new Error(`Prompt '${request.promptId}' could not be fetched and no fallback was provided${reason}`)
388
+ }
389
+ const prompt = ManagedPrompt.fromFallback(request.promptId, fallback)
390
+ telemetry.recordPromptSource('fallback')
391
+ return prompt
392
+ }
393
+
394
+ /**
395
+ * Get a prompt by exact version or current environment.
396
+ * @param {string} promptId
397
+ * @param {object} [options]
398
+ * @param {number} [options.version]
399
+ * @param {string | object | Array<{role: string, content: string}> |
400
+ * (() => string | object | Array<{role: string, content: string}>)} [options.fallback]
401
+ * @param {string} [options.targetingKey]
402
+ * @param {Record<string, unknown>} [options.attributes]
403
+ * @returns {Promise<ManagedPrompt>}
404
+ */
405
+ async getPrompt (promptId, options = {}) {
406
+ const { fallback, targetingKey, attributes = {} } = options
407
+ const version = options.version ?? undefined
408
+ if (version !== undefined) {
409
+ return this.#getHttpPrompt(promptRequest(promptId, { version }), fallback)
410
+ }
411
+
412
+ const request = promptRequest(promptId, {
413
+ env: this.config.env,
414
+ targetingKey,
415
+ attributes,
416
+ })
417
+ if (request.resolve) {
418
+ const prompt = await this.#fetchFromProvider(request)
419
+ if (prompt) {
420
+ telemetry.recordPromptSource('ff')
421
+ return prompt
422
+ }
423
+ }
424
+ return this.#getHttpPrompt(request, fallback)
425
+ }
426
+
427
+ /**
428
+ * Refresh the selector implied by the configured environment.
429
+ * @param {string} promptId
430
+ * @returns {Promise<ManagedPrompt | undefined>}
431
+ */
432
+ async refreshPrompt (promptId) {
433
+ this.#requireOrigin()
434
+ this.#requireApiKey()
435
+ const request = promptRequest(promptId, { env: this.config.env })
436
+ this.pendingFetches.delete(request.key)
437
+ const result = await this.#fetchAndCache(request)
438
+ return result.prompt
439
+ }
440
+
441
+ /**
442
+ * Clear hot and/or warm prompt caches.
443
+ * @param {{hot?: boolean, warm?: boolean}} [options]
444
+ */
445
+ clearPromptCache ({ hot = true, warm = true } = {}) {
446
+ this.cacheGeneration++
447
+ this.pendingFetches.clear()
448
+ if (hot) this.hotCache.clear()
449
+ if (warm) this.warmCache.clear()
450
+ }
451
+
452
+ /**
453
+ * Evict every cached selector for one exact prompt ID.
454
+ * @param {string} promptId
455
+ */
456
+ #evictPrompt (promptId) {
457
+ for (const key of this.fetchTokens.keys()) {
458
+ if (promptIdFromKey(key) === promptId) this.fetchTokens.delete(key)
459
+ }
460
+ for (const key of this.pendingFetches.keys()) {
461
+ if (promptIdFromKey(key) === promptId) this.pendingFetches.delete(key)
462
+ }
463
+ this.hotCache.evictPrompt(promptId)
464
+ this.warmCache.evictPrompt(promptId)
465
+ }
466
+
467
+ /**
468
+ * Record a Prompt Management CRUD error.
469
+ * @param {'GET'|'POST'|'PATCH'|'DELETE'} method
470
+ * @param {PromptAPIError} error
471
+ */
472
+ #recordCrudError (method, error) {
473
+ telemetry.recordPromptCrudError(method, error.name, error.status)
474
+ return error
475
+ }
476
+
477
+ /**
478
+ * Execute one CRUD request and normalize its response.
479
+ * @param {'GET'|'POST'|'PATCH'|'DELETE'} method
480
+ * @param {string} path
481
+ * @param {object | undefined} body
482
+ * @param {boolean} requireAppKey
483
+ * @returns {Promise<object | object[]>}
484
+ */
485
+ async #request (method, path, body, requireAppKey) {
486
+ try {
487
+ const origin = this.#requireOrigin()
488
+ const apiKey = this.#requireApiKey()
489
+ if (requireAppKey && !this.config.DD_APP_KEY) {
490
+ throw new PromptAPIError(0, 'DD_APP_KEY is required for prompt write operations', ERROR_NAMES.AUTH)
491
+ }
492
+ if (body?.config !== undefined && !isPlainObject(body.config)) {
493
+ throw new PromptAPIError(0, 'config must be a JSON object', ERROR_NAMES.VALIDATION)
494
+ }
495
+
496
+ const headers = {
497
+ 'Content-Type': 'application/json',
498
+ 'DD-API-KEY': apiKey,
499
+ 'X-Datadog-SDK-Language': 'javascript',
500
+ }
501
+ if (requireAppKey) headers['DD-APPLICATION-KEY'] = this.config.DD_APP_KEY
502
+
503
+ const response = await httpRequest(body === undefined ? undefined : JSON.stringify(body), {
504
+ url: `${origin}${path}`,
505
+ method,
506
+ headers,
507
+ timeout: this.timeoutMs,
508
+ signal: AbortSignal.timeout(this.timeoutMs),
509
+ })
510
+
511
+ const responseBody = response.body
512
+ if (!response.ok) throw new PromptAPIError(response.status, detailFromBody(responseBody))
513
+ if (!responseBody) return {}
514
+ try {
515
+ const data = JSON.parse(responseBody)
516
+ return Array.isArray(data) ? data.map(normalizeItem) : normalizeItem(data)
517
+ } catch {
518
+ throw new PromptAPIError(response.status, 'invalid JSON in response body', ERROR_NAMES.SERVER)
519
+ }
520
+ } catch (error) {
521
+ const promptError = error instanceof PromptAPIError ? error : new PromptAPIError(0, error.message)
522
+ throw this.#recordCrudError(method, promptError)
523
+ }
524
+ }
525
+
526
+ /**
527
+ * Create a text or chat prompt and its first version.
528
+ * @param {string} promptId
529
+ * @param {string | Array<{role: string, content: string}>} template
530
+ * @param {{title?: string, description?: string, userVersion?: string, envIds?: string[],
531
+ * config?: Record<string, unknown>}} [options]
532
+ * @returns {Promise<object | object[]>}
533
+ */
534
+ async createPrompt (promptId, template, options = {}) {
535
+ const body = { prompt_id: promptId, template }
536
+ if (options.title) body.title = options.title
537
+ if (options.description) body.description = options.description
538
+ if (options.userVersion) body.user_version = options.userVersion
539
+ if (options.envIds !== undefined) body.env_ids = options.envIds
540
+ if (options.config !== undefined) body.config = options.config
541
+ const response = await this.#request('POST', PROMPTS_PATH, body, true)
542
+ this.#evictPrompt(promptId)
543
+ return response
544
+ }
545
+
546
+ /**
547
+ * Add a text or chat version to an existing prompt.
548
+ * @param {string} promptId
549
+ * @param {string | Array<{role: string, content: string}>} template
550
+ * @param {{description?: string, userVersion?: string, envIds?: string[],
551
+ * config?: Record<string, unknown>}} [options]
552
+ * @returns {Promise<object | object[]>}
553
+ */
554
+ async createPromptVersion (promptId, template, options = {}) {
555
+ const body = { template }
556
+ if (options.description) body.description = options.description
557
+ if (options.userVersion) body.user_version = options.userVersion
558
+ if (options.envIds !== undefined) body.env_ids = options.envIds
559
+ if (options.config !== undefined) body.config = options.config
560
+ const path = `${PROMPTS_PATH}/${encodeURIComponent(promptId)}/versions`
561
+ const response = await this.#request('POST', path, body, true)
562
+ this.#evictPrompt(promptId)
563
+ return response
564
+ }
565
+
566
+ /**
567
+ * Update prompt metadata.
568
+ * @param {string} promptId
569
+ * @param {{title?: string, description?: string}} [options]
570
+ * @returns {Promise<object | object[]>}
571
+ */
572
+ async updatePrompt (promptId, options = {}) {
573
+ try {
574
+ this.#requireApiKey()
575
+ } catch (error) {
576
+ throw this.#recordCrudError('PATCH', error)
577
+ }
578
+ if (options.title === undefined && options.description === undefined) {
579
+ const error = new PromptAPIError(0, 'At least one of title or description must be provided',
580
+ ERROR_NAMES.VALIDATION)
581
+ throw this.#recordCrudError('PATCH', error)
582
+ }
583
+ const body = {}
584
+ if (options.title !== undefined) body.title = options.title
585
+ if (options.description !== undefined) body.description = options.description
586
+ const response = await this.#request('PATCH', `${PROMPTS_PATH}/${encodeURIComponent(promptId)}`, body, true)
587
+ this.#evictPrompt(promptId)
588
+ return response
589
+ }
590
+
591
+ /**
592
+ * Update prompt-version metadata.
593
+ * @param {string} promptId
594
+ * @param {number} version
595
+ * @param {{description?: string, envIds?: string[]}} [options]
596
+ * @returns {Promise<object | object[]>}
597
+ */
598
+ async updatePromptVersion (promptId, version, options = {}) {
599
+ try {
600
+ this.#requireApiKey()
601
+ } catch (error) {
602
+ throw this.#recordCrudError('PATCH', error)
603
+ }
604
+ if (options.description === undefined && options.envIds === undefined) {
605
+ const error = new PromptAPIError(0, 'At least one of description or envIds must be provided',
606
+ ERROR_NAMES.VALIDATION)
607
+ throw this.#recordCrudError('PATCH', error)
608
+ }
609
+ const body = {}
610
+ if (options.description !== undefined) body.description = options.description
611
+ if (options.envIds !== undefined) body.env_ids = options.envIds
612
+ const path = `${PROMPTS_PATH}/${encodeURIComponent(promptId)}/versions/${encodeURIComponent(version)}`
613
+ const response = await this.#request('PATCH', path, body, true)
614
+ this.#evictPrompt(promptId)
615
+ return response
616
+ }
617
+
618
+ /**
619
+ * Delete a prompt.
620
+ * @param {string} promptId
621
+ * @returns {Promise<object | object[]>}
622
+ */
623
+ async deletePrompt (promptId) {
624
+ const response = await this.#request('DELETE', `${PROMPTS_PATH}/${encodeURIComponent(promptId)}`, undefined, true)
625
+ this.#evictPrompt(promptId)
626
+ return response
627
+ }
628
+
629
+ /**
630
+ * List prompts.
631
+ * @returns {Promise<object | object[]>}
632
+ */
633
+ listPrompts () {
634
+ return this.#request('GET', PROMPTS_PATH, undefined, false)
635
+ }
636
+
637
+ /**
638
+ * List versions for a prompt.
639
+ * @param {string} promptId
640
+ * @returns {Promise<object | object[]>}
641
+ */
642
+ listPromptVersions (promptId) {
643
+ return this.#request('GET', `${PROMPTS_PATH}/${encodeURIComponent(promptId)}/versions`, undefined, false)
644
+ }
645
+ }
646
+
647
+ module.exports = PromptManager
@@ -0,0 +1,29 @@
1
+ 'use strict'
2
+
3
+ function unavailable () {
4
+ return Promise.reject(new Error('Prompt Management requires tracer.init()'))
5
+ }
6
+
7
+ class NoopPrompts {
8
+ getPrompt (promptId, options) { return unavailable() }
9
+
10
+ refreshPrompt (promptId) { return unavailable() }
11
+
12
+ clearPromptCache (options) {}
13
+
14
+ createPrompt (promptId, template, options) { return unavailable() }
15
+
16
+ createPromptVersion (promptId, template, options) { return unavailable() }
17
+
18
+ updatePrompt (promptId, options) { return unavailable() }
19
+
20
+ updatePromptVersion (promptId, version, options) { return unavailable() }
21
+
22
+ deletePrompt (promptId) { return unavailable() }
23
+
24
+ listPrompts () { return unavailable() }
25
+
26
+ listPromptVersions (promptId) { return unavailable() }
27
+ }
28
+
29
+ module.exports = NoopPrompts