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
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const dc = require('dc-polyfill')
|
|
4
|
+
const shimmer = require('../../../datadog-shimmer')
|
|
5
|
+
const {
|
|
6
|
+
convertOpenAIResponseItemsToMessages,
|
|
7
|
+
convertOpenAIResponsePromptToMessages,
|
|
8
|
+
normalizeOpenAIChatMessages,
|
|
9
|
+
} = require('./ai-messages')
|
|
10
|
+
|
|
11
|
+
// TODO: this channel name is incorrect, instrumentations publish with THEIR name, not with their subscribers names.
|
|
12
|
+
const aiguardChannel = dc.channel('dd-trace:ai:aiguard')
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {object} ResourceHandler
|
|
16
|
+
* @property {(callArgs: object) => (Array<object>|undefined)} getInputMessages
|
|
17
|
+
* @property {(body: object) => Array<object>} getOutputMessages
|
|
18
|
+
* @property {(inputMessages: Array<object>, outputMessages: Array<object>) => Promise<unknown>}
|
|
19
|
+
* publishOutputEvaluation
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {object} Guard
|
|
24
|
+
* @property {ResourceHandler} handler
|
|
25
|
+
* @property {Array<object>} inputMessages
|
|
26
|
+
* @property {() => Promise<void>} getInputEval
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Publishes already-converted AI-style messages to the AI Guard evaluation channel.
|
|
31
|
+
*
|
|
32
|
+
* @param {Array<object>} messages - AI-style messages to evaluate.
|
|
33
|
+
* @returns {Promise<void>}
|
|
34
|
+
*/
|
|
35
|
+
function publishEvaluation (messages) {
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
aiguardChannel.publish({ messages, integration: 'openai', resolve, reject })
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Extracts OpenAI input messages from a `chat.completions.create` call.
|
|
43
|
+
*
|
|
44
|
+
* @param {object} callArgs - First argument passed to the wrapped method
|
|
45
|
+
* @returns {Array<object>|undefined}
|
|
46
|
+
*/
|
|
47
|
+
function getChatCompletionsInputMessages (callArgs) {
|
|
48
|
+
return normalizeOpenAIChatMessages(callArgs?.messages)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Extracts OpenAI output messages from a `chat.completions.create` parsed body.
|
|
53
|
+
* Includes any choice whose message carries content (including empty string),
|
|
54
|
+
* `tool_calls`, a `refusal` field, or the deprecated `function_call` field. GPT-4o
|
|
55
|
+
* emits `{content: null, refusal: "..."}` on policy refusals, and pre-tool-call
|
|
56
|
+
* SDK paths still produce `function_call`-only output — AI Guard must still see them.
|
|
57
|
+
*
|
|
58
|
+
* @param {object} body - Parsed response body
|
|
59
|
+
* @returns {Array<object>}
|
|
60
|
+
*/
|
|
61
|
+
function getChatCompletionsOutputMessages (body) {
|
|
62
|
+
const eligible = []
|
|
63
|
+
const choices = Array.isArray(body?.choices) ? body.choices : []
|
|
64
|
+
for (const choice of choices) {
|
|
65
|
+
const message = choice?.message
|
|
66
|
+
if (
|
|
67
|
+
message?.content != null ||
|
|
68
|
+
message?.tool_calls?.length ||
|
|
69
|
+
message?.refusal != null ||
|
|
70
|
+
message?.function_call != null
|
|
71
|
+
) {
|
|
72
|
+
eligible.push(message)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return normalizeOpenAIChatMessages(eligible) ?? []
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Publishes AI Guard After Model evaluation for `chat.completions` output.
|
|
80
|
+
*
|
|
81
|
+
* Chat completions may return multiple choices when `n > 1`. Screen every choice
|
|
82
|
+
* concurrently so any unsafe assistant output rejects `.parse()`, regardless of
|
|
83
|
+
* which choice the caller ends up using.
|
|
84
|
+
*
|
|
85
|
+
* @param {Array<object>} inputMessages
|
|
86
|
+
* @param {Array<object>} outputMessages - One entry per choice
|
|
87
|
+
* @returns {Promise<Array<void>>}
|
|
88
|
+
*/
|
|
89
|
+
function publishChatCompletionsOutputEvaluation (inputMessages, outputMessages) {
|
|
90
|
+
const evals = []
|
|
91
|
+
for (const message of outputMessages) {
|
|
92
|
+
evals.push(publishEvaluation([...inputMessages, message]))
|
|
93
|
+
}
|
|
94
|
+
return Promise.all(evals)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Extracts OpenAI input messages from a `responses.create` call. The `instructions`
|
|
99
|
+
* field is treated as a developer prompt — it directly steers model behavior and the
|
|
100
|
+
* LLMObs OpenAI plugin already surfaces it as one — so AI Guard must screen it too.
|
|
101
|
+
*
|
|
102
|
+
* AI Guard `/evaluate` accepts a single leading system/developer message; if the
|
|
103
|
+
* caller's `input` already begins with one, prepend the `instructions` text to its
|
|
104
|
+
* content rather than emit a second developer turn.
|
|
105
|
+
*
|
|
106
|
+
* @param {object} callArgs - First argument passed to the wrapped method
|
|
107
|
+
* @returns {Array<object>|undefined}
|
|
108
|
+
*/
|
|
109
|
+
function getResponsesInputMessages (callArgs) {
|
|
110
|
+
const messages = [
|
|
111
|
+
...convertOpenAIResponseItemsToMessages(callArgs?.input, 'user'),
|
|
112
|
+
...convertOpenAIResponsePromptToMessages(callArgs?.prompt),
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
const instructions = typeof callArgs?.instructions === 'string' && callArgs.instructions.length
|
|
116
|
+
? callArgs.instructions
|
|
117
|
+
: null
|
|
118
|
+
if (!instructions) return messages.length ? messages : undefined
|
|
119
|
+
|
|
120
|
+
const first = messages[0]
|
|
121
|
+
if (first && (first.role === 'developer' || first.role === 'system')) {
|
|
122
|
+
const merged = { role: 'developer', content: mergeInstructionsWithContent(instructions, first.content) }
|
|
123
|
+
return [merged, ...messages.slice(1)]
|
|
124
|
+
}
|
|
125
|
+
return [{ role: 'developer', content: instructions }, ...messages]
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Merges Responses API instructions with an existing leading developer/system content value.
|
|
130
|
+
*
|
|
131
|
+
* @param {string} instructions
|
|
132
|
+
* @param {string|Array<object>|undefined} content
|
|
133
|
+
* @returns {string|Array<object>}
|
|
134
|
+
*/
|
|
135
|
+
function mergeInstructionsWithContent (instructions, content) {
|
|
136
|
+
if (Array.isArray(content)) return [{ type: 'text', text: instructions }, ...content]
|
|
137
|
+
if (typeof content === 'string' && content.length) return `${instructions}\n\n${content}`
|
|
138
|
+
return instructions
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Extracts OpenAI output messages from a `responses.create` parsed body.
|
|
143
|
+
*
|
|
144
|
+
* @param {object} body - Parsed response body
|
|
145
|
+
* @returns {Array<object>}
|
|
146
|
+
*/
|
|
147
|
+
function getResponsesOutputMessages (body) {
|
|
148
|
+
return convertOpenAIResponseItemsToMessages(body?.output, 'assistant')
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Publishes AI Guard After Model evaluation for `responses` output.
|
|
153
|
+
*
|
|
154
|
+
* The Responses API returns a single conversation turn whose `output` items form one
|
|
155
|
+
* coherent message (reasoning steps + final assistant message + tool calls + ...);
|
|
156
|
+
* they are screened together as a single evaluation.
|
|
157
|
+
*
|
|
158
|
+
* @param {Array<object>} inputMessages
|
|
159
|
+
* @param {Array<object>} outputMessages
|
|
160
|
+
* @returns {Promise<void>}
|
|
161
|
+
*/
|
|
162
|
+
function publishResponsesOutputEvaluation (inputMessages, outputMessages) {
|
|
163
|
+
return publishEvaluation([...inputMessages, ...outputMessages])
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Per-resource handlers describing how AI Guard reads inputs and screens outputs for
|
|
168
|
+
* each LLM-prompt-accepting OpenAI endpoint. The keys also serve as the set of
|
|
169
|
+
* resources eligible for AI Guard evaluation.
|
|
170
|
+
*
|
|
171
|
+
* @type {Record<string, ResourceHandler>}
|
|
172
|
+
*/
|
|
173
|
+
const RESOURCE_HANDLERS = {
|
|
174
|
+
'chat.completions': {
|
|
175
|
+
getInputMessages: getChatCompletionsInputMessages,
|
|
176
|
+
getOutputMessages: getChatCompletionsOutputMessages,
|
|
177
|
+
publishOutputEvaluation: publishChatCompletionsOutputEvaluation,
|
|
178
|
+
},
|
|
179
|
+
responses: {
|
|
180
|
+
getInputMessages: getResponsesInputMessages,
|
|
181
|
+
getOutputMessages: getResponsesOutputMessages,
|
|
182
|
+
publishOutputEvaluation: publishResponsesOutputEvaluation,
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Reports whether the AI Guard channel has subscribers. The OpenAI instrumentation
|
|
188
|
+
* uses this to decide whether to take the AI Guard path at all.
|
|
189
|
+
*
|
|
190
|
+
* @returns {boolean}
|
|
191
|
+
*/
|
|
192
|
+
function hasSubscribers () {
|
|
193
|
+
return aiguardChannel.hasSubscribers
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Builds a guard handle when AI Guard is enabled and applicable to this call. The
|
|
198
|
+
* handle binds the per-resource handler so downstream functions never re-dispatch
|
|
199
|
+
* on `baseResource`. Returns null when AI Guard does not apply (no subscribers,
|
|
200
|
+
* non-eligible resource, streaming, or no input messages).
|
|
201
|
+
*
|
|
202
|
+
* @param {string} baseResource - e.g. `'chat.completions'` or `'responses'`
|
|
203
|
+
* @param {object} callArgs - First argument passed to the wrapped OpenAI method
|
|
204
|
+
* @param {boolean} stream - Whether the caller asked for a streamed response
|
|
205
|
+
* @returns {Guard|null}
|
|
206
|
+
*/
|
|
207
|
+
function createGuard (baseResource, callArgs, stream) {
|
|
208
|
+
// Streaming AI Guard support lands in a follow-up PR. For now, provider-level AI
|
|
209
|
+
// Guard only evaluates non-streaming responses.
|
|
210
|
+
if (stream || !aiguardChannel.hasSubscribers) return null
|
|
211
|
+
const handler = RESOURCE_HANDLERS[baseResource]
|
|
212
|
+
if (!handler) return null
|
|
213
|
+
|
|
214
|
+
const inputMessages = handler.getInputMessages(callArgs)
|
|
215
|
+
if (!inputMessages) return null
|
|
216
|
+
|
|
217
|
+
let inputEvalPromise
|
|
218
|
+
const getInputEval = () => (inputEvalPromise ??= publishEvaluation(inputMessages))
|
|
219
|
+
return { handler, inputMessages, getInputEval }
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Wraps `apiProm.asResponse` so callers that consume the raw `Response` object still
|
|
224
|
+
* receive the Before Model verdict. After Model evaluation is not performed on this
|
|
225
|
+
* path because the response body has not been parsed.
|
|
226
|
+
*
|
|
227
|
+
* @param {object} apiProm - APIPromise returned from the OpenAI SDK method
|
|
228
|
+
* @param {Guard} guard
|
|
229
|
+
*/
|
|
230
|
+
function wrapAsResponse (apiProm, guard) {
|
|
231
|
+
if (typeof apiProm.asResponse !== 'function') return
|
|
232
|
+
shimmer.wrap(apiProm, 'asResponse', origAsResponse => function (...args) {
|
|
233
|
+
const responsePromise = origAsResponse.apply(this, args)
|
|
234
|
+
return Promise.all([guard.getInputEval(), responsePromise]).then(([, response]) => response)
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Gates the parsed-body promise on Before Model evaluation. Resolves to the SDK's
|
|
240
|
+
* result only once the Before Model verdict is in.
|
|
241
|
+
*
|
|
242
|
+
* @param {Promise<unknown>} parsedPromise
|
|
243
|
+
* @param {Guard} guard
|
|
244
|
+
* @returns {Promise<unknown>}
|
|
245
|
+
*/
|
|
246
|
+
function gateParse (parsedPromise, guard) {
|
|
247
|
+
return Promise.all([guard.getInputEval(), parsedPromise]).then(([, result]) => result)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Runs After Model evaluation against the response body.
|
|
252
|
+
*
|
|
253
|
+
* @param {Guard} guard
|
|
254
|
+
* @param {object} body - Parsed OpenAI response body
|
|
255
|
+
* @returns {Promise<unknown>}
|
|
256
|
+
*/
|
|
257
|
+
function evaluateOutput (guard, body) {
|
|
258
|
+
const outputMessages = guard.handler.getOutputMessages(body)
|
|
259
|
+
if (!outputMessages.length) return Promise.resolve()
|
|
260
|
+
return guard.handler.publishOutputEvaluation(guard.inputMessages, outputMessages)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
module.exports = {
|
|
264
|
+
hasSubscribers,
|
|
265
|
+
createGuard,
|
|
266
|
+
wrapAsResponse,
|
|
267
|
+
gateParse,
|
|
268
|
+
evaluateOutput,
|
|
269
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const dc = require('dc-polyfill')
|
|
4
|
+
|
|
5
|
+
const { channel } = require('./instrument')
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Shimmer-compatible instrumentor for promise-returning APIs (e.g. `dns.promises.lookup`).
|
|
9
|
+
* Mirrors `createCallbackInstrumentor`'s channel triplet (`<prefix>:start`, `:finish`, `:error`)
|
|
10
|
+
* so a plugin subscribing to those channels for the callback variant works for the promise
|
|
11
|
+
* variant unchanged. `:finish` is the `tracingChannel` `asyncEnd` slot, so it fires after the
|
|
12
|
+
* promise settles with `ctx.result` set to the resolved value.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} prefix
|
|
15
|
+
* @returns {(buildContext: (thisArg: unknown, args: unknown[]) => object | undefined) =>
|
|
16
|
+
* (fn: Function) => Function}
|
|
17
|
+
*/
|
|
18
|
+
function createPromiseInstrumentor (prefix) {
|
|
19
|
+
const start = channel(prefix + ':start')
|
|
20
|
+
const finish = channel(prefix + ':finish')
|
|
21
|
+
const error = channel(prefix + ':error')
|
|
22
|
+
const tracing = dc.tracingChannel({
|
|
23
|
+
start,
|
|
24
|
+
end: channel(prefix + ':end'),
|
|
25
|
+
asyncStart: channel(prefix + ':asyncStart'),
|
|
26
|
+
asyncEnd: finish,
|
|
27
|
+
error,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
return function instrument (buildContext) {
|
|
31
|
+
return function wrap (fn) {
|
|
32
|
+
return function (...args) {
|
|
33
|
+
if (!start.hasSubscribers) return fn.apply(this, args)
|
|
34
|
+
const ctx = buildContext(this, args)
|
|
35
|
+
if (ctx === undefined) return fn.apply(this, args)
|
|
36
|
+
return tracing.tracePromise(fn, ctx, this, ...args)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = { createPromiseInstrumentor }
|
|
@@ -133,7 +133,7 @@ for (const name of names) {
|
|
|
133
133
|
try {
|
|
134
134
|
loadChannel.publish({ name })
|
|
135
135
|
|
|
136
|
-
moduleExports = hook(moduleExports, moduleVersion, isIitm) ?? moduleExports
|
|
136
|
+
moduleExports = hook(moduleExports, moduleVersion, isIitm, { moduleBaseDir, moduleName }) ?? moduleExports
|
|
137
137
|
} catch (error) {
|
|
138
138
|
log.info('Error during ddtrace instrumentation of application, aborting.', error)
|
|
139
139
|
telemetry('error', [
|
|
@@ -19,9 +19,10 @@ const compiler = {
|
|
|
19
19
|
// TODO: Figure out ESBuild `createRequire` issue and remove this hack.
|
|
20
20
|
const oxc = runtimeRequire(['oxc', 'parser'].join('-'))
|
|
21
21
|
|
|
22
|
-
compiler.parse = (sourceText,
|
|
22
|
+
compiler.parse = (sourceText, { range, isModule } = {}) => {
|
|
23
23
|
const { program, errors } = oxc.parseSync('index.js', sourceText, {
|
|
24
|
-
|
|
24
|
+
range,
|
|
25
|
+
sourceType: isModule ? 'module' : 'script',
|
|
25
26
|
preserveParens: false,
|
|
26
27
|
})
|
|
27
28
|
|
|
@@ -2,15 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
const { readFileSync } = require('fs')
|
|
4
4
|
const { join } = require('path')
|
|
5
|
+
const { pathToFileURL } = require('url')
|
|
5
6
|
const log = require('../../../../dd-trace/src/log')
|
|
6
7
|
const { create } = require('../../../../../vendor/dist/@apm-js-collab/code-transformer')
|
|
7
|
-
const {
|
|
8
|
+
const { waitForAsyncEnd } = require('./transforms')
|
|
8
9
|
const instrumentations = require('./instrumentations')
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
// `dc-polyfill` is referenced from injected `require()` (CJS) and `import`
|
|
12
|
+
// (ESM) statements that the transformer splices into the rewritten module.
|
|
13
|
+
// `require()` accepts an absolute filesystem path; the ESM resolver rejects it
|
|
14
|
+
// with `ERR_INVALID_MODULE_SPECIFIER` and needs a `file://` URL instead. We
|
|
15
|
+
// pre-compute both forms here so each matcher hands the transformer a
|
|
16
|
+
// specifier that is valid for the module type it is rewriting.
|
|
17
|
+
let dcPolyfillCjs
|
|
18
|
+
let dcPolyfillEsm
|
|
11
19
|
|
|
12
20
|
try {
|
|
13
|
-
|
|
21
|
+
const resolved = require.resolve('dc-polyfill')
|
|
22
|
+
dcPolyfillCjs = resolved.replaceAll('\\', '/')
|
|
23
|
+
dcPolyfillEsm = pathToFileURL(resolved).href
|
|
14
24
|
} catch {
|
|
15
25
|
// The `dc-polyfill` module is unavailable for some reason (like bundling).
|
|
16
26
|
// Let's just keep the default of using `diagnostics-channel` as a fallback
|
|
@@ -20,10 +30,12 @@ try {
|
|
|
20
30
|
/** @type {Record<string, string>} map of module base name to version */
|
|
21
31
|
const moduleVersions = {}
|
|
22
32
|
const disabled = new Set()
|
|
23
|
-
const
|
|
33
|
+
const matcherCjs = create(instrumentations, dcPolyfillCjs)
|
|
34
|
+
const matcherEsm = create(instrumentations, dcPolyfillEsm)
|
|
24
35
|
|
|
25
|
-
matcher
|
|
26
|
-
matcher.addTransform('
|
|
36
|
+
for (const matcher of [matcherCjs, matcherEsm]) {
|
|
37
|
+
matcher.addTransform('waitForAsyncEnd', waitForAsyncEnd)
|
|
38
|
+
}
|
|
27
39
|
|
|
28
40
|
function rewrite (content, filename, format) {
|
|
29
41
|
if (!content) return content
|
|
@@ -41,6 +53,7 @@ function rewrite (content, filename, format) {
|
|
|
41
53
|
|
|
42
54
|
if (disabled.has(moduleName)) return content
|
|
43
55
|
|
|
56
|
+
const matcher = moduleType === 'esm' ? matcherEsm : matcherCjs
|
|
44
57
|
const transformer = matcher.getTransformer(moduleName, version, filePath)
|
|
45
58
|
|
|
46
59
|
if (!transformer) return content
|
package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports = [{
|
|
4
|
+
module: {
|
|
5
|
+
name: '@azure/cosmos',
|
|
6
|
+
versionRange: '>=4.4.1',
|
|
7
|
+
filePath: 'dist/browser/plugins/Plugin.js',
|
|
8
|
+
},
|
|
9
|
+
functionQuery: {
|
|
10
|
+
functionName: 'executePlugins',
|
|
11
|
+
kind: 'Async',
|
|
12
|
+
},
|
|
13
|
+
channelName: 'executePlugins',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
module: {
|
|
17
|
+
name: '@azure/cosmos',
|
|
18
|
+
versionRange: '>=4.4.1',
|
|
19
|
+
filePath: 'dist/commonjs/plugins/Plugin.js',
|
|
20
|
+
},
|
|
21
|
+
functionQuery: {
|
|
22
|
+
functionName: 'executePlugins',
|
|
23
|
+
kind: 'Async',
|
|
24
|
+
},
|
|
25
|
+
channelName: 'executePlugins',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
module: {
|
|
29
|
+
name: '@azure/cosmos',
|
|
30
|
+
versionRange: '>=4.4.1',
|
|
31
|
+
filePath: 'dist/esm/plugins/Plugin.js',
|
|
32
|
+
},
|
|
33
|
+
functionQuery: {
|
|
34
|
+
functionName: 'executePlugins',
|
|
35
|
+
kind: 'Async',
|
|
36
|
+
},
|
|
37
|
+
channelName: 'executePlugins',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
module: {
|
|
41
|
+
name: '@azure/cosmos',
|
|
42
|
+
versionRange: '>=4.4.1',
|
|
43
|
+
filePath: 'dist/react-native/plugins/Plugin.js',
|
|
44
|
+
},
|
|
45
|
+
functionQuery: {
|
|
46
|
+
functionName: 'executePlugins',
|
|
47
|
+
kind: 'Async',
|
|
48
|
+
},
|
|
49
|
+
channelName: 'executePlugins',
|
|
50
|
+
}]
|
package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js
CHANGED
|
@@ -10,9 +10,10 @@ module.exports = [
|
|
|
10
10
|
functionQuery: {
|
|
11
11
|
methodName: 'stream',
|
|
12
12
|
className: 'Pregel',
|
|
13
|
+
kind: 'Async',
|
|
14
|
+
returnKind: 'AsyncIterator',
|
|
13
15
|
},
|
|
14
16
|
channelName: 'Pregel_stream',
|
|
15
|
-
transform: 'traceAsyncIterator',
|
|
16
17
|
},
|
|
17
18
|
{
|
|
18
19
|
module: {
|
|
@@ -23,8 +24,9 @@ module.exports = [
|
|
|
23
24
|
functionQuery: {
|
|
24
25
|
methodName: 'stream',
|
|
25
26
|
className: 'Pregel',
|
|
27
|
+
kind: 'Async',
|
|
28
|
+
returnKind: 'AsyncIterator',
|
|
26
29
|
},
|
|
27
30
|
channelName: 'Pregel_stream',
|
|
28
|
-
transform: 'traceAsyncIterator',
|
|
29
31
|
},
|
|
30
32
|
]
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Playwright 1.60 bundles several former hook targets into local classes/functions.
|
|
4
|
+
// Keep these rewrites limited to private bundled internals that addHook cannot wrap.
|
|
5
|
+
module.exports = [
|
|
6
|
+
{
|
|
7
|
+
module: {
|
|
8
|
+
name: 'playwright',
|
|
9
|
+
versionRange: '>=1.60.0',
|
|
10
|
+
filePath: 'lib/runner/index.js',
|
|
11
|
+
},
|
|
12
|
+
functionQuery: {
|
|
13
|
+
className: 'Dispatcher',
|
|
14
|
+
methodName: 'run',
|
|
15
|
+
kind: 'Async',
|
|
16
|
+
},
|
|
17
|
+
channelName: 'Dispatcher_run',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
module: {
|
|
21
|
+
name: 'playwright',
|
|
22
|
+
versionRange: '>=1.60.0',
|
|
23
|
+
filePath: 'lib/runner/index.js',
|
|
24
|
+
},
|
|
25
|
+
functionQuery: {
|
|
26
|
+
className: 'Dispatcher',
|
|
27
|
+
methodName: '_createWorker',
|
|
28
|
+
kind: 'Sync',
|
|
29
|
+
},
|
|
30
|
+
channelName: 'Dispatcher_createWorker',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
module: {
|
|
34
|
+
name: 'playwright',
|
|
35
|
+
versionRange: '>=1.60.0',
|
|
36
|
+
filePath: 'lib/runner/index.js',
|
|
37
|
+
},
|
|
38
|
+
functionQuery: {
|
|
39
|
+
className: 'ProcessHost',
|
|
40
|
+
methodName: 'startRunner',
|
|
41
|
+
kind: 'Async',
|
|
42
|
+
},
|
|
43
|
+
channelName: 'ProcessHost_startRunner',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
module: {
|
|
47
|
+
name: 'playwright',
|
|
48
|
+
versionRange: '>=1.60.0',
|
|
49
|
+
filePath: 'lib/runner/index.js',
|
|
50
|
+
},
|
|
51
|
+
functionQuery: {
|
|
52
|
+
functionName: 'createRootSuite',
|
|
53
|
+
kind: 'Async',
|
|
54
|
+
},
|
|
55
|
+
channelName: 'createRootSuite',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
module: {
|
|
59
|
+
name: 'playwright-core',
|
|
60
|
+
versionRange: '>=1.60.0',
|
|
61
|
+
filePath: 'lib/coreBundle.js',
|
|
62
|
+
},
|
|
63
|
+
astQuery: 'AssignmentExpression[left.name="Page2"] > ClassExpression > ClassBody > ' +
|
|
64
|
+
'MethodDefinition[kind="method"][key.name="goto"] > FunctionExpression[async], ' +
|
|
65
|
+
'VariableDeclarator[id.name="Page2"] > ClassExpression > ClassBody > ' +
|
|
66
|
+
'MethodDefinition[kind="method"][key.name="goto"] > FunctionExpression[async], ' +
|
|
67
|
+
'ClassDeclaration[id.name="Page2"] > ClassBody > ' +
|
|
68
|
+
'MethodDefinition[kind="method"][key.name="goto"] > FunctionExpression[async]',
|
|
69
|
+
functionQuery: {
|
|
70
|
+
methodName: 'goto',
|
|
71
|
+
kind: 'Async',
|
|
72
|
+
},
|
|
73
|
+
channelName: 'Page_goto',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
module: {
|
|
77
|
+
name: 'playwright-core',
|
|
78
|
+
versionRange: '>=1.60.0',
|
|
79
|
+
filePath: 'lib/coreBundle.js',
|
|
80
|
+
},
|
|
81
|
+
astQuery: 'ReturnStatement > CallExpression[callee.object.name="promise"][callee.property.name="then"]',
|
|
82
|
+
channelName: 'Page_goto',
|
|
83
|
+
transform: 'waitForAsyncEnd',
|
|
84
|
+
},
|
|
85
|
+
]
|