dd-trace 5.116.0 → 5.118.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 (98) hide show
  1. package/ci/diagnose.js +162 -21
  2. package/ci/init.js +0 -1
  3. package/ci/runbook.md +187 -180
  4. package/ci/test-optimization-validation/approval-artifacts.js +3 -1
  5. package/ci/test-optimization-validation/approval.js +52 -15
  6. package/ci/test-optimization-validation/ci-command-candidate.js +26 -32
  7. package/ci/test-optimization-validation/ci-discovery.js +1 -1
  8. package/ci/test-optimization-validation/ci-package-scripts.js +141 -0
  9. package/ci/test-optimization-validation/ci-remediation.js +112 -39
  10. package/ci/test-optimization-validation/cli.js +516 -681
  11. package/ci/test-optimization-validation/command-blocker.js +188 -33
  12. package/ci/test-optimization-validation/command-output-policy.js +3 -26
  13. package/ci/test-optimization-validation/command-runner.js +189 -245
  14. package/ci/test-optimization-validation/environment.js +90 -0
  15. package/ci/test-optimization-validation/executable.js +159 -388
  16. package/ci/test-optimization-validation/framework-adapters/cucumber.js +119 -0
  17. package/ci/test-optimization-validation/framework-adapters/cypress.js +107 -0
  18. package/ci/test-optimization-validation/framework-adapters/playwright.js +181 -0
  19. package/ci/test-optimization-validation/generated-files.js +75 -13
  20. package/ci/test-optimization-validation/generated-test-contract.js +283 -0
  21. package/ci/test-optimization-validation/generated-verifier.js +49 -16
  22. package/ci/test-optimization-validation/literal-environment.js +57 -0
  23. package/ci/test-optimization-validation/manifest-loader.js +2 -22
  24. package/ci/test-optimization-validation/manifest-scaffold.js +816 -515
  25. package/ci/test-optimization-validation/manifest-schema.js +494 -702
  26. package/ci/test-optimization-validation/offline-fixtures.js +4 -1
  27. package/ci/test-optimization-validation/plan-writer.js +243 -984
  28. package/ci/test-optimization-validation/preflight-runner.js +49 -55
  29. package/ci/test-optimization-validation/redaction.js +2 -1
  30. package/ci/test-optimization-validation/report-writer.js +391 -1357
  31. package/ci/test-optimization-validation/result-semantics.js +86 -0
  32. package/ci/test-optimization-validation/runner-command.js +249 -0
  33. package/ci/test-optimization-validation/runner-contract.js +664 -0
  34. package/ci/test-optimization-validation/scenarios/auto-test-retries.js +29 -3
  35. package/ci/test-optimization-validation/scenarios/basic-reporting.js +240 -543
  36. package/ci/test-optimization-validation/scenarios/ci-wiring.js +450 -670
  37. package/ci/test-optimization-validation/scenarios/early-flake-detection.js +4 -3
  38. package/ci/test-optimization-validation/scenarios/helpers.js +67 -9
  39. package/ci/test-optimization-validation/scenarios/test-management.js +4 -3
  40. package/ci/test-optimization-validation/source-text.js +87 -0
  41. package/ci/test-optimization-validation/test-output.js +12 -22
  42. package/ext/tags.d.ts +1 -0
  43. package/index.d.ts +7 -0
  44. package/package.json +3 -3
  45. package/packages/datadog-instrumentations/src/cucumber.js +11 -12
  46. package/packages/datadog-instrumentations/src/helpers/channel.js +74 -0
  47. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  48. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  49. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/openai-agents.js +31 -0
  50. package/packages/datadog-instrumentations/src/jest.js +18 -17
  51. package/packages/datadog-instrumentations/src/mocha/main.js +79 -30
  52. package/packages/datadog-instrumentations/src/openai-agents.js +159 -0
  53. package/packages/datadog-instrumentations/src/playwright.js +3 -24
  54. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1 -1
  55. package/packages/datadog-instrumentations/src/vitest-main.js +14 -26
  56. package/packages/datadog-instrumentations/src/vitest-util.js +0 -7
  57. package/packages/datadog-instrumentations/src/vitest-worker.js +5 -8
  58. package/packages/datadog-plugin-cucumber/src/index.js +2 -1
  59. package/packages/datadog-plugin-mocha/src/index.js +2 -1
  60. package/packages/datadog-plugin-openai-agents/src/index.js +74 -0
  61. package/packages/datadog-plugin-openai-agents/src/integration.js +503 -0
  62. package/packages/datadog-plugin-openai-agents/src/processor.js +108 -0
  63. package/packages/datadog-plugin-openai-agents/src/util.js +60 -0
  64. package/packages/datadog-plugin-playwright/src/index.js +4 -1
  65. package/packages/datadog-plugin-vitest/src/index.js +5 -5
  66. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +48 -49
  67. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +161 -33
  68. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +6 -4
  69. package/packages/dd-trace/src/config/generated-config-types.d.ts +2 -0
  70. package/packages/dd-trace/src/config/supported-configurations.json +7 -0
  71. package/packages/dd-trace/src/encode/span-stats.js +7 -1
  72. package/packages/dd-trace/src/exporter.js +16 -9
  73. package/packages/dd-trace/src/llmobs/index.js +9 -1
  74. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +104 -22
  75. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +5 -9
  76. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +20 -0
  77. package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +321 -0
  78. package/packages/dd-trace/src/llmobs/sdk.js +2 -1
  79. package/packages/dd-trace/src/llmobs/span_processor.js +7 -2
  80. package/packages/dd-trace/src/llmobs/tagger.js +23 -3
  81. package/packages/dd-trace/src/llmobs/util.js +56 -3
  82. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +3 -6
  83. package/packages/dd-trace/src/openfeature/configuration_source.js +5 -8
  84. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +5 -1
  85. package/packages/dd-trace/src/plugins/ci_plugin.js +9 -3
  86. package/packages/dd-trace/src/plugins/index.js +1 -0
  87. package/packages/dd-trace/src/plugins/outbound.js +4 -1
  88. package/packages/dd-trace/src/profiling/profilers/space.js +1 -1
  89. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
  90. package/packages/dd-trace/src/span_processor.js +1 -1
  91. package/packages/dd-trace/src/span_stats.js +22 -4
  92. package/ci/test-optimization-validation/command-suitability.js +0 -471
  93. package/ci/test-optimization-validation/init-probe-preload.js +0 -163
  94. package/ci/test-optimization-validation/init-probe.js +0 -246
  95. package/ci/test-optimization-validation/late-initialization.js +0 -63
  96. package/ci/test-optimization-validation/local-command.js +0 -163
  97. package/ci/test-optimization-validation/setup-runner.js +0 -97
  98. package/ci/test-optimization-validation-manifest.schema.json +0 -1
