dd-trace 6.7.0 → 6.9.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/ci/diagnose.js +27 -25
- package/ci/init.js +6 -6
- package/ci/runbook.md +114 -20
- package/ci/test-optimization-validation/approval-artifacts.js +36 -3
- package/ci/test-optimization-validation/approval.js +78 -22
- package/ci/test-optimization-validation/blocker-category.js +24 -0
- package/ci/test-optimization-validation/ci-discovery.js +23 -17
- package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
- package/ci/test-optimization-validation/ci-remediation.js +1 -1
- package/ci/test-optimization-validation/cli.js +280 -52
- package/ci/test-optimization-validation/command-blocker.js +159 -20
- package/ci/test-optimization-validation/command-output-policy.js +14 -8
- package/ci/test-optimization-validation/command-runner.js +9 -7
- package/ci/test-optimization-validation/environment.js +4 -2
- package/ci/test-optimization-validation/executable.js +15 -13
- package/ci/test-optimization-validation/execution-lock.js +70 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
- package/ci/test-optimization-validation/framework-adapters/playwright.js +5 -5
- package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
- package/ci/test-optimization-validation/generated-files.js +47 -37
- package/ci/test-optimization-validation/generated-test-contract.js +9 -7
- package/ci/test-optimization-validation/generated-verifier.js +24 -17
- package/ci/test-optimization-validation/literal-glob.js +52 -0
- package/ci/test-optimization-validation/manifest-loader.js +3 -0
- package/ci/test-optimization-validation/manifest-scaffold.js +301 -52
- package/ci/test-optimization-validation/manifest-schema.js +80 -17
- package/ci/test-optimization-validation/offline-fixtures.js +13 -4
- package/ci/test-optimization-validation/offline-output.js +6 -6
- package/ci/test-optimization-validation/package-check.js +94 -0
- package/ci/test-optimization-validation/plan-writer.js +183 -10
- package/ci/test-optimization-validation/preflight-runner.js +110 -31
- package/ci/test-optimization-validation/project-build-artifact.js +31 -0
- package/ci/test-optimization-validation/redaction.js +18 -27
- package/ci/test-optimization-validation/report-writer.js +182 -48
- package/ci/test-optimization-validation/result-semantics.js +20 -3
- package/ci/test-optimization-validation/runner-command.js +41 -21
- package/ci/test-optimization-validation/runner-contract.js +79 -43
- package/ci/test-optimization-validation/safe-files.js +4 -4
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +60 -6
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
- package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
- package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
- package/ci/test-optimization-validation/static-diagnosis.js +10 -3
- package/ci/test-optimization-validation/test-output.js +2 -1
- package/ci/test-optimization-validation/validation-blocker.js +21 -0
- package/ci/vitest-no-worker-init-setup.mjs +377 -84
- package/index.d.ts +175 -14
- package/init.js +1 -17
- package/initialize.mjs +11 -0
- package/loader-hook.mjs +6 -4
- package/package.json +12 -4
- package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
- package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
- package/packages/datadog-esbuild/index.js +4 -2
- package/packages/datadog-esbuild/src/utils.js +17 -2
- package/packages/datadog-instrumentations/src/ai.js +61 -34
- package/packages/datadog-instrumentations/src/bluebird.js +6 -6
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +85 -9
- package/packages/datadog-instrumentations/src/cucumber.js +131 -51
- package/packages/datadog-instrumentations/src/dns.js +21 -2
- package/packages/datadog-instrumentations/src/electron.js +1 -0
- package/packages/datadog-instrumentations/src/fastify.js +3 -1
- package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
- package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +175 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +61 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +38 -7
- package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
- package/packages/datadog-instrumentations/src/http/client.js +1 -3
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +986 -246
- package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
- package/packages/datadog-instrumentations/src/mocha/main.js +109 -51
- package/packages/datadog-instrumentations/src/mocha/utils.js +120 -32
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +44 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +441 -43
- package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
- package/packages/datadog-instrumentations/src/mysql.js +1 -1
- package/packages/datadog-instrumentations/src/next.js +155 -23
- package/packages/datadog-instrumentations/src/openai.js +14 -0
- package/packages/datadog-instrumentations/src/pg.js +180 -6
- package/packages/datadog-instrumentations/src/playwright.js +176 -81
- package/packages/datadog-instrumentations/src/promise-js.js +4 -4
- package/packages/datadog-instrumentations/src/promise.js +3 -3
- package/packages/datadog-instrumentations/src/rhea.js +1 -1
- package/packages/datadog-instrumentations/src/router.js +195 -19
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +567 -65
- package/packages/datadog-instrumentations/src/vitest-main.js +438 -54
- package/packages/datadog-instrumentations/src/vitest-util.js +42 -7
- package/packages/datadog-instrumentations/src/vitest-worker.js +234 -17
- package/packages/datadog-instrumentations/src/webdriverio.js +1090 -0
- package/packages/datadog-instrumentations/src/when.js +3 -3
- package/packages/datadog-instrumentations/src/ws.js +5 -1
- package/packages/datadog-plugin-aerospike/src/index.js +1 -3
- package/packages/datadog-plugin-amqplib/src/client.js +1 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
- package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
- package/packages/datadog-plugin-child_process/src/index.js +3 -3
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -11
- package/packages/datadog-plugin-cucumber/src/index.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +50 -46
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
- package/packages/datadog-plugin-cypress/src/support.js +7 -4
- package/packages/datadog-plugin-electron/src/net.js +10 -4
- package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
- package/packages/datadog-plugin-fs/src/index.js +0 -4
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
- package/packages/datadog-plugin-graphql/src/execute.js +1 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +3 -2
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +3 -21
- package/packages/datadog-plugin-jest/src/util.js +4 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
- package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
- package/packages/datadog-plugin-mocha/src/index.js +342 -6
- package/packages/datadog-plugin-next/src/index.js +57 -9
- package/packages/datadog-plugin-openai/src/tracing.js +4 -0
- package/packages/datadog-plugin-pg/src/index.js +65 -1
- package/packages/datadog-plugin-playwright/src/index.js +1 -1
- package/packages/datadog-plugin-prisma/src/index.js +5 -1
- package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-undici/src/index.js +2 -1
- package/packages/datadog-plugin-vitest/src/index.js +179 -18
- package/packages/datadog-shimmer/src/shimmer.js +6 -2
- package/packages/datadog-webpack/index.js +2 -2
- package/packages/dd-trace/src/aiguard/sdk.js +3 -0
- package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
- package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
- package/packages/dd-trace/src/appsec/handlers/http-request.js +215 -0
- package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
- package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
- package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +48 -476
- package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -1
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
- package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
- package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -15
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +19 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +25 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +2 -2
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
- package/packages/dd-trace/src/config/defaults.js +14 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
- package/packages/dd-trace/src/config/helper.js +2 -0
- package/packages/dd-trace/src/config/index.js +31 -5
- package/packages/dd-trace/src/config/parsers.js +19 -1
- package/packages/dd-trace/src/config/remote_config.js +1 -1
- package/packages/dd-trace/src/config/supported-configurations.json +13 -6
- package/packages/dd-trace/src/datastreams/encoding.js +3 -4
- package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
- package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
- package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
- package/packages/dd-trace/src/encode/tags-processors.js +2 -2
- package/packages/dd-trace/src/exporters/common/url.js +3 -5
- package/packages/dd-trace/src/exporters/electron/index.js +4 -1
- package/packages/dd-trace/src/external-logger/src/index.js +1 -2
- package/packages/dd-trace/src/flare/index.js +2 -2
- package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
- package/packages/dd-trace/src/guardrails/log.js +1 -10
- package/packages/dd-trace/src/id.js +1 -1
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
- package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
- package/packages/dd-trace/src/llmobs/experiments/index.js +66 -19
- package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
- package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
- package/packages/dd-trace/src/llmobs/experiments/util.js +220 -0
- package/packages/dd-trace/src/llmobs/noop.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.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 +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +152 -78
- package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
- package/packages/dd-trace/src/llmobs/tagger.js +1 -2
- package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
- package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
- package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
- package/packages/dd-trace/src/log/channels.js +1 -9
- package/packages/dd-trace/src/log/levels.js +12 -0
- package/packages/dd-trace/src/noop/proxy.js +2 -2
- package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
- package/packages/dd-trace/src/opentelemetry/span.js +4 -0
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/opentracing/span_context.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +124 -23
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/tracing.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -6
- package/packages/dd-trace/src/plugins/util/git.js +7 -5
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +3 -3
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/llm.js +2 -2
- package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
- package/packages/dd-trace/src/plugins/util/tags.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +356 -86
- package/packages/dd-trace/src/plugins/util/url.js +5 -5
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
- package/packages/dd-trace/src/plugins/util/web.js +24 -2
- package/packages/dd-trace/src/priority_sampler.js +6 -3
- package/packages/dd-trace/src/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
- package/packages/dd-trace/src/proxy.js +1 -0
- package/packages/dd-trace/src/ritm.js +10 -20
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
- package/packages/dd-trace/src/sampling_rule.js +4 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
- package/packages/dd-trace/src/startup-log.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
- package/packages/dd-trace/src/util.js +16 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/source-map/index.js +1 -1
- package/version.js +10 -8
- /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
|
@@ -1,8 +1,90 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const log = require('../../log')
|
|
4
|
+
|
|
5
|
+
class NoopDataset {
|
|
6
|
+
#name
|
|
7
|
+
#records
|
|
8
|
+
|
|
9
|
+
constructor (name = '', options = {}) {
|
|
10
|
+
this.#name = name
|
|
11
|
+
this.#records = (typeof options === 'string' ? [] : (options.records ?? [])).map(record => ({
|
|
12
|
+
id: record.id ?? null,
|
|
13
|
+
input: record.inputData,
|
|
14
|
+
expectedOutput: record.expectedOutput ?? null,
|
|
15
|
+
metadata: record.metadata ?? {},
|
|
16
|
+
}))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
addRecord (input, expectedOutput, metadata) {
|
|
20
|
+
this.#records.push({ id: null, input, expectedOutput: expectedOutput ?? null, metadata: metadata ?? {} })
|
|
21
|
+
return this
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
push () {
|
|
25
|
+
return Promise.resolve({ pushedCount: 0, totalCount: 0 })
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
name () {
|
|
29
|
+
return this.#name
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
id () {
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
projectId () {
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
version () {
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
latestVersion () {
|
|
45
|
+
return null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
records () {
|
|
49
|
+
return [...this.#records]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
recordIds () {
|
|
53
|
+
return []
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
url () {
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
class NoopExperiment {
|
|
62
|
+
#name
|
|
63
|
+
|
|
64
|
+
constructor (name = '') {
|
|
65
|
+
this.#name = name
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
name () {
|
|
69
|
+
return this.#name
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
experimentId () {
|
|
73
|
+
return null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
url () {
|
|
77
|
+
return null
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
run () {
|
|
81
|
+
return Promise.resolve({ experimentId: null, rows: [], url: null })
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
3
85
|
// No-op Experiments used when LLM Observability is disabled or the API/APP keys
|
|
4
|
-
// are not configured.
|
|
5
|
-
//
|
|
86
|
+
// are not configured. Operations warn and return inert objects rather than
|
|
87
|
+
// throwing, so intentionally disabled experiments remain graceful.
|
|
6
88
|
class NoopExperiments {
|
|
7
89
|
#reason
|
|
8
90
|
|
|
@@ -10,20 +92,23 @@ class NoopExperiments {
|
|
|
10
92
|
this.#reason = reason || 'LLMObs experiments are not available'
|
|
11
93
|
}
|
|
12
94
|
|
|
13
|
-
#
|
|
14
|
-
|
|
95
|
+
#warn () {
|
|
96
|
+
log.warn('LLMObs experiments unavailable: %s', this.#reason)
|
|
15
97
|
}
|
|
16
98
|
|
|
17
|
-
createDataset () {
|
|
18
|
-
|
|
99
|
+
createDataset (name, options = {}) {
|
|
100
|
+
this.#warn()
|
|
101
|
+
return new NoopDataset(name, options)
|
|
19
102
|
}
|
|
20
103
|
|
|
21
|
-
pullDataset () {
|
|
22
|
-
|
|
104
|
+
pullDataset (name) {
|
|
105
|
+
this.#warn()
|
|
106
|
+
return Promise.resolve(new NoopDataset(name))
|
|
23
107
|
}
|
|
24
108
|
|
|
25
|
-
experiment () {
|
|
26
|
-
|
|
109
|
+
experiment (options = {}) {
|
|
110
|
+
this.#warn()
|
|
111
|
+
return new NoopExperiment(options.name)
|
|
27
112
|
}
|
|
28
113
|
}
|
|
29
114
|
|
|
@@ -22,13 +22,24 @@ class Row {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
class ExperimentRun {
|
|
26
|
+
constructor (fields) {
|
|
27
|
+
this.runId = fields.runId
|
|
28
|
+
this.runIteration = fields.runIteration
|
|
29
|
+
this.rows = fields.rows
|
|
30
|
+
this.summaryEvaluations = fields.summaryEvaluations
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
25
34
|
// Returned by Experiment.run().
|
|
26
35
|
class ExperimentResult {
|
|
27
|
-
constructor (experimentId, rows, url) {
|
|
36
|
+
constructor (experimentId, rows, url, runs = [], summaryEvaluations = {}) {
|
|
28
37
|
this.experimentId = experimentId
|
|
29
38
|
this.rows = rows
|
|
30
39
|
this.url = url
|
|
40
|
+
this.runs = runs
|
|
41
|
+
this.summaryEvaluations = summaryEvaluations
|
|
31
42
|
}
|
|
32
43
|
}
|
|
33
44
|
|
|
34
|
-
module.exports = { Row, ExperimentResult }
|
|
45
|
+
module.exports = { Row, ExperimentRun, ExperimentResult }
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const log = require('../../log')
|
|
4
|
+
|
|
5
|
+
// Matches the backend and dd-trace-py evaluator metric label contract.
|
|
6
|
+
const EVALUATOR_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {null | string | number | boolean | NormalizedJsonValue[] | { [key: string]: NormalizedJsonValue }}
|
|
10
|
+
* NormalizedJsonValue
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {object | null | undefined} value
|
|
15
|
+
* @returns {boolean}
|
|
16
|
+
*/
|
|
17
|
+
function hasEntries (value) {
|
|
18
|
+
if (!value) return false
|
|
19
|
+
for (const key of Object.keys(value)) {
|
|
20
|
+
if (Object.hasOwn(value, key)) return true
|
|
21
|
+
}
|
|
22
|
+
return false
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {string} name
|
|
27
|
+
*/
|
|
28
|
+
function validateEvaluatorName (name) {
|
|
29
|
+
if (typeof name !== 'string') throw new TypeError('Evaluator name must be a string')
|
|
30
|
+
if (name.length === 0) throw new Error('Evaluator name cannot be empty')
|
|
31
|
+
if (!EVALUATOR_NAME_PATTERN.test(name)) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Evaluator name '${name}' is invalid. Name must contain only alphanumeric characters, underscores, and hyphens.`
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {(...args: unknown[]) => unknown} fn
|
|
40
|
+
* @param {string} fallback
|
|
41
|
+
* @returns {string}
|
|
42
|
+
*/
|
|
43
|
+
function functionName (fn, fallback) {
|
|
44
|
+
return typeof fn.name === 'string' && fn.name.length > 0 ? fn.name : fallback
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {unknown} evaluators
|
|
49
|
+
* @param {string} kind
|
|
50
|
+
* @returns {Array<[string, (...args: unknown[]) => unknown]>}
|
|
51
|
+
*/
|
|
52
|
+
function normalizeEvaluators (evaluators, kind) {
|
|
53
|
+
if (evaluators == null) return []
|
|
54
|
+
|
|
55
|
+
const normalized = []
|
|
56
|
+
if (Array.isArray(evaluators)) {
|
|
57
|
+
const indexesByName = new Map()
|
|
58
|
+
for (let i = 0; i < evaluators.length; i++) {
|
|
59
|
+
const evaluator = evaluators[i]
|
|
60
|
+
if (typeof evaluator !== 'function') throw new TypeError(`${kind} evaluator must be a function`)
|
|
61
|
+
const name = functionName(evaluator, `${kind}_evaluator_${i}`)
|
|
62
|
+
validateEvaluatorName(name)
|
|
63
|
+
if (indexesByName.has(name)) {
|
|
64
|
+
log.warn('Duplicate %s evaluator name %s; previous evaluator will be overwritten', kind, name)
|
|
65
|
+
normalized[indexesByName.get(name)] = [name, evaluator]
|
|
66
|
+
} else {
|
|
67
|
+
indexesByName.set(name, normalized.length)
|
|
68
|
+
normalized.push([name, evaluator])
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return normalized
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (typeof evaluators !== 'object') {
|
|
75
|
+
throw new TypeError(`${kind} evaluators must be an array of functions or an object keyed by evaluator name`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
for (const [name, evaluator] of Object.entries(evaluators)) {
|
|
79
|
+
validateEvaluatorName(name)
|
|
80
|
+
if (typeof evaluator !== 'function') throw new TypeError(`${kind} evaluator '${name}' must be a function`)
|
|
81
|
+
normalized.push([name, evaluator])
|
|
82
|
+
}
|
|
83
|
+
return normalized
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {unknown} value
|
|
88
|
+
* @returns {string}
|
|
89
|
+
*/
|
|
90
|
+
function inferMetricType (value) {
|
|
91
|
+
if (typeof value === 'boolean') return 'boolean'
|
|
92
|
+
if (typeof value === 'number' && Number.isFinite(value)) return 'score'
|
|
93
|
+
if (typeof value === 'string') return 'categorical'
|
|
94
|
+
return 'json'
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @param {unknown} value
|
|
99
|
+
* @param {WeakSet<object>} seen
|
|
100
|
+
* @returns {NormalizedJsonValue}
|
|
101
|
+
*/
|
|
102
|
+
function normalizeJsonValue (value, seen) {
|
|
103
|
+
if (value === null) return null
|
|
104
|
+
|
|
105
|
+
const valueType = typeof value
|
|
106
|
+
if (valueType === 'string' || valueType === 'boolean') return value
|
|
107
|
+
if (valueType === 'number') return Number.isFinite(value) ? value : String(value)
|
|
108
|
+
if (valueType === 'bigint') return value.toString()
|
|
109
|
+
if (valueType === 'undefined') return null
|
|
110
|
+
if (valueType === 'symbol') return value.toString()
|
|
111
|
+
if (valueType === 'function') return { type: 'function', name: value.name || '<anonymous>' }
|
|
112
|
+
|
|
113
|
+
if (value instanceof Date) return value.toISOString()
|
|
114
|
+
if (value instanceof Error) {
|
|
115
|
+
return { type: value.name, message: value.message, stack: value.stack ?? '' }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (seen.has(value)) return '[Circular]'
|
|
119
|
+
seen.add(value)
|
|
120
|
+
|
|
121
|
+
if (Array.isArray(value)) {
|
|
122
|
+
const normalized = new Array(value.length)
|
|
123
|
+
for (let i = 0; i < value.length; i++) normalized[i] = normalizeJsonValue(value[i], seen)
|
|
124
|
+
seen.delete(value)
|
|
125
|
+
return normalized
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const normalized = {}
|
|
129
|
+
for (const [key, nestedValue] of Object.entries(value)) {
|
|
130
|
+
normalized[key] = normalizeJsonValue(nestedValue, seen)
|
|
131
|
+
}
|
|
132
|
+
seen.delete(value)
|
|
133
|
+
return normalized
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @param {unknown} value
|
|
138
|
+
* @returns {{ [key: string]: NormalizedJsonValue }}
|
|
139
|
+
*/
|
|
140
|
+
function normalizeJsonMetricValue (value) {
|
|
141
|
+
const normalized = normalizeJsonValue(value, new WeakSet())
|
|
142
|
+
if (normalized !== null && typeof normalized === 'object' && !Array.isArray(normalized)) return normalized
|
|
143
|
+
return { value: normalized }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @param {unknown} value
|
|
148
|
+
* @returns {string}
|
|
149
|
+
*/
|
|
150
|
+
function stringify (value) {
|
|
151
|
+
if (value == null) return ''
|
|
152
|
+
if (typeof value === 'string') return value.toLowerCase()
|
|
153
|
+
if (typeof value === 'object') {
|
|
154
|
+
try {
|
|
155
|
+
const stringified = JSON.stringify(value)
|
|
156
|
+
if (stringified !== undefined) return stringified.toLowerCase()
|
|
157
|
+
} catch {}
|
|
158
|
+
}
|
|
159
|
+
return String(value).toLowerCase()
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @param {Record<string, unknown> | undefined} userTags
|
|
164
|
+
* @param {Record<string, unknown>} autoTags
|
|
165
|
+
* @returns {string[]}
|
|
166
|
+
*/
|
|
167
|
+
function buildTags (userTags, autoTags) {
|
|
168
|
+
const tags = new Map()
|
|
169
|
+
if ((userTags) != null) {
|
|
170
|
+
for (const [key, value] of Object.entries(userTags)) {
|
|
171
|
+
tags.set(key, `${key}:${value}`)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
for (const [key, value] of Object.entries(autoTags)) {
|
|
175
|
+
if (value !== undefined && value !== null && value !== '') tags.set(key, `${key}:${value}`)
|
|
176
|
+
}
|
|
177
|
+
return [...tags.values()]
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* @param {Record<string, unknown> | undefined} userTags
|
|
182
|
+
* @param {Record<string, unknown>} autoTags
|
|
183
|
+
* @returns {Record<string, unknown>}
|
|
184
|
+
*/
|
|
185
|
+
function buildExperimentTagObject (userTags, autoTags) {
|
|
186
|
+
return userTags ? { ...userTags, ...autoTags } : { ...autoTags }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @param {number} ms
|
|
191
|
+
* @returns {Promise<void>}
|
|
192
|
+
*/
|
|
193
|
+
function sleep (ms) {
|
|
194
|
+
if (ms <= 0) return Promise.resolve()
|
|
195
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @param {Record<string, unknown> | undefined} recordMetadata
|
|
200
|
+
* @param {Record<string, unknown>} config
|
|
201
|
+
* @returns {Record<string, unknown>}
|
|
202
|
+
*/
|
|
203
|
+
function buildSpanMetadata (recordMetadata, config) {
|
|
204
|
+
return recordMetadata
|
|
205
|
+
? { ...recordMetadata, experiment_config: config }
|
|
206
|
+
: { experiment_config: config }
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
module.exports = {
|
|
210
|
+
buildExperimentTagObject,
|
|
211
|
+
buildSpanMetadata,
|
|
212
|
+
buildTags,
|
|
213
|
+
hasEntries,
|
|
214
|
+
inferMetricType,
|
|
215
|
+
normalizeEvaluators,
|
|
216
|
+
normalizeJsonMetricValue,
|
|
217
|
+
sleep,
|
|
218
|
+
stringify,
|
|
219
|
+
validateEvaluatorName,
|
|
220
|
+
}
|
|
@@ -118,7 +118,7 @@ class DdTelemetryPlugin extends BaseLLMObsPlugin {
|
|
|
118
118
|
* @returns {string | undefined}
|
|
119
119
|
*/
|
|
120
120
|
findToolName (toolName, toolDescription) {
|
|
121
|
-
if (Number.isNaN(Number.parseInt(toolName))) return toolName
|
|
121
|
+
if (Number.isNaN(Number.parseInt(toolName, 10))) return toolName
|
|
122
122
|
|
|
123
123
|
for (const availableTool of this.#availableTools) {
|
|
124
124
|
const description = availableTool.description
|
|
@@ -322,7 +322,7 @@ function getToolNameFromTags (tags) {
|
|
|
322
322
|
const toolName = tags['ai.toolCall.name']
|
|
323
323
|
if (!toolName) return null
|
|
324
324
|
|
|
325
|
-
const parsedToolName = Number.parseInt(toolName)
|
|
325
|
+
const parsedToolName = Number.parseInt(toolName, 10)
|
|
326
326
|
if (!Number.isNaN(parsedToolName)) return null
|
|
327
327
|
|
|
328
328
|
return toolName
|
|
@@ -93,7 +93,7 @@ class AnthropicLLMObsPlugin extends LLMObsPlugin {
|
|
|
93
93
|
|
|
94
94
|
const { usage } = chunk
|
|
95
95
|
if (usage) {
|
|
96
|
-
const responseUsage =
|
|
96
|
+
const responseUsage = (response.usage ??= { input_tokens: 0, output_tokens: 0 })
|
|
97
97
|
responseUsage.output_tokens = usage.output_tokens
|
|
98
98
|
|
|
99
99
|
const cacheCreationTokens = usage.cache_creation_input_tokens
|
|
@@ -72,10 +72,10 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
72
72
|
const cacheWriteTokenCount = headers['x-amzn-bedrock-cache-write-input-token-count']
|
|
73
73
|
|
|
74
74
|
pendingTokenHeaders.set(requestId, {
|
|
75
|
-
inputTokensFromHeaders: inputTokenCount && Number.parseInt(inputTokenCount),
|
|
76
|
-
outputTokensFromHeaders: outputTokenCount && Number.parseInt(outputTokenCount),
|
|
77
|
-
cacheReadTokensFromHeaders: cacheReadTokenCount && Number.parseInt(cacheReadTokenCount),
|
|
78
|
-
cacheWriteTokensFromHeaders: cacheWriteTokenCount && Number.parseInt(cacheWriteTokenCount),
|
|
75
|
+
inputTokensFromHeaders: inputTokenCount && Number.parseInt(inputTokenCount, 10),
|
|
76
|
+
outputTokensFromHeaders: outputTokenCount && Number.parseInt(outputTokenCount, 10),
|
|
77
|
+
cacheReadTokensFromHeaders: cacheReadTokenCount && Number.parseInt(cacheReadTokenCount, 10),
|
|
78
|
+
cacheWriteTokensFromHeaders: cacheWriteTokenCount && Number.parseInt(cacheWriteTokenCount, 10),
|
|
79
79
|
})
|
|
80
80
|
})
|
|
81
81
|
|
|
@@ -138,7 +138,7 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
138
138
|
#tagCommon ({ span, requestParams, textAndResponseReason, tokensFromHeaders }) {
|
|
139
139
|
this._tagger.tagMetadata(span, {
|
|
140
140
|
temperature: Number.parseFloat(requestParams.temperature) || 0,
|
|
141
|
-
max_tokens: Number.parseInt(requestParams.maxTokens) || 0,
|
|
141
|
+
max_tokens: Number.parseInt(requestParams.maxTokens, 10) || 0,
|
|
142
142
|
})
|
|
143
143
|
this._tagger.tagLLMIO(span, requestParams.prompt, textAndResponseReason.messages)
|
|
144
144
|
this._tagger.tagMetrics(span, extractTokens({
|
|
@@ -8,7 +8,7 @@ const { splitModel } = require('../../../../../datadog-plugin-claude-agent-sdk/s
|
|
|
8
8
|
const subagentToolIds = new Set()
|
|
9
9
|
|
|
10
10
|
function normalizeToolOutputString (raw) {
|
|
11
|
-
const footerIndex = raw.search(
|
|
11
|
+
const footerIndex = raw.search(/agentId: \S+ \(use SendMessage\b/)
|
|
12
12
|
if (footerIndex === -1) return raw
|
|
13
13
|
|
|
14
14
|
return raw.slice(0, footerIndex).trimEnd()
|
|
@@ -24,7 +24,7 @@ class GenAiLLMObsPlugin extends LLMObsPlugin {
|
|
|
24
24
|
// Subscribe to streaming chunk events
|
|
25
25
|
this.addSub('apm:google:genai:request:chunk', ({ ctx, chunk, done }) => {
|
|
26
26
|
ctx.isStreaming = true
|
|
27
|
-
ctx.chunks
|
|
27
|
+
ctx.chunks ||= []
|
|
28
28
|
|
|
29
29
|
if (chunk) ctx.chunks.push(chunk)
|
|
30
30
|
if (!done) return
|
|
@@ -36,7 +36,7 @@ class LangChainLLMObsHandler {
|
|
|
36
36
|
const runIdBase = runId ? runId.split('-').slice(0, -1).join('-') : ''
|
|
37
37
|
|
|
38
38
|
const responseMetadata = message.response_metadata || {}
|
|
39
|
-
usage
|
|
39
|
+
usage ||= responseMetadata.usage || responseMetadata.tokenUsage || {}
|
|
40
40
|
|
|
41
41
|
const inputTokens = usage.promptTokens || usage.inputTokens || usage.prompt_tokens || usage.input_tokens || 0
|
|
42
42
|
const outputTokens =
|