dd-trace 5.110.0 → 5.112.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/LICENSE-3rdparty.csv +1 -2
- package/README.md +13 -8
- package/ci/init.js +21 -2
- package/ci/vitest-no-worker-init-setup.mjs +430 -0
- package/ext/tags.js +2 -0
- package/index.d.ts +34 -1
- package/initialize.mjs +5 -6
- package/loader-hook.mjs +76 -55
- package/package.json +37 -34
- package/packages/datadog-instrumentations/src/ai.js +45 -0
- package/packages/datadog-instrumentations/src/apollo-server.js +5 -13
- package/packages/datadog-instrumentations/src/child_process.js +3 -3
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +587 -0
- package/packages/datadog-instrumentations/src/cucumber.js +102 -43
- package/packages/datadog-instrumentations/src/cypress-config.js +11 -3
- package/packages/datadog-instrumentations/src/fastify.js +27 -8
- package/packages/datadog-instrumentations/src/fs.js +8 -6
- package/packages/datadog-instrumentations/src/graphql.js +26 -495
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +7 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +6 -6
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/claude-agent-sdk.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +201 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
- package/packages/datadog-instrumentations/src/jest.js +713 -63
- package/packages/datadog-instrumentations/src/mocha/main.js +24 -3
- package/packages/datadog-instrumentations/src/mocha/utils.js +128 -22
- package/packages/datadog-instrumentations/src/mocha/worker.js +13 -0
- package/packages/datadog-instrumentations/src/mongodb.js +74 -0
- package/packages/datadog-instrumentations/src/mongoose.js +13 -2
- package/packages/datadog-instrumentations/src/playwright.js +13 -9
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1297 -0
- package/packages/datadog-instrumentations/src/vitest-main.js +1594 -0
- package/packages/datadog-instrumentations/src/vitest-util.js +254 -0
- package/packages/datadog-instrumentations/src/vitest-worker.js +823 -0
- package/packages/datadog-instrumentations/src/vitest.js +11 -1855
- package/packages/datadog-plugin-ai/src/index.js +1 -1
- package/packages/datadog-plugin-ai/src/tracing.js +66 -3
- package/packages/datadog-plugin-ai/src/utils.js +17 -4
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/client.js +2 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +19 -10
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +1 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +47 -11
- package/packages/datadog-plugin-child_process/src/index.js +13 -2
- package/packages/datadog-plugin-claude-agent-sdk/src/index.js +31 -0
- package/packages/datadog-plugin-claude-agent-sdk/src/tracing.js +107 -0
- package/packages/datadog-plugin-claude-agent-sdk/src/util.js +15 -0
- package/packages/datadog-plugin-cucumber/src/index.js +15 -24
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +360 -14
- package/packages/datadog-plugin-cypress/src/index.js +47 -2
- package/packages/datadog-plugin-cypress/src/plugin.js +1 -0
- package/packages/datadog-plugin-cypress/src/support.js +45 -1
- package/packages/datadog-plugin-express/src/code_origin.js +1 -1
- package/packages/datadog-plugin-fastify/src/code_origin.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +639 -12
- package/packages/datadog-plugin-graphql/src/index.js +37 -9
- package/packages/datadog-plugin-graphql/src/parse.js +24 -4
- package/packages/datadog-plugin-graphql/src/utils.js +9 -2
- package/packages/datadog-plugin-graphql/src/validate.js +17 -6
- package/packages/datadog-plugin-http/src/index.js +6 -8
- package/packages/datadog-plugin-jest/src/index.js +31 -15
- package/packages/datadog-plugin-mocha/src/index.js +40 -15
- package/packages/datadog-plugin-mongodb-core/src/bulk-write.js +43 -0
- package/packages/datadog-plugin-mongodb-core/src/index.js +8 -443
- package/packages/datadog-plugin-mongodb-core/src/query.js +452 -0
- package/packages/datadog-plugin-openai/src/services.js +2 -2
- package/packages/datadog-plugin-playwright/src/index.js +4 -3
- package/packages/datadog-plugin-vitest/src/index.js +120 -72
- package/packages/datadog-shimmer/src/shimmer.js +37 -16
- package/packages/dd-trace/src/aiguard/index.js +9 -14
- package/packages/dd-trace/src/aiguard/integrations/index.js +34 -0
- package/packages/dd-trace/src/aiguard/integrations/openai.js +47 -33
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +42 -28
- package/packages/dd-trace/src/aiguard/sdk.js +2 -2
- package/packages/dd-trace/src/appsec/api_security/sampler.js +3 -3
- package/packages/dd-trace/src/appsec/channels.js +3 -1
- package/packages/dd-trace/src/appsec/downstream_requests.js +4 -4
- package/packages/dd-trace/src/appsec/graphql.js +14 -11
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +23 -23
- package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
- package/packages/dd-trace/src/appsec/iast/telemetry/index.js +2 -1
- package/packages/dd-trace/src/appsec/index.js +10 -1
- package/packages/dd-trace/src/appsec/lambda.js +135 -0
- package/packages/dd-trace/src/appsec/reporter.js +49 -10
- package/packages/dd-trace/src/appsec/telemetry/index.js +1 -1
- package/packages/dd-trace/src/appsec/waf/index.js +16 -4
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +4 -4
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +26 -1
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +115 -24
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +21 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +5 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +6 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +130 -20
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +17 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +47 -26
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +2 -2
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +64 -53
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +3 -3
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +156 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +23 -5
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +128 -0
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +287 -0
- package/packages/dd-trace/src/config/defaults.js +3 -2
- package/packages/dd-trace/src/config/generated-config-types.d.ts +71 -57
- package/packages/dd-trace/src/config/helper.js +1 -0
- package/packages/dd-trace/src/config/index.js +35 -22
- package/packages/dd-trace/src/config/major-overrides.js +4 -2
- package/packages/dd-trace/src/config/remote_config.js +1 -1
- package/packages/dd-trace/src/config/supported-configurations.json +127 -56
- package/packages/dd-trace/src/constants.js +7 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -2
- package/packages/dd-trace/src/datastreams/processor.js +11 -3
- package/packages/dd-trace/src/exporters/agent/index.js +1 -1
- package/packages/dd-trace/src/exporters/agentless/writer.js +4 -4
- package/packages/dd-trace/src/llmobs/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +403 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +8 -395
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +27 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +363 -0
- package/packages/dd-trace/src/llmobs/plugins/base.js +4 -4
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +270 -0
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/utils.js +10 -0
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +3 -3
- package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
- package/packages/dd-trace/src/llmobs/tagger.js +3 -3
- package/packages/dd-trace/src/llmobs/writers/base.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +54 -5
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +40 -0
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +169 -0
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +38 -39
- package/packages/dd-trace/src/opentelemetry/span.js +5 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +4 -0
- package/packages/dd-trace/src/opentelemetry/tracer_provider.js +1 -1
- package/packages/dd-trace/src/opentracing/tracer.js +6 -1
- package/packages/dd-trace/src/plugin_manager.js +23 -7
- package/packages/dd-trace/src/plugins/ci_plugin.js +159 -10
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/llm.js +6 -1
- package/packages/dd-trace/src/plugins/util/test.js +15 -9
- package/packages/dd-trace/src/profiling/exporter_cli.js +2 -2
- package/packages/dd-trace/src/profiling/exporters/agent.js +28 -3
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +3 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
- package/packages/dd-trace/src/proxy.js +8 -8
- package/packages/dd-trace/src/span_processor.js +5 -6
- package/packages/dd-trace/src/span_stats.js +96 -78
- package/packages/dd-trace/src/startup-log.js +2 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
- package/packages/dd-trace/src/telemetry/endpoints.js +6 -4
- package/packages/dd-trace/src/telemetry/index.js +2 -2
- package/packages/dd-trace/src/telemetry/logs/index.js +1 -1
- package/packages/dd-trace/src/telemetry/send-data.js +8 -8
- package/packages/dd-trace/src/telemetry/session-propagation.js +1 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +9 -9
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/vendor/dist/shell-quote/index.js +1 -1
- package/packages/datadog-plugin-graphql/src/resolve.js +0 -170
|
@@ -30,12 +30,12 @@ const {
|
|
|
30
30
|
TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX,
|
|
31
31
|
TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED,
|
|
32
32
|
TEST_HAS_FAILED_ALL_RETRIES,
|
|
33
|
-
getLibraryCapabilitiesTags,
|
|
33
|
+
getLibraryCapabilitiesTags: getDefaultLibraryCapabilitiesTags,
|
|
34
34
|
TEST_RETRY_REASON_TYPES,
|
|
35
|
-
isModifiedTest,
|
|
36
35
|
TEST_IS_MODIFIED,
|
|
37
36
|
TEST_HAS_DYNAMIC_NAME,
|
|
38
37
|
TEST_FINAL_STATUS,
|
|
38
|
+
TEST_IS_TEST_FRAMEWORK_WORKER,
|
|
39
39
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
40
40
|
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
41
41
|
const {
|
|
@@ -67,52 +67,10 @@ class VitestPlugin extends CiPlugin {
|
|
|
67
67
|
testCommand: this.command,
|
|
68
68
|
repositoryRoot: this.repositoryRoot,
|
|
69
69
|
codeOwnersEntries: this.codeOwnersEntries,
|
|
70
|
+
testEnvironmentMetadata: this.testEnvironmentMetadata,
|
|
70
71
|
})
|
|
71
72
|
})
|
|
72
73
|
|
|
73
|
-
this.addSub('ci:vitest:test:is-new', ({ knownTests, testSuiteAbsolutePath, testName, onDone }) => {
|
|
74
|
-
// if for whatever reason the worker does not receive valid known tests, we don't consider it as new
|
|
75
|
-
if (!knownTests.vitest) {
|
|
76
|
-
return onDone(false)
|
|
77
|
-
}
|
|
78
|
-
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
79
|
-
const testsForThisTestSuite = knownTests.vitest[testSuite] || []
|
|
80
|
-
onDone(!testsForThisTestSuite.includes(testName))
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
this.addSub('ci:vitest:test:is-attempt-to-fix', ({
|
|
84
|
-
testManagementTests,
|
|
85
|
-
testSuiteAbsolutePath,
|
|
86
|
-
testName,
|
|
87
|
-
onDone,
|
|
88
|
-
}) => {
|
|
89
|
-
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
90
|
-
const { isAttemptToFix } = this.getTestProperties(testManagementTests, testSuite, testName)
|
|
91
|
-
|
|
92
|
-
onDone(isAttemptToFix ?? false)
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
this.addSub('ci:vitest:test:is-disabled', ({ testManagementTests, testSuiteAbsolutePath, testName, onDone }) => {
|
|
96
|
-
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
97
|
-
const { isDisabled } = this.getTestProperties(testManagementTests, testSuite, testName)
|
|
98
|
-
|
|
99
|
-
onDone(isDisabled)
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
this.addSub('ci:vitest:test:is-quarantined', ({ testManagementTests, testSuiteAbsolutePath, testName, onDone }) => {
|
|
103
|
-
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
104
|
-
const { isQuarantined } = this.getTestProperties(testManagementTests, testSuite, testName)
|
|
105
|
-
|
|
106
|
-
onDone(isQuarantined)
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
this.addSub('ci:vitest:test:is-modified', ({ modifiedFiles, testSuiteAbsolutePath, onDone }) => {
|
|
110
|
-
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
111
|
-
const isModified = isModifiedTest(testSuite, 0, 0, modifiedFiles, this.constructor.id)
|
|
112
|
-
|
|
113
|
-
onDone(isModified)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
74
|
this.addSub('ci:vitest:is-early-flake-detection-faulty', ({
|
|
117
75
|
knownTests,
|
|
118
76
|
testFilepaths,
|
|
@@ -141,12 +99,16 @@ class VitestPlugin extends CiPlugin {
|
|
|
141
99
|
isRetryReasonAttemptToFix,
|
|
142
100
|
isRetryReasonAtr,
|
|
143
101
|
isModified,
|
|
102
|
+
isTestFrameworkWorker,
|
|
103
|
+
requestErrorTags,
|
|
144
104
|
} = ctx
|
|
145
105
|
|
|
146
106
|
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
147
|
-
const store = storage('legacy').getStore()
|
|
107
|
+
const store = ctx.currentStore || storage('legacy').getStore()
|
|
108
|
+
const testSuiteSpan = store?.testSuiteSpan || this.testSuiteSpan
|
|
148
109
|
|
|
149
110
|
const extraTags = {
|
|
111
|
+
...requestErrorTags,
|
|
150
112
|
[TEST_SOURCE_FILE]: testSuite,
|
|
151
113
|
}
|
|
152
114
|
if (isRetry) {
|
|
@@ -179,11 +141,14 @@ class VitestPlugin extends CiPlugin {
|
|
|
179
141
|
if (isModified) {
|
|
180
142
|
extraTags[TEST_IS_MODIFIED] = 'true'
|
|
181
143
|
}
|
|
144
|
+
if (isTestFrameworkWorker) {
|
|
145
|
+
extraTags[TEST_IS_TEST_FRAMEWORK_WORKER] = 'true'
|
|
146
|
+
}
|
|
182
147
|
|
|
183
148
|
const span = this.startTestSpan(
|
|
184
149
|
testName,
|
|
185
150
|
testSuite,
|
|
186
|
-
|
|
151
|
+
testSuiteSpan,
|
|
187
152
|
extraTags
|
|
188
153
|
)
|
|
189
154
|
|
|
@@ -204,7 +169,7 @@ class VitestPlugin extends CiPlugin {
|
|
|
204
169
|
})
|
|
205
170
|
|
|
206
171
|
this.addBind('ci:vitest:test:finish-time', (ctx) => {
|
|
207
|
-
const { status, task, attemptToFixPassed, attemptToFixFailed } = ctx
|
|
172
|
+
const { status, task, attemptToFixPassed, attemptToFixFailed, duration } = ctx
|
|
208
173
|
const span = ctx.currentStore?.span
|
|
209
174
|
|
|
210
175
|
// we store the finish time to finish at a later hook
|
|
@@ -218,7 +183,8 @@ class VitestPlugin extends CiPlugin {
|
|
|
218
183
|
span.setTag(TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED, 'false')
|
|
219
184
|
}
|
|
220
185
|
|
|
221
|
-
|
|
186
|
+
const finishTime = typeof duration === 'number' ? span._startTime + duration : span._getTime()
|
|
187
|
+
this.taskToFinishTime.set(task, finishTime)
|
|
222
188
|
|
|
223
189
|
ctx.parentStore = ctx.currentStore
|
|
224
190
|
ctx.currentStore = { ...ctx.currentStore, span }
|
|
@@ -227,7 +193,7 @@ class VitestPlugin extends CiPlugin {
|
|
|
227
193
|
return ctx.currentStore
|
|
228
194
|
})
|
|
229
195
|
|
|
230
|
-
this.addSub('ci:vitest:test:pass', ({ span, task, finalStatus, earlyFlakeAbortReason }) => {
|
|
196
|
+
this.addSub('ci:vitest:test:pass', ({ span, task, finalStatus, earlyFlakeAbortReason, promises }) => {
|
|
231
197
|
if (span) {
|
|
232
198
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'test', this.getTestTelemetryTags(span))
|
|
233
199
|
span.setTag(TEST_STATUS, 'pass')
|
|
@@ -237,8 +203,21 @@ class VitestPlugin extends CiPlugin {
|
|
|
237
203
|
if (earlyFlakeAbortReason) {
|
|
238
204
|
span.setTag(TEST_EARLY_FLAKE_ABORT_REASON, earlyFlakeAbortReason)
|
|
239
205
|
}
|
|
240
|
-
|
|
241
|
-
|
|
206
|
+
const finish = () => {
|
|
207
|
+
span.finish(this.taskToFinishTime.get(task))
|
|
208
|
+
finishAllTraceSpans(span)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (finalStatus) {
|
|
212
|
+
if (promises && this.diBreakpointHitPromise) {
|
|
213
|
+
promises.hitBreakpointPromise = this.waitForPreparedDiBreakpointHit().then(finish)
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
finish()
|
|
217
|
+
this.cancelDiBreakpointHitWait()
|
|
218
|
+
return
|
|
219
|
+
}
|
|
220
|
+
finish()
|
|
242
221
|
}
|
|
243
222
|
})
|
|
244
223
|
|
|
@@ -247,6 +226,7 @@ class VitestPlugin extends CiPlugin {
|
|
|
247
226
|
duration,
|
|
248
227
|
error,
|
|
249
228
|
shouldSetProbe,
|
|
229
|
+
shouldWaitForHitProbe,
|
|
250
230
|
promises,
|
|
251
231
|
hasFailedAllRetries,
|
|
252
232
|
attemptToFixFailed,
|
|
@@ -262,7 +242,8 @@ class VitestPlugin extends CiPlugin {
|
|
|
262
242
|
const { file, line, stackIndex, setProbePromise } = probeInformation
|
|
263
243
|
this.runningTestProbe = { file, line }
|
|
264
244
|
this.testErrorStackIndex = stackIndex
|
|
265
|
-
|
|
245
|
+
this.prepareDiBreakpointHitWait()
|
|
246
|
+
promises.setProbePromise = this.waitForDiOperation(setProbePromise)
|
|
266
247
|
}
|
|
267
248
|
}
|
|
268
249
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'test', this.getTestTelemetryTags(span))
|
|
@@ -283,27 +264,56 @@ class VitestPlugin extends CiPlugin {
|
|
|
283
264
|
if (earlyFlakeAbortReason) {
|
|
284
265
|
span.setTag(TEST_EARLY_FLAKE_ABORT_REASON, earlyFlakeAbortReason)
|
|
285
266
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
267
|
+
const finish = () => {
|
|
268
|
+
if (duration) {
|
|
269
|
+
span.finish(span._startTime + duration - MILLISECONDS_TO_SUBTRACT_FROM_FAILED_TEST_DURATION) // milliseconds
|
|
270
|
+
} else {
|
|
271
|
+
span.finish() // `duration` is empty for retries, so we'll use clock time
|
|
272
|
+
}
|
|
273
|
+
finishAllTraceSpans(span)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (!shouldSetProbe && finalStatus && promises && this.diBreakpointHitPromise) {
|
|
277
|
+
promises.hitBreakpointPromise = this.waitForPreparedDiBreakpointHit().then(finish)
|
|
278
|
+
return
|
|
279
|
+
}
|
|
280
|
+
finish()
|
|
281
|
+
if (shouldWaitForHitProbe) {
|
|
282
|
+
this.prepareDiBreakpointHitWait()
|
|
283
|
+
} else if (!shouldSetProbe) {
|
|
284
|
+
this.cancelDiBreakpointHitWait()
|
|
285
|
+
}
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
this.addSub('ci:vitest:test:di:wait', ({ promises }) => {
|
|
289
|
+
if (this.di) {
|
|
290
|
+
promises.hitBreakpointPromise = this.waitForDiBreakpointHits()
|
|
290
291
|
}
|
|
291
|
-
finishAllTraceSpans(span)
|
|
292
292
|
})
|
|
293
293
|
|
|
294
|
-
this.addSub('ci:vitest:test:skip', ({
|
|
294
|
+
this.addSub('ci:vitest:test:skip', ({
|
|
295
|
+
testName,
|
|
296
|
+
testSuiteAbsolutePath,
|
|
297
|
+
isNew,
|
|
298
|
+
isDisabled,
|
|
299
|
+
isTestFrameworkWorker,
|
|
300
|
+
requestErrorTags,
|
|
301
|
+
testSuiteSpan,
|
|
302
|
+
}) => {
|
|
295
303
|
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
296
304
|
const testSpan = this.startTestSpan(
|
|
297
305
|
testName,
|
|
298
306
|
testSuite,
|
|
299
|
-
this.testSuiteSpan,
|
|
307
|
+
testSuiteSpan || this.testSuiteSpan,
|
|
300
308
|
{
|
|
309
|
+
...requestErrorTags,
|
|
301
310
|
[TEST_SOURCE_FILE]: testSuite,
|
|
302
311
|
[TEST_SOURCE_START]: 1, // we can't get the proper start line in vitest
|
|
303
312
|
[TEST_STATUS]: 'skip',
|
|
304
313
|
[TEST_FINAL_STATUS]: 'skip',
|
|
305
314
|
...(isDisabled ? { [TEST_MANAGEMENT_IS_DISABLED]: 'true' } : {}),
|
|
306
315
|
...(isNew ? { [TEST_IS_NEW]: 'true' } : {}),
|
|
316
|
+
...(isTestFrameworkWorker ? { [TEST_IS_TEST_FRAMEWORK_WORKER]: 'true' } : {}),
|
|
307
317
|
}
|
|
308
318
|
)
|
|
309
319
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'test', this.getTestTelemetryTags(testSpan))
|
|
@@ -311,10 +321,25 @@ class VitestPlugin extends CiPlugin {
|
|
|
311
321
|
})
|
|
312
322
|
|
|
313
323
|
this.addBind('ci:vitest:test-suite:start', (ctx) => {
|
|
314
|
-
const {
|
|
324
|
+
const {
|
|
325
|
+
codeOwnersEntries,
|
|
326
|
+
repositoryRoot,
|
|
327
|
+
testEnvironmentMetadata,
|
|
328
|
+
requestErrorTags,
|
|
329
|
+
testSuiteAbsolutePath,
|
|
330
|
+
frameworkVersion,
|
|
331
|
+
isTestFrameworkWorker,
|
|
332
|
+
isVitestNoWorkerInitActive,
|
|
333
|
+
} = ctx
|
|
315
334
|
|
|
316
335
|
const testCommand = ctx.testCommand || 'vitest run'
|
|
317
336
|
const { testSessionId, testModuleId } = ctx
|
|
337
|
+
if (testEnvironmentMetadata) {
|
|
338
|
+
this.testEnvironmentMetadata = {
|
|
339
|
+
...this.testEnvironmentMetadata,
|
|
340
|
+
...testEnvironmentMetadata,
|
|
341
|
+
}
|
|
342
|
+
}
|
|
318
343
|
this._setRepositoryRoot(repositoryRoot, codeOwnersEntries)
|
|
319
344
|
this.command = testCommand
|
|
320
345
|
this.frameworkVersion = frameworkVersion
|
|
@@ -329,13 +354,16 @@ class VitestPlugin extends CiPlugin {
|
|
|
329
354
|
// test suites run in a different process, so they also need to init the metadata dictionary
|
|
330
355
|
const testSessionName = getTestSessionName(this.config, trimmedCommand, this.testEnvironmentMetadata)
|
|
331
356
|
if (this.tracer._exporter.addMetadataTags) {
|
|
357
|
+
const libraryCapabilitiesTags = this.getLibraryCapabilitiesTags(frameworkVersion, {
|
|
358
|
+
isVitestNoWorkerInitActive,
|
|
359
|
+
})
|
|
332
360
|
this.tracer._exporter.addMetadataTags({
|
|
333
361
|
[TEST_LEVELS_METADATA]: {
|
|
334
362
|
[TEST_COMMAND]: testCommand,
|
|
335
363
|
[TEST_SESSION_NAME]: testSessionName,
|
|
336
364
|
...getTestLevelsMetadataTags(this.testEnvironmentMetadata),
|
|
337
365
|
},
|
|
338
|
-
test:
|
|
366
|
+
test: libraryCapabilitiesTags,
|
|
339
367
|
})
|
|
340
368
|
}
|
|
341
369
|
|
|
@@ -348,9 +376,13 @@ class VitestPlugin extends CiPlugin {
|
|
|
348
376
|
testSuite,
|
|
349
377
|
'vitest'
|
|
350
378
|
),
|
|
379
|
+
...requestErrorTags,
|
|
351
380
|
[TEST_SOURCE_FILE]: testSuite,
|
|
352
381
|
[TEST_SOURCE_START]: 1,
|
|
353
382
|
}
|
|
383
|
+
if (isTestFrameworkWorker) {
|
|
384
|
+
testSuiteMetadata[TEST_IS_TEST_FRAMEWORK_WORKER] = 'true'
|
|
385
|
+
}
|
|
354
386
|
|
|
355
387
|
const codeOwners = this.getCodeOwners(testSuiteMetadata)
|
|
356
388
|
if (codeOwners) {
|
|
@@ -374,13 +406,17 @@ class VitestPlugin extends CiPlugin {
|
|
|
374
406
|
return ctx.currentStore
|
|
375
407
|
})
|
|
376
408
|
|
|
377
|
-
this.addSub('ci:vitest:test-suite:finish', ({ testSuiteSpan, status, onFinish }) => {
|
|
409
|
+
this.addSub('ci:vitest:test-suite:finish', ({ testSuiteSpan, status, deferFlush, onFinish }) => {
|
|
378
410
|
if (testSuiteSpan) {
|
|
379
411
|
testSuiteSpan.setTag(TEST_STATUS, status)
|
|
380
412
|
testSuiteSpan.finish()
|
|
381
413
|
finishAllTraceSpans(testSuiteSpan)
|
|
382
414
|
}
|
|
383
415
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'suite')
|
|
416
|
+
if (deferFlush) {
|
|
417
|
+
onFinish()
|
|
418
|
+
return
|
|
419
|
+
}
|
|
384
420
|
this.tracer._exporter.flush(onFinish)
|
|
385
421
|
if (this.runningTestProbe) {
|
|
386
422
|
this.removeDiProbe(this.runningTestProbe)
|
|
@@ -409,9 +445,15 @@ class VitestPlugin extends CiPlugin {
|
|
|
409
445
|
isEarlyFlakeDetectionEnabled,
|
|
410
446
|
isEarlyFlakeDetectionFaulty,
|
|
411
447
|
isTestManagementTestsEnabled,
|
|
448
|
+
requestErrorTags,
|
|
412
449
|
vitestPool,
|
|
450
|
+
isVitestNoWorkerInitActive,
|
|
413
451
|
onFinish,
|
|
414
452
|
}) => {
|
|
453
|
+
for (const [tag, value] of Object.entries(requestErrorTags || {})) {
|
|
454
|
+
this.testSessionSpan.setTag(tag, value)
|
|
455
|
+
this.testModuleSpan.setTag(tag, value)
|
|
456
|
+
}
|
|
415
457
|
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
416
458
|
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
417
459
|
if (error) {
|
|
@@ -438,12 +480,12 @@ class VitestPlugin extends CiPlugin {
|
|
|
438
480
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'module')
|
|
439
481
|
this.testSessionSpan.finish()
|
|
440
482
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'session', {
|
|
441
|
-
hasFailedTestReplay: this.libraryConfig?.isDiEnabled
|
|
483
|
+
hasFailedTestReplay: this.libraryConfig?.isDiEnabled && !isVitestNoWorkerInitActive ? true : undefined,
|
|
442
484
|
})
|
|
443
485
|
finishAllTraceSpans(this.testSessionSpan)
|
|
444
486
|
this.telemetry.count(TELEMETRY_TEST_SESSION, {
|
|
445
487
|
provider: this.ciProviderName,
|
|
446
|
-
autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
|
|
488
|
+
autoInjected: !!this._tracerConfig.testOptimization.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
|
|
447
489
|
})
|
|
448
490
|
this.tracer._exporter.flush(onFinish)
|
|
449
491
|
})
|
|
@@ -453,6 +495,19 @@ class VitestPlugin extends CiPlugin {
|
|
|
453
495
|
})
|
|
454
496
|
}
|
|
455
497
|
|
|
498
|
+
/**
|
|
499
|
+
* Returns Vitest library capability metadata tags.
|
|
500
|
+
* @param {string} frameworkVersion - The Vitest version.
|
|
501
|
+
* @param {object} [ctx] - Diagnostic channel context.
|
|
502
|
+
* @param {boolean} [ctx.isVitestNoWorkerInitActive] - Whether no-worker init is active for this run.
|
|
503
|
+
* @returns {Record<string, string|undefined>}
|
|
504
|
+
*/
|
|
505
|
+
getLibraryCapabilitiesTags (frameworkVersion, ctx = {}) {
|
|
506
|
+
return getDefaultLibraryCapabilitiesTags(this.constructor.id, frameworkVersion, {
|
|
507
|
+
omitFailedTestReplay: ctx.isVitestNoWorkerInitActive,
|
|
508
|
+
})
|
|
509
|
+
}
|
|
510
|
+
|
|
456
511
|
/**
|
|
457
512
|
* Handles the coverage report by discovering and uploading it if enabled.
|
|
458
513
|
* @param {string} rootDir - The root directory where coverage reports are located.
|
|
@@ -469,13 +524,6 @@ class VitestPlugin extends CiPlugin {
|
|
|
469
524
|
onDone,
|
|
470
525
|
})
|
|
471
526
|
}
|
|
472
|
-
|
|
473
|
-
getTestProperties (testManagementTests, testSuite, testName) {
|
|
474
|
-
const { attempt_to_fix: isAttemptToFix, disabled: isDisabled, quarantined: isQuarantined } =
|
|
475
|
-
testManagementTests?.vitest?.suites?.[testSuite]?.tests?.[testName]?.properties || {}
|
|
476
|
-
|
|
477
|
-
return { isAttemptToFix, isDisabled, isQuarantined }
|
|
478
|
-
}
|
|
479
527
|
}
|
|
480
528
|
|
|
481
529
|
module.exports = VitestPlugin
|
|
@@ -119,11 +119,14 @@ function wrapCallback (original, wrapper) {
|
|
|
119
119
|
* object.
|
|
120
120
|
* @param {string | symbol} name - The property key of the method to wrap.
|
|
121
121
|
* @param {(original: Function) => (...args: unknown[]) => unknown} wrapper - The wrapper function.
|
|
122
|
-
* @param {{ replaceGetter?: boolean }} [options] -
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
122
|
+
* @param {{ replaceGetter?: boolean }} [options] - By default the getter is
|
|
123
|
+
* wrapped in place, so each property access runs the wrapper. A getter+setter
|
|
124
|
+
* pair keeps its setter; a setter-only property throws. If `replaceGetter` is
|
|
125
|
+
* true, the getter is instead accessed once and replaced with one returning the
|
|
126
|
+
* resolved wrapped value — for a lazy getter+setter pair (e.g. Node 20's
|
|
127
|
+
* `fs.opendir`) the setter is rebuilt to materialize a writable data property on
|
|
128
|
+
* assignment, keeping the descriptor observationally identical for downstream
|
|
129
|
+
* consumers. Use with care! This may only be done when the getter has no side effect.
|
|
127
130
|
* @returns {Record<string | symbol, unknown> | Function | undefined} The target object with
|
|
128
131
|
* the wrapped method.
|
|
129
132
|
*/
|
|
@@ -151,17 +154,13 @@ function wrap (target, name, wrapper, options) {
|
|
|
151
154
|
enumerable: false,
|
|
152
155
|
}
|
|
153
156
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
// this is not a common use case.
|
|
159
|
-
throw new Error(options?.replaceGetter
|
|
160
|
-
? 'Replacing a getter/setter pair is not supported. Implement if required.'
|
|
161
|
-
: 'Replacing setters is not supported. Implement if required.')
|
|
157
|
+
// A setter-only property has nothing to wrap. Instrumenting the setter is not
|
|
158
|
+
// implemented; a getter+setter pair is handled below.
|
|
159
|
+
if (descriptor.set && !descriptor.get) {
|
|
160
|
+
throw new Error('Replacing setters is not supported. Implement if required.')
|
|
162
161
|
}
|
|
163
162
|
|
|
164
|
-
const original = descriptor.value ?? options?.replaceGetter ? target[name] : descriptor.get
|
|
163
|
+
const original = (descriptor.value ?? options?.replaceGetter) ? target[name] : descriptor.get
|
|
165
164
|
|
|
166
165
|
assertMethod(target, name, original)
|
|
167
166
|
|
|
@@ -176,8 +175,30 @@ function wrap (target, name, wrapper, options) {
|
|
|
176
175
|
}
|
|
177
176
|
descriptor.value = wrapped
|
|
178
177
|
} else {
|
|
179
|
-
if (descriptor.
|
|
180
|
-
//
|
|
178
|
+
if (descriptor.set && options?.replaceGetter) {
|
|
179
|
+
// A lazy accessor pair (e.g. Node 20's `fs.opendir`). `original` already
|
|
180
|
+
// resolved the value through the getter. Keep the property an accessor pair
|
|
181
|
+
// so the shape stays observationally identical — a downstream consumer may
|
|
182
|
+
// read the descriptor or assign to it on a specific Node.js version. The
|
|
183
|
+
// getter returns the wrapped value; the setter mirrors the native lazy
|
|
184
|
+
// contract (assignment self-replaces the property with a writable data
|
|
185
|
+
// property holding the assigned value), so a caller that overwrites the
|
|
186
|
+
// method gets exactly what they set, unwrapped, as before. The descriptor
|
|
187
|
+
// is the original accessor descriptor (no `value`/`writable` slots), so
|
|
188
|
+
// reassigning `get`/`set` keeps it a valid accessor descriptor.
|
|
189
|
+
descriptor.get = () => wrapped
|
|
190
|
+
descriptor.set = function (value) {
|
|
191
|
+
Object.defineProperty(this, name, {
|
|
192
|
+
configurable: descriptor.configurable,
|
|
193
|
+
enumerable: descriptor.enumerable,
|
|
194
|
+
writable: true,
|
|
195
|
+
value,
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
} else if (descriptor.get) {
|
|
199
|
+
// Wrap the getter in place; for a getter+setter pair the original setter
|
|
200
|
+
// stays untouched. `replaceGetter` (no side effect on read) instead returns
|
|
201
|
+
// the value resolved once into `wrapped`.
|
|
181
202
|
descriptor.get = options?.replaceGetter ? () => wrapped : wrapped
|
|
182
203
|
} else {
|
|
183
204
|
descriptor.value = wrapped
|
|
@@ -2,15 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
const log = require('../log')
|
|
4
4
|
const { incomingHttpRequestStart } = require('./channels')
|
|
5
|
-
const
|
|
6
|
-
const vercelAiIntegration = require('./integrations/vercel-ai')
|
|
5
|
+
const integrations = require('./integrations')
|
|
7
6
|
const AIGuard = require('./sdk')
|
|
8
7
|
|
|
9
8
|
let isEnabled = false
|
|
10
9
|
let aiguard
|
|
11
|
-
let block
|
|
12
|
-
let disableOpenAIIntegration
|
|
13
|
-
let disableVercelAiIntegration
|
|
14
10
|
|
|
15
11
|
function onIncomingHttpRequestStart () {
|
|
16
12
|
// No-op: subscribing ensures the HTTP plugin spreads req onto the store
|
|
@@ -21,31 +17,30 @@ function enable (tracer, config) {
|
|
|
21
17
|
|
|
22
18
|
try {
|
|
23
19
|
aiguard = new AIGuard(tracer, config)
|
|
24
|
-
block = config.experimental?.aiguard?.block !== false
|
|
20
|
+
const block = config.experimental?.aiguard?.block !== false
|
|
25
21
|
|
|
26
22
|
incomingHttpRequestStart.subscribe(onIncomingHttpRequestStart)
|
|
27
|
-
|
|
28
|
-
disableVercelAiIntegration = vercelAiIntegration.enable(aiguard, block)
|
|
23
|
+
integrations.enable(aiguard, block)
|
|
29
24
|
|
|
30
25
|
isEnabled = true
|
|
31
26
|
} catch (err) {
|
|
32
27
|
log.error('AIGuard: unexpected error during initialization: %s', err.message)
|
|
33
|
-
|
|
28
|
+
reset()
|
|
34
29
|
}
|
|
35
30
|
}
|
|
36
31
|
|
|
37
32
|
function disable () {
|
|
38
33
|
if (!isEnabled) return
|
|
39
34
|
|
|
35
|
+
reset()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function reset () {
|
|
40
39
|
incomingHttpRequestStart.unsubscribe(onIncomingHttpRequestStart)
|
|
41
|
-
|
|
42
|
-
disableVercelAiIntegration?.()
|
|
40
|
+
integrations.disable()
|
|
43
41
|
|
|
44
42
|
aiguard = undefined
|
|
45
43
|
isEnabled = false
|
|
46
|
-
block = false
|
|
47
|
-
disableOpenAIIntegration = undefined
|
|
48
|
-
disableVercelAiIntegration = undefined
|
|
49
44
|
}
|
|
50
45
|
|
|
51
46
|
module.exports = { enable, disable }
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const openai = require('./openai')
|
|
4
|
+
const vercelAi = require('./vercel-ai')
|
|
5
|
+
|
|
6
|
+
let isEnabled = false
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Enables all AI Guard provider integrations.
|
|
10
|
+
*
|
|
11
|
+
* @param {object} aiguard
|
|
12
|
+
* @param {boolean} block
|
|
13
|
+
*/
|
|
14
|
+
function enable (aiguard, block) {
|
|
15
|
+
if (isEnabled) return
|
|
16
|
+
|
|
17
|
+
openai.enable(aiguard, block)
|
|
18
|
+
vercelAi.enable(aiguard, block)
|
|
19
|
+
|
|
20
|
+
isEnabled = true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function disable () {
|
|
24
|
+
vercelAi.disable()
|
|
25
|
+
openai.disable()
|
|
26
|
+
isEnabled = false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = {
|
|
30
|
+
enable,
|
|
31
|
+
disable,
|
|
32
|
+
openai,
|
|
33
|
+
vercelAi,
|
|
34
|
+
}
|
|
@@ -16,51 +16,65 @@ const chatCompletionsAfterChannel = channel('dd-trace:openai:chat.completions:af
|
|
|
16
16
|
const responsesBeforeChannel = channel('dd-trace:openai:responses:before')
|
|
17
17
|
const responsesAfterChannel = channel('dd-trace:openai:responses:after')
|
|
18
18
|
|
|
19
|
+
let isEnabled = false
|
|
20
|
+
let aiguard
|
|
21
|
+
let opts
|
|
22
|
+
|
|
19
23
|
/**
|
|
20
24
|
* Subscribes AI Guard to OpenAI lifecycle channels.
|
|
21
25
|
*
|
|
22
|
-
* @param {object}
|
|
26
|
+
* @param {object} aiguardInstance
|
|
23
27
|
* @param {boolean} block
|
|
24
|
-
* @returns {() => void}
|
|
25
28
|
*/
|
|
26
|
-
function enable (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
function onChatCompletionsBefore (ctx) {
|
|
30
|
-
pushEvaluation(ctx, aiguard, getChatCompletionsInputMessages(ctx.args?.[0]), opts)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function onChatCompletionsAfter (ctx) {
|
|
34
|
-
const inputMessages = getChatCompletionsInputMessages(ctx.args?.[0])
|
|
35
|
-
if (!inputMessages?.length) return
|
|
36
|
-
for (const message of getChatCompletionsOutputMessages(ctx.body)) {
|
|
37
|
-
pushEvaluation(ctx, aiguard, [...inputMessages, message], opts)
|
|
38
|
-
}
|
|
39
|
-
}
|
|
29
|
+
function enable (aiguardInstance, block) {
|
|
30
|
+
if (isEnabled) return
|
|
40
31
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function onResponsesAfter (ctx) {
|
|
46
|
-
const inputMessages = getResponsesInputMessages(ctx.args?.[0])
|
|
47
|
-
if (!inputMessages?.length) return
|
|
48
|
-
const outputMessages = getResponsesOutputMessages(ctx.body)
|
|
49
|
-
if (!outputMessages.length) return
|
|
50
|
-
pushEvaluation(ctx, aiguard, [...inputMessages, ...outputMessages], opts)
|
|
51
|
-
}
|
|
32
|
+
aiguard = aiguardInstance
|
|
33
|
+
opts = { block, source: SOURCE_AUTO, integration: 'openai' }
|
|
52
34
|
|
|
53
35
|
chatCompletionsBeforeChannel.subscribe(onChatCompletionsBefore)
|
|
54
36
|
chatCompletionsAfterChannel.subscribe(onChatCompletionsAfter)
|
|
55
37
|
responsesBeforeChannel.subscribe(onResponsesBefore)
|
|
56
38
|
responsesAfterChannel.subscribe(onResponsesAfter)
|
|
57
39
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
40
|
+
isEnabled = true
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function disable () {
|
|
44
|
+
if (!isEnabled) return
|
|
45
|
+
|
|
46
|
+
chatCompletionsBeforeChannel.unsubscribe(onChatCompletionsBefore)
|
|
47
|
+
chatCompletionsAfterChannel.unsubscribe(onChatCompletionsAfter)
|
|
48
|
+
responsesBeforeChannel.unsubscribe(onResponsesBefore)
|
|
49
|
+
responsesAfterChannel.unsubscribe(onResponsesAfter)
|
|
50
|
+
|
|
51
|
+
aiguard = undefined
|
|
52
|
+
opts = undefined
|
|
53
|
+
isEnabled = false
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function onChatCompletionsBefore (ctx) {
|
|
57
|
+
pushEvaluation(ctx, aiguard, getChatCompletionsInputMessages(ctx.args?.[0]), opts)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function onChatCompletionsAfter (ctx) {
|
|
61
|
+
const inputMessages = getChatCompletionsInputMessages(ctx.args?.[0])
|
|
62
|
+
if (!inputMessages?.length) return
|
|
63
|
+
for (const message of getChatCompletionsOutputMessages(ctx.body)) {
|
|
64
|
+
pushEvaluation(ctx, aiguard, [...inputMessages, message], opts)
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
67
|
|
|
66
|
-
|
|
68
|
+
function onResponsesBefore (ctx) {
|
|
69
|
+
pushEvaluation(ctx, aiguard, getResponsesInputMessages(ctx.args?.[0]), opts)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function onResponsesAfter (ctx) {
|
|
73
|
+
const inputMessages = getResponsesInputMessages(ctx.args?.[0])
|
|
74
|
+
if (!inputMessages?.length) return
|
|
75
|
+
const outputMessages = getResponsesOutputMessages(ctx.body)
|
|
76
|
+
if (!outputMessages.length) return
|
|
77
|
+
pushEvaluation(ctx, aiguard, [...inputMessages, ...outputMessages], opts)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports = { enable, disable }
|