dd-trace 5.30.0 → 5.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/README.md +9 -7
  3. package/package.json +7 -6
  4. package/packages/datadog-core/src/storage.js +11 -2
  5. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  6. package/packages/datadog-instrumentations/src/aws-sdk.js +2 -1
  7. package/packages/datadog-instrumentations/src/cucumber.js +14 -5
  8. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
  9. package/packages/datadog-instrumentations/src/jest.js +70 -36
  10. package/packages/datadog-instrumentations/src/mocha/utils.js +23 -7
  11. package/packages/datadog-instrumentations/src/node-serialize.js +22 -0
  12. package/packages/datadog-instrumentations/src/openai.js +2 -0
  13. package/packages/datadog-instrumentations/src/vitest.js +107 -59
  14. package/packages/datadog-instrumentations/src/vm.js +49 -0
  15. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime.js +295 -0
  16. package/packages/datadog-plugin-aws-sdk/src/services/index.js +1 -0
  17. package/packages/datadog-plugin-cucumber/src/index.js +30 -32
  18. package/packages/datadog-plugin-jest/src/index.js +34 -37
  19. package/packages/datadog-plugin-langchain/src/index.js +12 -80
  20. package/packages/datadog-plugin-langchain/src/tracing.js +89 -0
  21. package/packages/datadog-plugin-mocha/src/index.js +18 -36
  22. package/packages/datadog-plugin-vitest/src/index.js +20 -34
  23. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  24. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +2 -0
  25. package/packages/dd-trace/src/appsec/iast/analyzers/untrusted-deserialization-analyzer.js +16 -0
  26. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +9 -8
  27. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  28. package/packages/dd-trace/src/appsec/remote_config/manager.js +11 -1
  29. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +37 -0
  30. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +65 -28
  31. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +57 -17
  32. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +18 -3
  33. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +20 -3
  34. package/packages/dd-trace/src/config.js +39 -3
  35. package/packages/dd-trace/src/crashtracking/crashtracker.js +9 -0
  36. package/packages/dd-trace/src/crashtracking/noop.js +3 -0
  37. package/packages/dd-trace/src/datastreams/fnv.js +1 -1
  38. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -2
  39. package/packages/dd-trace/src/debugger/devtools_client/config.js +3 -1
  40. package/packages/dd-trace/src/debugger/devtools_client/defaults.js +1 -0
  41. package/packages/dd-trace/src/debugger/devtools_client/index.js +32 -14
  42. package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +36 -0
  43. package/packages/dd-trace/src/debugger/devtools_client/send.js +29 -10
  44. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +35 -1
  45. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +112 -0
  46. package/packages/dd-trace/src/debugger/devtools_client/status.js +20 -11
  47. package/packages/dd-trace/src/debugger/index.js +2 -13
  48. package/packages/dd-trace/src/llmobs/plugins/base.js +40 -11
  49. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +24 -0
  50. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +111 -0
  51. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +42 -0
  52. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +102 -0
  53. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/llm.js +32 -0
  54. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +131 -0
  55. package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -1
  56. package/packages/dd-trace/src/llmobs/sdk.js +90 -26
  57. package/packages/dd-trace/src/llmobs/tagger.js +11 -3
  58. package/packages/dd-trace/src/llmobs/util.js +7 -1
  59. package/packages/dd-trace/src/llmobs/writers/spans/agentProxy.js +3 -3
  60. package/packages/dd-trace/src/log/index.js +8 -9
  61. package/packages/dd-trace/src/noop/proxy.js +2 -2
  62. package/packages/dd-trace/src/noop/span.js +1 -1
  63. package/packages/dd-trace/src/opentelemetry/context_manager.js +43 -3
  64. package/packages/dd-trace/src/opentracing/span.js +11 -1
  65. package/packages/dd-trace/src/opentracing/span_context.js +12 -0
  66. package/packages/dd-trace/src/plugins/ci_plugin.js +57 -27
  67. package/packages/dd-trace/src/plugins/util/test.js +42 -12
  68. package/packages/dd-trace/src/priority_sampler.js +7 -2
  69. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +21 -0
  70. package/packages/dd-trace/src/profiling/profiler.js +11 -8
  71. package/packages/dd-trace/src/profiling/profilers/events.js +17 -1
  72. package/packages/dd-trace/src/proxy.js +6 -3
  73. package/packages/dd-trace/src/scope.js +1 -1
  74. package/packages/dd-trace/src/telemetry/index.js +2 -0
