dd-trace 5.103.0 → 5.105.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 +90 -102
- package/index.d.ts +107 -6
- package/package.json +18 -17
- package/packages/datadog-core/src/storage.js +1 -1
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/ai.js +8 -7
- package/packages/datadog-instrumentations/src/aws-sdk.js +15 -2
- package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
- package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
- package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -2
- package/packages/datadog-instrumentations/src/cucumber.js +181 -35
- package/packages/datadog-instrumentations/src/dns.js +54 -18
- package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
- package/packages/datadog-instrumentations/src/fastify.js +142 -82
- package/packages/datadog-instrumentations/src/graphql.js +188 -67
- package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/kafka.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
- package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +3 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -6
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +31 -229
- package/packages/datadog-instrumentations/src/hono.js +54 -3
- package/packages/datadog-instrumentations/src/http/client.js +2 -2
- package/packages/datadog-instrumentations/src/http/server.js +9 -4
- package/packages/datadog-instrumentations/src/ioredis.js +3 -3
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
- package/packages/datadog-instrumentations/src/jest.js +390 -183
- package/packages/datadog-instrumentations/src/kafkajs.js +140 -17
- package/packages/datadog-instrumentations/src/mariadb.js +1 -1
- package/packages/datadog-instrumentations/src/memcached.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +399 -107
- package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
- package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
- package/packages/datadog-instrumentations/src/mongoose.js +10 -12
- package/packages/datadog-instrumentations/src/mysql.js +2 -2
- package/packages/datadog-instrumentations/src/mysql2.js +1 -1
- package/packages/datadog-instrumentations/src/nats.js +182 -0
- package/packages/datadog-instrumentations/src/nyc.js +38 -1
- package/packages/datadog-instrumentations/src/openai.js +33 -18
- package/packages/datadog-instrumentations/src/oracledb.js +6 -1
- package/packages/datadog-instrumentations/src/pg.js +1 -1
- package/packages/datadog-instrumentations/src/pino.js +17 -5
- package/packages/datadog-instrumentations/src/playwright.js +537 -297
- package/packages/datadog-instrumentations/src/router.js +80 -34
- package/packages/datadog-instrumentations/src/stripe.js +1 -1
- package/packages/datadog-instrumentations/src/vitest.js +246 -149
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
- package/packages/datadog-plugin-bunyan/src/index.js +28 -0
- package/packages/datadog-plugin-cucumber/src/index.js +17 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +223 -45
- package/packages/datadog-plugin-cypress/src/support.js +69 -1
- package/packages/datadog-plugin-dns/src/lookup.js +8 -6
- package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +2 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
- package/packages/datadog-plugin-graphql/src/utils.js +4 -1
- package/packages/datadog-plugin-http/src/server.js +40 -15
- package/packages/datadog-plugin-jest/src/index.js +11 -3
- package/packages/datadog-plugin-jest/src/util.js +15 -8
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +35 -0
- package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +19 -4
- package/packages/datadog-plugin-mongodb-core/src/index.js +311 -35
- package/packages/datadog-plugin-nats/src/consumer.js +43 -0
- package/packages/datadog-plugin-nats/src/index.js +20 -0
- package/packages/datadog-plugin-nats/src/producer.js +62 -0
- package/packages/datadog-plugin-nats/src/util.js +33 -0
- package/packages/datadog-plugin-next/src/index.js +5 -3
- package/packages/datadog-plugin-openai/src/tracing.js +15 -2
- package/packages/datadog-plugin-oracledb/src/index.js +13 -2
- package/packages/datadog-plugin-pino/src/index.js +42 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -4
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-redis/src/index.js +37 -2
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +33 -44
- package/packages/datadog-plugin-selenium/src/index.js +1 -1
- package/packages/datadog-plugin-undici/src/index.js +19 -0
- package/packages/datadog-plugin-vitest/src/index.js +24 -20
- package/packages/datadog-plugin-winston/src/index.js +30 -0
- package/packages/datadog-shimmer/src/shimmer.js +49 -21
- package/packages/dd-trace/src/aiguard/index.js +1 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/blocking.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +11 -4
- package/packages/dd-trace/src/appsec/reporter.js +24 -11
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
- package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
- package/packages/dd-trace/src/baggage.js +7 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -1
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -2
- package/packages/dd-trace/src/config/supported-configurations.json +36 -8
- package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
- package/packages/dd-trace/src/datastreams/context.js +4 -2
- package/packages/dd-trace/src/datastreams/writer.js +2 -4
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
- package/packages/dd-trace/src/encode/0.4.js +124 -108
- package/packages/dd-trace/src/encode/0.5.js +114 -26
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +57 -42
- package/packages/dd-trace/src/encode/agentless-json.js +4 -2
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
- package/packages/dd-trace/src/encode/span-stats.js +16 -16
- package/packages/dd-trace/src/encode/tags-processors.js +16 -0
- package/packages/dd-trace/src/exporters/common/agents.js +3 -1
- package/packages/dd-trace/src/exporters/common/request.js +3 -1
- package/packages/dd-trace/src/id.js +17 -4
- package/packages/dd-trace/src/lambda/handler.js +2 -4
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +10 -16
- package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
- package/packages/dd-trace/src/llmobs/tagger.js +9 -1
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/util.js +66 -3
- package/packages/dd-trace/src/log/index.js +1 -1
- package/packages/dd-trace/src/log/writer.js +3 -1
- package/packages/dd-trace/src/msgpack/chunk.js +394 -10
- package/packages/dd-trace/src/msgpack/index.js +96 -2
- package/packages/dd-trace/src/noop/span.js +3 -1
- package/packages/dd-trace/src/openfeature/encoding.js +70 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
- package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
- package/packages/dd-trace/src/openfeature/writers/exposures.js +51 -20
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
- package/packages/dd-trace/src/opentelemetry/span.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
- package/packages/dd-trace/src/opentracing/span.js +59 -19
- package/packages/dd-trace/src/opentracing/span_context.js +49 -0
- package/packages/dd-trace/src/plugins/apollo.js +3 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +23 -33
- package/packages/dd-trace/src/plugins/database.js +7 -6
- package/packages/dd-trace/src/plugins/index.js +4 -0
- package/packages/dd-trace/src/plugins/log_injection.js +56 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -46
- package/packages/dd-trace/src/plugins/outbound.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +15 -17
- package/packages/dd-trace/src/plugins/tracing.js +48 -8
- package/packages/dd-trace/src/plugins/util/git.js +3 -1
- package/packages/dd-trace/src/plugins/util/test.js +318 -13
- package/packages/dd-trace/src/plugins/util/web.js +89 -64
- package/packages/dd-trace/src/priority_sampler.js +2 -2
- package/packages/dd-trace/src/profiling/profiler.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
- package/packages/dd-trace/src/sampling_rule.js +7 -7
- package/packages/dd-trace/src/scope.js +7 -5
- package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
- package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
- package/packages/dd-trace/src/span_format.js +190 -58
- package/packages/dd-trace/src/spanleak.js +1 -1
- package/packages/dd-trace/src/standalone/index.js +3 -3
- package/packages/dd-trace/src/tagger.js +0 -2
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
- package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
- 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/packages/dd-trace/src/msgpack/encoder.js +0 -308
- package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
- package/vendor/dist/opentracing/LICENSE +0 -201
- package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
- package/vendor/dist/opentracing/constants.d.ts +0 -61
- package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
- package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
- package/vendor/dist/opentracing/functions.d.ts +0 -20
- package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
- package/vendor/dist/opentracing/index.d.ts +0 -12
- package/vendor/dist/opentracing/index.js +0 -1
- package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
- package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
- package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
- package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
- package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
- package/vendor/dist/opentracing/noop.d.ts +0 -8
- package/vendor/dist/opentracing/reference.d.ts +0 -33
- package/vendor/dist/opentracing/span.d.ts +0 -147
- package/vendor/dist/opentracing/span_context.d.ts +0 -26
- package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
- package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
- package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
- package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
- package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
- package/vendor/dist/opentracing/tracer.d.ts +0 -127
|
@@ -14,11 +14,14 @@ const finishChannel = channel('apm:grpc:client:request:finish')
|
|
|
14
14
|
const emitChannel = channel('apm:grpc:client:request:emit')
|
|
15
15
|
|
|
16
16
|
function createWrapMakeRequest (type, hasPeer = false) {
|
|
17
|
+
const metadataIndex = type === types.client_stream || type === types.bidi ? 3 : 4
|
|
18
|
+
|
|
17
19
|
return function wrapMakeRequest (makeRequest) {
|
|
18
20
|
return function (path) {
|
|
19
|
-
|
|
21
|
+
if (!startChannel.hasSubscribers) return makeRequest.apply(this, arguments)
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
const { metadata, args } = resolveMetadata(this, arguments, metadataIndex)
|
|
24
|
+
return callMethod(this, makeRequest, args, path, metadata, type, hasPeer)
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
}
|
|
@@ -82,9 +85,13 @@ function wrapMethod (method, path, type, hasPeer) {
|
|
|
82
85
|
return method
|
|
83
86
|
}
|
|
84
87
|
|
|
88
|
+
const metadataIndex = type === types.client_stream || type === types.bidi ? 0 : 1
|
|
89
|
+
|
|
85
90
|
const wrapped = shimmer.wrapFunction(method, method => function () {
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
if (!startChannel.hasSubscribers) return method.apply(this, arguments)
|
|
92
|
+
|
|
93
|
+
const { metadata, args } = resolveMetadata(this, arguments, metadataIndex)
|
|
94
|
+
return callMethod(this, method, args, path, metadata, type, hasPeer)
|
|
88
95
|
})
|
|
89
96
|
|
|
90
97
|
patched.add(wrapped)
|
|
@@ -140,24 +147,25 @@ function createWrapEmit (ctx, hasPeer = false) {
|
|
|
140
147
|
}
|
|
141
148
|
|
|
142
149
|
function callMethod (client, method, args, path, metadata, type, hasPeer = false) {
|
|
143
|
-
if (!startChannel.hasSubscribers) return method.apply(client, args)
|
|
144
|
-
|
|
145
|
-
const length = args.length
|
|
146
|
-
const callback = args[length - 1]
|
|
147
|
-
|
|
148
150
|
const ctx = { metadata, path, type }
|
|
149
151
|
|
|
150
152
|
return startChannel.runStores(ctx, () => {
|
|
151
153
|
try {
|
|
154
|
+
let callArgs = args
|
|
155
|
+
|
|
152
156
|
if (type === types.unary || type === types.client_stream) {
|
|
157
|
+
if (!Array.isArray(callArgs)) callArgs = [...callArgs]
|
|
158
|
+
|
|
159
|
+
const length = callArgs.length
|
|
160
|
+
const callback = callArgs[length - 1]
|
|
153
161
|
if (typeof callback === 'function') {
|
|
154
|
-
|
|
162
|
+
callArgs[length - 1] = wrapCallback(ctx, callback)
|
|
155
163
|
} else {
|
|
156
|
-
|
|
164
|
+
callArgs[length] = wrapCallback(ctx)
|
|
157
165
|
}
|
|
158
166
|
}
|
|
159
167
|
|
|
160
|
-
const call = method.apply(client,
|
|
168
|
+
const call = method.apply(client, callArgs)
|
|
161
169
|
|
|
162
170
|
if (call && typeof call.emit === 'function') {
|
|
163
171
|
shimmer.wrap(call, 'emit', createWrapEmit(ctx, hasPeer))
|
|
@@ -167,36 +175,44 @@ function callMethod (client, method, args, path, metadata, type, hasPeer = false
|
|
|
167
175
|
} catch (e) {
|
|
168
176
|
ctx.error = e
|
|
169
177
|
errorChannel.publish(ctx)
|
|
178
|
+
throw e
|
|
170
179
|
}
|
|
171
180
|
// No end channel needed
|
|
172
181
|
})
|
|
173
182
|
}
|
|
174
183
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Returns the `Metadata` for a gRPC client invocation, splicing or replacing
|
|
186
|
+
* one at `index` when the user did not pass their own.
|
|
187
|
+
*
|
|
188
|
+
* @param {object} client
|
|
189
|
+
* @param {ArrayLike<unknown>} args
|
|
190
|
+
* @param {number} index
|
|
191
|
+
* @returns {{ metadata: object | undefined, args: ArrayLike<unknown> }}
|
|
192
|
+
*/
|
|
193
|
+
function resolveMetadata (client, args, index) {
|
|
194
|
+
const grpc = client && getGrpc(client)
|
|
195
|
+
if (!grpc) return { metadata: undefined, args }
|
|
196
|
+
|
|
197
|
+
const slot = args[index]
|
|
198
|
+
|
|
199
|
+
if (slot instanceof grpc.Metadata || slot?.constructor?.name === 'Metadata') {
|
|
200
|
+
return { metadata: slot, args }
|
|
185
201
|
}
|
|
186
202
|
|
|
187
|
-
|
|
188
|
-
normalized.push(new grpc.Metadata())
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (meta) {
|
|
192
|
-
normalized.push(meta)
|
|
193
|
-
}
|
|
203
|
+
const metadata = new grpc.Metadata()
|
|
194
204
|
|
|
195
|
-
|
|
196
|
-
|
|
205
|
+
if (slot == null) {
|
|
206
|
+
const out = [...args]
|
|
207
|
+
out[index] = metadata
|
|
208
|
+
return { metadata, args: out }
|
|
197
209
|
}
|
|
198
210
|
|
|
199
|
-
|
|
211
|
+
const out = new Array(args.length + 1)
|
|
212
|
+
for (let i = 0; i < index; i++) out[i] = args[i]
|
|
213
|
+
out[index] = metadata
|
|
214
|
+
for (let i = index; i < args.length; i++) out[i + 1] = args[i]
|
|
215
|
+
return { metadata, args: out }
|
|
200
216
|
}
|
|
201
217
|
|
|
202
218
|
function getType (definition) {
|
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Returns the value as a string, JSON-stringifying it when it is not already a string.
|
|
5
|
+
* Returns the value unchanged when it is `null` or `undefined`.
|
|
6
|
+
*
|
|
7
|
+
* @param {unknown} value
|
|
8
|
+
* @returns {string|undefined|null}
|
|
9
|
+
*/
|
|
10
|
+
function stringifyIfNeeded (value) {
|
|
11
|
+
if (value == null) return value
|
|
12
|
+
return typeof value === 'string' ? value : JSON.stringify(value)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const FILE_FALLBACK = '[file]'
|
|
16
|
+
const IMAGE_FALLBACK = '[image]'
|
|
17
|
+
|
|
18
|
+
const OPENAI_RESPONSE_TOOL_CALL_TYPES = new Set([
|
|
19
|
+
'apply_patch_call',
|
|
20
|
+
'code_interpreter_call',
|
|
21
|
+
'computer_call',
|
|
22
|
+
'custom_tool_call',
|
|
23
|
+
'file_search_call',
|
|
24
|
+
'function_call',
|
|
25
|
+
'image_generation_call',
|
|
26
|
+
'local_shell_call',
|
|
27
|
+
'mcp_call',
|
|
28
|
+
'shell_call',
|
|
29
|
+
'web_search_call',
|
|
30
|
+
])
|
|
31
|
+
|
|
32
|
+
const OPENAI_RESPONSE_TOOL_OUTPUT_TYPES = new Set([
|
|
33
|
+
'apply_patch_call_output',
|
|
34
|
+
'computer_call_output',
|
|
35
|
+
'custom_tool_call_output',
|
|
36
|
+
'function_call_output',
|
|
37
|
+
'local_shell_call_output',
|
|
38
|
+
'shell_call_output',
|
|
39
|
+
])
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Returns a stringified value, falling back to an empty string for absent values.
|
|
43
|
+
*
|
|
44
|
+
* @param {unknown} value
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
47
|
+
function stringifyOrEmpty (value) {
|
|
48
|
+
return stringifyIfNeeded(value) ?? ''
|
|
49
|
+
}
|
|
50
|
+
|
|
3
51
|
/**
|
|
4
52
|
* Converts a LanguageModelV2FilePart with an image mediaType to an AI guard style image_url content part.
|
|
5
53
|
*
|
|
@@ -79,12 +127,11 @@ function convertVercelPromptToMessages (prompt) {
|
|
|
79
127
|
if (part.type === 'text') {
|
|
80
128
|
textParts.push(part.text)
|
|
81
129
|
} else if (part.type === 'tool-call') {
|
|
82
|
-
const args = part.args ?? part.input
|
|
83
130
|
toolCalls.push({
|
|
84
131
|
id: part.toolCallId,
|
|
85
132
|
function: {
|
|
86
133
|
name: part.toolName,
|
|
87
|
-
arguments:
|
|
134
|
+
arguments: stringifyIfNeeded(part.args ?? part.input),
|
|
88
135
|
},
|
|
89
136
|
})
|
|
90
137
|
}
|
|
@@ -103,11 +150,10 @@ function convertVercelPromptToMessages (prompt) {
|
|
|
103
150
|
|
|
104
151
|
for (const part of msg.content) {
|
|
105
152
|
if (part.type === 'tool-result') {
|
|
106
|
-
const result = part.result ?? part.output
|
|
107
153
|
messages.push({
|
|
108
154
|
role: 'tool',
|
|
109
155
|
tool_call_id: part.toolCallId,
|
|
110
|
-
content:
|
|
156
|
+
content: stringifyIfNeeded(part.result ?? part.output),
|
|
111
157
|
})
|
|
112
158
|
}
|
|
113
159
|
}
|
|
@@ -118,6 +164,58 @@ function convertVercelPromptToMessages (prompt) {
|
|
|
118
164
|
return messages
|
|
119
165
|
}
|
|
120
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Converts OpenAI chat-completions messages to the message format expected by AI Guard.
|
|
169
|
+
*
|
|
170
|
+
* Modern `tool_calls` messages already match the expected shape. Deprecated chat
|
|
171
|
+
* completions `function_call` and `function` role messages are normalized to the
|
|
172
|
+
* equivalent tool-call shape so AI Guard can classify them as tool interactions.
|
|
173
|
+
*
|
|
174
|
+
* @param {Array<object>} messages
|
|
175
|
+
* @returns {Array<object>|undefined}
|
|
176
|
+
*/
|
|
177
|
+
function normalizeOpenAIChatMessages (messages) {
|
|
178
|
+
if (!Array.isArray(messages) || messages.length === 0) return
|
|
179
|
+
|
|
180
|
+
const normalizedMessages = []
|
|
181
|
+
for (const message of messages) {
|
|
182
|
+
const normalized = normalizeOpenAIChatMessage(message)
|
|
183
|
+
if (normalized) normalizedMessages.push(normalized)
|
|
184
|
+
}
|
|
185
|
+
return normalizedMessages.length ? normalizedMessages : undefined
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Converts one OpenAI chat-completions message to AI Guard's expected shape.
|
|
190
|
+
*
|
|
191
|
+
* @param {object} message
|
|
192
|
+
* @returns {object|undefined}
|
|
193
|
+
*/
|
|
194
|
+
function normalizeOpenAIChatMessage (message) {
|
|
195
|
+
if (!message || typeof message !== 'object') return
|
|
196
|
+
|
|
197
|
+
if (message.role === 'function') {
|
|
198
|
+
return {
|
|
199
|
+
role: 'tool',
|
|
200
|
+
tool_call_id: message.tool_call_id ?? message.name,
|
|
201
|
+
content: stringifyOrEmpty(message.content),
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (!message.function_call) return message
|
|
206
|
+
|
|
207
|
+
const { function_call: functionCall, ...normalized } = message
|
|
208
|
+
const name = functionCall.name
|
|
209
|
+
normalized.tool_calls ??= [{
|
|
210
|
+
id: message.tool_call_id ?? name,
|
|
211
|
+
function: {
|
|
212
|
+
name,
|
|
213
|
+
arguments: stringifyOrEmpty(functionCall.arguments),
|
|
214
|
+
},
|
|
215
|
+
}]
|
|
216
|
+
return normalized
|
|
217
|
+
}
|
|
218
|
+
|
|
121
219
|
/**
|
|
122
220
|
* Converts LLM output tool calls to AI guard style message format.
|
|
123
221
|
*
|
|
@@ -130,16 +228,13 @@ function buildToolCallOutputMessages (inputMessages, toolCalls) {
|
|
|
130
228
|
...inputMessages,
|
|
131
229
|
{
|
|
132
230
|
role: 'assistant',
|
|
133
|
-
tool_calls: toolCalls.map(tc => {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
},
|
|
141
|
-
}
|
|
142
|
-
}),
|
|
231
|
+
tool_calls: toolCalls.map(tc => ({
|
|
232
|
+
id: tc.toolCallId,
|
|
233
|
+
function: {
|
|
234
|
+
name: tc.toolName,
|
|
235
|
+
arguments: stringifyIfNeeded(tc.args ?? tc.input),
|
|
236
|
+
},
|
|
237
|
+
})),
|
|
143
238
|
},
|
|
144
239
|
]
|
|
145
240
|
}
|
|
@@ -173,10 +268,223 @@ function buildOutputMessages (inputMessages, content) {
|
|
|
173
268
|
return inputMessages
|
|
174
269
|
}
|
|
175
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Converts OpenAI Responses API input/output items to OpenAI chat-style messages.
|
|
273
|
+
*
|
|
274
|
+
* @param {string|Array<object>|undefined} items
|
|
275
|
+
* @param {string} defaultRole
|
|
276
|
+
* @returns {Array<object>}
|
|
277
|
+
*/
|
|
278
|
+
function convertOpenAIResponseItemsToMessages (items, defaultRole) {
|
|
279
|
+
if (typeof items === 'string') return [{ role: defaultRole, content: items }]
|
|
280
|
+
if (!Array.isArray(items)) return []
|
|
281
|
+
|
|
282
|
+
const messages = []
|
|
283
|
+
for (const item of items) {
|
|
284
|
+
const converted = openAIResponseItemToMessage(item, defaultRole)
|
|
285
|
+
if (Array.isArray(converted)) {
|
|
286
|
+
for (const message of converted) messages.push(message)
|
|
287
|
+
} else if (converted) {
|
|
288
|
+
messages.push(converted)
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return messages
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Converts OpenAI reusable prompt variables to user messages for AI Guard.
|
|
296
|
+
*
|
|
297
|
+
* The reusable prompt template body is not available on the request, but its
|
|
298
|
+
* variables are user/application-provided content that OpenAI substitutes into
|
|
299
|
+
* the prompt. Screening them closes prompt-only `responses.create({ prompt })`
|
|
300
|
+
* calls and prompt variables used alongside `input`.
|
|
301
|
+
*
|
|
302
|
+
* @param {{variables?: Record<string, string|object>|null}|undefined|null} prompt
|
|
303
|
+
* @returns {Array<object>}
|
|
304
|
+
*/
|
|
305
|
+
function convertOpenAIResponsePromptToMessages (prompt) {
|
|
306
|
+
const variables = prompt?.variables
|
|
307
|
+
if (!variables || typeof variables !== 'object') return []
|
|
308
|
+
|
|
309
|
+
const messages = []
|
|
310
|
+
for (const value of Object.values(variables)) {
|
|
311
|
+
const content = openAIResponsePromptVariableToMessageContent(value)
|
|
312
|
+
if (content != null) messages.push({ role: 'user', content })
|
|
313
|
+
}
|
|
314
|
+
return messages
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Converts one OpenAI reusable prompt variable value to message content.
|
|
319
|
+
*
|
|
320
|
+
* Routes every variable through `openAIResponseContentToMessageContent` so the
|
|
321
|
+
* result follows the same string-when-text-only / array-when-multimodal shape
|
|
322
|
+
* convention used elsewhere in this file. Media variables that produce no
|
|
323
|
+
* usable content (e.g. an `input_image` with no URL or `file_id`) fall back to
|
|
324
|
+
* a stable text marker so AI Guard still observes that a media variable was
|
|
325
|
+
* attached.
|
|
326
|
+
*
|
|
327
|
+
* @param {string|object} value
|
|
328
|
+
* @returns {string|Array<{type: string, text?: string, image_url?: {url: string}}>|undefined}
|
|
329
|
+
*/
|
|
330
|
+
function openAIResponsePromptVariableToMessageContent (value) {
|
|
331
|
+
let part
|
|
332
|
+
if (typeof value === 'string') {
|
|
333
|
+
part = { type: 'input_text', text: value }
|
|
334
|
+
} else if (value && typeof value === 'object') {
|
|
335
|
+
part = value
|
|
336
|
+
} else {
|
|
337
|
+
return
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const content = openAIResponseContentToMessageContent([part])
|
|
341
|
+
if (content != null) return content
|
|
342
|
+
if (part.type === 'input_image') return IMAGE_FALLBACK
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Converts one OpenAI Responses API item to an OpenAI chat-style message.
|
|
347
|
+
*
|
|
348
|
+
* @param {object} item
|
|
349
|
+
* @param {string} defaultRole
|
|
350
|
+
* @returns {object|Array<object>|undefined}
|
|
351
|
+
*/
|
|
352
|
+
function openAIResponseItemToMessage (item, defaultRole) {
|
|
353
|
+
if (!item || typeof item !== 'object') return
|
|
354
|
+
const type = item.type ?? 'message'
|
|
355
|
+
|
|
356
|
+
if (type === 'message') {
|
|
357
|
+
const content = openAIResponseContentToMessageContent(item.content)
|
|
358
|
+
if (content != null) return { role: item.role || defaultRole, content }
|
|
359
|
+
} else if (OPENAI_RESPONSE_TOOL_CALL_TYPES.has(type)) {
|
|
360
|
+
return openAIResponseToolCallToMessages(item)
|
|
361
|
+
} else if (OPENAI_RESPONSE_TOOL_OUTPUT_TYPES.has(type)) {
|
|
362
|
+
return openAIResponseToolOutputToMessage(item)
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Converts a Responses API tool-call item to one or more chat-style messages.
|
|
368
|
+
*
|
|
369
|
+
* Most tool-call items represent only the assistant's tool request. MCP and
|
|
370
|
+
* image-generation items can also carry tool output on the same item, so include
|
|
371
|
+
* a linked tool message when output-like fields are present.
|
|
372
|
+
*
|
|
373
|
+
* @param {object} item
|
|
374
|
+
* @returns {object|Array<object>}
|
|
375
|
+
*/
|
|
376
|
+
function openAIResponseToolCallToMessages (item) {
|
|
377
|
+
const toolCallId = item.call_id ?? item.id ?? item.name ?? item.type
|
|
378
|
+
const message = {
|
|
379
|
+
role: 'assistant',
|
|
380
|
+
tool_calls: [{
|
|
381
|
+
id: toolCallId,
|
|
382
|
+
function: {
|
|
383
|
+
name: item.name ?? item.server_label ?? item.type,
|
|
384
|
+
arguments: stringifyOrEmpty(item.arguments ?? item.input ?? item.action),
|
|
385
|
+
},
|
|
386
|
+
}],
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (item.output == null && item.result == null && item.error == null) return message
|
|
390
|
+
return [message, openAIResponseToolOutputToMessage(item)]
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Converts a Responses API tool-output item to a chat-style tool message.
|
|
395
|
+
*
|
|
396
|
+
* @param {object} item
|
|
397
|
+
* @returns {object}
|
|
398
|
+
*/
|
|
399
|
+
function openAIResponseToolOutputToMessage (item) {
|
|
400
|
+
return {
|
|
401
|
+
role: 'tool',
|
|
402
|
+
tool_call_id: item.call_id ?? item.id,
|
|
403
|
+
content: openAIResponseOutputValueToMessageContent(item.output ?? item.result ?? item.error),
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Converts Responses API tool output to message content.
|
|
409
|
+
*
|
|
410
|
+
* @param {unknown} output
|
|
411
|
+
* @returns {string|Array<{type: string, text?: string, image_url?: {url: string}}>}
|
|
412
|
+
*/
|
|
413
|
+
function openAIResponseOutputValueToMessageContent (output) {
|
|
414
|
+
const content = openAIResponseContentToMessageContent(output)
|
|
415
|
+
return content ?? stringifyOrEmpty(output)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Converts OpenAI Responses API content to OpenAI chat-style message content.
|
|
420
|
+
*
|
|
421
|
+
* @param {string|Array<string|{type?: string, text?: string, refusal?: string,
|
|
422
|
+
* image_url?: string|{url?: string}, file_id?: string, file_url?: string,
|
|
423
|
+
* filename?: string}>|undefined} content
|
|
424
|
+
* @returns {string|Array<{type: string, text?: string, image_url?: {url: string}}>|undefined}
|
|
425
|
+
*/
|
|
426
|
+
function openAIResponseContentToMessageContent (content) {
|
|
427
|
+
if (typeof content === 'string') return content
|
|
428
|
+
if (!Array.isArray(content)) return
|
|
429
|
+
|
|
430
|
+
const parts = []
|
|
431
|
+
let hasImages = false
|
|
432
|
+
|
|
433
|
+
for (const part of content) {
|
|
434
|
+
if (!part) continue
|
|
435
|
+
if (typeof part === 'string') {
|
|
436
|
+
parts.push({ type: 'text', text: part })
|
|
437
|
+
} else if ((part.type === 'input_text' || part.type === 'output_text' || part.type === 'text') &&
|
|
438
|
+
typeof part.text === 'string') {
|
|
439
|
+
parts.push({ type: 'text', text: part.text })
|
|
440
|
+
} else if (part.type === 'refusal' && typeof part.refusal === 'string') {
|
|
441
|
+
parts.push({ type: 'text', text: part.refusal })
|
|
442
|
+
} else if (part.type === 'input_image' || part.type === 'image_url') {
|
|
443
|
+
const image = openAIResponseImageContentPart(part)
|
|
444
|
+
if (image) {
|
|
445
|
+
hasImages = true
|
|
446
|
+
parts.push(image)
|
|
447
|
+
}
|
|
448
|
+
} else if (part.type === 'input_file') {
|
|
449
|
+
parts.push({ type: 'text', text: openAIResponseFileContentPart(part) })
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (!parts.length) return
|
|
454
|
+
if (hasImages) return parts
|
|
455
|
+
return parts.map(part => part.text).join('\n')
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Converts an OpenAI image content part to AI Guard image_url content.
|
|
460
|
+
*
|
|
461
|
+
* @param {{image_url?: string|{url?: string}, file_id?: string, url?: string}} part
|
|
462
|
+
* @returns {{type: 'image_url', image_url: {url: string}}|undefined}
|
|
463
|
+
*/
|
|
464
|
+
function openAIResponseImageContentPart (part) {
|
|
465
|
+
const url = typeof part.image_url === 'string' ? part.image_url : part.image_url?.url ?? part.url
|
|
466
|
+
if (url) return { type: 'image_url', image_url: { url } }
|
|
467
|
+
if (part.file_id) return { type: 'image_url', image_url: { url: part.file_id } }
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Extracts a stable text marker from an OpenAI file content part.
|
|
472
|
+
*
|
|
473
|
+
* @param {{file_id?: string|null, file_url?: string, filename?: string, file_data?: string}} part
|
|
474
|
+
* @returns {string}
|
|
475
|
+
*/
|
|
476
|
+
function openAIResponseFileContentPart (part) {
|
|
477
|
+
return part.file_id ?? part.file_url ?? part.filename ?? FILE_FALLBACK
|
|
478
|
+
}
|
|
479
|
+
|
|
176
480
|
module.exports = {
|
|
177
481
|
convertVercelPromptToMessages,
|
|
178
482
|
convertFilePartToImageUrl,
|
|
483
|
+
normalizeOpenAIChatMessages,
|
|
179
484
|
buildToolCallOutputMessages,
|
|
180
485
|
buildTextOutputMessages,
|
|
181
486
|
buildOutputMessages,
|
|
487
|
+
convertOpenAIResponseItemsToMessages,
|
|
488
|
+
convertOpenAIResponsePromptToMessages,
|
|
489
|
+
openAIResponseContentToMessageContent,
|
|
182
490
|
}
|
|
@@ -45,7 +45,7 @@ function createCallbackInstrumentor (prefix, { captureResult = false } = {}) {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
return startCh.runStores(ctx, () => {
|
|
48
|
-
args[lastIndex] = shimmer.
|
|
48
|
+
args[lastIndex] = shimmer.wrapCallback(cb, cb => function (error, ...rest) {
|
|
49
49
|
if (error) {
|
|
50
50
|
ctx.error = error
|
|
51
51
|
errorCh.publish(ctx)
|
|
@@ -5,6 +5,7 @@ module.exports = {
|
|
|
5
5
|
child_process: () => require('../child_process'),
|
|
6
6
|
crypto: () => require('../crypto'),
|
|
7
7
|
dns: () => require('../dns'),
|
|
8
|
+
'dns/promises': () => require('../dns'),
|
|
8
9
|
fs: { serverless: false, fn: () => require('../fs') },
|
|
9
10
|
http: () => require('../http'),
|
|
10
11
|
http2: () => require('../http2'),
|
|
@@ -21,6 +22,7 @@ module.exports = {
|
|
|
21
22
|
'@modelcontextprotocol/sdk': () => require('../modelcontextprotocol-sdk'),
|
|
22
23
|
'apollo-server-core': () => require('../apollo-server-core'),
|
|
23
24
|
'@aws-sdk/smithy-client': () => require('../aws-sdk'),
|
|
25
|
+
'@azure/cosmos': { esmFirst: true, fn: () => require('../azure-cosmos') },
|
|
24
26
|
'@azure/event-hubs': () => require('../azure-event-hubs'),
|
|
25
27
|
'@azure/functions': () => require('../azure-functions'),
|
|
26
28
|
'durable-functions': () => require('../azure-durable-functions'),
|
|
@@ -48,6 +50,7 @@ module.exports = {
|
|
|
48
50
|
'@prisma/client': { esmFirst: true, fn: () => require('../prisma') },
|
|
49
51
|
'./runtime/library.js': () => require('../prisma'),
|
|
50
52
|
'@redis/client': () => require('../redis'),
|
|
53
|
+
'@smithy/core': () => require('../aws-sdk'),
|
|
51
54
|
'@smithy/smithy-client': () => require('../aws-sdk'),
|
|
52
55
|
'@vitest/runner': { esmFirst: true, fn: () => require('../vitest') },
|
|
53
56
|
aerospike: () => require('../aerospike'),
|
|
@@ -111,6 +114,7 @@ module.exports = {
|
|
|
111
114
|
multer: () => require('../multer'),
|
|
112
115
|
mysql: () => require('../mysql'),
|
|
113
116
|
mysql2: () => require('../mysql2'),
|
|
117
|
+
'@nats-io/nats-core': () => require('../nats'),
|
|
114
118
|
next: () => require('../next'),
|
|
115
119
|
'node-serialize': () => require('../node-serialize'),
|
|
116
120
|
nyc: () => require('../nyc'),
|
|
@@ -58,7 +58,8 @@ exports.getHooks = function getHooks (names) {
|
|
|
58
58
|
* @param {string} [args.file] path to file within package to instrument. Defaults to 'index.js'.
|
|
59
59
|
* @param {string} [args.filePattern] pattern to match files within package to instrument
|
|
60
60
|
* @param {boolean} [args.patchDefault] whether to patch the default export. Defaults to true.
|
|
61
|
-
* @param {(moduleExports: unknown, version: string, isIitm?: boolean) => unknown} [hook]
|
|
61
|
+
* @param {(moduleExports: unknown, version: string, isIitm?: boolean, hookMeta?: object) => unknown} [hook]
|
|
62
|
+
* Patches module exports
|
|
62
63
|
*/
|
|
63
64
|
exports.addHook = function addHook ({ name, versions, file, filePattern, patchDefault }, hook) {
|
|
64
65
|
if (!instrumentations[name]) {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
// Produce API key 0; v0–v2 use the legacy MessageSet format with no header
|
|
4
|
+
// field, so trace headers can only be carried on v3+ (Kafka >=0.11).
|
|
5
|
+
const PRODUCE_API_KEY = 0
|
|
6
|
+
const PRODUCE_VERSION_WITH_HEADERS = 3
|
|
7
|
+
|
|
3
8
|
// Side-table mapping a kafkajs producer/consumer to the cluster captured at
|
|
4
9
|
// creation time. The boundary uses it to read `cluster.brokerPool` lazily on
|
|
5
10
|
// first send/consume instead of opening a parallel admin connection. A
|
|
@@ -35,7 +40,19 @@ function cloneMessages (messages, ensureHeaders) {
|
|
|
35
40
|
return result
|
|
36
41
|
}
|
|
37
42
|
|
|
43
|
+
/**
|
|
44
|
+
* @param {{ versions?: Record<number, { minVersion: number, maxVersion: number }> } | undefined} brokerPool
|
|
45
|
+
* kafkajs's `cluster.brokerPool`. `versions` is populated once the seed
|
|
46
|
+
* broker handshakes; before that, the answer is unknown and we return
|
|
47
|
+
* `true` so the caller defaults to injection.
|
|
48
|
+
*/
|
|
49
|
+
function brokerSupportsMessageHeaders (brokerPool) {
|
|
50
|
+
const produce = brokerPool?.versions?.[PRODUCE_API_KEY]
|
|
51
|
+
return !produce || produce.maxVersion >= PRODUCE_VERSION_WITH_HEADERS
|
|
52
|
+
}
|
|
53
|
+
|
|
38
54
|
module.exports = {
|
|
55
|
+
brokerSupportsMessageHeaders,
|
|
39
56
|
clientToCluster,
|
|
40
57
|
cloneMessages,
|
|
41
58
|
}
|