dd-trace 6.9.0 → 6.11.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 (175) hide show
  1. package/README.md +0 -17
  2. package/ci/vitest-no-worker-init-setup.mjs +112 -10
  3. package/index.d.ts +150 -3
  4. package/initialize.mjs +28 -17
  5. package/openfeature.js +2 -2
  6. package/package.json +14 -10
  7. package/packages/datadog-esbuild/index.js +0 -34
  8. package/packages/datadog-instrumentations/src/anthropic.js +210 -15
  9. package/packages/datadog-instrumentations/src/aws-sdk.js +9 -1
  10. package/packages/datadog-instrumentations/src/browser-bunyan.js +11 -0
  11. package/packages/datadog-instrumentations/src/bunyan.js +3 -16
  12. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +111 -6
  13. package/packages/datadog-instrumentations/src/cucumber.js +26 -11
  14. package/packages/datadog-instrumentations/src/cypress-config.js +182 -16
  15. package/packages/datadog-instrumentations/src/cypress-legacy-finalizers.js +30 -0
  16. package/packages/datadog-instrumentations/src/cypress.js +2 -0
  17. package/packages/datadog-instrumentations/src/fastify.js +2 -0
  18. package/packages/datadog-instrumentations/src/helpers/bunyan.js +22 -0
  19. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -1
  20. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +634 -0
  21. package/packages/datadog-instrumentations/src/helpers/register.js +10 -8
  22. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -1
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +81 -0
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +83 -1
  26. package/packages/datadog-instrumentations/src/jest.js +26 -18
  27. package/packages/datadog-instrumentations/src/mariadb.js +278 -21
  28. package/packages/datadog-instrumentations/src/mocha/main.js +540 -56
  29. package/packages/datadog-instrumentations/src/mocha/utils.js +132 -25
  30. package/packages/datadog-instrumentations/src/mysql.js +45 -15
  31. package/packages/datadog-instrumentations/src/mysql2.js +119 -18
  32. package/packages/datadog-instrumentations/src/path-to-regexp.js +67 -1
  33. package/packages/datadog-instrumentations/src/pg.js +116 -92
  34. package/packages/datadog-instrumentations/src/playwright-reporter.js +99 -0
  35. package/packages/datadog-instrumentations/src/playwright.js +149 -2
  36. package/packages/datadog-instrumentations/src/router.js +2 -0
  37. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +43 -4
  38. package/packages/datadog-instrumentations/src/vitest-main.js +180 -20
  39. package/packages/datadog-instrumentations/src/vitest-util.js +64 -5
  40. package/packages/datadog-instrumentations/src/vitest-worker.js +150 -25
  41. package/packages/datadog-instrumentations/src/webdriverio.js +31 -17
  42. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +12 -6
  43. package/packages/datadog-plugin-aws-sdk/src/base.js +1 -0
  44. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +163 -44
  45. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -13
  46. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
  47. package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
  48. package/packages/datadog-plugin-browser-bunyan/src/index.js +9 -0
  49. package/packages/datadog-plugin-bunyan/src/index.js +5 -8
  50. package/packages/datadog-plugin-cucumber/src/index.js +11 -0
  51. package/packages/datadog-plugin-cypress/src/after-run.js +5 -1
  52. package/packages/datadog-plugin-cypress/src/after-spec.js +5 -1
  53. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +82 -30
  54. package/packages/datadog-plugin-cypress/src/finalization.js +76 -0
  55. package/packages/datadog-plugin-cypress/src/index.js +12 -6
  56. package/packages/datadog-plugin-cypress/src/plugin.js +16 -3
  57. package/packages/datadog-plugin-dd-trace-api/src/index.js +4 -0
  58. package/packages/datadog-plugin-electron/src/index.js +2 -0
  59. package/packages/datadog-plugin-fs/src/index.js +1 -1
  60. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
  61. package/packages/datadog-plugin-jest/src/index.js +11 -4
  62. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -3
  63. package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -3
  64. package/packages/datadog-plugin-kafkajs/src/producer.js +3 -2
  65. package/packages/datadog-plugin-kafkajs/src/utils.js +65 -7
  66. package/packages/datadog-plugin-mocha/src/index.js +606 -40
  67. package/packages/datadog-plugin-mysql/src/index.js +37 -0
  68. package/packages/datadog-plugin-nats/src/index.js +1 -1
  69. package/packages/datadog-plugin-next/src/index.js +1 -19
  70. package/packages/datadog-plugin-openai/src/tracing.js +41 -30
  71. package/packages/datadog-plugin-openai-agents/src/integration.js +279 -69
  72. package/packages/datadog-plugin-openai-agents/src/processor.js +16 -4
  73. package/packages/datadog-plugin-pg/src/index.js +1 -0
  74. package/packages/datadog-plugin-playwright/src/index.js +42 -13
  75. package/packages/datadog-plugin-vitest/src/index.js +14 -20
  76. package/packages/datadog-plugin-ws/src/util.js +2 -1
  77. package/packages/datadog-webpack/index.js +0 -11
  78. package/packages/dd-trace/index.js +0 -1
  79. package/packages/dd-trace/src/agent/info.js +6 -5
  80. package/packages/dd-trace/src/aiguard/client.js +100 -1
  81. package/packages/dd-trace/src/aiguard/errors.js +41 -0
  82. package/packages/dd-trace/src/aiguard/evaluation.js +357 -0
  83. package/packages/dd-trace/src/aiguard/integrations/anthropic.js +70 -0
  84. package/packages/dd-trace/src/aiguard/integrations/index.js +4 -0
  85. package/packages/dd-trace/src/aiguard/messages/anthropic.js +423 -0
  86. package/packages/dd-trace/src/aiguard/messages/openai.js +1 -24
  87. package/packages/dd-trace/src/aiguard/messages/utils.js +28 -0
  88. package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +1 -11
  89. package/packages/dd-trace/src/aiguard/sdk.js +22 -278
  90. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +453 -0
  91. package/packages/dd-trace/src/appsec/handlers/http-request.js +13 -0
  92. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +9 -12
  93. package/packages/dd-trace/src/carrier.js +356 -0
  94. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +1 -0
  95. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +27 -3
  96. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +22 -6
  97. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +21 -5
  98. package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +164 -0
  99. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +22 -6
  100. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +365 -32
  101. package/packages/dd-trace/src/ci-visibility/exporters/request.js +201 -0
  102. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +5 -3
  103. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -5
  104. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -1
  105. package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +39 -0
  106. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -6
  107. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +6 -2
  108. package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -0
  109. package/packages/dd-trace/src/config/index.js +13 -2
  110. package/packages/dd-trace/src/config/major-overrides.js +7 -0
  111. package/packages/dd-trace/src/config/supported-configurations.json +24 -0
  112. package/packages/dd-trace/src/datastreams/context.js +6 -1
  113. package/packages/dd-trace/src/datastreams/index.js +2 -0
  114. package/packages/dd-trace/src/datastreams/manager.js +14 -3
  115. package/packages/dd-trace/src/datastreams/pathway.js +23 -22
  116. package/packages/dd-trace/src/datastreams/processor.js +16 -13
  117. package/packages/dd-trace/src/datastreams/size.js +5 -0
  118. package/packages/dd-trace/src/debugger/devtools_client/index.js +3 -2
  119. package/packages/dd-trace/src/exporters/agent/writer.js +49 -9
  120. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +6 -4
  121. package/packages/dd-trace/src/exporters/common/writer.js +11 -6
  122. package/packages/dd-trace/src/llmobs/constants/tags.js +5 -0
  123. package/packages/dd-trace/src/llmobs/experiments/client.js +163 -5
  124. package/packages/dd-trace/src/llmobs/experiments/dataset.js +241 -87
  125. package/packages/dd-trace/src/llmobs/experiments/experiment.js +280 -20
  126. package/packages/dd-trace/src/llmobs/experiments/index.js +58 -59
  127. package/packages/dd-trace/src/llmobs/experiments/noop.js +71 -3
  128. package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
  129. package/packages/dd-trace/src/llmobs/experiments/util.js +41 -5
  130. package/packages/dd-trace/src/llmobs/index.js +34 -2
  131. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -3
  132. package/packages/dd-trace/src/llmobs/plugins/base.js +4 -2
  133. package/packages/dd-trace/src/llmobs/span_processor.js +16 -0
  134. package/packages/dd-trace/src/llmobs/tagger.js +96 -0
  135. package/packages/dd-trace/src/llmobs/util.js +78 -0
  136. package/packages/dd-trace/src/noop/proxy.js +3 -4
  137. package/packages/dd-trace/src/openfeature/flagging_provider.js +18 -2
  138. package/packages/dd-trace/src/openfeature/remote_config.js +1 -1
  139. package/packages/dd-trace/src/opentelemetry/context_manager.js +7 -7
  140. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +2 -1
  141. package/packages/dd-trace/src/opentelemetry/logs/logger.js +67 -11
  142. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +14 -3
  143. package/packages/dd-trace/src/opentelemetry/metrics/index.js +25 -12
  144. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +2 -5
  145. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +96 -43
  146. package/packages/dd-trace/src/opentracing/propagation/text_map.js +126 -120
  147. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +4 -8
  148. package/packages/dd-trace/src/opentracing/tracer.js +5 -2
  149. package/packages/dd-trace/src/otel-thread-ctx.js +387 -0
  150. package/packages/dd-trace/src/plugin_manager.js +5 -3
  151. package/packages/dd-trace/src/plugins/ci_plugin.js +6 -1
  152. package/packages/dd-trace/src/plugins/index.js +1 -0
  153. package/packages/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +5 -65
  154. package/packages/dd-trace/src/plugins/util/test.js +93 -14
  155. package/packages/dd-trace/src/plugins/util/web.js +56 -2
  156. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  157. package/packages/dd-trace/src/profiling/profilers/space.js +1 -3
  158. package/packages/dd-trace/src/profiling/profilers/wall.js +37 -90
  159. package/packages/dd-trace/src/profiling/webspan-utils.js +45 -0
  160. package/packages/dd-trace/src/proxy.js +38 -29
  161. package/packages/dd-trace/src/ritm.js +9 -2
  162. package/packages/dd-trace/src/serverless.js +37 -0
  163. package/packages/dd-trace/src/span_format.js +1 -0
  164. package/packages/dd-trace/src/span_stats.js +30 -3
  165. package/packages/dd-trace/src/storage-channels.js +86 -0
  166. package/packages/dd-trace/src/tracer.js +9 -2
  167. package/packages/dd-trace/src/tracer_metadata.js +14 -1
  168. package/packages/dd-trace/src/web-tags-cache.js +132 -0
  169. package/vendor/dist/@datadog/openfeature-node-server/LICENSE +201 -0
  170. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -0
  171. package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +0 -65
  172. package/packages/datadog-webpack/src/optional-peer-loader.js +0 -17
  173. package/packages/dd-trace/src/feature-registry.js +0 -29
  174. package/packages/dd-trace/src/openfeature/register.js +0 -35
  175. package/packages/dd-trace/src/openfeature/require-provider.js +0 -18