@@ -28,6 +28,42 @@ const newTasks = new WeakSet()
28
28
  const switchedStatuses = new WeakSet()
29
29
  const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
30
30
 
31
+ const BREAKPOINT_HIT_GRACE_PERIOD_MS = 400
32
+
33
+ function waitForHitProbe () {
34
+ return new Promise(resolve => {
35
+ setTimeout(() => {
36
+ resolve()
37
+ }, BREAKPOINT_HIT_GRACE_PERIOD_MS)
38
+ })
39
+ }
40
+
41
+ function getProvidedContext () {
42
+ try {
43
+ const {
44
+ _ddIsEarlyFlakeDetectionEnabled,
45
+ _ddIsDiEnabled,
46
+ _ddKnownTests: knownTests,
47
+ _ddEarlyFlakeDetectionNumRetries: numRepeats
48
+ } = globalThis.__vitest_worker__.providedContext
49
+
50
+ return {
51
+ isDiEnabled: _ddIsDiEnabled,
52
+ isEarlyFlakeDetectionEnabled: _ddIsEarlyFlakeDetectionEnabled,
53
+ knownTests,
54
+ numRepeats
55
+ }
56
+ } catch (e) {
57
+ log.error('Vitest workers could not parse provided context, so some features will not work.')
58
+ return {
59
+ isDiEnabled: false,
60
+ isEarlyFlakeDetectionEnabled: false,
61
+ knownTests: {},
62
+ numRepeats: 0
63
+ }
64
+ }
65
+ }
66
+
31
67
  function isReporterPackage (vitestPackage) {
32
68
  return vitestPackage.B?.name === 'BaseSequencer'
33
69
  }
