dd-trace 5.32.0 → 5.33.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/README.md +12 -11
- package/index.d.ts +11 -1
- package/package.json +2 -2
- package/packages/datadog-instrumentations/src/aws-sdk.js +3 -1
- package/packages/datadog-instrumentations/src/cucumber.js +17 -9
- package/packages/datadog-instrumentations/src/jest.js +36 -21
- package/packages/datadog-instrumentations/src/mocha/main.js +9 -4
- package/packages/datadog-instrumentations/src/mocha/utils.js +4 -2
- package/packages/datadog-instrumentations/src/mocha/worker.js +4 -2
- package/packages/datadog-instrumentations/src/playwright.js +8 -3
- package/packages/datadog-instrumentations/src/vitest.js +35 -11
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +16 -0
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +63 -0
- package/packages/datadog-plugin-aws-sdk/src/services/{bedrockruntime.js → bedrockruntime/utils.js} +67 -75
- package/packages/datadog-plugin-cucumber/src/index.js +3 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +19 -8
- package/packages/datadog-plugin-cypress/src/support.js +6 -2
- package/packages/datadog-plugin-fetch/src/index.js +3 -3
- package/packages/datadog-plugin-http/src/client.js +5 -33
- package/packages/datadog-plugin-jest/src/index.js +4 -1
- package/packages/datadog-plugin-mocha/src/index.js +3 -1
- package/packages/datadog-plugin-playwright/src/index.js +3 -1
- package/packages/datadog-plugin-vitest/src/index.js +16 -4
- package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +3 -3
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +41 -24
- package/packages/dd-trace/src/appsec/iast/iast-context.js +12 -0
- package/packages/dd-trace/src/appsec/iast/path-line.js +19 -23
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +75 -24
- package/packages/dd-trace/src/appsec/rasp/utils.js +10 -5
- package/packages/dd-trace/src/appsec/stack_trace.js +38 -28
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +5 -4
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +5 -3
- package/packages/dd-trace/src/config.js +4 -0
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +59 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +1 -0
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +0 -2
- package/packages/dd-trace/src/plugins/util/test.js +2 -0
|
@@ -25,6 +25,7 @@ const isEarlyFlakeDetectionFaultyCh = channel('ci:vitest:is-early-flake-detectio
|
|
|
25
25
|
const taskToAsync = new WeakMap()
|
|
26
26
|
const taskToStatuses = new WeakMap()
|
|
27
27
|
const newTasks = new WeakSet()
|
|
28
|
+
let isRetryReasonEfd = false
|
|
28
29
|
const switchedStatuses = new WeakSet()
|
|
29
30
|
const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
30
31
|
|
|
@@ -44,14 +45,16 @@ function getProvidedContext () {
|
|
|
44
45
|
_ddIsEarlyFlakeDetectionEnabled,
|
|
45
46
|
_ddIsDiEnabled,
|
|
46
47
|
_ddKnownTests: knownTests,
|
|
47
|
-
_ddEarlyFlakeDetectionNumRetries: numRepeats
|
|
48
|
+
_ddEarlyFlakeDetectionNumRetries: numRepeats,
|
|
49
|
+
_ddIsKnownTestsEnabled: isKnownTestsEnabled
|
|
48
50
|
} = globalThis.__vitest_worker__.providedContext
|
|
49
51
|
|
|
50
52
|
return {
|
|
51
53
|
isDiEnabled: _ddIsDiEnabled,
|
|
52
54
|
isEarlyFlakeDetectionEnabled: _ddIsEarlyFlakeDetectionEnabled,
|
|
53
55
|
knownTests,
|
|
54
|
-
numRepeats
|
|
56
|
+
numRepeats,
|
|
57
|
+
isKnownTestsEnabled
|
|
55
58
|
}
|
|
56
59
|
} catch (e) {
|
|
57
60
|
log.error('Vitest workers could not parse provided context, so some features will not work.')
|
|
@@ -59,7 +62,8 @@ function getProvidedContext () {
|
|
|
59
62
|
isDiEnabled: false,
|
|
60
63
|
isEarlyFlakeDetectionEnabled: false,
|
|
61
64
|
knownTests: {},
|
|
62
|
-
numRepeats: 0
|
|
65
|
+
numRepeats: 0,
|
|
66
|
+
isKnownTestsEnabled: false
|
|
63
67
|
}
|
|
64
68
|
}
|
|
65
69
|
}
|
|
@@ -153,6 +157,7 @@ function getSortWrapper (sort) {
|
|
|
153
157
|
let isEarlyFlakeDetectionEnabled = false
|
|
154
158
|
let earlyFlakeDetectionNumRetries = 0
|
|
155
159
|
let isEarlyFlakeDetectionFaulty = false
|
|
160
|
+
let isKnownTestsEnabled = false
|
|
156
161
|
let isDiEnabled = false
|
|
157
162
|
let knownTests = {}
|
|
158
163
|
|
|
@@ -164,18 +169,20 @@ function getSortWrapper (sort) {
|
|
|
164
169
|
isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
|
|
165
170
|
earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
|
|
166
171
|
isDiEnabled = libraryConfig.isDiEnabled
|
|
172
|
+
isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
|
|
167
173
|
}
|
|
168
174
|
} catch (e) {
|
|
169
175
|
isFlakyTestRetriesEnabled = false
|
|
170
176
|
isEarlyFlakeDetectionEnabled = false
|
|
171
177
|
isDiEnabled = false
|
|
178
|
+
isKnownTestsEnabled = false
|
|
172
179
|
}
|
|
173
180
|
|
|
174
181
|
if (isFlakyTestRetriesEnabled && !this.ctx.config.retry && flakyTestRetriesCount > 0) {
|
|
175
182
|
this.ctx.config.retry = flakyTestRetriesCount
|
|
176
183
|
}
|
|
177
184
|
|
|
178
|
-
if (
|
|
185
|
+
if (isKnownTestsEnabled) {
|
|
179
186
|
const knownTestsResponse = await getChannelPromise(knownTestsCh)
|
|
180
187
|
if (!knownTestsResponse.err) {
|
|
181
188
|
knownTests = knownTestsResponse.knownTests
|
|
@@ -192,13 +199,15 @@ function getSortWrapper (sort) {
|
|
|
192
199
|
})
|
|
193
200
|
if (isEarlyFlakeDetectionFaulty) {
|
|
194
201
|
isEarlyFlakeDetectionEnabled = false
|
|
195
|
-
|
|
202
|
+
isKnownTestsEnabled = false
|
|
203
|
+
log.warn('New test detection is disabled because the number of new tests is too high.')
|
|
196
204
|
} else {
|
|
197
205
|
// TODO: use this to pass session and module IDs to the worker, instead of polluting process.env
|
|
198
206
|
// Note: setting this.ctx.config.provide directly does not work because it's cached
|
|
199
207
|
try {
|
|
200
208
|
const workspaceProject = this.ctx.getCoreWorkspaceProject()
|
|
201
|
-
workspaceProject._provided.
|
|
209
|
+
workspaceProject._provided._ddIsKnownTestsEnabled = isKnownTestsEnabled
|
|
210
|
+
workspaceProject._provided._ddKnownTests = knownTests.vitest || {}
|
|
202
211
|
workspaceProject._provided._ddIsEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
|
|
203
212
|
workspaceProject._provided._ddEarlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
|
|
204
213
|
} catch (e) {
|
|
@@ -207,6 +216,7 @@ function getSortWrapper (sort) {
|
|
|
207
216
|
}
|
|
208
217
|
} else {
|
|
209
218
|
isEarlyFlakeDetectionEnabled = false
|
|
219
|
+
isKnownTestsEnabled = false
|
|
210
220
|
}
|
|
211
221
|
}
|
|
212
222
|
|
|
@@ -295,17 +305,21 @@ addHook({
|
|
|
295
305
|
const {
|
|
296
306
|
knownTests,
|
|
297
307
|
isEarlyFlakeDetectionEnabled,
|
|
308
|
+
isKnownTestsEnabled,
|
|
298
309
|
numRepeats
|
|
299
310
|
} = getProvidedContext()
|
|
300
311
|
|
|
301
|
-
if (
|
|
312
|
+
if (isKnownTestsEnabled) {
|
|
302
313
|
isNewTestCh.publish({
|
|
303
314
|
knownTests,
|
|
304
315
|
testSuiteAbsolutePath: task.file.filepath,
|
|
305
316
|
testName,
|
|
306
317
|
onDone: (isNew) => {
|
|
307
318
|
if (isNew) {
|
|
308
|
-
|
|
319
|
+
if (isEarlyFlakeDetectionEnabled) {
|
|
320
|
+
isRetryReasonEfd = task.repeats !== numRepeats
|
|
321
|
+
task.repeats = numRepeats
|
|
322
|
+
}
|
|
309
323
|
newTasks.add(task)
|
|
310
324
|
taskToStatuses.set(task, [])
|
|
311
325
|
}
|
|
@@ -344,11 +358,12 @@ addHook({
|
|
|
344
358
|
let isNew = false
|
|
345
359
|
|
|
346
360
|
const {
|
|
361
|
+
isKnownTestsEnabled,
|
|
347
362
|
isEarlyFlakeDetectionEnabled,
|
|
348
363
|
isDiEnabled
|
|
349
364
|
} = getProvidedContext()
|
|
350
365
|
|
|
351
|
-
if (
|
|
366
|
+
if (isKnownTestsEnabled) {
|
|
352
367
|
isNew = newTasks.has(task)
|
|
353
368
|
}
|
|
354
369
|
|
|
@@ -431,6 +446,7 @@ addHook({
|
|
|
431
446
|
testName,
|
|
432
447
|
testSuiteAbsolutePath: task.file.filepath,
|
|
433
448
|
isRetry: numAttempt > 0 || numRepetition > 0,
|
|
449
|
+
isRetryReasonEfd,
|
|
434
450
|
isNew,
|
|
435
451
|
mightHitProbe: isDiEnabled && numAttempt > 0
|
|
436
452
|
})
|
|
@@ -576,7 +592,11 @@ addHook({
|
|
|
576
592
|
if (result) {
|
|
577
593
|
const { state, duration, errors } = result
|
|
578
594
|
if (state === 'skip') { // programmatic skip
|
|
579
|
-
testSkipCh.publish({
|
|
595
|
+
testSkipCh.publish({
|
|
596
|
+
testName: getTestName(task),
|
|
597
|
+
testSuiteAbsolutePath: task.file.filepath,
|
|
598
|
+
isNew: newTasks.has(task)
|
|
599
|
+
})
|
|
580
600
|
} else if (state === 'pass' && !isSwitchedStatus) {
|
|
581
601
|
if (testAsyncResource) {
|
|
582
602
|
testAsyncResource.runInAsyncScope(() => {
|
|
@@ -602,7 +622,11 @@ addHook({
|
|
|
602
622
|
}
|
|
603
623
|
}
|
|
604
624
|
} else { // test.skip or test.todo
|
|
605
|
-
testSkipCh.publish({
|
|
625
|
+
testSkipCh.publish({
|
|
626
|
+
testName: getTestName(task),
|
|
627
|
+
testSuiteAbsolutePath: task.file.filepath,
|
|
628
|
+
isNew: newTasks.has(task)
|
|
629
|
+
})
|
|
606
630
|
}
|
|
607
631
|
})
|
|
608
632
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const CompositePlugin = require('../../../../dd-trace/src/plugins/composite')
|
|
2
|
+
const BedrockRuntimeTracing = require('./tracing')
|
|
3
|
+
const BedrockRuntimeLLMObsPlugin = require('../../../../dd-trace/src/llmobs/plugins/bedrockruntime')
|
|
4
|
+
class BedrockRuntimePlugin extends CompositePlugin {
|
|
5
|
+
static get id () {
|
|
6
|
+
return 'bedrockruntime'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static get plugins () {
|
|
10
|
+
return {
|
|
11
|
+
llmobs: BedrockRuntimeLLMObsPlugin,
|
|
12
|
+
tracing: BedrockRuntimeTracing
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
module.exports = BedrockRuntimePlugin
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const BaseAwsSdkPlugin = require('../../base')
|
|
4
|
+
const { parseModelId, extractRequestParams, extractTextAndResponseReason } = require('./utils')
|
|
5
|
+
|
|
6
|
+
const enabledOperations = ['invokeModel']
|
|
7
|
+
|
|
8
|
+
class BedrockRuntime extends BaseAwsSdkPlugin {
|
|
9
|
+
static get id () { return 'bedrockruntime' }
|
|
10
|
+
|
|
11
|
+
isEnabled (request) {
|
|
12
|
+
const operation = request.operation
|
|
13
|
+
if (!enabledOperations.includes(operation)) {
|
|
14
|
+
return false
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return super.isEnabled(request)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
generateTags (params, operation, response) {
|
|
21
|
+
const { modelProvider, modelName } = parseModelId(params.modelId)
|
|
22
|
+
|
|
23
|
+
const requestParams = extractRequestParams(params, modelProvider)
|
|
24
|
+
const textAndResponseReason = extractTextAndResponseReason(response, modelProvider, modelName)
|
|
25
|
+
|
|
26
|
+
const tags = buildTagsFromParams(requestParams, textAndResponseReason, modelProvider, modelName, operation)
|
|
27
|
+
|
|
28
|
+
return tags
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function buildTagsFromParams (requestParams, textAndResponseReason, modelProvider, modelName, operation) {
|
|
33
|
+
const tags = {}
|
|
34
|
+
|
|
35
|
+
// add request tags
|
|
36
|
+
tags['resource.name'] = operation
|
|
37
|
+
tags['aws.bedrock.request.model'] = modelName
|
|
38
|
+
tags['aws.bedrock.request.model_provider'] = modelProvider.toLowerCase()
|
|
39
|
+
tags['aws.bedrock.request.prompt'] = requestParams.prompt
|
|
40
|
+
tags['aws.bedrock.request.temperature'] = requestParams.temperature
|
|
41
|
+
tags['aws.bedrock.request.top_p'] = requestParams.topP
|
|
42
|
+
tags['aws.bedrock.request.top_k'] = requestParams.topK
|
|
43
|
+
tags['aws.bedrock.request.max_tokens'] = requestParams.maxTokens
|
|
44
|
+
tags['aws.bedrock.request.stop_sequences'] = requestParams.stopSequences
|
|
45
|
+
tags['aws.bedrock.request.input_type'] = requestParams.inputType
|
|
46
|
+
tags['aws.bedrock.request.truncate'] = requestParams.truncate
|
|
47
|
+
tags['aws.bedrock.request.stream'] = requestParams.stream
|
|
48
|
+
tags['aws.bedrock.request.n'] = requestParams.n
|
|
49
|
+
|
|
50
|
+
// add response tags
|
|
51
|
+
if (modelName.includes('embed')) {
|
|
52
|
+
tags['aws.bedrock.response.embedding_length'] = textAndResponseReason.message.length
|
|
53
|
+
}
|
|
54
|
+
if (textAndResponseReason.choiceId) {
|
|
55
|
+
tags['aws.bedrock.response.choices.id'] = textAndResponseReason.choiceId
|
|
56
|
+
}
|
|
57
|
+
tags['aws.bedrock.response.choices.text'] = textAndResponseReason.message
|
|
58
|
+
tags['aws.bedrock.response.choices.finish_reason'] = textAndResponseReason.finishReason
|
|
59
|
+
|
|
60
|
+
return tags
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = BedrockRuntime
|
package/packages/datadog-plugin-aws-sdk/src/services/{bedrockruntime.js → bedrockruntime/utils.js}
RENAMED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
3
|
+
const log = require('../../../../dd-trace/src/log')
|
|
4
|
+
|
|
5
|
+
const MODEL_TYPE_IDENTIFIERS = [
|
|
6
|
+
'foundation-model/',
|
|
7
|
+
'custom-model/',
|
|
8
|
+
'provisioned-model/',
|
|
9
|
+
'imported-module/',
|
|
10
|
+
'prompt/',
|
|
11
|
+
'endpoint/',
|
|
12
|
+
'inference-profile/',
|
|
13
|
+
'default-prompt-router/'
|
|
14
|
+
]
|
|
5
15
|
|
|
6
16
|
const PROVIDER = {
|
|
7
17
|
AI21: 'AI21',
|
|
@@ -13,44 +23,6 @@ const PROVIDER = {
|
|
|
13
23
|
MISTRAL: 'MISTRAL'
|
|
14
24
|
}
|
|
15
25
|
|
|
16
|
-
const enabledOperations = ['invokeModel']
|
|
17
|
-
|
|
18
|
-
class BedrockRuntime extends BaseAwsSdkPlugin {
|
|
19
|
-
static get id () { return 'bedrock runtime' }
|
|
20
|
-
|
|
21
|
-
isEnabled (request) {
|
|
22
|
-
const operation = request.operation
|
|
23
|
-
if (!enabledOperations.includes(operation)) {
|
|
24
|
-
return false
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return super.isEnabled(request)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
generateTags (params, operation, response) {
|
|
31
|
-
let tags = {}
|
|
32
|
-
let modelName = ''
|
|
33
|
-
let modelProvider = ''
|
|
34
|
-
const modelMeta = params.modelId.split('.')
|
|
35
|
-
if (modelMeta.length === 2) {
|
|
36
|
-
[modelProvider, modelName] = modelMeta
|
|
37
|
-
modelProvider = modelProvider.toUpperCase()
|
|
38
|
-
} else {
|
|
39
|
-
[, modelProvider, modelName] = modelMeta
|
|
40
|
-
modelProvider = modelProvider.toUpperCase()
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const shouldSetChoiceIds = modelProvider === PROVIDER.COHERE && !modelName.includes('embed')
|
|
44
|
-
|
|
45
|
-
const requestParams = extractRequestParams(params, modelProvider)
|
|
46
|
-
const textAndResponseReason = extractTextAndResponseReason(response, modelProvider, modelName, shouldSetChoiceIds)
|
|
47
|
-
|
|
48
|
-
tags = buildTagsFromParams(requestParams, textAndResponseReason, modelProvider, modelName, operation)
|
|
49
|
-
|
|
50
|
-
return tags
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
26
|
class Generation {
|
|
55
27
|
constructor ({ message = '', finishReason = '', choiceId = '' } = {}) {
|
|
56
28
|
// stringify message as it could be a single generated message as well as a list of embeddings
|
|
@@ -65,6 +37,7 @@ class RequestParams {
|
|
|
65
37
|
prompt = '',
|
|
66
38
|
temperature = undefined,
|
|
67
39
|
topP = undefined,
|
|
40
|
+
topK = undefined,
|
|
68
41
|
maxTokens = undefined,
|
|
69
42
|
stopSequences = [],
|
|
70
43
|
inputType = '',
|
|
@@ -72,11 +45,11 @@ class RequestParams {
|
|
|
72
45
|
stream = '',
|
|
73
46
|
n = undefined
|
|
74
47
|
} = {}) {
|
|
75
|
-
// TODO: set a truncation limit to prompt
|
|
76
48
|
// stringify prompt as it could be a single prompt as well as a list of message objects
|
|
77
49
|
this.prompt = typeof prompt === 'string' ? prompt : JSON.stringify(prompt) || ''
|
|
78
50
|
this.temperature = temperature !== undefined ? temperature : undefined
|
|
79
51
|
this.topP = topP !== undefined ? topP : undefined
|
|
52
|
+
this.topK = topK !== undefined ? topK : undefined
|
|
80
53
|
this.maxTokens = maxTokens !== undefined ? maxTokens : undefined
|
|
81
54
|
this.stopSequences = stopSequences || []
|
|
82
55
|
this.inputType = inputType || ''
|
|
@@ -86,11 +59,53 @@ class RequestParams {
|
|
|
86
59
|
}
|
|
87
60
|
}
|
|
88
61
|
|
|
62
|
+
function parseModelId (modelId) {
|
|
63
|
+
// Best effort to extract the model provider and model name from the bedrock model ID.
|
|
64
|
+
// modelId can be a 1/2 period-separated string or a full AWS ARN, based on the following formats:
|
|
65
|
+
// 1. Base model: "{model_provider}.{model_name}"
|
|
66
|
+
// 2. Cross-region model: "{region}.{model_provider}.{model_name}"
|
|
67
|
+
// 3. Other: Prefixed by AWS ARN "arn:aws{+region?}:bedrock:{region}:{account-id}:"
|
|
68
|
+
// a. Foundation model: ARN prefix + "foundation-model/{region?}.{model_provider}.{model_name}"
|
|
69
|
+
// b. Custom model: ARN prefix + "custom-model/{model_provider}.{model_name}"
|
|
70
|
+
// c. Provisioned model: ARN prefix + "provisioned-model/{model-id}"
|
|
71
|
+
// d. Imported model: ARN prefix + "imported-module/{model-id}"
|
|
72
|
+
// e. Prompt management: ARN prefix + "prompt/{prompt-id}"
|
|
73
|
+
// f. Sagemaker: ARN prefix + "endpoint/{model-id}"
|
|
74
|
+
// g. Inference profile: ARN prefix + "{application-?}inference-profile/{model-id}"
|
|
75
|
+
// h. Default prompt router: ARN prefix + "default-prompt-router/{prompt-id}"
|
|
76
|
+
// If model provider cannot be inferred from the modelId formatting, then default to "custom"
|
|
77
|
+
modelId = modelId.toLowerCase()
|
|
78
|
+
if (!modelId.startsWith('arn:aws')) {
|
|
79
|
+
const modelMeta = modelId.split('.')
|
|
80
|
+
if (modelMeta.length < 2) {
|
|
81
|
+
return { modelProvider: 'custom', modelName: modelMeta[0] }
|
|
82
|
+
}
|
|
83
|
+
return { modelProvider: modelMeta[modelMeta.length - 2], modelName: modelMeta[modelMeta.length - 1] }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
for (const identifier of MODEL_TYPE_IDENTIFIERS) {
|
|
87
|
+
if (!modelId.includes(identifier)) {
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
90
|
+
modelId = modelId.split(identifier).pop()
|
|
91
|
+
if (['foundation-model/', 'custom-model/'].includes(identifier)) {
|
|
92
|
+
const modelMeta = modelId.split('.')
|
|
93
|
+
if (modelMeta.length < 2) {
|
|
94
|
+
return { modelProvider: 'custom', modelName: modelId }
|
|
95
|
+
}
|
|
96
|
+
return { modelProvider: modelMeta[modelMeta.length - 2], modelName: modelMeta[modelMeta.length - 1] }
|
|
97
|
+
}
|
|
98
|
+
return { modelProvider: 'custom', modelName: modelId }
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return { modelProvider: 'custom', modelName: 'custom' }
|
|
102
|
+
}
|
|
103
|
+
|
|
89
104
|
function extractRequestParams (params, provider) {
|
|
90
105
|
const requestBody = JSON.parse(params.body)
|
|
91
106
|
const modelId = params.modelId
|
|
92
107
|
|
|
93
|
-
switch (provider) {
|
|
108
|
+
switch (provider.toUpperCase()) {
|
|
94
109
|
case PROVIDER.AI21: {
|
|
95
110
|
let userPrompt = requestBody.prompt
|
|
96
111
|
if (modelId.includes('jamba')) {
|
|
@@ -176,11 +191,11 @@ function extractRequestParams (params, provider) {
|
|
|
176
191
|
}
|
|
177
192
|
}
|
|
178
193
|
|
|
179
|
-
function extractTextAndResponseReason (response, provider, modelName
|
|
194
|
+
function extractTextAndResponseReason (response, provider, modelName) {
|
|
180
195
|
const body = JSON.parse(Buffer.from(response.body).toString('utf8'))
|
|
181
|
-
|
|
196
|
+
const shouldSetChoiceIds = provider.toUpperCase() === PROVIDER.COHERE && !modelName.includes('embed')
|
|
182
197
|
try {
|
|
183
|
-
switch (provider) {
|
|
198
|
+
switch (provider.toUpperCase()) {
|
|
184
199
|
case PROVIDER.AI21: {
|
|
185
200
|
if (modelName.includes('jamba')) {
|
|
186
201
|
const generations = body.choices || []
|
|
@@ -262,34 +277,11 @@ function extractTextAndResponseReason (response, provider, modelName, shouldSetC
|
|
|
262
277
|
return new Generation()
|
|
263
278
|
}
|
|
264
279
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
tags['aws.bedrock.request.prompt'] = requestParams.prompt
|
|
273
|
-
tags['aws.bedrock.request.temperature'] = requestParams.temperature
|
|
274
|
-
tags['aws.bedrock.request.top_p'] = requestParams.topP
|
|
275
|
-
tags['aws.bedrock.request.max_tokens'] = requestParams.maxTokens
|
|
276
|
-
tags['aws.bedrock.request.stop_sequences'] = requestParams.stopSequences
|
|
277
|
-
tags['aws.bedrock.request.input_type'] = requestParams.inputType
|
|
278
|
-
tags['aws.bedrock.request.truncate'] = requestParams.truncate
|
|
279
|
-
tags['aws.bedrock.request.stream'] = requestParams.stream
|
|
280
|
-
tags['aws.bedrock.request.n'] = requestParams.n
|
|
281
|
-
|
|
282
|
-
// add response tags
|
|
283
|
-
if (modelName.includes('embed')) {
|
|
284
|
-
tags['aws.bedrock.response.embedding_length'] = textAndResponseReason.message.length
|
|
285
|
-
}
|
|
286
|
-
if (textAndResponseReason.choiceId) {
|
|
287
|
-
tags['aws.bedrock.response.choices.id'] = textAndResponseReason.choiceId
|
|
288
|
-
}
|
|
289
|
-
tags['aws.bedrock.response.choices.text'] = textAndResponseReason.message
|
|
290
|
-
tags['aws.bedrock.response.choices.finish_reason'] = textAndResponseReason.finishReason
|
|
291
|
-
|
|
292
|
-
return tags
|
|
280
|
+
module.exports = {
|
|
281
|
+
Generation,
|
|
282
|
+
RequestParams,
|
|
283
|
+
parseModelId,
|
|
284
|
+
extractRequestParams,
|
|
285
|
+
extractTextAndResponseReason,
|
|
286
|
+
PROVIDER
|
|
293
287
|
}
|
|
294
|
-
|
|
295
|
-
module.exports = BedrockRuntime
|
|
@@ -26,7 +26,8 @@ const {
|
|
|
26
26
|
TEST_MODULE,
|
|
27
27
|
TEST_MODULE_ID,
|
|
28
28
|
TEST_SUITE,
|
|
29
|
-
CUCUMBER_IS_PARALLEL
|
|
29
|
+
CUCUMBER_IS_PARALLEL,
|
|
30
|
+
TEST_RETRY_REASON
|
|
30
31
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
31
32
|
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
32
33
|
const { COMPONENT, ERROR_MESSAGE } = require('../../dd-trace/src/constants')
|
|
@@ -321,6 +322,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
321
322
|
span.setTag(TEST_IS_NEW, 'true')
|
|
322
323
|
if (isEfdRetry) {
|
|
323
324
|
span.setTag(TEST_IS_RETRY, 'true')
|
|
325
|
+
span.setTag(TEST_RETRY_REASON, 'efd')
|
|
324
326
|
}
|
|
325
327
|
}
|
|
326
328
|
|
|
@@ -31,7 +31,8 @@ const {
|
|
|
31
31
|
TEST_EARLY_FLAKE_ENABLED,
|
|
32
32
|
getTestSessionName,
|
|
33
33
|
TEST_SESSION_NAME,
|
|
34
|
-
TEST_LEVEL_EVENT_TYPES
|
|
34
|
+
TEST_LEVEL_EVENT_TYPES,
|
|
35
|
+
TEST_RETRY_REASON
|
|
35
36
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
36
37
|
const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util')
|
|
37
38
|
const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
|
|
@@ -112,7 +113,7 @@ function getCypressCommand (details) {
|
|
|
112
113
|
function getLibraryConfiguration (tracer, testConfiguration) {
|
|
113
114
|
return new Promise(resolve => {
|
|
114
115
|
if (!tracer._tracer._exporter?.getLibraryConfiguration) {
|
|
115
|
-
return resolve({ err: new Error('
|
|
116
|
+
return resolve({ err: new Error('Test Optimization was not initialized correctly') })
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
tracer._tracer._exporter.getLibraryConfiguration(testConfiguration, (err, libraryConfig) => {
|
|
@@ -124,7 +125,7 @@ function getLibraryConfiguration (tracer, testConfiguration) {
|
|
|
124
125
|
function getSkippableTests (tracer, testConfiguration) {
|
|
125
126
|
return new Promise(resolve => {
|
|
126
127
|
if (!tracer._tracer._exporter?.getSkippableSuites) {
|
|
127
|
-
return resolve({ err: new Error('
|
|
128
|
+
return resolve({ err: new Error('Test Optimization was not initialized correctly') })
|
|
128
129
|
}
|
|
129
130
|
tracer._tracer._exporter.getSkippableSuites(testConfiguration, (err, skippableTests, correlationId) => {
|
|
130
131
|
resolve({
|
|
@@ -139,7 +140,7 @@ function getSkippableTests (tracer, testConfiguration) {
|
|
|
139
140
|
function getKnownTests (tracer, testConfiguration) {
|
|
140
141
|
return new Promise(resolve => {
|
|
141
142
|
if (!tracer._tracer._exporter?.getKnownTests) {
|
|
142
|
-
return resolve({ err: new Error('
|
|
143
|
+
return resolve({ err: new Error('Test Optimization was not initialized correctly') })
|
|
143
144
|
}
|
|
144
145
|
tracer._tracer._exporter.getKnownTests(testConfiguration, (err, knownTests) => {
|
|
145
146
|
resolve({
|
|
@@ -203,6 +204,7 @@ class CypressPlugin {
|
|
|
203
204
|
this.isSuitesSkippingEnabled = false
|
|
204
205
|
this.isCodeCoverageEnabled = false
|
|
205
206
|
this.isEarlyFlakeDetectionEnabled = false
|
|
207
|
+
this.isKnownTestsEnabled = false
|
|
206
208
|
this.earlyFlakeDetectionNumRetries = 0
|
|
207
209
|
this.testsToSkip = []
|
|
208
210
|
this.skippedTests = []
|
|
@@ -232,13 +234,15 @@ class CypressPlugin {
|
|
|
232
234
|
isEarlyFlakeDetectionEnabled,
|
|
233
235
|
earlyFlakeDetectionNumRetries,
|
|
234
236
|
isFlakyTestRetriesEnabled,
|
|
235
|
-
flakyTestRetriesCount
|
|
237
|
+
flakyTestRetriesCount,
|
|
238
|
+
isKnownTestsEnabled
|
|
236
239
|
}
|
|
237
240
|
} = libraryConfigurationResponse
|
|
238
241
|
this.isSuitesSkippingEnabled = isSuitesSkippingEnabled
|
|
239
242
|
this.isCodeCoverageEnabled = isCodeCoverageEnabled
|
|
240
243
|
this.isEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
|
|
241
244
|
this.earlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
|
|
245
|
+
this.isKnownTestsEnabled = isKnownTestsEnabled
|
|
242
246
|
if (isFlakyTestRetriesEnabled) {
|
|
243
247
|
this.cypressConfig.retries.runMode = flakyTestRetriesCount
|
|
244
248
|
}
|
|
@@ -354,7 +358,7 @@ class CypressPlugin {
|
|
|
354
358
|
this.frameworkVersion = getCypressVersion(details)
|
|
355
359
|
this.rootDir = getRootDir(details)
|
|
356
360
|
|
|
357
|
-
if (this.
|
|
361
|
+
if (this.isKnownTestsEnabled) {
|
|
358
362
|
const knownTestsResponse = await getKnownTests(
|
|
359
363
|
this.tracer,
|
|
360
364
|
this.testConfiguration
|
|
@@ -362,6 +366,7 @@ class CypressPlugin {
|
|
|
362
366
|
if (knownTestsResponse.err) {
|
|
363
367
|
log.error('Cypress known tests response error', knownTestsResponse.err)
|
|
364
368
|
this.isEarlyFlakeDetectionEnabled = false
|
|
369
|
+
this.isKnownTestsEnabled = false
|
|
365
370
|
} else {
|
|
366
371
|
// We use TEST_FRAMEWORK_NAME for the name of the module
|
|
367
372
|
this.knownTestsByTestSuite = knownTestsResponse.knownTests[TEST_FRAMEWORK_NAME]
|
|
@@ -567,6 +572,9 @@ class CypressPlugin {
|
|
|
567
572
|
cypressTestStatus = CYPRESS_STATUS_TO_TEST_STATUS[cypressTest.attempts[attemptIndex].state]
|
|
568
573
|
if (attemptIndex > 0) {
|
|
569
574
|
finishedTest.testSpan.setTag(TEST_IS_RETRY, 'true')
|
|
575
|
+
if (finishedTest.isEfdRetry) {
|
|
576
|
+
finishedTest.testSpan.setTag(TEST_RETRY_REASON, 'efd')
|
|
577
|
+
}
|
|
570
578
|
}
|
|
571
579
|
}
|
|
572
580
|
if (cypressTest.displayError) {
|
|
@@ -618,7 +626,8 @@ class CypressPlugin {
|
|
|
618
626
|
const suitePayload = {
|
|
619
627
|
isEarlyFlakeDetectionEnabled: this.isEarlyFlakeDetectionEnabled,
|
|
620
628
|
knownTestsForSuite: this.knownTestsByTestSuite?.[testSuite] || [],
|
|
621
|
-
earlyFlakeDetectionNumRetries: this.earlyFlakeDetectionNumRetries
|
|
629
|
+
earlyFlakeDetectionNumRetries: this.earlyFlakeDetectionNumRetries,
|
|
630
|
+
isKnownTestsEnabled: this.isKnownTestsEnabled
|
|
622
631
|
}
|
|
623
632
|
|
|
624
633
|
if (this.testSuiteSpan) {
|
|
@@ -703,13 +712,15 @@ class CypressPlugin {
|
|
|
703
712
|
this.activeTestSpan.setTag(TEST_IS_NEW, 'true')
|
|
704
713
|
if (isEfdRetry) {
|
|
705
714
|
this.activeTestSpan.setTag(TEST_IS_RETRY, 'true')
|
|
715
|
+
this.activeTestSpan.setTag(TEST_RETRY_REASON, 'efd')
|
|
706
716
|
}
|
|
707
717
|
}
|
|
708
718
|
const finishedTest = {
|
|
709
719
|
testName,
|
|
710
720
|
testStatus,
|
|
711
721
|
finishTime: this.activeTestSpan._getTime(), // we store the finish time here
|
|
712
|
-
testSpan: this.activeTestSpan
|
|
722
|
+
testSpan: this.activeTestSpan,
|
|
723
|
+
isEfdRetry
|
|
713
724
|
}
|
|
714
725
|
if (this.finishedTestsByFile[testSuite]) {
|
|
715
726
|
this.finishedTestsByFile[testSuite].push(finishedTest)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
2
|
let isEarlyFlakeDetectionEnabled = false
|
|
3
|
+
let isKnownTestsEnabled = false
|
|
3
4
|
let knownTestsForSuite = []
|
|
4
5
|
let suiteTests = []
|
|
5
6
|
let earlyFlakeDetectionNumRetries = 0
|
|
@@ -33,7 +34,7 @@ function retryTest (test, suiteTests) {
|
|
|
33
34
|
|
|
34
35
|
const oldRunTests = Cypress.mocha.getRunner().runTests
|
|
35
36
|
Cypress.mocha.getRunner().runTests = function (suite, fn) {
|
|
36
|
-
if (!
|
|
37
|
+
if (!isKnownTestsEnabled) {
|
|
37
38
|
return oldRunTests.apply(this, arguments)
|
|
38
39
|
}
|
|
39
40
|
// We copy the new tests at the beginning of the suite run (runTests), so that they're run
|
|
@@ -41,7 +42,9 @@ Cypress.mocha.getRunner().runTests = function (suite, fn) {
|
|
|
41
42
|
suite.tests.forEach(test => {
|
|
42
43
|
if (!test._ddIsNew && !test.isPending() && isNewTest(test)) {
|
|
43
44
|
test._ddIsNew = true
|
|
44
|
-
|
|
45
|
+
if (isEarlyFlakeDetectionEnabled) {
|
|
46
|
+
retryTest(test, suite.tests)
|
|
47
|
+
}
|
|
45
48
|
}
|
|
46
49
|
})
|
|
47
50
|
|
|
@@ -67,6 +70,7 @@ before(function () {
|
|
|
67
70
|
}).then((suiteConfig) => {
|
|
68
71
|
if (suiteConfig) {
|
|
69
72
|
isEarlyFlakeDetectionEnabled = suiteConfig.isEarlyFlakeDetectionEnabled
|
|
73
|
+
isKnownTestsEnabled = suiteConfig.isKnownTestsEnabled
|
|
70
74
|
knownTestsForSuite = suiteConfig.knownTestsForSuite
|
|
71
75
|
earlyFlakeDetectionNumRetries = suiteConfig.earlyFlakeDetectionNumRetries
|
|
72
76
|
}
|
|
@@ -9,7 +9,7 @@ class FetchPlugin extends HttpClientPlugin {
|
|
|
9
9
|
bindStart (ctx) {
|
|
10
10
|
const req = ctx.req
|
|
11
11
|
const options = new URL(req.url)
|
|
12
|
-
|
|
12
|
+
options.headers = Object.fromEntries(req.headers.entries())
|
|
13
13
|
|
|
14
14
|
options.method = req.method
|
|
15
15
|
|
|
@@ -17,9 +17,9 @@ class FetchPlugin extends HttpClientPlugin {
|
|
|
17
17
|
|
|
18
18
|
const store = super.bindStart(ctx)
|
|
19
19
|
|
|
20
|
-
for (const name in headers) {
|
|
20
|
+
for (const name in options.headers) {
|
|
21
21
|
if (!req.headers.has(name)) {
|
|
22
|
-
req.headers.set(name, headers[name])
|
|
22
|
+
req.headers.set(name, options.headers[name])
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|