@@ -1,90 +1,18 @@
1
1
  'use strict'
2
2
 
3
- const rfdc = require('../../../../vendor/dist/rfdc')({ proto: false, circles: false })
4
- const { HTTP_CLIENT_IP, NETWORK_CLIENT_IP, HTTP_USERAGENT } = require('../../../../ext/tags')
5
- const { USER_ID, USER_SESSION_ID } = require('../appsec/addresses')
6
- const { getActiveRequest } = require('../appsec/store')
7
3
  const log = require('../log')
8
- const { extractIp } = require('../plugins/util/ip_extractor')
9
- const telemetryMetrics = require('../telemetry/metrics')
10
- const tracerVersion = require('../../../../package.json').version
11
- const { keepTrace } = require('../priority_sampler')
12
- const { AI_GUARD } = require('../standalone/product')
4
+ const AIGuardClient = require('./client')
5
+ const { createEvaluationOutcome, EvaluationReporter } = require('./evaluation')
6
+ const { AIGuardAbortError } = require('./errors')
13
7
  const NoopAIGuard = require('./noop')
14
- const executeRequest = require('./client')
15
8
  const TAGS = require('./tags')
16
9
 
17
- const aiguardMetrics = telemetryMetrics.manager.namespace('ai_guard')
18
-
19
- const ALLOW = 'ALLOW'
20
-
21
- // Tags from the service entry span that must be mirrored onto every AI Guard span
22
- // so anomaly detection pipelines can process each span independently.
23
- const SERVICE_ENTRY_TAG_MAPPINGS = [
24
- [HTTP_USERAGENT, TAGS.HTTP_USERAGENT_TAG_KEY],
25
- [HTTP_CLIENT_IP, TAGS.HTTP_CLIENT_IP_TAG_KEY],
26
- [NETWORK_CLIENT_IP, TAGS.NETWORK_CLIENT_IP_TAG_KEY],
27
- [USER_ID, TAGS.USR_ID_TAG_KEY],
28
- [USER_SESSION_ID, TAGS.USR_SESSION_ID_TAG_KEY],
29
- ]
30
-
31
- /**
32
- * Reports a telemetry error
33
- *
34
- * @param {string} errorType - The error type constant (client_error, bad_status, bad_response)
35
- * @param {{ source: string, integration: string }} telemetryTags - Source and integration tags
36
- */
37
- function reportTelemetryError (errorType, telemetryTags) {
38
- aiguardMetrics.count(TAGS.TELEMETRY_REQUESTS, { error: true, ...telemetryTags }).inc(1)
39
- aiguardMetrics.count(TAGS.TELEMETRY_ERROR, { type: errorType, ...telemetryTags }).inc(1)
40
- }
41
-
42
- class AIGuardAbortError extends Error {
43
- constructor (reason, tags, tagProbs, sds) {
44
- super(reason)
45
- this.name = 'AIGuardAbortError'
46
- this.reason = reason
47
- this.tags = tags
48
- this.tagProbabilities = tagProbs
49
- this.sds = sds || []
50
- }
51
- }
52
-
53
- class AIGuardClientError extends Error {
54
- constructor (message, opts = {}) {
55
- super(message)
56
- this.name = 'AIGuardClientError'
57
- if (opts.errors) {
58
- this.errors = opts.errors
59
- }
60
- if (opts.cause) {
61
- this.cause = opts.cause
62
- }
63
- }
64
- }
65
-
66
- /**
67
- * Resolves the AI Guard host for a given Datadog site. Sites with a single subdomain level
68
- * (e.g. `datadoghq.com`, `ddog-gov.com`) are served from the `app.` subdomain, while regional
69
- * sites (e.g. `us3.datadoghq.com`, `ap1.datadoghq.com`) are used as-is.
70
- *
71
- * @param {string} site - Datadog site (e.g. `datadoghq.com`, `us3.datadoghq.com`)
72
- * @returns {string} The host to use for the AI Guard endpoint
73
- */
74
- function aiGuardHost (site) {
75
- return site.split('.').length === 2 ? `app.${site}` : site
76
- }
77
-
78
10
  class AIGuard extends NoopAIGuard {
79
11
  #initialized
80
12
  #tracer
81
- #headers
82
- #evaluateUrl
83
- #timeout
84
- #maxMessagesLength
85
- #maxContentSize
13
+ #client
14
+ #reporter
86
15
  #meta
87
- #config
88
16
 
89
17
  /**
90
18
  * @param {import('../tracer')} tracer - Tracer instance
@@ -99,223 +27,39 @@ class AIGuard extends NoopAIGuard {
99
27
  return
100
28
  }
101
29
  this.#tracer = tracer
102
- this.#headers = {
103
- 'DD-API-KEY': config.DD_API_KEY,
104
- 'DD-APPLICATION-KEY': config.DD_APP_KEY,
105
- 'DD-AI-GUARD-VERSION': tracerVersion,
106
- 'DD-AI-GUARD-SOURCE': 'SDK',
107
- 'DD-AI-GUARD-LANGUAGE': 'nodejs',
108
- }
109
- const endpoint = config.experimental.aiguard.endpoint || `https://${aiGuardHost(config.site)}/api/v2/ai-guard`
110
- this.#evaluateUrl = `${endpoint}/evaluate`
111
- this.#timeout = config.experimental.aiguard.timeout
112
- this.#maxMessagesLength = config.experimental.aiguard.maxMessagesLength
113
- this.#maxContentSize = config.experimental.aiguard.maxContentSize
30
+ this.#client = new AIGuardClient(config)
31
+ this.#reporter = new EvaluationReporter(config)
114
32
  this.#meta = { service: config.service, env: config.env }
115
- this.#config = config
116
33
  this.#initialized = true
117
34
  }
118
35
 
119
- /**
120
- * Returns a safe copy of the messages to be serialized into the meta struct.
121
- *
122
- * - Clones each message so callers cannot mutate the data set in the meta struct.
123
- * - Truncates the list of messages and `content` fields emitting metrics accordingly.
124
- *
125
- * @param {import('../../../../index').aiguard.Message[]} messages
126
- * @param {{ source: string, integration: string }} telemetryTags
127
- */
128
- #buildMessagesForMetaStruct (messages, telemetryTags) {
129
- const size = Math.min(messages.length, this.#maxMessagesLength)
130
- if (messages.length > size) {
131
- aiguardMetrics.count(TAGS.TELEMETRY_TRUNCATED, { type: 'messages', ...telemetryTags }).inc(1)
132
- }
133
- const result = []
134
- let contentTruncated = false
135
- for (let i = messages.length - size; i < messages.length; i++) {
136
- const message = rfdc(messages[i])
137
- if (message.content?.length > this.#maxContentSize) {
138
- contentTruncated = true
139
- message.content = message.content.slice(0, this.#maxContentSize)
140
- }
141
- result.push(message)
142
- }
143
- if (contentTruncated) {
144
- aiguardMetrics.count(TAGS.TELEMETRY_TRUNCATED, { type: 'content', ...telemetryTags }).inc(1)
145
- }
146
- return result
147
- }
148
-
149
- #isToolCall (message) {
150
- return message.tool_calls || message.tool_call_id
151
- }
152
-
153
- #getToolName (message, history) {
154
- // 1. assistant message with tool calls
155
- if (message.tool_calls) {
156
- const names = message.tool_calls.map((tool) => tool.function.name)
157
- return names.length === 0 ? null : names.join(',')
158
- }
159
- // 2. assistant message with tool output (search the linked tool call in reverse order)
160
- const id = message.tool_call_id
161
- for (let i = history.length - 2; i >= 0; i--) {
162
- const item = history[i]
163
- if (item.tool_calls) {
164
- for (const toolCall of item.tool_calls) {
165
- if (toolCall.id === id) {
166
- return toolCall.function.name
167
- }
168
- }
169
- }
170
- }
171
- return null
172
- }
173
-
174
- #setRootSpanClientIpTags (rootSpan) {
175
- if (!rootSpan) return
176
-
177
- const currentTags = rootSpan.context().getTags()
178
- const needsHttpClientIp = !Object.hasOwn(currentTags, HTTP_CLIENT_IP)
179
- const needsNetworkClientIp = !Object.hasOwn(currentTags, NETWORK_CLIENT_IP)
180
-
181
- if (!needsHttpClientIp && !needsNetworkClientIp) return
182
-
183
- const req = getActiveRequest()
184
-
185
- if (!req) return
186
-
187
- const newTags = {}
188
-
189
- if (needsHttpClientIp) {
190
- const clientIp = extractIp(this.#config, req)
191
-
192
- if (clientIp) {
193
- newTags[HTTP_CLIENT_IP] = clientIp
194
- }
195
- }
196
-
197
- if (needsNetworkClientIp) {
198
- const networkClientIp = req.socket?.remoteAddress
199
-
200
- if (networkClientIp) {
201
- newTags[NETWORK_CLIENT_IP] = networkClientIp
202
- }
203
- }
204
-
205
- if (Object.keys(newTags).length > 0) {
206
- rootSpan.addTags(newTags)
207
- }
208
- }
209
-
210
- /**
211
- * Copies service entry span tags needed by anomaly detection to the AI Guard span.
212
- *
213
- * @param {import('../opentracing/span')} guardSpan
214
- * @param {import('../opentracing/span')} rootSpan
215
- */
216
- #copyServiceEntryTagsToGuardSpan (guardSpan, rootSpan) {
217
- const rootTags = rootSpan.context().getTags()
218
- for (const [sourceTag, destTag] of SERVICE_ENTRY_TAG_MAPPINGS) {
219
- const value = rootTags[sourceTag]
220
- if (value !== undefined && value !== null) {
221
- guardSpan.setTag(destTag, value)
222
- }
223
- }
224
- }
225
-
226
36
  evaluate (messages, opts) {
227
37
  if (!this.#initialized) {
228
38
  return super.evaluate(messages, opts)
229
39
  }
230
40
  const { block = true, source = TAGS.SOURCE_SDK, integration = TAGS.INTEGRATION_NONE, childOf } = opts ?? {}
231
- const telemetryTags = { source, integration }
232
41
  // Only pass `childOf` when truthy so `tracer.trace`'s default (`scope().active()`)
233
42
  // still applies for SDK callers that don't supply an explicit parent.
234
43
  const traceOpts = childOf ? { childOf } : {}
235
44
  return this.#tracer.trace(TAGS.RESOURCE, traceOpts, async (span) => {
236
- const last = messages.at(-1)
237
- const target = this.#isToolCall(last) ? 'tool' : 'prompt'
238
- span.setTag(TAGS.TARGET_TAG_KEY, target)
239
- if (target === 'tool') {
240
- const name = this.#getToolName(last, messages)
241
- if (name) {
242
- span.setTag(TAGS.TOOL_NAME_TAG_KEY, name)
243
- }
244
- }
245
- const metaStruct = {
246
- messages: this.#buildMessagesForMetaStruct(messages, telemetryTags),
247
- }
248
- span.meta_struct = {
249
- [TAGS.META_STRUCT_KEY]: metaStruct,
250
- }
251
- const rootSpan = span.context()?._trace?.started?.[0]
252
- if (rootSpan) {
253
- this.#setRootSpanClientIpTags(rootSpan)
254
- this.#copyServiceEntryTagsToGuardSpan(span, rootSpan)
255
- // keepTrace must be called before executeRequest so the sampling decision
256
- // is propagated correctly to outgoing HTTP client calls.
257
- keepTrace(rootSpan, AI_GUARD)
258
- rootSpan.setTag(TAGS.EVENT_TAG_KEY, 'true')
259
- }
260
- let response
45
+ const report = this.#reporter.start(span, messages, { source, integration })
46
+ let evaluation
261
47
  try {
262
- const payload = {
263
- data: {
264
- attributes: {
265
- messages,
266
- meta: this.#meta,
267
- },
268
- },
269
- }
270
- response = await executeRequest(
271
- payload,
272
- { url: this.#evaluateUrl, headers: this.#headers, timeout: this.#timeout })
273
- } catch (e) {
274
- reportTelemetryError(TAGS.ERROR_TYPE_CLIENT, telemetryTags)
275
- throw new AIGuardClientError(`Unexpected error calling AI Guard service: ${e.message}`, { cause: e })
276
- }
277
- if (response.status !== 200) {
278
- reportTelemetryError(TAGS.ERROR_TYPE_STATUS, telemetryTags)
279
- throw new AIGuardClientError(
280
- `AI Guard service call failed, status ${response.status}`,
281
- { errors: response.body?.errors })
48
+ evaluation = await this.#client.evaluate(messages, this.#meta)
49
+ } catch (error) {
50
+ this.#reporter.fail(report, error.telemetryType ?? TAGS.ERROR_TYPE_CLIENT)
51
+ throw error
282
52
  }
283
- const attr = response.body?.data?.attributes
284
- if (!attr?.action) {
285
- reportTelemetryError(TAGS.ERROR_TYPE_RESPONSE, telemetryTags)
286
- throw new AIGuardClientError(`AI Guard service returned unexpected response : ${response.body}`)
287
- }
288
- const action = attr.action
289
- const reason = attr.reason
290
- const tags = attr.tags ?? []
291
- if (tags.length > 0) {
292
- metaStruct.attack_categories = tags
293
- }
294
- const sdsFindings = attr.sds_findings ?? []
295
- if (sdsFindings.length > 0) {
296
- metaStruct.sds = sdsFindings
297
- }
298
- const tagProbabilities = attr.tag_probs ?? {}
299
- if (attr.tag_probs) {
300
- metaStruct.tag_probs = tagProbabilities
301
- }
302
- const blockingEnabled = attr.is_blocking_enabled ?? false
303
- const shouldBlock = block && blockingEnabled && action !== ALLOW
304
- aiguardMetrics.count(TAGS.TELEMETRY_REQUESTS, {
305
- action,
306
- error: false,
307
- block: shouldBlock,
308
- ...telemetryTags,
309
- }).inc(1)
310
- span.setTag(TAGS.ACTION_TAG_KEY, action)
311
- if (reason) {
312
- span.setTag(TAGS.REASON_TAG_KEY, reason)
313
- }
314
- if (shouldBlock) {
315
- span.setTag(TAGS.BLOCKED_TAG_KEY, 'true')
316
- throw new AIGuardAbortError(reason, tags, tagProbabilities, sdsFindings)
53
+
54
+ const outcome = createEvaluationOutcome(evaluation, block)
55
+ this.#reporter.finish(report, outcome)
56
+
57
+ if (outcome.shouldBlock) {
58
+ const { reason, tags, tagProbabilities, sds } = outcome.result
59
+ throw new AIGuardAbortError(reason, tags, tagProbabilities, sds)
317
60
  }
318
- return { action, reason, tags, tagProbabilities, sds: sdsFindings }
61
+
62
+ return outcome.result
319
63
  })
320
64
  }
321
65
  }