@@ -143,7 +179,9 @@ function getSortWrapper (sort) {
143
179
  const knownTestsResponse = await getChannelPromise(knownTestsCh)
144
180
  if (!knownTestsResponse.err) {
145
181
  knownTests = knownTestsResponse.knownTests
146
- const testFilepaths = await this.ctx.getTestFilepaths()
182
+ const getFilePaths = this.ctx.getTestFilepaths || this.ctx._globTestFilepaths
183
+
184
+ const testFilepaths = await getFilePaths.call(this.ctx)
147
185
 
148
186
  isEarlyFlakeDetectionFaultyCh.publish({
149
187
  knownTests: knownTests.vitest || {},
@@ -253,29 +291,26 @@ addHook({
253
291
  // `onBeforeRunTask` is run before any repetition or attempt is run
254
292
  shimmer.wrap(VitestTestRunner.prototype, 'onBeforeRunTask', onBeforeRunTask => async function (task) {
255
293
  const testName = getTestName(task)
256
- try {
257
- const {
258
- _ddKnownTests: knownTests,
259
- _ddIsEarlyFlakeDetectionEnabled: isEarlyFlakeDetectionEnabled,
260
- _ddEarlyFlakeDetectionNumRetries: numRepeats
261
- } = globalThis.__vitest_worker__.providedContext
262
-
263
- if (isEarlyFlakeDetectionEnabled) {
264
- isNewTestCh.publish({
265
- knownTests,
266
- testSuiteAbsolutePath: task.file.filepath,
267
- testName,
268
- onDone: (isNew) => {
269
- if (isNew) {
270
- task.repeats = numRepeats
271
- newTasks.add(task)
272
- taskToStatuses.set(task, [])
273
- }
294
+
295
+ const {
296
+ knownTests,
297
+ isEarlyFlakeDetectionEnabled,
298
+ numRepeats
299
+ } = getProvidedContext()
300
+
301
+ if (isEarlyFlakeDetectionEnabled) {
302
+ isNewTestCh.publish({
303
+ knownTests,
304
+ testSuiteAbsolutePath: task.file.filepath,
305
+ testName,
306
+ onDone: (isNew) => {
307
+ if (isNew) {
308
+ task.repeats = numRepeats
309
+ newTasks.add(task)
310
+ taskToStatuses.set(task, [])
274
311
  }
275
- })
276
- }
277
- } catch (e) {
278
- log.error('Vitest workers could not parse known tests, so Early Flake Detection will not work.')
312
+ }
313
+ })
279
314
  }
280
315
 
281
316
  return onBeforeRunTask.apply(this, arguments)
@@ -283,9 +318,7 @@ addHook({
283
318
 
284
319
  // `onAfterRunTask` is run after all repetitions or attempts are run
285
320
  shimmer.wrap(VitestTestRunner.prototype, 'onAfterRunTask', onAfterRunTask => async function (task) {
286
- const {
287
- _ddIsEarlyFlakeDetectionEnabled: isEarlyFlakeDetectionEnabled
288
- } = globalThis.__vitest_worker__.providedContext
321
+ const { isEarlyFlakeDetectionEnabled } = getProvidedContext()
289
322
 
290
323
  if (isEarlyFlakeDetectionEnabled && taskToStatuses.has(task)) {
291
324
  const statuses = taskToStatuses.get(task)
@@ -309,43 +342,40 @@ addHook({
309
342
  }
310
343
  const testName = getTestName(task)
311
344
  let isNew = false
312
- let isEarlyFlakeDetectionEnabled = false
313
- let isDiEnabled = false
314
-
315
- try {
316
- const {
317
- _ddIsEarlyFlakeDetectionEnabled,
318
- _ddIsDiEnabled
319
- } = globalThis.__vitest_worker__.providedContext
320
345
 
321
- isEarlyFlakeDetectionEnabled = _ddIsEarlyFlakeDetectionEnabled
322
- isDiEnabled = _ddIsDiEnabled
346
+ const {
347
+ isEarlyFlakeDetectionEnabled,
348
+ isDiEnabled
349
+ } = getProvidedContext()
323
350
 
324
- if (isEarlyFlakeDetectionEnabled) {
325
- isNew = newTasks.has(task)
326
- }
327
- } catch (e) {
328
- log.error('Vitest workers could not parse known tests, so Early Flake Detection will not work.')
351
+ if (isEarlyFlakeDetectionEnabled) {
352
+ isNew = newTasks.has(task)
329
353
  }
354
+
330
355
  const { retry: numAttempt, repeats: numRepetition } = retryInfo
331
356
 
332
357
  // We finish the previous test here because we know it has failed already
333
358
  if (numAttempt > 0) {
334
- const probe = {}
359
+ const shouldWaitForHitProbe = isDiEnabled && numAttempt > 1
360
+ if (shouldWaitForHitProbe) {
361
+ await waitForHitProbe()
362
+ }
363
+
364
+ const promises = {}
365
+ const shouldSetProbe = isDiEnabled && numAttempt === 1
335
366
  const asyncResource = taskToAsync.get(task)
336
367
  const testError = task.result?.errors?.[0]
337
368
  if (asyncResource) {
338
369
  asyncResource.runInAsyncScope(() => {
339
370
  testErrorCh.publish({
340
371
  error: testError,
341
- willBeRetried: true,
342
- probe,
343
- isDiEnabled
372
+ shouldSetProbe,
373
+ promises
344
374
  })
345
375
  })
346
376
  // We wait for the probe to be set
347
- if (probe.setProbePromise) {
348
- await probe.setProbePromise
377
+ if (promises.setProbePromise) {
378
+ await promises.setProbePromise
349
379
  }
350
380
  }
351
381
  }
@@ -401,7 +431,8 @@ addHook({
401
431
  testName,
402
432
  testSuiteAbsolutePath: task.file.filepath,
403
433
  isRetry: numAttempt > 0 || numRepetition > 0,
404
- isNew
434
+ isNew,
435
+ mightHitProbe: isDiEnabled && numAttempt > 0
405
436
  })
406
437
  })
407
438
  return onBeforeTryTask.apply(this, arguments)
@@ -418,6 +449,12 @@ addHook({
418
449
  const status = getVitestTestStatus(task, retryCount)
419
450
  const asyncResource = taskToAsync.get(task)
420
451
 
452
+ const { isDiEnabled } = getProvidedContext()
453
+
454
+ if (isDiEnabled && retryCount > 1) {
455
+ await waitForHitProbe()
456
+ }
457
+
421
458
  if (asyncResource) {
422
459
  // We don't finish here because the test might fail in a later hook (afterEach)
423
460
  asyncResource.runInAsyncScope(() => {
@@ -457,15 +494,6 @@ addHook({
457
494
  return vitestPackage
458
495
  })
459
496
 
460
- addHook({
461
- name: 'vitest',
462
- versions: ['>=2.1.0'],
463
- filePattern: 'dist/chunks/RandomSequencer.*'
464
- }, (randomSequencerPackage) => {
465
- shimmer.wrap(randomSequencerPackage.B.prototype, 'sort', getSortWrapper)
466
- return randomSequencerPackage
467
- })
468
-
469
497
  addHook({
470
498
  name: 'vitest',
471
499
  versions: ['>=2.0.5 <2.1.0'],
@@ -478,6 +506,24 @@ addHook({
478
506
  return vitestPackage
479
507
  })
480
508
 
509
+ addHook({
510
+ name: 'vitest',
511
+ versions: ['>=2.1.0 <3.0.0'],
512
+ filePattern: 'dist/chunks/RandomSequencer.*'
513
+ }, (randomSequencerPackage) => {
514
+ shimmer.wrap(randomSequencerPackage.B.prototype, 'sort', getSortWrapper)
515
+ return randomSequencerPackage
516
+ })
517
+
518
+ addHook({
519
+ name: 'vitest',
520
+ versions: ['>=3.0.0'],
521
+ filePattern: 'dist/chunks/resolveConfig.*'
522
+ }, (randomSequencerPackage) => {
523
+ shimmer.wrap(randomSequencerPackage.B.prototype, 'sort', getSortWrapper)
524
+ return randomSequencerPackage
525
+ })
526
+
481
527
  // Can't specify file because compiled vitest includes hashes in their files
482
528
  addHook({
483
529
  name: 'vitest',
@@ -498,15 +544,17 @@ addHook({
498
544
  versions: ['>=1.6.0'],
499
545
  file: 'dist/index.js'
500
546
  }, (vitestPackage, frameworkVersion) => {
501
- shimmer.wrap(vitestPackage, 'startTests', startTests => async function (testPath) {
547
+ shimmer.wrap(vitestPackage, 'startTests', startTests => async function (testPaths) {
502
548
  let testSuiteError = null
503
549
  if (!testSuiteStartCh.hasSubscribers) {
504
550
  return startTests.apply(this, arguments)
505
551
  }
552
+ // From >=3.0.1, the first arguments changes from a string to an object containing the filepath
553
+ const testSuiteAbsolutePath = testPaths[0]?.filepath || testPaths[0]
506
554
 
507
555
  const testSuiteAsyncResource = new AsyncResource('bound-anonymous-fn')
508
556
  testSuiteAsyncResource.runInAsyncScope(() => {
509
- testSuiteStartCh.publish({ testSuiteAbsolutePath: testPath[0], frameworkVersion })
557
+ testSuiteStartCh.publish({ testSuiteAbsolutePath, frameworkVersion })
510
558
  })
511
559
  const startTestsResponse = await startTests.apply(this, arguments)
512
560
 
@@ -0,0 +1,49 @@
1
+ 'use strict'
2
+
3
+ const { channel, addHook } = require('./helpers/instrument')
4
+ const shimmer = require('../../datadog-shimmer')
5
+ const names = ['vm', 'node:vm']
6
+
7
+ const runScriptStartChannel = channel('datadog:vm:run-script:start')
8
+ const sourceTextModuleStartChannel = channel('datadog:vm:source-text-module:start')
9
+
10
+ addHook({ name: names }, function (vm) {
11
+ vm.Script = class extends vm.Script {
12
+ constructor (code) {
13
+ super(...arguments)
14
+
15
+ if (runScriptStartChannel.hasSubscribers && code) {
16
+ runScriptStartChannel.publish({ code })
17
+ }
18
+ }
19
+ }
20
+
21
+ if (vm.SourceTextModule && typeof vm.SourceTextModule === 'function') {
22
+ vm.SourceTextModule = class extends vm.SourceTextModule {
23
+ constructor (code) {
24
+ super(...arguments)
25
+
26
+ if (sourceTextModuleStartChannel.hasSubscribers && code) {
27
+ sourceTextModuleStartChannel.publish({ code })
28
+ }
29
+ }
30
+ }
31
+ }
32
+
33
+ shimmer.wrap(vm, 'runInContext', wrapVMMethod)
34
+ shimmer.wrap(vm, 'runInNewContext', wrapVMMethod)
35
+ shimmer.wrap(vm, 'runInThisContext', wrapVMMethod)
36
+ shimmer.wrap(vm, 'compileFunction', wrapVMMethod)
37
+
38
+ return vm
39
+ })
40
+
41
+ function wrapVMMethod (original) {
42
+ return function wrappedVMMethod (code) {
43
+ if (runScriptStartChannel.hasSubscribers && code) {
44
+ runScriptStartChannel.publish({ code })
45
+ }
46
+
47
+ return original.apply(this, arguments)
48
+ }
49
+ }
@@ -0,0 +1,295 @@
1
+ 'use strict'
2
+
3
+ const BaseAwsSdkPlugin = require('../base')
4
+ const log = require('../../../dd-trace/src/log')
5
+
6
+ const PROVIDER = {
7
+ AI21: 'AI21',
8
+ AMAZON: 'AMAZON',
9
+ ANTHROPIC: 'ANTHROPIC',
10
+ COHERE: 'COHERE',
11
+ META: 'META',
12
+ STABILITY: 'STABILITY',
13
+ MISTRAL: 'MISTRAL'
14
+ }
15
+
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
+ class Generation {
55
+ constructor ({ message = '', finishReason = '', choiceId = '' } = {}) {
56
+ // stringify message as it could be a single generated message as well as a list of embeddings
57
+ this.message = typeof message === 'string' ? message : JSON.stringify(message) || ''
58
+ this.finishReason = finishReason || ''
59
+ this.choiceId = choiceId || undefined
60
+ }
61
+ }
62
+
63
+ class RequestParams {
64
+ constructor ({
65
+ prompt = '',
66
+ temperature = undefined,
67
+ topP = undefined,
68
+ maxTokens = undefined,
69
+ stopSequences = [],
70
+ inputType = '',
71
+ truncate = '',
72
+ stream = '',
73
+ n = undefined
74
+ } = {}) {
75
+ // TODO: set a truncation limit to prompt
76
+ // stringify prompt as it could be a single prompt as well as a list of message objects
77
+ this.prompt = typeof prompt === 'string' ? prompt : JSON.stringify(prompt) || ''
78
+ this.temperature = temperature !== undefined ? temperature : undefined
79
+ this.topP = topP !== undefined ? topP : undefined
80
+ this.maxTokens = maxTokens !== undefined ? maxTokens : undefined
81
+ this.stopSequences = stopSequences || []
82
+ this.inputType = inputType || ''
83
+ this.truncate = truncate || ''
84
+ this.stream = stream || ''
85
+ this.n = n !== undefined ? n : undefined
86
+ }
87
+ }
88
+
89
+ function extractRequestParams (params, provider) {
90
+ const requestBody = JSON.parse(params.body)
91
+ const modelId = params.modelId
92
+
93
+ switch (provider) {
94
+ case PROVIDER.AI21: {
95
+ let userPrompt = requestBody.prompt
96
+ if (modelId.includes('jamba')) {
97
+ for (const message of requestBody.messages) {
98
+ if (message.role === 'user') {
99
+ userPrompt = message.content // Return the content of the most recent user message
100
+ }
101
+ }
102
+ }
103
+ return new RequestParams({
104
+ prompt: userPrompt,
105
+ temperature: requestBody.temperature,
106
+ topP: requestBody.top_p,
107
+ maxTokens: requestBody.max_tokens,
108
+ stopSequences: requestBody.stop_sequences
109
+ })
110
+ }
111
+ case PROVIDER.AMAZON: {
112
+ if (modelId.includes('embed')) {
113
+ return new RequestParams({ prompt: requestBody.inputText })
114
+ }
115
+ const textGenerationConfig = requestBody.textGenerationConfig || {}
116
+ return new RequestParams({
117
+ prompt: requestBody.inputText,
118
+ temperature: textGenerationConfig.temperature,
119
+ topP: textGenerationConfig.topP,
120
+ maxTokens: textGenerationConfig.maxTokenCount,
121
+ stopSequences: textGenerationConfig.stopSequences
122
+ })
123
+ }
124
+ case PROVIDER.ANTHROPIC: {
125
+ const prompt = requestBody.prompt || requestBody.messages
126
+ return new RequestParams({
127
+ prompt,
128
+ temperature: requestBody.temperature,
129
+ topP: requestBody.top_p,
130
+ maxTokens: requestBody.max_tokens_to_sample,
131
+ stopSequences: requestBody.stop_sequences
132
+ })
133
+ }
134
+ case PROVIDER.COHERE: {
135
+ if (modelId.includes('embed')) {
136
+ return new RequestParams({
137
+ prompt: requestBody.texts,
138
+ inputType: requestBody.input_type,
139
+ truncate: requestBody.truncate
140
+ })
141
+ }
142
+ return new RequestParams({
143
+ prompt: requestBody.prompt,
144
+ temperature: requestBody.temperature,
145
+ topP: requestBody.p,
146
+ maxTokens: requestBody.max_tokens,
147
+ stopSequences: requestBody.stop_sequences,
148
+ stream: requestBody.stream,
149
+ n: requestBody.num_generations
150
+ })
151
+ }
152
+ case PROVIDER.META: {
153
+ return new RequestParams({
154
+ prompt: requestBody.prompt,
155
+ temperature: requestBody.temperature,
156
+ topP: requestBody.top_p,
157
+ maxTokens: requestBody.max_gen_len
158
+ })
159
+ }
160
+ case PROVIDER.MISTRAL: {
161
+ return new RequestParams({
162
+ prompt: requestBody.prompt,
163
+ temperature: requestBody.temperature,
164
+ topP: requestBody.top_p,
165
+ maxTokens: requestBody.max_tokens,
166
+ stopSequences: requestBody.stop,
167
+ topK: requestBody.top_k
168
+ })
169
+ }
170
+ case PROVIDER.STABILITY: {
171
+ return new RequestParams()
172
+ }
173
+ default: {
174
+ return new RequestParams()
175
+ }
176
+ }
177
+ }
178
+
179
+ function extractTextAndResponseReason (response, provider, modelName, shouldSetChoiceIds) {
180
+ const body = JSON.parse(Buffer.from(response.body).toString('utf8'))
181
+
182
+ try {
183
+ switch (provider) {
184
+ case PROVIDER.AI21: {
185
+ if (modelName.includes('jamba')) {
186
+ const generations = body.choices || []
187
+ if (generations.length > 0) {
188
+ const generation = generations[0]
189
+ return new Generation({
190
+ message: generation.message,
191
+ finishReason: generation.finish_reason,
192
+ choiceId: shouldSetChoiceIds ? generation.id : undefined
193
+ })
194
+ }
195
+ }
196
+ const completions = body.completions || []
197
+ if (completions.length > 0) {
198
+ const completion = completions[0]
199
+ return new Generation({
200
+ message: completion.data?.text,
201
+ finishReason: completion?.finishReason,
202
+ choiceId: shouldSetChoiceIds ? completion?.id : undefined
203
+ })
204
+ }
205
+ return new Generation()
206
+ }
207
+ case PROVIDER.AMAZON: {
208
+ if (modelName.includes('embed')) {
209
+ return new Generation({ message: body.embedding })
210
+ }
211
+ const results = body.results || []
212
+ if (results.length > 0) {
213
+ const result = results[0]
214
+ return new Generation({ message: result.outputText, finishReason: result.completionReason })
215
+ }
216
+ break
217
+ }
218
+ case PROVIDER.ANTHROPIC: {
219
+ return new Generation({ message: body.completion || body.content, finishReason: body.stop_reason })
220
+ }
221
+ case PROVIDER.COHERE: {
222
+ if (modelName.includes('embed')) {
223
+ const embeddings = body.embeddings || [[]]
224
+ if (embeddings.length > 0) {
225
+ return new Generation({ message: embeddings[0] })
226
+ }
227
+ }
228
+ const generations = body.generations || []
229
+ if (generations.length > 0) {
230
+ const generation = generations[0]
231
+ return new Generation({
232
+ message: generation.text,
233
+ finishReason: generation.finish_reason,
234
+ choiceId: shouldSetChoiceIds ? generation.id : undefined
235
+ })
236
+ }
237
+ break
238
+ }
239
+ case PROVIDER.META: {
240
+ return new Generation({ message: body.generation, finishReason: body.stop_reason })
241
+ }
242
+ case PROVIDER.MISTRAL: {
243
+ const mistralGenerations = body.outputs || []
244
+ if (mistralGenerations.length > 0) {
245
+ const generation = mistralGenerations[0]
246
+ return new Generation({ message: generation.text, finishReason: generation.stop_reason })
247
+ }
248
+ break
249
+ }
250
+ case PROVIDER.STABILITY: {
251
+ return new Generation()
252
+ }
253
+ default: {
254
+ return new Generation()
255
+ }
256
+ }
257
+ } catch (error) {
258
+ log.warn('Unable to extract text/finishReason from response body. Defaulting to empty text/finishReason.')
259
+ return new Generation()
260
+ }
261
+
262
+ return new Generation()
263
+ }
264
+
265
+ function buildTagsFromParams (requestParams, textAndResponseReason, modelProvider, modelName, operation) {
266
+ const tags = {}
267
+
268
+ // add request tags
269
+ tags['resource.name'] = operation
270
+ tags['aws.bedrock.request.model'] = modelName
271
+ tags['aws.bedrock.request.model_provider'] = modelProvider
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
293
+ }
294
+
295
+ module.exports = BedrockRuntime
@@ -12,4 +12,5 @@ exports.sns = require('./sns')
12
12
  exports.sqs = require('./sqs')
13
13
  exports.states = require('./states')
14
14
  exports.stepfunctions = require('./stepfunctions')
15
+ exports.bedrockruntime = require('./bedrockruntime')
15
16
  exports.default = require('./default')