dd-trace 6.6.0 → 6.8.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.
- package/ci/diagnose.js +162 -21
- package/ci/init.js +0 -1
- package/ci/runbook.md +187 -180
- package/ci/test-optimization-validation/approval-artifacts.js +3 -1
- package/ci/test-optimization-validation/approval.js +52 -15
- package/ci/test-optimization-validation/ci-command-candidate.js +26 -32
- package/ci/test-optimization-validation/ci-discovery.js +1 -1
- package/ci/test-optimization-validation/ci-package-scripts.js +141 -0
- package/ci/test-optimization-validation/ci-remediation.js +112 -39
- package/ci/test-optimization-validation/cli.js +516 -681
- package/ci/test-optimization-validation/command-blocker.js +188 -33
- package/ci/test-optimization-validation/command-output-policy.js +8 -31
- package/ci/test-optimization-validation/command-runner.js +189 -245
- package/ci/test-optimization-validation/environment.js +90 -0
- package/ci/test-optimization-validation/executable.js +159 -388
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +119 -0
- package/ci/test-optimization-validation/framework-adapters/cypress.js +107 -0
- package/ci/test-optimization-validation/framework-adapters/playwright.js +181 -0
- package/ci/test-optimization-validation/generated-files.js +84 -22
- package/ci/test-optimization-validation/generated-test-contract.js +281 -0
- package/ci/test-optimization-validation/generated-verifier.js +49 -16
- package/ci/test-optimization-validation/literal-environment.js +57 -0
- package/ci/test-optimization-validation/manifest-loader.js +2 -22
- package/ci/test-optimization-validation/manifest-scaffold.js +815 -515
- package/ci/test-optimization-validation/manifest-schema.js +494 -702
- package/ci/test-optimization-validation/offline-fixtures.js +4 -1
- package/ci/test-optimization-validation/offline-output.js +6 -6
- package/ci/test-optimization-validation/plan-writer.js +243 -984
- package/ci/test-optimization-validation/preflight-runner.js +49 -55
- package/ci/test-optimization-validation/redaction.js +2 -1
- package/ci/test-optimization-validation/report-writer.js +391 -1357
- package/ci/test-optimization-validation/result-semantics.js +86 -0
- package/ci/test-optimization-validation/runner-command.js +249 -0
- package/ci/test-optimization-validation/runner-contract.js +664 -0
- package/ci/test-optimization-validation/safe-files.js +4 -4
- package/ci/test-optimization-validation/scenarios/auto-test-retries.js +29 -3
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +240 -543
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +450 -670
- package/ci/test-optimization-validation/scenarios/early-flake-detection.js +4 -3
- package/ci/test-optimization-validation/scenarios/helpers.js +67 -9
- package/ci/test-optimization-validation/scenarios/test-management.js +6 -5
- package/ci/test-optimization-validation/source-text.js +87 -0
- package/ci/test-optimization-validation/test-output.js +12 -22
- package/ci/vitest-no-worker-init-setup.mjs +348 -51
- package/ext/tags.d.ts +1 -0
- package/index.d.ts +84 -13
- package/package.json +10 -4
- package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
- package/packages/datadog-esbuild/index.js +4 -2
- package/packages/datadog-esbuild/src/utils.js +1 -1
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +4 -4
- package/packages/datadog-instrumentations/src/cucumber.js +9 -6
- package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/openai-agents.js +31 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +57 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
- package/packages/datadog-instrumentations/src/http/client.js +1 -3
- package/packages/datadog-instrumentations/src/jest.js +8 -14
- package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
- package/packages/datadog-instrumentations/src/mocha/main.js +2 -42
- package/packages/datadog-instrumentations/src/mocha/utils.js +68 -2
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +19 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +446 -42
- package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
- package/packages/datadog-instrumentations/src/openai-agents.js +159 -0
- package/packages/datadog-instrumentations/src/playwright.js +3 -2
- package/packages/datadog-instrumentations/src/rhea.js +1 -1
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +525 -56
- package/packages/datadog-instrumentations/src/vitest-main.js +90 -10
- package/packages/datadog-instrumentations/src/webdriverio.js +914 -0
- package/packages/datadog-plugin-aerospike/src/index.js +1 -3
- package/packages/datadog-plugin-amqplib/src/client.js +1 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
- package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
- package/packages/datadog-plugin-child_process/src/index.js +3 -3
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +5 -8
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
- package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
- package/packages/datadog-plugin-fs/src/index.js +0 -4
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
- package/packages/datadog-plugin-graphql/src/execute.js +1 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +2 -1
- package/packages/datadog-plugin-jest/src/index.js +2 -3
- package/packages/datadog-plugin-jest/src/util.js +2 -1
- package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
- package/packages/datadog-plugin-mocha/src/index.js +25 -6
- package/packages/datadog-plugin-openai-agents/src/index.js +74 -0
- package/packages/datadog-plugin-openai-agents/src/integration.js +503 -0
- package/packages/datadog-plugin-openai-agents/src/processor.js +108 -0
- package/packages/datadog-plugin-openai-agents/src/util.js +60 -0
- package/packages/datadog-plugin-prisma/src/index.js +5 -1
- package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-undici/src/index.js +2 -1
- package/packages/datadog-plugin-vitest/src/index.js +84 -11
- package/packages/datadog-webpack/index.js +2 -2
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
- package/packages/dd-trace/src/appsec/sdk/track_event.js +1 -1
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +50 -51
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +4 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +161 -33
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +7 -5
- package/packages/dd-trace/src/config/defaults.js +14 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
- package/packages/dd-trace/src/config/index.js +15 -0
- package/packages/dd-trace/src/config/parsers.js +19 -1
- package/packages/dd-trace/src/config/supported-configurations.json +12 -6
- package/packages/dd-trace/src/datastreams/encoding.js +3 -4
- package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
- package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
- package/packages/dd-trace/src/encode/span-stats.js +7 -1
- package/packages/dd-trace/src/encode/tags-processors.js +2 -2
- package/packages/dd-trace/src/exporter.js +16 -9
- package/packages/dd-trace/src/exporters/common/url.js +3 -5
- package/packages/dd-trace/src/exporters/electron/index.js +4 -1
- package/packages/dd-trace/src/external-logger/src/index.js +1 -2
- package/packages/dd-trace/src/flare/index.js +2 -2
- package/packages/dd-trace/src/id.js +1 -1
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
- package/packages/dd-trace/src/llmobs/experiments/index.js +51 -12
- package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
- package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
- package/packages/dd-trace/src/llmobs/experiments/util.js +218 -0
- package/packages/dd-trace/src/llmobs/index.js +9 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +104 -22
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +5 -9
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +20 -0
- package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +321 -0
- package/packages/dd-trace/src/llmobs/sdk.js +6 -12
- package/packages/dd-trace/src/llmobs/span_processor.js +14 -7
- package/packages/dd-trace/src/llmobs/tagger.js +24 -5
- package/packages/dd-trace/src/llmobs/util.js +56 -3
- package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
- package/packages/dd-trace/src/noop/proxy.js +2 -2
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +3 -6
- package/packages/dd-trace/src/openfeature/configuration_source.js +5 -8
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +5 -1
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/opentracing/span_context.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +114 -23
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/outbound.js +4 -1
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/tracing.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +7 -6
- package/packages/dd-trace/src/plugins/util/git.js +1 -1
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +1 -1
- package/packages/dd-trace/src/plugins/util/llm.js +2 -2
- package/packages/dd-trace/src/plugins/util/tags.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +38 -12
- package/packages/dd-trace/src/plugins/util/url.js +5 -5
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
- package/packages/dd-trace/src/plugins/util/web.js +1 -1
- package/packages/dd-trace/src/priority_sampler.js +6 -3
- package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
- package/packages/dd-trace/src/ritm.js +5 -20
- package/packages/dd-trace/src/span_processor.js +1 -1
- package/packages/dd-trace/src/span_stats.js +22 -4
- package/packages/dd-trace/src/startup-log.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
- package/packages/dd-trace/src/util.js +16 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/source-map/index.js +1 -1
- package/ci/test-optimization-validation/command-suitability.js +0 -471
- package/ci/test-optimization-validation/init-probe-preload.js +0 -163
- package/ci/test-optimization-validation/init-probe.js +0 -246
- package/ci/test-optimization-validation/late-initialization.js +0 -63
- package/ci/test-optimization-validation/local-command.js +0 -163
- package/ci/test-optimization-validation/setup-runner.js +0 -97
- package/ci/test-optimization-validation-manifest.schema.json +0 -1
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const { addHook, channel } = require('../helpers/instrument')
|
|
4
4
|
const shimmer = require('../../../datadog-shimmer')
|
|
5
|
+
const { getEnvironmentVariable } = require('../../../dd-trace/src/config/helper')
|
|
6
|
+
const log = require('../../../dd-trace/src/log')
|
|
5
7
|
const { DD_MAJOR } = require('../../../../version')
|
|
6
8
|
|
|
7
9
|
const {
|
|
@@ -14,14 +16,351 @@ const {
|
|
|
14
16
|
getOnTestRetryHandler,
|
|
15
17
|
getRunTestsWrapper,
|
|
16
18
|
patchFailedTestReplayHookUp,
|
|
19
|
+
adjustRunnerFailuresForTestOptimization,
|
|
20
|
+
efdTests,
|
|
21
|
+
getTestFullName,
|
|
17
22
|
} = require('./utils')
|
|
23
|
+
const {
|
|
24
|
+
CONFIGURATION_REQUEST,
|
|
25
|
+
CONFIGURATION_RESPONSE,
|
|
26
|
+
createWebdriverioWorkerMessage,
|
|
27
|
+
SUITE_FINISH,
|
|
28
|
+
WEBDRIVERIO_WORKER_ENV,
|
|
29
|
+
WORKER_READY,
|
|
30
|
+
} = require('./webdriverio-protocol')
|
|
18
31
|
require('./common')
|
|
19
32
|
|
|
20
33
|
const MINIMUM_MOCHA_VERSION = DD_MAJOR >= 6 ? '>=8.0.0' : '>=5.2.0'
|
|
21
34
|
|
|
22
35
|
const workerFinishCh = channel('ci:mocha:worker:finish')
|
|
36
|
+
const workerConfigurationCh = channel('ci:mocha:worker:configuration')
|
|
23
37
|
|
|
24
38
|
const config = {}
|
|
39
|
+
const runnerToFiles = new WeakMap()
|
|
40
|
+
const runnerToFailedHooks = new WeakMap()
|
|
41
|
+
const isWebdriverioWorker = !!getEnvironmentVariable(WEBDRIVERIO_WORKER_ENV)
|
|
42
|
+
let configurationRequestId = 0
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Sends a message to the WebdriverIO launcher without surfacing closed IPC channels.
|
|
46
|
+
*
|
|
47
|
+
* @param {object} message
|
|
48
|
+
* @param {() => void} [onError]
|
|
49
|
+
* @param {() => void} [onDone]
|
|
50
|
+
* @returns {void}
|
|
51
|
+
*/
|
|
52
|
+
function sendWebdriverioMessage (message, onError, onDone) {
|
|
53
|
+
if (!process.send || !process.connected) {
|
|
54
|
+
onError?.()
|
|
55
|
+
onDone?.()
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
process.send(createWebdriverioWorkerMessage(message), (error) => {
|
|
60
|
+
if (error) {
|
|
61
|
+
log.error('WebdriverIO Test Optimization IPC error', error)
|
|
62
|
+
onError?.()
|
|
63
|
+
}
|
|
64
|
+
onDone?.()
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Applies configuration encoded as private Mocha options by its parallel runner.
|
|
70
|
+
*
|
|
71
|
+
* @param {object} options
|
|
72
|
+
* @returns {void}
|
|
73
|
+
*/
|
|
74
|
+
function applyMochaOptions (options) {
|
|
75
|
+
if (options._ddIsKnownTestsEnabled) {
|
|
76
|
+
config.isKnownTestsEnabled = true
|
|
77
|
+
config.isEarlyFlakeDetectionEnabled = options._ddIsEfdEnabled
|
|
78
|
+
config.knownTests = options._ddKnownTests
|
|
79
|
+
config.earlyFlakeDetectionNumRetries = options._ddEfdNumRetries
|
|
80
|
+
config.earlyFlakeDetectionSlowTestRetries = options._ddEfdSlowTestRetries ?? {}
|
|
81
|
+
delete options._ddIsEfdEnabled
|
|
82
|
+
delete options._ddKnownTests
|
|
83
|
+
delete options._ddEfdNumRetries
|
|
84
|
+
delete options._ddEfdSlowTestRetries
|
|
85
|
+
delete options._ddIsKnownTestsEnabled
|
|
86
|
+
}
|
|
87
|
+
if (options._ddIsImpactedTestsEnabled) {
|
|
88
|
+
config.isImpactedTestsEnabled = true
|
|
89
|
+
config.modifiedFiles = options._ddModifiedFiles
|
|
90
|
+
delete options._ddIsImpactedTestsEnabled
|
|
91
|
+
delete options._ddModifiedFiles
|
|
92
|
+
}
|
|
93
|
+
if (options._ddIsTestManagementTestsEnabled) {
|
|
94
|
+
config.isTestManagementTestsEnabled = true
|
|
95
|
+
config.testManagementAttemptToFixRetries = options._ddTestManagementAttemptToFixRetries
|
|
96
|
+
config.testManagementTests = options._ddTestManagementTests
|
|
97
|
+
delete options._ddIsTestManagementTestsEnabled
|
|
98
|
+
delete options._ddTestManagementAttemptToFixRetries
|
|
99
|
+
delete options._ddTestManagementTests
|
|
100
|
+
}
|
|
101
|
+
if (options._ddIsFlakyTestRetriesEnabled) {
|
|
102
|
+
config.isFlakyTestRetriesEnabled = true
|
|
103
|
+
config.flakyTestRetriesCount = options._ddFlakyTestRetriesCount
|
|
104
|
+
delete options._ddIsFlakyTestRetriesEnabled
|
|
105
|
+
delete options._ddFlakyTestRetriesCount
|
|
106
|
+
}
|
|
107
|
+
if (options._ddIsFailedTestReplayEnabled) {
|
|
108
|
+
config.isTestDynamicInstrumentationEnabled = true
|
|
109
|
+
config.isDiEnabled = true
|
|
110
|
+
delete options._ddIsFailedTestReplayEnabled
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Removes files selected for suite-level skipping from an already loaded Mocha root suite.
|
|
116
|
+
*
|
|
117
|
+
* @param {object} runner
|
|
118
|
+
* @param {string[]} skippedFiles
|
|
119
|
+
* @returns {void}
|
|
120
|
+
*/
|
|
121
|
+
function filterSkippedFiles (runner, skippedFiles) {
|
|
122
|
+
if (!skippedFiles.length) {
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const skippedFilesSet = new Set(skippedFiles)
|
|
127
|
+
runner.suite.suites = runner.suite.suites.filter(suite => !skippedFilesSet.has(suite.file))
|
|
128
|
+
runner.suite.tests = runner.suite.tests.filter(test => !skippedFilesSet.has(test.file))
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Requests configuration from the WebdriverIO launcher before releasing Mocha's delayed root suite.
|
|
133
|
+
*
|
|
134
|
+
* @param {string} frameworkVersion
|
|
135
|
+
* @param {string[]} files
|
|
136
|
+
* @param {(response: object) => void} onDone
|
|
137
|
+
* @returns {void}
|
|
138
|
+
*/
|
|
139
|
+
function requestWebdriverioConfiguration (frameworkVersion, files, onDone) {
|
|
140
|
+
const requestId = `${process.pid}-${++configurationRequestId}`
|
|
141
|
+
let finished = false
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Finishes the configuration request exactly once.
|
|
145
|
+
*
|
|
146
|
+
* @param {object} response
|
|
147
|
+
* @returns {void}
|
|
148
|
+
*/
|
|
149
|
+
function finish (response) {
|
|
150
|
+
if (finished) {
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
finished = true
|
|
154
|
+
clearTimeout(timeout)
|
|
155
|
+
process.off('message', onMessage)
|
|
156
|
+
process.off('disconnect', onDisconnect)
|
|
157
|
+
onDone(response)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Receives the matching coordinator response.
|
|
162
|
+
*
|
|
163
|
+
* @param {object} message
|
|
164
|
+
* @returns {void}
|
|
165
|
+
*/
|
|
166
|
+
function onMessage (message) {
|
|
167
|
+
if (message?.name === CONFIGURATION_RESPONSE && message.content?.requestId === requestId) {
|
|
168
|
+
finish(message.content)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Releases the runner if its parent disconnects.
|
|
174
|
+
*
|
|
175
|
+
* @returns {void}
|
|
176
|
+
*/
|
|
177
|
+
function onDisconnect () {
|
|
178
|
+
finish({})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const timeout = setTimeout(() => finish({}), 30_000)
|
|
182
|
+
process.on('message', onMessage)
|
|
183
|
+
process.once('disconnect', onDisconnect)
|
|
184
|
+
sendWebdriverioMessage({
|
|
185
|
+
origin: 'datadog',
|
|
186
|
+
name: CONFIGURATION_REQUEST,
|
|
187
|
+
content: {
|
|
188
|
+
files,
|
|
189
|
+
frameworkVersion,
|
|
190
|
+
requestId,
|
|
191
|
+
},
|
|
192
|
+
}, () => finish({}))
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Reports the Mocha version as soon as WebdriverIO loads its framework adapter.
|
|
197
|
+
*
|
|
198
|
+
* @param {string} frameworkVersion
|
|
199
|
+
* @returns {void}
|
|
200
|
+
*/
|
|
201
|
+
function reportWebdriverioWorkerReady (frameworkVersion) {
|
|
202
|
+
if (!isWebdriverioWorker) {
|
|
203
|
+
return
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
sendWebdriverioMessage({
|
|
207
|
+
origin: 'datadog',
|
|
208
|
+
name: WORKER_READY,
|
|
209
|
+
content: { frameworkVersion },
|
|
210
|
+
})
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Checks whether Test Optimization converts a failed WebdriverIO test attempt to a passing result.
|
|
215
|
+
*
|
|
216
|
+
* @param {object|undefined} test
|
|
217
|
+
* @returns {boolean}
|
|
218
|
+
*/
|
|
219
|
+
function isWebdriverioFailureSuppressed (test) {
|
|
220
|
+
if (!test) {
|
|
221
|
+
return false
|
|
222
|
+
}
|
|
223
|
+
const hasPassingEfdAttempt = config.isEarlyFlakeDetectionEnabled &&
|
|
224
|
+
efdTests[getTestFullName(test)]?.some(attempt => attempt.state === 'passed' && !attempt._ddHookFailed)
|
|
225
|
+
return (test._ddIsQuarantined && !test._ddIsAttemptToFix) || hasPassingEfdAttempt
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Gets the test owned by a per-test hook without associating suite hooks with boundary tests.
|
|
230
|
+
*
|
|
231
|
+
* @param {object} hook
|
|
232
|
+
* @returns {object|undefined}
|
|
233
|
+
*/
|
|
234
|
+
function getWebdriverioHookTest (hook) {
|
|
235
|
+
const { parent } = hook
|
|
236
|
+
const isTestHook = parent?._beforeEach?.includes(hook) || parent?._afterEach?.includes(hook)
|
|
237
|
+
return isTestHook ? hook.ctx?.currentTest : undefined
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Removes managed hook failures from WebdriverIO's Mocha runner totals.
|
|
242
|
+
*
|
|
243
|
+
* @param {object} runner
|
|
244
|
+
* @returns {void}
|
|
245
|
+
*/
|
|
246
|
+
function adjustWebdriverioHookFailures (runner) {
|
|
247
|
+
let suppressedFailures = 0
|
|
248
|
+
for (const { test } of runnerToFailedHooks.get(runner) || []) {
|
|
249
|
+
if (isWebdriverioFailureSuppressed(test)) {
|
|
250
|
+
suppressedFailures++
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (runner.stats) {
|
|
254
|
+
runner.stats.failures -= suppressedFailures
|
|
255
|
+
}
|
|
256
|
+
runner.failures -= suppressedFailures
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Computes a final result for every file loaded into one Mocha worker.
|
|
261
|
+
*
|
|
262
|
+
* @param {object} runner
|
|
263
|
+
* @returns {object[]}
|
|
264
|
+
*/
|
|
265
|
+
function getWebdriverioSuiteResults (runner) {
|
|
266
|
+
const resultsByFile = new Map()
|
|
267
|
+
const files = runnerToFiles.get(runner) || []
|
|
268
|
+
|
|
269
|
+
for (const file of files) {
|
|
270
|
+
resultsByFile.set(file, {
|
|
271
|
+
file,
|
|
272
|
+
hasPassingTest: false,
|
|
273
|
+
status: 'skip',
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
runner.suite.eachTest(test => {
|
|
278
|
+
const result = resultsByFile.get(test.file)
|
|
279
|
+
if (!result) {
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
const isSuppressedFailure = isWebdriverioFailureSuppressed(test)
|
|
283
|
+
if ((test.state === 'failed' || test.timedOut || test._ddHookFailed) && !isSuppressedFailure) {
|
|
284
|
+
result.status = 'fail'
|
|
285
|
+
} else if (test.state === 'passed' || isSuppressedFailure) {
|
|
286
|
+
result.hasPassingTest = true
|
|
287
|
+
}
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
for (const { file, test } of runnerToFailedHooks.get(runner) || []) {
|
|
291
|
+
const result = resultsByFile.get(file)
|
|
292
|
+
if (result && !isWebdriverioFailureSuppressed(test)) {
|
|
293
|
+
result.status = 'fail'
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const results = []
|
|
298
|
+
let hasFailedSuite = false
|
|
299
|
+
for (const result of resultsByFile.values()) {
|
|
300
|
+
if (result.status === 'fail') {
|
|
301
|
+
hasFailedSuite = true
|
|
302
|
+
} else if (result.hasPassingTest) {
|
|
303
|
+
result.status = 'pass'
|
|
304
|
+
}
|
|
305
|
+
delete result.hasPassingTest
|
|
306
|
+
results.push(result)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (runner.failures > 0 && !hasFailedSuite) {
|
|
310
|
+
for (const result of results) {
|
|
311
|
+
result.status = 'fail'
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return results
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Sends suite results to the WebdriverIO launcher.
|
|
320
|
+
*
|
|
321
|
+
* @param {object} runner
|
|
322
|
+
* @param {() => void} [onDone]
|
|
323
|
+
* @returns {void}
|
|
324
|
+
*/
|
|
325
|
+
function reportWebdriverioSuiteResults (runner, onDone) {
|
|
326
|
+
if (!isWebdriverioWorker) {
|
|
327
|
+
onDone?.()
|
|
328
|
+
return
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
sendWebdriverioMessage({
|
|
332
|
+
origin: 'datadog',
|
|
333
|
+
name: SUITE_FINISH,
|
|
334
|
+
content: {
|
|
335
|
+
results: getWebdriverioSuiteResults(runner),
|
|
336
|
+
},
|
|
337
|
+
}, undefined, onDone)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Flushes worker payloads before reporting suite results and completing Mocha.
|
|
342
|
+
*
|
|
343
|
+
* @param {object} runner
|
|
344
|
+
* @param {() => void} onDone
|
|
345
|
+
* @returns {void}
|
|
346
|
+
*/
|
|
347
|
+
function finishWebdriverioWorker (runner, onDone) {
|
|
348
|
+
try {
|
|
349
|
+
workerFinishCh.publish({
|
|
350
|
+
onDone: () => {
|
|
351
|
+
try {
|
|
352
|
+
reportWebdriverioSuiteResults(runner, onDone)
|
|
353
|
+
} catch (error) {
|
|
354
|
+
log.error('WebdriverIO Test Optimization worker completion error', error)
|
|
355
|
+
onDone()
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
})
|
|
359
|
+
} catch (error) {
|
|
360
|
+
log.error('WebdriverIO Test Optimization worker completion error', error)
|
|
361
|
+
onDone()
|
|
362
|
+
}
|
|
363
|
+
}
|
|
25
364
|
|
|
26
365
|
function isFailedTestReplayEnabled () {
|
|
27
366
|
return config.isTestDynamicInstrumentationEnabled && config.isDiEnabled
|
|
@@ -31,46 +370,77 @@ addHook({
|
|
|
31
370
|
name: 'mocha',
|
|
32
371
|
versions: ['>=8.0.0'],
|
|
33
372
|
file: 'lib/mocha.js',
|
|
34
|
-
}, (Mocha) => {
|
|
373
|
+
}, (Mocha, frameworkVersion) => {
|
|
374
|
+
reportWebdriverioWorkerReady(frameworkVersion)
|
|
375
|
+
|
|
35
376
|
shimmer.wrap(Mocha.prototype, 'run', run => function (...args) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
config.knownTests = this.options._ddKnownTests
|
|
40
|
-
config.earlyFlakeDetectionNumRetries = this.options._ddEfdNumRetries
|
|
41
|
-
config.earlyFlakeDetectionSlowTestRetries = this.options._ddEfdSlowTestRetries ?? {}
|
|
42
|
-
delete this.options._ddIsEfdEnabled
|
|
43
|
-
delete this.options._ddKnownTests
|
|
44
|
-
delete this.options._ddEfdNumRetries
|
|
45
|
-
delete this.options._ddEfdSlowTestRetries
|
|
46
|
-
delete this.options._ddIsKnownTestsEnabled
|
|
47
|
-
}
|
|
48
|
-
if (this.options._ddIsImpactedTestsEnabled) {
|
|
49
|
-
config.isImpactedTestsEnabled = true
|
|
50
|
-
config.modifiedFiles = this.options._ddModifiedFiles
|
|
51
|
-
delete this.options._ddIsImpactedTestsEnabled
|
|
52
|
-
delete this.options._ddModifiedFiles
|
|
53
|
-
}
|
|
54
|
-
if (this.options._ddIsTestManagementTestsEnabled) {
|
|
55
|
-
config.isTestManagementTestsEnabled = true
|
|
56
|
-
config.testManagementAttemptToFixRetries = this.options._ddTestManagementAttemptToFixRetries
|
|
57
|
-
config.testManagementTests = this.options._ddTestManagementTests
|
|
58
|
-
delete this.options._ddIsTestManagementTestsEnabled
|
|
59
|
-
delete this.options._ddTestManagementAttemptToFixRetries
|
|
60
|
-
delete this.options._ddTestManagementTests
|
|
61
|
-
}
|
|
62
|
-
if (this.options._ddIsFlakyTestRetriesEnabled) {
|
|
63
|
-
config.isFlakyTestRetriesEnabled = true
|
|
64
|
-
config.flakyTestRetriesCount = this.options._ddFlakyTestRetriesCount
|
|
65
|
-
delete this.options._ddIsFlakyTestRetriesEnabled
|
|
66
|
-
delete this.options._ddFlakyTestRetriesCount
|
|
67
|
-
}
|
|
68
|
-
if (this.options._ddIsFailedTestReplayEnabled) {
|
|
69
|
-
config.isTestDynamicInstrumentationEnabled = true
|
|
70
|
-
config.isDiEnabled = true
|
|
71
|
-
delete this.options._ddIsFailedTestReplayEnabled
|
|
377
|
+
applyMochaOptions(this.options)
|
|
378
|
+
if (!isWebdriverioWorker || !workerFinishCh.hasSubscribers) {
|
|
379
|
+
return run.apply(this, args)
|
|
72
380
|
}
|
|
73
|
-
|
|
381
|
+
|
|
382
|
+
const isUserDelayed = this.options.delay
|
|
383
|
+
const rootSuite = this.suite
|
|
384
|
+
const rootSuiteRun = rootSuite.run
|
|
385
|
+
const hasOwnRootSuiteRun = Object.hasOwn(rootSuite, 'run')
|
|
386
|
+
let configurationReady = false
|
|
387
|
+
let userReady = !isUserDelayed
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Restores the root suite method after both delayed-mode gates are open.
|
|
391
|
+
*
|
|
392
|
+
* @returns {void}
|
|
393
|
+
*/
|
|
394
|
+
function restoreRootSuiteRun () {
|
|
395
|
+
if (hasOwnRootSuiteRun) {
|
|
396
|
+
rootSuite.run = rootSuiteRun
|
|
397
|
+
} else {
|
|
398
|
+
delete rootSuite.run
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (isUserDelayed) {
|
|
403
|
+
rootSuite.run = function (...args) {
|
|
404
|
+
userReady = true
|
|
405
|
+
if (!configurationReady) {
|
|
406
|
+
return
|
|
407
|
+
}
|
|
408
|
+
restoreRootSuiteRun()
|
|
409
|
+
return rootSuiteRun.apply(this, args)
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
this.options.delay = true
|
|
414
|
+
const files = [...this.files]
|
|
415
|
+
const runner = run.apply(this, args)
|
|
416
|
+
runnerToFiles.set(runner, files)
|
|
417
|
+
|
|
418
|
+
requestWebdriverioConfiguration(frameworkVersion, files, ({
|
|
419
|
+
configuration,
|
|
420
|
+
skippedFiles = [],
|
|
421
|
+
}) => {
|
|
422
|
+
if (configuration) {
|
|
423
|
+
Object.assign(config, configuration)
|
|
424
|
+
workerConfigurationCh.publish({
|
|
425
|
+
libraryConfig: config,
|
|
426
|
+
repositoryRoot: config.repositoryRoot,
|
|
427
|
+
testFramework: config.testFramework,
|
|
428
|
+
})
|
|
429
|
+
}
|
|
430
|
+
filterSkippedFiles(runner, skippedFiles)
|
|
431
|
+
if (isFailedTestReplayEnabled()) {
|
|
432
|
+
patchFailedTestReplayHookUp(runner.constructor)
|
|
433
|
+
}
|
|
434
|
+
configurationReady = true
|
|
435
|
+
if (userReady) {
|
|
436
|
+
if (isUserDelayed) {
|
|
437
|
+
restoreRootSuiteRun()
|
|
438
|
+
}
|
|
439
|
+
rootSuite.run()
|
|
440
|
+
}
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
return runner
|
|
74
444
|
})
|
|
75
445
|
|
|
76
446
|
return Mocha
|
|
@@ -91,10 +461,32 @@ addHook({
|
|
|
91
461
|
if (isFailedTestReplayEnabled()) {
|
|
92
462
|
patchFailedTestReplayHookUp(Runner)
|
|
93
463
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
464
|
+
if (isWebdriverioWorker) {
|
|
465
|
+
this.prependOnceListener('end', () => {
|
|
466
|
+
try {
|
|
467
|
+
adjustRunnerFailuresForTestOptimization(this, config)
|
|
468
|
+
adjustWebdriverioHookFailures(this)
|
|
469
|
+
} catch (error) {
|
|
470
|
+
log.error('WebdriverIO Test Optimization failure adjustment error', error)
|
|
471
|
+
}
|
|
472
|
+
})
|
|
473
|
+
}
|
|
474
|
+
const onRunDone = args[0]
|
|
475
|
+
if (isWebdriverioWorker && typeof onRunDone === 'function') {
|
|
476
|
+
args[0] = (...onRunDoneArgs) => {
|
|
477
|
+
finishWebdriverioWorker(this, () => onRunDone(...onRunDoneArgs))
|
|
478
|
+
}
|
|
479
|
+
} else {
|
|
480
|
+
// Flush after the worker finishes its Mocha run, including grouped spec files.
|
|
481
|
+
this.once('end', () => {
|
|
482
|
+
try {
|
|
483
|
+
workerFinishCh.publish()
|
|
484
|
+
reportWebdriverioSuiteResults(this)
|
|
485
|
+
} catch (error) {
|
|
486
|
+
log.error('WebdriverIO Test Optimization worker completion error', error)
|
|
487
|
+
}
|
|
488
|
+
})
|
|
489
|
+
}
|
|
98
490
|
this.on('test', getOnTestHandler(false))
|
|
99
491
|
|
|
100
492
|
this.on('test end', getOnTestEndHandler(config))
|
|
@@ -104,6 +496,18 @@ addHook({
|
|
|
104
496
|
// If the hook passes, 'hook end' will be emitted. Otherwise, 'fail' will be emitted
|
|
105
497
|
this.on('hook end', getOnHookEndHandler(config))
|
|
106
498
|
|
|
499
|
+
if (isWebdriverioWorker) {
|
|
500
|
+
const failedHooks = []
|
|
501
|
+
runnerToFailedHooks.set(this, failedHooks)
|
|
502
|
+
this.on('fail', runnable => {
|
|
503
|
+
if (runnable.type === 'hook' && runnable.file) {
|
|
504
|
+
failedHooks.push({
|
|
505
|
+
file: runnable.file,
|
|
506
|
+
test: getWebdriverioHookTest(runnable),
|
|
507
|
+
})
|
|
508
|
+
}
|
|
509
|
+
})
|
|
510
|
+
}
|
|
107
511
|
this.on('fail', getOnFailHandler(false, config))
|
|
108
512
|
|
|
109
513
|
this.on('pending', getOnPendingHandler())
|
|
@@ -10,7 +10,7 @@ const errorChannel = channel('apm:moleculer:call:error')
|
|
|
10
10
|
function wrapCall (call) {
|
|
11
11
|
return function (actionName, params, opts) {
|
|
12
12
|
opts = arguments[2] = opts || {}
|
|
13
|
-
opts.meta
|
|
13
|
+
opts.meta ||= {}
|
|
14
14
|
|
|
15
15
|
arguments.length = Math.max(3, arguments.length)
|
|
16
16
|
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { channel, tracingChannel } = require('dc-polyfill')
|
|
4
|
+
const shimmer = require('../../datadog-shimmer')
|
|
5
|
+
const { addHook, getHooks } = require('./helpers/instrument')
|
|
6
|
+
|
|
7
|
+
// `WeakSet` keyed by module exports — replaces the underscored
|
|
8
|
+
// `mod._datadogPatched` flag while keeping dedupe semantics. Mods are kept
|
|
9
|
+
// alive by `require.cache` anyway, so this doesn't add lifetime to anything.
|
|
10
|
+
const patchedMods = new WeakSet()
|
|
11
|
+
const modelBaseURLs = new WeakMap()
|
|
12
|
+
const chatCompletionsModelConstructorCh =
|
|
13
|
+
tracingChannel('orchestrion:@openai/agents-openai:OpenAIChatCompletionsModel_constructor')
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Capture the client base URL before the SDK stores the client in a #private field.
|
|
17
|
+
*
|
|
18
|
+
* @param {{ arguments?: [{ baseURL?: string }], self?: object }} ctx
|
|
19
|
+
*/
|
|
20
|
+
function captureChatCompletionsModelBaseURL (ctx) {
|
|
21
|
+
const baseURL = ctx.arguments?.[0]?.baseURL
|
|
22
|
+
if (ctx.self && typeof baseURL === 'string') modelBaseURLs.set(ctx.self, baseURL)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
chatCompletionsModelConstructorCh.end.subscribe(captureChatCompletionsModelBaseURL)
|
|
26
|
+
|
|
27
|
+
for (const hook of getHooks('@openai/agents-openai')) {
|
|
28
|
+
addHook(hook, moduleExports => moduleExports)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Plugin subscribes to this and registers its TracingProcessor when
|
|
32
|
+
// `@openai/agents` loads. Publishing from here keeps this file free of
|
|
33
|
+
// any cross-package import from the plugin.
|
|
34
|
+
const agentsCoreLoadedCh = channel('apm:openai-agents:agents-core:loaded')
|
|
35
|
+
|
|
36
|
+
// Plugin uses addBind on this channel so that legacyStorage.run(store, fn) wraps
|
|
37
|
+
// the model call — including async iterator advancement for streaming responses.
|
|
38
|
+
// This ensures the active dd-trace span is visible to the openai plugin when it
|
|
39
|
+
// creates its openai.request span, correctly parenting it under the agent span.
|
|
40
|
+
const modelStartCh = channel('apm:openai-agents:model:start')
|
|
41
|
+
|
|
42
|
+
// Tool.invoke runs inside agents-core's public function-span context. Bind the
|
|
43
|
+
// corresponding dd-trace tool span around that public invocation boundary so
|
|
44
|
+
// spans created by user tool code inherit it.
|
|
45
|
+
const toolStartCh = channel('apm:openai-agents:tool:start')
|
|
46
|
+
|
|
47
|
+
// Reference to the loaded @openai/agents module, captured in the first hook
|
|
48
|
+
// so that wrapResponseMethod can call getCurrentSpan() without an additional
|
|
49
|
+
// require (and without triggering n/no-missing-require on agents-core internals).
|
|
50
|
+
let agentsMod
|
|
51
|
+
|
|
52
|
+
// @openai/agents >=0.8.0 moved addTraceProcessor / getCurrentSpan out of the
|
|
53
|
+
// top-level re-exports. The new public surface uses getGlobalTraceProvider():
|
|
54
|
+
// provider.registerProcessor(processor) (replaces addTraceProcessor)
|
|
55
|
+
// provider.getCurrentSpan() (replaces getCurrentSpan)
|
|
56
|
+
// Both APIs are tried so this file works across the full supported version range.
|
|
57
|
+
// The plugin subscriber (index.js) handles processor registration via the channel.
|
|
58
|
+
function getCurrentSpan () {
|
|
59
|
+
if (typeof agentsMod?.getCurrentSpan === 'function') {
|
|
60
|
+
return agentsMod.getCurrentSpan()
|
|
61
|
+
}
|
|
62
|
+
if (typeof agentsMod?.getGlobalTraceProvider === 'function') {
|
|
63
|
+
return agentsMod.getGlobalTraceProvider().getCurrentSpan()
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getCurrentSpanId () {
|
|
68
|
+
return getCurrentSpan()?.spanId
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
addHook({ name: '@openai/agents', versions: ['>=0.7.0'] }, (mod) => {
|
|
72
|
+
if (patchedMods.has(mod)) return mod
|
|
73
|
+
if (typeof mod?.addTraceProcessor !== 'function' && typeof mod?.getGlobalTraceProvider !== 'function') return mod
|
|
74
|
+
patchedMods.add(mod)
|
|
75
|
+
agentsMod = mod
|
|
76
|
+
if (typeof mod.tool === 'function') {
|
|
77
|
+
shimmer.wrap(mod, 'tool', wrapToolFactory, { replaceGetter: true })
|
|
78
|
+
}
|
|
79
|
+
agentsCoreLoadedCh.publish({ mod })
|
|
80
|
+
return mod
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
function wrapToolFactory (original) {
|
|
84
|
+
return function (...args) {
|
|
85
|
+
const tool = original.apply(this, args)
|
|
86
|
+
if (typeof tool?.invoke === 'function') {
|
|
87
|
+
shimmer.wrap(tool, 'invoke', wrapToolInvoke)
|
|
88
|
+
}
|
|
89
|
+
return tool
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function wrapToolInvoke (original) {
|
|
94
|
+
return function (...args) {
|
|
95
|
+
const agentsCoreSpan = getCurrentSpan()
|
|
96
|
+
return toolStartCh.runStores({ agentsCoreSpan }, () => original.apply(this, args))
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function wrapResponseMethod (original) {
|
|
101
|
+
return function (...args) {
|
|
102
|
+
const agentsCoreSpanId = getCurrentSpanId()
|
|
103
|
+
const baseURL = getClientBaseURL(this)
|
|
104
|
+
return modelStartCh.runStores({ agentsCoreSpanId, baseURL }, () => original.apply(this, args))
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function wrapStreamedResponseMethod (original) {
|
|
109
|
+
return function (...args) {
|
|
110
|
+
const agentsCoreSpanId = getCurrentSpanId()
|
|
111
|
+
const baseURL = getClientBaseURL(this)
|
|
112
|
+
const context = { agentsCoreSpanId, baseURL }
|
|
113
|
+
const iterator = modelStartCh.runStores(context, () => original.apply(this, args))
|
|
114
|
+
return wrapAsyncIterator(iterator, context)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function getClientBaseURL (model) {
|
|
119
|
+
return model?.client?.baseURL ?? model?._client?.baseURL ?? modelBaseURLs.get(model)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function wrapAsyncIterator (iterator, context) {
|
|
123
|
+
if (!iterator || typeof iterator !== 'object') return iterator
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
next () {
|
|
127
|
+
return modelStartCh.runStores(context, () => iterator.next.apply(iterator, arguments))
|
|
128
|
+
},
|
|
129
|
+
throw () {
|
|
130
|
+
if (typeof iterator.throw !== 'function') return Promise.reject(arguments[0])
|
|
131
|
+
return modelStartCh.runStores(context, () => iterator.throw.apply(iterator, arguments))
|
|
132
|
+
},
|
|
133
|
+
return () {
|
|
134
|
+
if (typeof iterator.return !== 'function') return Promise.resolve({ done: true, value: arguments[0] })
|
|
135
|
+
return modelStartCh.runStores(context, () => iterator.return.apply(iterator, arguments))
|
|
136
|
+
},
|
|
137
|
+
[Symbol.asyncIterator] () {
|
|
138
|
+
return this
|
|
139
|
+
},
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
addHook({ name: '@openai/agents-openai', versions: ['>=0.7.0'] }, (mod) => {
|
|
144
|
+
if (patchedMods.has(mod)) return mod
|
|
145
|
+
const responseProto = mod?.OpenAIResponsesModel?.prototype
|
|
146
|
+
const chatCompletionsProto = mod?.OpenAIChatCompletionsModel?.prototype
|
|
147
|
+
if (!responseProto && !chatCompletionsProto) return mod
|
|
148
|
+
|
|
149
|
+
patchedMods.add(mod)
|
|
150
|
+
for (const proto of [responseProto, chatCompletionsProto]) {
|
|
151
|
+
if (typeof proto?.getResponse === 'function') {
|
|
152
|
+
shimmer.wrap(proto, 'getResponse', wrapResponseMethod)
|
|
153
|
+
}
|
|
154
|
+
if (typeof proto?.getStreamedResponse === 'function') {
|
|
155
|
+
shimmer.wrap(proto, 'getStreamedResponse', wrapStreamedResponseMethod)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return mod
|
|
159
|
+
})
|