@@ -7,6 +7,7 @@ const {
7
7
  failWithDebugRerun,
8
8
  pass,
9
9
  prepareGeneratedScenario,
10
+ reportMissingGeneratedTest,
10
11
  requireGeneratedScenario,
11
12
  runInstrumentedCommand,
12
13
  skip,
@@ -28,14 +29,14 @@ async function runEarlyFlakeDetection ({ framework, out, options }) {
28
29
 
29
30
  const discovery = await discoverScenarioTests({ framework, out, scenarioName, scenario, options })
30
31
  if (discovery.tests.length === 0) {
31
- return failWithDebugRerun({
32
+ return reportMissingGeneratedTest({
32
33
  command: scenario.runCommand,
33
34
  diagnosis: 'The generated new-test candidate was not reported during baseline identity discovery.',
34
- evidence: discoveryEvidence(discovery),
35
+ discovery,
35
36
  framework,
36
37
  options,
37
38
  out,
38
- outDir: discovery.outDir,
39
+ scenario,
39
40
  scenarioName,
40
41
  })
41
42
  }
@@ -4,7 +4,7 @@ const fs = require('node:fs')
4
4
  const path = require('path')
5
5
 
6
6
  const { getArtifactId } = require('../artifact-id')
7
- const { buildCiWiringEnv, buildDatadogEnv, runCommand } = require('../command-runner')
7
+ const { buildDatadogEnv, buildOfflineCaptureEnv, runCommand } = require('../command-runner')
8
8
  const {
9
9
  cleanupGeneratedRuntimeFiles,
10
10
  findGeneratedScenario,
@@ -14,10 +14,10 @@ const {
14
14
  eventsOfType,
15
15
  findTestsByIdentity,
16
16
  } = require('../payload-normalizer')
17
- const { getLocalValidationCommand } = require('../local-command')
18
17
  const { cleanupOfflineFixture, createOfflineFixture } = require('../offline-fixtures')
19
18
  const { readOfflineOutput } = require('../offline-output')
20
19
  const { sanitizeForReport, sanitizeString } = require('../redaction')
20
+ const { getGeneratedCommand } = require('../runner-command')
21
21
  const { ensureSafeDirectory, writeFileSafely } = require('../safe-files')
22
22
 
23
23
  const ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}${String.raw`\[[0-?]*[ -/]*[@-~]`}`, 'g')
@@ -34,7 +34,7 @@ async function runInstrumentedCommand ({
34
34
  options,
35
35
  extraEnv,
36
36
  fixtureConfig,
37
- ciWiring = false,
37
+ injectInitialization = true,
38
38
  allowMissingInitialization = false,
39
39
  }) {
40
40
  const outDir = frameworkOutDir(out, framework, scenarioName)
@@ -52,9 +52,9 @@ async function runInstrumentedCommand ({
52
52
  scenarioName,
53
53
  ...fixtureConfig,
54
54
  })
55
- const validationEnv = ciWiring
56
- ? buildCiWiringEnv({ fixture, outputRoot: rawOutputRoot })
57
- : buildDatadogEnv({ fixture, outputRoot: rawOutputRoot, scenario: scenarioName, framework })
55
+ const validationEnv = injectInitialization
56
+ ? buildDatadogEnv({ fixture, outputRoot: rawOutputRoot, scenario: scenarioName, framework })
57
+ : buildOfflineCaptureEnv({ fixture, outputRoot: rawOutputRoot })
58
58
  result = await runCommand(command, {
59
59
  env: {
60
60
  ...validationEnv,
@@ -82,7 +82,7 @@ async function runInstrumentedCommand ({
82
82
  `${JSON.stringify(sanitizeForReport(result), null, 2)}\n`,
83
83
  'scenario result artifact'
84
84
  )
85
- if (!offline.initialized && !ciWiring && !allowMissingInitialization) {
85
+ if (!offline.initialized && injectInitialization && !allowMissingInitialization) {
86
86
  const stderr = sanitizeString(result.stderr).trim().slice(-2000)
87
87
  throw new Error(
88
88
  'Offline Test Optimization exporter did not initialize or write completion evidence. ' +
@@ -180,11 +180,11 @@ async function prepareGeneratedScenario (framework, scenarioId) {
180
180
  const scenario = findGeneratedScenario(framework, scenarioId)
181
181
  if (!scenario) return { scenario: null, written: [] }
182
182
  cleanupGeneratedRuntimeFiles(framework)
183
- const written = await writeGeneratedFiles(framework)
183
+ const written = await writeGeneratedFiles(framework, scenario)
184
184
  return {
185
185
  scenario: {
186
186
  ...scenario,
187
- runCommand: getLocalValidationCommand(framework, scenario.runCommand),
187
+ runCommand: getGeneratedCommand(framework, scenario),
188
188
  },
189
189
  written,
190
190
  }
@@ -314,6 +314,63 @@ async function discoverScenarioTests ({ framework, out, scenarioName, scenario,
314
314
  }
315
315
  }
316
316
 
317
+ /**
318
+ * Reports a missing generated test without blaming dd-trace when clean execution was unproven.
319
+ *
320
+ * @param {object} input missing-test evidence
321
+ * @param {object} input.command generated scenario command
322
+ * @param {string} input.diagnosis diagnosis used when clean execution was proven
323
+ * @param {object} input.discovery instrumented baseline result
324
+ * @param {object} input.framework framework manifest entry
325
+ * @param {object} input.options execution options
326
+ * @param {string} input.out validation output root
327
+ * @param {object} input.scenario generated scenario
328
+ * @param {string} input.scenarioName advanced scenario name
329
+ * @returns {object|Promise<object>} incomplete or confirmed failure result
330
+ */
331
+ function reportMissingGeneratedTest ({
332
+ command,
333
+ diagnosis,
334
+ discovery,
335
+ framework,
336
+ options,
337
+ out,
338
+ scenario,
339
+ scenarioName,
340
+ }) {
341
+ const verification = framework.generatedTestStrategy?.verification?.observedScenarios
342
+ ?.find(observed => observed.id === scenario.id)
343
+ const evidence = {
344
+ ...discoveryEvidence(discovery),
345
+ generatedVerificationObservedTestCount: verification?.observedTestCount,
346
+ }
347
+ if (verification?.observedTestCount === null) {
348
+ return inconclusive(
349
+ framework,
350
+ scenarioName,
351
+ 'The clean temporary validation command exited as expected without a parseable test count, and the ' +
352
+ 'instrumented baseline emitted no matching test event. The validator cannot prove that the generated test ' +
353
+ 'executed, so no advanced-feature conclusion was reached.',
354
+ {
355
+ ...evidence,
356
+ reasonCode: 'generated-test-execution-unproven',
357
+ },
358
+ discovery.outDir
359
+ )
360
+ }
361
+
362
+ return failWithDebugRerun({
363
+ command,
364
+ diagnosis,
365
+ evidence,
366
+ framework,
367
+ options,
368
+ out,
369
+ outDir: discovery.outDir,
370
+ scenarioName,
371
+ })
372
+ }
373
+
317
374
  function testsForDiscoveredScenario (events, scenario, discovery) {
318
375
  if (discovery?.testIdentities?.length > 0) {
319
376
  return findTestsByIdentity(events, discovery.testIdentities)
@@ -528,6 +585,7 @@ module.exports = {
528
585
  inconclusive,
529
586
  pass,
530
587
  prepareGeneratedScenario,
588
+ reportMissingGeneratedTest,
531
589
  requireGeneratedScenario,
532
590
  runDebugInstrumentedCommand,
533
591
  runInstrumentedCommand,
@@ -9,6 +9,7 @@ const {
9
9
  failWithDebugRerun,
10
10
  pass,
11
11
  prepareGeneratedScenario,
12
+ reportMissingGeneratedTest,
12
13
  requireGeneratedScenario,
13
14
  runInstrumentedCommand,
14
15
  testEventSamples,
@@ -25,14 +26,14 @@ async function runTestManagement ({ framework, out, options }) {
25
26
  const { scenario } = await prepareGeneratedScenario(framework, 'test-management-target')
26
27
  const discovery = await discoverScenarioTests({ framework, out, scenarioName, scenario, options })
27
28
  if (discovery.tests.length === 0) {
28
- return failWithDebugRerun({
29
+ return reportMissingGeneratedTest({
29
30
  command: scenario.runCommand,
30
31
  diagnosis: 'The test-management target was not reported during baseline identity discovery.',
31
- evidence: discoveryEvidence(discovery),
32
+ discovery,
32
33
  framework,
33
34
  options,
34
35
  out,
35
- outDir: discovery.outDir,
36
+ scenario,
36
37
  scenarioName,
37
38
  })
38
39
  }
@@ -0,0 +1,87 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * Replaces JavaScript comments with spaces while preserving line structure and string literals.
5
+ *
6
+ * @param {string} source JavaScript or TypeScript source
7
+ * @returns {string} source with comments masked
8
+ */
9
+ function maskJavaScriptComments (source) {
10
+ return maskJavaScriptSource(source, false)
11
+ }
12
+
13
+ /**
14
+ * Replaces JavaScript comments and string literals with spaces while preserving line structure.
15
+ *
16
+ * @param {string} source JavaScript or TypeScript source
17
+ * @returns {string} source with non-code text masked
18
+ */
19
+ function maskJavaScriptNonCode (source) {
20
+ return maskJavaScriptSource(source, true)
21
+ }
22
+
23
+ /**
24
+ * Masks comments and optionally string literals in JavaScript-like source.
25
+ *
26
+ * @param {string} source JavaScript or TypeScript source
27
+ * @param {boolean} maskStrings whether string and template literal contents should be masked
28
+ * @returns {string} masked source
29
+ */
30
+ function maskJavaScriptSource (source, maskStrings) {
31
+ const characters = [...source]
32
+ let blockComment = false
33
+ let lineComment = false
34
+ let quote = ''
35
+
36
+ for (let index = 0; index < characters.length; index++) {
37
+ const character = characters[index]
38
+ const next = characters[index + 1]
39
+ if (lineComment) {
40
+ if (character === '\n') {
41
+ lineComment = false
42
+ } else {
43
+ characters[index] = ' '
44
+ }
45
+ continue
46
+ }
47
+ if (blockComment) {
48
+ if (character === '*' && next === '/') {
49
+ characters[index] = ' '
50
+ characters[++index] = ' '
51
+ blockComment = false
52
+ } else if (character !== '\r' && character !== '\n') {
53
+ characters[index] = ' '
54
+ }
55
+ continue
56
+ }
57
+ if (quote) {
58
+ if (maskStrings && character !== '\r' && character !== '\n') characters[index] = ' '
59
+ if (character.charCodeAt(0) === 92) {
60
+ if (maskStrings && index + 1 < characters.length &&
61
+ characters[index + 1] !== '\r' && characters[index + 1] !== '\n') {
62
+ characters[index + 1] = ' '
63
+ }
64
+ index++
65
+ } else if (character === quote) {
66
+ quote = ''
67
+ }
68
+ continue
69
+ }
70
+ if (character === '"' || character === '\'' || character === '`') {
71
+ quote = character
72
+ if (maskStrings) characters[index] = ' '
73
+ } else if (character === '/' && next === '/') {
74
+ characters[index] = ' '
75
+ characters[++index] = ' '
76
+ lineComment = true
77
+ } else if (character === '/' && next === '*') {
78
+ characters[index] = ' '
79
+ characters[++index] = ' '
80
+ blockComment = true
81
+ }
82
+ }
83
+
84
+ return characters.join('')
85
+ }
86
+
87
+ module.exports = { maskJavaScriptComments, maskJavaScriptNonCode }
@@ -1,5 +1,9 @@
1
1
  'use strict'
2
2
 
3
+ const cypressAdapter = require('./framework-adapters/cypress')
4
+ const cucumberAdapter = require('./framework-adapters/cucumber')
5
+ const playwrightAdapter = require('./framework-adapters/playwright')
6
+
3
7
  const ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}${String.raw`\[[0-?]*[ -/]*[@-~]`}`, 'g')
4
8
 
5
9
  /**
@@ -11,16 +15,14 @@ const ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}${String.raw`\[[0-?]*
11
15
  * @returns {number|null} observed count when a supported summary was found
12
16
  */
13
17
  function getObservedTestCount (framework, stdout = '', stderr = '') {
14
- const output = `${stdout}\n${stderr}`.replaceAll(ANSI_PATTERN, '')
18
+ const output = stripAnsi(`${stdout}\n${stderr}`)
19
+ if (framework === 'cucumber') return cucumberAdapter.getObservedTestCount(output)
20
+ if (framework === 'cypress') return cypressAdapter.getObservedTestCount(output)
21
+ if (framework === 'playwright') return playwrightAdapter.getObservedTestCount(output)
15
22
  if (framework === 'jest') return getJestObservedTestCount(output)
16
23
  if (framework === 'vitest') return getVitestObservedTestCount(output)
17
- if (framework === 'playwright') return getPlaywrightObservedTestCount(output)
18
24
 
19
- const totalPatterns = framework === 'node:test'
20
- ? [/^# tests\s+(\d+)\s*$/gim]
21
- : framework === 'cucumber'
22
- ? [/\b(\d+)\s+scenarios?\b/gi]
23
- : []
25
+ const totalPatterns = framework === 'node:test' ? [/^# tests\s+(\d+)\s*$/gim] : []
24
26
 
25
27
  for (const pattern of totalPatterns) {
26
28
  const count = getLastMatchCount(output, pattern)
@@ -38,20 +40,8 @@ function getObservedTestCount (framework, stdout = '', stderr = '') {
38
40
  return getLastMatchCount(output, /\b(\d+)\s+tests?\s+(?:passed|failed)\b/gi)
39
41
  }
40
42
 
41
- /**
42
- * Counts Playwright tests that completed instead of treating skipped tests as executions.
43
- *
44
- * @param {string} output test output without ANSI codes
45
- * @returns {number|null} executed test count
46
- */
47
- function getPlaywrightObservedTestCount (output) {
48
- const observed = sumLastMatchCounts(output, [
49
- /^\s*(\d+)\s+passed\b/gim,
50
- /^\s*(\d+)\s+failed\b/gim,
51
- /^\s*(\d+)\s+flaky\b/gim,
52
- ])
53
- if (observed !== null) return observed
54
- return /^\s*\d+\s+skipped\b/im.test(output) ? 0 : null
43
+ function stripAnsi (value) {
44
+ return String(value || '').replaceAll(ANSI_PATTERN, '')
55
45
  }
56
46
 
57
47
  /**
@@ -126,4 +116,4 @@ function sumLastMatchCounts (output, patterns) {
126
116
  return found ? count : null
127
117
  }
128
118
 
129
- module.exports = { getObservedTestCount }
119
+ module.exports = { getObservedTestCount, stripAnsi }
package/ext/tags.d.ts CHANGED
@@ -20,6 +20,7 @@ declare const tags: {
20
20
  HTTP_RESPONSE_HEADERS: 'http.response.headers'
21
21
  HTTP_USERAGENT: 'http.useragent',
22
22
  HTTP_CLIENT_IP: 'http.client_ip',
23
+ GRPC_STATUS_CODE: 'grpc.status.code'
23
24
  PATHWAY_HASH: 'pathway.hash'
24
25
  }
25
26
 
package/index.d.ts CHANGED
@@ -293,6 +293,7 @@ interface Plugins {
293
293
  "next": tracer.plugins.next;
294
294
  "nyc": tracer.plugins.nyc;
295
295
  "openai": tracer.plugins.openai;
296
+ "openai-agents": tracer.plugins.openai_agents;
296
297
  "opensearch": tracer.plugins.opensearch;
297
298
  "oracledb": tracer.plugins.oracledb;
298
299
  "playwright": tracer.plugins.playwright;
@@ -3138,6 +3139,12 @@ declare namespace tracer {
3138
3139
  */
3139
3140
  interface openai extends Instrumentation {}
3140
3141
 
3142
+ /**
3143
+ * This plugin automatically instruments the
3144
+ * [@openai/agents](https://www.npmjs.com/package/@openai/agents) library.
3145
+ */
3146
+ interface openai_agents extends Instrumentation {}
3147
+
3141
3148
  /**
3142
3149
  * This plugin automatically instruments the
3143
3150
  * [opensearch](https://github.com/opensearch-project/opensearch-js) module.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.116.0",
3
+ "version": "5.118.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -179,7 +179,7 @@
179
179
  "@datadog/native-iast-taint-tracking": "4.2.0",
180
180
  "@datadog/native-metrics": "3.1.2",
181
181
  "@datadog/openfeature-node-server": "2.0.0",
182
- "@datadog/pprof": "5.15.1",
182
+ "@datadog/pprof": "5.17.0",
183
183
  "@datadog/wasm-js-rewriter": "5.0.1",
184
184
  "@opentelemetry/api": ">=1.0.0 <1.10.0",
185
185
  "@opentelemetry/api-logs": "<1.0.0",
@@ -198,7 +198,7 @@
198
198
  "@types/mocha": "^10.0.10",
199
199
  "@types/node": "^18.19.106",
200
200
  "@types/sinon": "^22.0.0",
201
- "@vercel/nft": "^0.29.4",
201
+ "@vercel/nft": "^1.10.2",
202
202
  "axios": "^1.18.1",
203
203
  "benchmark": "^2.1.4",
204
204
  "body-parser": "^2.3.0",
@@ -28,6 +28,7 @@ const {
28
28
  } = require('../../dd-trace/src/plugins/util/test')
29
29
  const { writeCoverageBackfillToCache } = require('../../dd-trace/src/ci-visibility/test-optimization-cache')
30
30
  const satisfies = require('../../../vendor/dist/semifies')
31
+ const { getChannelPromise } = require('./helpers/channel')
31
32
  const { addHook, channel } = require('./helpers/instrument')
32
33
 
33
34
  const cucumberWorkerThreadsPatchModule = require.resolve('./cucumber-worker-threads')
@@ -563,12 +564,6 @@ function getErrorFromCucumberResult (cucumberResult) {
563
564
  return error
564
565
  }
565
566
 
566
- function getChannelPromise (channelToPublishTo, frameworkVersion = null) {
567
- return new Promise(resolve => {
568
- channelToPublishTo.publish({ onDone: resolve, frameworkVersion })
569
- })
570
- }
571
-
572
567
  function getShouldBeSkippedSuite (pickle, suitesToSkip) {
573
568
  const testSuitePath = getTestSuitePath(pickle.uri, process.cwd())
574
569
  const isUnskippable = isMarkedAsUnskippable(pickle)
@@ -1056,7 +1051,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1056
1051
  }
1057
1052
  let errorSkippableRequest
1058
1053
 
1059
- const configurationResponse = await getChannelPromise(libraryConfigurationCh, frameworkVersion)
1054
+ const configurationResponse = await getChannelPromise(libraryConfigurationCh, { frameworkVersion }) || {}
1060
1055
 
1061
1056
  repositoryRoot = configurationResponse.repositoryRoot
1062
1057
  isItrEnabled = configurationResponse.libraryConfig?.isItrEnabled
@@ -1089,7 +1084,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1089
1084
 
1090
1085
  if (isKnownTestsEnabled) {
1091
1086
  const currentKnownTestsResponse = knownTestsResponse || await getChannelPromise(knownTestsCh)
1092
- if (currentKnownTestsResponse.err) {
1087
+ if (!currentKnownTestsResponse || currentKnownTestsResponse.err) {
1093
1088
  isEarlyFlakeDetectionEnabled = false
1094
1089
  isKnownTestsEnabled = false
1095
1090
  } else {
@@ -1098,7 +1093,9 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1098
1093
  }
1099
1094
 
1100
1095
  if (isSuitesSkippingEnabled) {
1101
- const skippableResponse = skippableSuitesResponse || await getChannelPromise(skippableSuitesCh)
1096
+ const skippableResponse = skippableSuitesResponse ||
1097
+ await getChannelPromise(skippableSuitesCh) ||
1098
+ { err: true }
1102
1099
 
1103
1100
  errorSkippableRequest = skippableResponse.err
1104
1101
  skippableSuites = skippableResponse.skippableSuites ?? []
@@ -1147,7 +1144,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1147
1144
  if (isTestManagementTestsEnabled) {
1148
1145
  const currentTestManagementTestsResponse =
1149
1146
  testManagementTestsResponse || await getChannelPromise(testManagementTestsCh)
1150
- if (currentTestManagementTestsResponse.err) {
1147
+ if (!currentTestManagementTestsResponse || currentTestManagementTestsResponse.err) {
1151
1148
  isTestManagementTestsEnabled = false
1152
1149
  } else {
1153
1150
  testManagementTests = currentTestManagementTestsResponse.testManagementTests
@@ -1156,7 +1153,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1156
1153
 
1157
1154
  if (isImpactedTestsEnabled) {
1158
1155
  const impactedTestsResponse = await getChannelPromise(modifiedFilesCh)
1159
- if (!impactedTestsResponse.err) {
1156
+ if (impactedTestsResponse && !impactedTestsResponse.err) {
1160
1157
  modifiedFiles = impactedTestsResponse.modifiedFiles
1161
1158
  }
1162
1159
  }
@@ -1215,7 +1212,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1215
1212
  global.__coverage__ = fromCoverageMapToCoverage(originalCoverageMap)
1216
1213
  }
1217
1214
 
1218
- sessionFinishCh.publish({
1215
+ const flushPromise = getChannelPromise(sessionFinishCh, {
1219
1216
  status: success ? 'pass' : 'fail',
1220
1217
  isSuitesSkipped,
1221
1218
  testCodeCoverageLinesTotal,
@@ -1228,9 +1225,11 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1228
1225
  isTestManagementTestsEnabled,
1229
1226
  isParallel,
1230
1227
  })
1228
+
1231
1229
  logTestOptimizationSummary({ attemptToFixExecutions })
1232
1230
  loggedAttemptToFixTests.clear()
1233
1231
  eventDataCollector = null
1232
+ await flushPromise
1234
1233
  return result
1235
1234
  }
1236
1235
  }
@@ -0,0 +1,74 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * @template {unknown[]} T
5
+ * @param {(...args: T) => void} onDone
6
+ * @returns {(...args: T) => void}
7
+ */
8
+ function getCompletion (onDone) {
9
+ let hasCompleted = false
10
+ return (...args) => {
11
+ if (hasCompleted) return
12
+
13
+ hasCompleted = true
14
+ onDone(...args)
15
+ }
16
+ }
17
+
18
+ /**
19
+ * @template {unknown[]} T
20
+ * @param {import('node:diagnostics_channel').Channel} channel
21
+ * @param {Record<string, unknown>} payload
22
+ * @param {(...args: T) => void} onDone
23
+ * @returns {void}
24
+ */
25
+ function publishWithCompletion (channel, payload, onDone) {
26
+ const complete = getCompletion(onDone)
27
+ channel.publish({ ...payload, onDone: complete })
28
+ if (!channel.hasSubscribers) complete()
29
+ }
30
+
31
+ /**
32
+ * @template {unknown[]} T
33
+ * @param {import('node:diagnostics_channel').Channel} channel
34
+ * @param {Record<string, unknown> & { onDone?: (...args: T) => void }} payload
35
+ * @param {(...args: T) => void} onDone
36
+ * @returns {void}
37
+ */
38
+ function runStoresWithCompletion (channel, payload, onDone) {
39
+ const complete = getCompletion(onDone)
40
+ payload.onDone = complete
41
+ channel.runStores(payload, () => {})
42
+ if (!channel.hasSubscribers) complete()
43
+ }
44
+
45
+ /**
46
+ * @template T
47
+ * @param {import('node:diagnostics_channel').Channel} channel
48
+ * @param {Record<string, unknown>} [payload]
49
+ * @returns {Promise<T>}
50
+ */
51
+ function getChannelPromise (channel, payload = {}) {
52
+ return new Promise(resolve => {
53
+ publishWithCompletion(channel, payload, resolve)
54
+ })
55
+ }
56
+
57
+ /**
58
+ * @template T
59
+ * @param {import('node:diagnostics_channel').Channel} channel
60
+ * @param {Record<string, unknown>} [payload]
61
+ * @returns {Promise<T>}
62
+ */
63
+ function getRunStoresPromise (channel, payload = {}) {
64
+ return new Promise(resolve => {
65
+ runStoresWithCompletion(channel, { ...payload }, resolve)
66
+ })
67
+ }
68
+
69
+ module.exports = {
70
+ getChannelPromise,
71
+ getRunStoresPromise,
72
+ publishWithCompletion,
73
+ runStoresWithCompletion,
74
+ }
@@ -21,6 +21,8 @@ module.exports = {
21
21
  '@apollo/gateway': () => require('../apollo'),
22
22
  '@langchain/langgraph': { esmFirst: true, fn: () => require('../langgraph') },
23
23
  '@modelcontextprotocol/sdk': { esmFirst: true, fn: () => require('../modelcontextprotocol-sdk') },
24
+ '@openai/agents': () => require('../openai-agents'),
25
+ '@openai/agents-openai': () => require('../openai-agents'),
24
26
  'apollo-server-core': () => require('../apollo-server-core'),
25
27
  '@aws-sdk/smithy-client': () => require('../aws-sdk'),
26
28
  '@aws/durable-execution-sdk-js': () => require('../aws-durable-execution-sdk-js'),
@@ -10,6 +10,7 @@ module.exports = [
10
10
  ...require('./langgraph'),
11
11
  ...require('./mercurius'),
12
12
  ...require('./modelcontextprotocol-sdk'),
13
+ ...require('./openai-agents'),
13
14
  ...require('./playwright'),
14
15
  ...require('./aws-durable-execution-sdk-js'),
15
16
  ]
@@ -0,0 +1,31 @@
1
+ 'use strict'
2
+
3
+ const moduleName = '@openai/agents-openai'
4
+ const versionRange = '>=0.7.0'
5
+ const functionQuery = {
6
+ methodName: 'constructor',
7
+ className: 'OpenAIChatCompletionsModel',
8
+ kind: 'Sync',
9
+ }
10
+ const channelName = 'OpenAIChatCompletionsModel_constructor'
11
+
12
+ module.exports = [
13
+ {
14
+ module: {
15
+ name: moduleName,
16
+ versionRange,
17
+ filePath: 'dist/openaiChatCompletionsModel.js',
18
+ },
19
+ functionQuery,
20
+ channelName,
21
+ },
22
+ {
23
+ module: {
24
+ name: moduleName,
25
+ versionRange,
26
+ filePath: 'dist/openaiChatCompletionsModel.mjs',
27
+ },
28
+ functionQuery,
29
+ channelName,
30
+ },
31
+ ]