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