dd-trace 6.18.0 → 6.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/ci/vitest-no-worker-init-setup.mjs +22 -12
  3. package/index.d.ts +166 -24
  4. package/package.json +7 -7
  5. package/packages/datadog-esbuild/index.js +9 -6
  6. package/packages/datadog-instrumentations/src/ai.js +26 -0
  7. package/packages/datadog-instrumentations/src/anthropic.js +111 -9
  8. package/packages/datadog-instrumentations/src/aws-sdk.js +2 -2
  9. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +5 -1
  10. package/packages/datadog-instrumentations/src/cucumber.js +40 -4
  11. package/packages/datadog-instrumentations/src/helpers/hooks.js +0 -7
  12. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +2 -2
  13. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +25 -0
  14. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +8 -0
  15. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +2 -0
  16. package/packages/datadog-instrumentations/src/jest/session-error.js +102 -0
  17. package/packages/datadog-instrumentations/src/jest.js +3 -10
  18. package/packages/datadog-instrumentations/src/playwright.js +26 -0
  19. package/packages/datadog-instrumentations/src/vitest-main.js +4 -1
  20. package/packages/datadog-instrumentations/src/vitest-worker.js +34 -3
  21. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +83 -29
  22. package/packages/datadog-plugin-cucumber/src/index.js +19 -4
  23. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +7 -0
  24. package/packages/datadog-plugin-fetch/src/index.js +3 -0
  25. package/packages/datadog-plugin-openai/src/stream-helpers.js +50 -1
  26. package/packages/datadog-plugin-oracledb/src/connection-parser.js +3 -1
  27. package/packages/datadog-plugin-undici/src/index.js +5 -0
  28. package/packages/dd-trace/src/aiguard/client.js +38 -19
  29. package/packages/dd-trace/src/aiguard/integrations/anthropic.js +29 -4
  30. package/packages/dd-trace/src/aiguard/integrations/index.js +1 -1
  31. package/packages/dd-trace/src/aiguard/integrations/openai.js +20 -56
  32. package/packages/dd-trace/src/aiguard/integrations/stream.js +60 -0
  33. package/packages/dd-trace/src/aiguard/messages/anthropic.js +64 -0
  34. package/packages/dd-trace/src/config/generated-config-types.d.ts +8 -4
  35. package/packages/dd-trace/src/config/remote_config.js +12 -0
  36. package/packages/dd-trace/src/config/supported-configurations.json +26 -5
  37. package/packages/dd-trace/src/constants.js +2 -0
  38. package/packages/dd-trace/src/debugger/constants.js +13 -4
  39. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +14 -1
  40. package/packages/dd-trace/src/debugger/devtools_client/condition.js +109 -6
  41. package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
  42. package/packages/dd-trace/src/debugger/devtools_client/index.js +65 -6
  43. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +22 -10
  44. package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +12 -8
  45. package/packages/dd-trace/src/debugger/devtools_client/send.js +14 -0
  46. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +43 -5
  47. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +3 -8
  48. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +2 -122
  49. package/packages/dd-trace/src/debugger/guardrail-metrics.js +0 -2
  50. package/packages/dd-trace/src/debugger/index.js +60 -28
  51. package/packages/dd-trace/src/debugger/inspect-segment.js +92 -23
  52. package/packages/dd-trace/src/debugger/pause-duration-histogram.js +74 -0
  53. package/packages/dd-trace/src/debugger/probe_sampler.js +192 -52
  54. package/packages/dd-trace/src/debugger/redaction.js +139 -0
  55. package/packages/dd-trace/src/knuth-hash.js +17 -0
  56. package/packages/dd-trace/src/llmobs/constants/tags.js +33 -8
  57. package/packages/dd-trace/src/llmobs/experiments/client.js +66 -2
  58. package/packages/dd-trace/src/llmobs/experiments/evaluator.js +138 -0
  59. package/packages/dd-trace/src/llmobs/experiments/experiment.js +213 -90
  60. package/packages/dd-trace/src/llmobs/experiments/index.js +40 -1
  61. package/packages/dd-trace/src/llmobs/experiments/noop.js +53 -2
  62. package/packages/dd-trace/src/llmobs/experiments/remote-evaluator.js +110 -0
  63. package/packages/dd-trace/src/llmobs/experiments/util.js +34 -6
  64. package/packages/dd-trace/src/llmobs/gen-ai-tags.js +127 -0
  65. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +18 -0
  66. package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +33 -8
  67. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +77 -41
  68. package/packages/dd-trace/src/llmobs/plugins/base.js +154 -15
  69. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +162 -10
  70. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +65 -16
  71. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +14 -0
  72. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +34 -35
  73. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +10 -0
  74. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +25 -2
  75. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +8 -7
  76. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +15 -2
  77. package/packages/dd-trace/src/llmobs/plugins/openai/realtime.js +5 -0
  78. package/packages/dd-trace/src/llmobs/plugins/vertexai.js +7 -0
  79. package/packages/dd-trace/src/llmobs/prompts/prompt.js +2 -1
  80. package/packages/dd-trace/src/llmobs/sdk.js +19 -3
  81. package/packages/dd-trace/src/llmobs/span_processor.js +52 -91
  82. package/packages/dd-trace/src/llmobs/tagger.js +37 -36
  83. package/packages/dd-trace/src/llmobs/writers/base.js +1 -6
  84. package/packages/dd-trace/src/openfeature/constants/constants.js +10 -0
  85. package/packages/dd-trace/src/openfeature/flagging_provider.js +14 -1
  86. package/packages/dd-trace/src/openfeature/writers/base.js +39 -18
  87. package/packages/dd-trace/src/openfeature/writers/flag-eval-evp-hook.js +105 -0
  88. package/packages/dd-trace/src/openfeature/writers/flag-evaluation-aggregation.js +190 -0
  89. package/packages/dd-trace/src/openfeature/writers/flag-evaluation-consumer.js +233 -0
  90. package/packages/dd-trace/src/openfeature/writers/flag-evaluation-context.js +262 -0
  91. package/packages/dd-trace/src/openfeature/writers/flag-evaluation-payload.js +181 -0
  92. package/packages/dd-trace/src/openfeature/writers/flag-evaluation-pii.js +108 -0
  93. package/packages/dd-trace/src/openfeature/writers/flag-evaluation-telemetry.js +154 -0
  94. package/packages/dd-trace/src/openfeature/writers/flag-evaluation-worker.js +77 -0
  95. package/packages/dd-trace/src/openfeature/writers/flag-evaluations.js +398 -0
  96. package/packages/dd-trace/src/openfeature/writers/util.js +5 -4
  97. package/packages/dd-trace/src/opentelemetry/context_manager.js +3 -0
  98. package/packages/dd-trace/src/opentelemetry/span_context.js +6 -2
  99. package/packages/dd-trace/src/opentelemetry/trace/index.js +5 -0
  100. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +6 -0
  101. package/packages/dd-trace/src/opentelemetry/tracer.js +16 -18
  102. package/packages/dd-trace/src/opentracing/propagation/text_map.js +116 -25
  103. package/packages/dd-trace/src/opentracing/propagation/tracestate.js +80 -16
  104. package/packages/dd-trace/src/opentracing/span.js +14 -9
  105. package/packages/dd-trace/src/opentracing/tracer.js +10 -3
  106. package/packages/dd-trace/src/otel-sampling.js +171 -0
  107. package/packages/dd-trace/src/plugins/index.js +0 -1
  108. package/packages/dd-trace/src/plugins/util/test.js +4 -0
  109. package/packages/dd-trace/src/priority_sampler.js +155 -33
  110. package/packages/dd-trace/src/profiler.js +51 -5
  111. package/packages/dd-trace/src/profiling/profiler.js +24 -20
  112. package/packages/dd-trace/src/remote_config/capabilities.js +9 -0
  113. package/packages/dd-trace/src/ritm.js +12 -9
  114. package/packages/dd-trace/src/sampler.js +2 -5
  115. package/packages/dd-trace/src/sampling_rule.js +4 -8
  116. package/packages/dd-trace/src/span_format.js +6 -0
  117. package/packages/dd-trace/src/span_processor.js +32 -3
  118. package/packages/dd-trace/src/standalone/index.js +5 -4
  119. package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +25 -5
  120. package/packages/dd-trace/src/telemetry/metrics.js +4 -3
  121. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
  122. package/packages/datadog-instrumentations/src/postgres.js +0 -7
  123. package/packages/datadog-instrumentations/src/supabase.js +0 -15
@@ -0,0 +1,139 @@
1
+ 'use strict'
2
+
3
+ // Used by both the main thread, which renders log template values, and the devtools client worker, which captures
4
+ // snapshots and compiles probe expressions, so that both redact the same identifiers.
5
+
6
+ // What a redacted value is rendered as in a log message.
7
+ const REDACTED_PLACEHOLDER = '{redacted}'
8
+
9
+ const DEFAULT_REDACTED_IDENTIFIERS = [
10
+ '2fa',
11
+ '_csrf',
12
+ '_csrf_token',
13
+ '_session',
14
+ '_xsrf',
15
+ 'access_token',
16
+ 'aiohttp_session',
17
+ 'api_key',
18
+ 'apisecret',
19
+ 'apisignature',
20
+ 'applicationkey',
21
+ 'appkey',
22
+ 'auth',
23
+ 'authtoken',
24
+ 'authorization',
25
+ 'cc_number',
26
+ 'certificatepin',
27
+ 'cipher',
28
+ 'client_secret',
29
+ 'clientid',
30
+ 'connect.sid',
31
+ 'connectionstring',
32
+ 'cookie',
33
+ 'credentials',
34
+ 'creditcard',
35
+ 'csrf',
36
+ 'csrf_token',
37
+ 'cvv',
38
+ 'databaseurl',
39
+ 'db_url',
40
+ 'encryption_key',
41
+ 'encryptionkeyid',
42
+ 'geo_location',
43
+ 'gpg_key',
44
+ 'ip_address',
45
+ 'jti',
46
+ 'jwt',
47
+ 'license_key',
48
+ 'masterkey',
49
+ 'mysql_pwd',
50
+ 'nonce',
51
+ 'oauth',
52
+ 'oauthtoken',
53
+ 'otp',
54
+ 'passhash',
55
+ 'passwd',
56
+ 'password',
57
+ 'passwordb',
58
+ 'pem_file',
59
+ 'pgp_key',
60
+ 'PHPSESSID',
61
+ 'pin',
62
+ 'pincode',
63
+ 'pkcs8',
64
+ 'private_key',
65
+ 'publickey',
66
+ 'pwd',
67
+ 'recaptcha_key',
68
+ 'refresh_token',
69
+ 'routingnumber',
70
+ 'salt',
71
+ 'secret',
72
+ 'secretKey',
73
+ 'secrettoken',
74
+ 'securitycode',
75
+ 'security_answer',
76
+ 'security_question',
77
+ 'serviceaccountcredentials',
78
+ 'session',
79
+ 'sessionid',
80
+ 'sessionkey',
81
+ 'set_cookie',
82
+ 'signature',
83
+ 'signaturekey',
84
+ 'ssh_key',
85
+ 'ssn',
86
+ 'symfony',
87
+ 'token',
88
+ 'transactionid',
89
+ 'twilio_token',
90
+ 'user_session',
91
+ 'voterid',
92
+ 'x-auth-token',
93
+ 'x_api_key',
94
+ 'x_csrftoken',
95
+ 'x_forwarded_for',
96
+ 'x_real_ip',
97
+ 'XSRF-TOKEN',
98
+ ]
99
+
100
+ module.exports = {
101
+ createIsRedactedIdentifier,
102
+ REDACTED_PLACEHOLDER,
103
+ }
104
+
105
+ /**
106
+ * Create a predicate for whether the value of an identifier must be redacted, based on the default list of redacted
107
+ * identifiers and the user's configuration.
108
+ *
109
+ * @param {object} config - The `dynamicInstrumentation` config.
110
+ * @param {string[]} config.DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS - Identifiers to redact in addition to the
111
+ * defaults.
112
+ * @param {string[]} config.DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS - Identifiers to never redact.
113
+ * @returns {(name: string, isSymbol?: boolean) => boolean} Whether the identifier must be redacted. If `isSymbol` is
114
+ * `true`, `name` is a `Symbol(...)` description.
115
+ */
116
+ function createIsRedactedIdentifier ({
117
+ DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS: redactedIdentifiers,
118
+ DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS: excludedIdentifiers,
119
+ }) {
120
+ const excluded = new Set(excludedIdentifiers.map((name) => normalizeName(name)))
121
+ const redacted = new Set()
122
+ for (const name of [...DEFAULT_REDACTED_IDENTIFIERS, ...redactedIdentifiers]) {
123
+ const normalized = normalizeName(name)
124
+ if (!excluded.has(normalized)) redacted.add(normalized)
125
+ }
126
+
127
+ return function isRedactedIdentifier (name, isSymbol) {
128
+ return redacted.has(normalizeName(name, isSymbol))
129
+ }
130
+ }
131
+
132
+ /**
133
+ * @param {string} name - The identifier name.
134
+ * @param {boolean} [isSymbol] - Whether the name is a `Symbol(...)` description.
135
+ */
136
+ function normalizeName (name, isSymbol) {
137
+ if (isSymbol) name = name.slice(7, -1) // Remove `Symbol(` and `)`
138
+ return name.toLowerCase().replaceAll(/[-_@$.]/g, '')
139
+ }
@@ -0,0 +1,17 @@
1
+ 'use strict'
2
+
3
+ const UINT64_MODULO = 2n ** 64n
4
+
5
+ // Knuth's factor for the sampling algorithm shared across Datadog tracers.
6
+ const SAMPLING_KNUTH_FACTOR = 1_111_111_111_111_111_111n
7
+
8
+ /**
9
+ * Hashes the lower 64 bits of a trace ID for deterministic trace sampling.
10
+ *
11
+ * @param {bigint} traceId
12
+ */
13
+ function knuthHash (traceId) {
14
+ return (traceId * SAMPLING_KNUTH_FACTOR) % UINT64_MODULO
15
+ }
16
+
17
+ module.exports = knuthHash
@@ -1,5 +1,14 @@
1
1
  'use strict'
2
2
 
3
+ const INPUT_TOKENS_METRIC_KEY = 'input_tokens'
4
+ const OUTPUT_TOKENS_METRIC_KEY = 'output_tokens'
5
+ const TOTAL_TOKENS_METRIC_KEY = 'total_tokens'
6
+ const CACHE_READ_INPUT_TOKENS_METRIC_KEY = 'cache_read_input_tokens'
7
+ const CACHE_WRITE_INPUT_TOKENS_METRIC_KEY = 'cache_write_input_tokens'
8
+ const CACHE_WRITE_5M_INPUT_TOKENS_METRIC_KEY = 'ephemeral_5m_input_tokens'
9
+ const CACHE_WRITE_1H_INPUT_TOKENS_METRIC_KEY = 'ephemeral_1h_input_tokens'
10
+ const REASONING_OUTPUT_TOKENS_METRIC_KEY = 'reasoning_output_tokens'
11
+
3
12
  module.exports = {
4
13
  SPAN_KINDS: ['llm', 'agent', 'workflow', 'task', 'tool', 'embedding', 'retrieval', 'experiment'],
5
14
  SPAN_KIND: '_ml_obs.meta.span.kind',
@@ -42,24 +51,40 @@ module.exports = {
42
51
  MODEL_NAME: '_ml_obs.meta.model_name',
43
52
  MODEL_PROVIDER: '_ml_obs.meta.model_provider',
44
53
  UNKNOWN_MODEL_PROVIDER: 'unknown',
54
+ DEFAULT_MODEL: 'custom',
45
55
 
46
56
  INPUT_DOCUMENTS: '_ml_obs.meta.input.documents',
57
+ EXPERIMENT_INPUT: '_ml_obs.meta.input',
47
58
  INPUT_MESSAGES: '_ml_obs.meta.input.messages',
48
59
  INPUT_VALUE: '_ml_obs.meta.input.value',
49
60
  INPUT_PROMPT: '_ml_obs.meta.input.prompt',
50
61
 
51
62
  OUTPUT_DOCUMENTS: '_ml_obs.meta.output.documents',
63
+ EXPERIMENT_OUTPUT: '_ml_obs.meta.output',
52
64
  OUTPUT_MESSAGES: '_ml_obs.meta.output.messages',
53
65
  OUTPUT_VALUE: '_ml_obs.meta.output.value',
54
66
 
55
- INPUT_TOKENS_METRIC_KEY: 'input_tokens',
56
- OUTPUT_TOKENS_METRIC_KEY: 'output_tokens',
57
- TOTAL_TOKENS_METRIC_KEY: 'total_tokens',
58
- CACHE_READ_INPUT_TOKENS_METRIC_KEY: 'cache_read_input_tokens',
59
- CACHE_WRITE_INPUT_TOKENS_METRIC_KEY: 'cache_write_input_tokens',
60
- CACHE_WRITE_5M_INPUT_TOKENS_METRIC_KEY: 'ephemeral_5m_input_tokens',
61
- CACHE_WRITE_1H_INPUT_TOKENS_METRIC_KEY: 'ephemeral_1h_input_tokens',
62
- REASONING_OUTPUT_TOKENS_METRIC_KEY: 'reasoning_output_tokens',
67
+ INPUT_TOKENS_METRIC_KEY,
68
+ OUTPUT_TOKENS_METRIC_KEY,
69
+ TOTAL_TOKENS_METRIC_KEY,
70
+ CACHE_READ_INPUT_TOKENS_METRIC_KEY,
71
+ CACHE_WRITE_INPUT_TOKENS_METRIC_KEY,
72
+ CACHE_WRITE_5M_INPUT_TOKENS_METRIC_KEY,
73
+ CACHE_WRITE_1H_INPUT_TOKENS_METRIC_KEY,
74
+ REASONING_OUTPUT_TOKENS_METRIC_KEY,
75
+
76
+ // integrations build metric objects with these camelCase spellings. Null prototype: a metric
77
+ // named after an `Object.prototype` member must not resolve to an inherited property.
78
+ METRIC_KEY_ALIASES: Object.assign(Object.create(null), {
79
+ inputTokens: INPUT_TOKENS_METRIC_KEY,
80
+ outputTokens: OUTPUT_TOKENS_METRIC_KEY,
81
+ totalTokens: TOTAL_TOKENS_METRIC_KEY,
82
+ cacheReadTokens: CACHE_READ_INPUT_TOKENS_METRIC_KEY,
83
+ cacheWriteTokens: CACHE_WRITE_INPUT_TOKENS_METRIC_KEY,
84
+ cacheWrite5mTokens: CACHE_WRITE_5M_INPUT_TOKENS_METRIC_KEY,
85
+ cacheWrite1hTokens: CACHE_WRITE_1H_INPUT_TOKENS_METRIC_KEY,
86
+ reasoningOutputTokens: REASONING_OUTPUT_TOKENS_METRIC_KEY,
87
+ }),
63
88
 
64
89
  DROPPED_IO_COLLECTION_ERROR: 'dropped_io',
65
90
 
@@ -5,8 +5,23 @@
5
5
 
6
6
  const { Dataset, DatasetRecord } = require('./dataset')
7
7
  const { ExperimentResult } = require('./result')
8
+ const { RemoteEvaluatorError } = require('./remote-evaluator')
8
9
 
9
10
  const API_BASE_PATH = '/api/v2/llm-obs/v1'
11
+ const EVALUATOR_INFERENCE_API_BASE_PATH = '/api/unstable/llm-obs/v1'
12
+
13
+ class ExperimentsRequestError extends Error {
14
+ /**
15
+ * @param {string} message
16
+ * @param {number} statusCode
17
+ * @param {object} responseBody
18
+ */
19
+ constructor (message, statusCode, responseBody) {
20
+ super(message)
21
+ this.statusCode = statusCode
22
+ this.responseBody = responseBody
23
+ }
24
+ }
10
25
 
11
26
  // Control-plane host for a Datadog site, e.g.
12
27
  // datadoghq.com -> api.datadoghq.com
@@ -151,7 +166,15 @@ class ExperimentsClient {
151
166
 
152
167
  const text = await response.text()
153
168
  if (!response.ok) {
154
- throw new Error(`${method} ${path} failed: HTTP ${response.status} ${text}`)
169
+ let responseBody = {}
170
+ try {
171
+ responseBody = text ? JSON.parse(text) : {}
172
+ } catch {}
173
+ throw new ExperimentsRequestError(
174
+ `${method} ${path} failed: HTTP ${response.status} ${text}`,
175
+ response.status,
176
+ responseBody
177
+ )
155
178
  }
156
179
  return text ? JSON.parse(text) : {}
157
180
  }
@@ -247,6 +270,41 @@ class ExperimentsClient {
247
270
  return experimentFromResource(this, response?.data ?? null)
248
271
  }
249
272
 
273
+ /**
274
+ * @param {string} evalName
275
+ * @param {object} context
276
+ */
277
+ evaluatorInfer (evalName, context) {
278
+ const encodedName = encodeURIComponent(evalName)
279
+ const path = `${EVALUATOR_INFERENCE_API_BASE_PATH}/evaluators/${encodedName}/infer`
280
+ return this.jsonApiRequest('POST', path, 'evaluator_inference', { context }).then(response => {
281
+ const attributes = response?.data?.attributes ?? {}
282
+ return {
283
+ value: attributes.value,
284
+ reasoning: attributes.reasoning,
285
+ assessment: attributes.assessment,
286
+ status: attributes.status,
287
+ }
288
+ }).catch(err => {
289
+ const attributes = err.responseBody?.data?.attributes ?? {}
290
+ const backendError = attributes.error
291
+ if (backendError !== null && typeof backendError === 'object' && !Array.isArray(backendError)) {
292
+ const fallback = err.statusCode === undefined ? err.message : `HTTP ${err.statusCode}`
293
+ throw new RemoteEvaluatorError(
294
+ `Remote evaluator '${evalName}' failed: ${backendError.message ?? fallback}`,
295
+ { status: attributes.status, backendError }
296
+ )
297
+ }
298
+
299
+ const apiError = Array.isArray(err.responseBody?.errors) ? err.responseBody.errors[0] : undefined
300
+ const detail = apiError !== null && typeof apiError === 'object'
301
+ ? apiError.detail ?? apiError.title
302
+ : undefined
303
+ const fallback = err.statusCode === undefined ? err.message : `HTTP ${err.statusCode}`
304
+ throw new Error(`Failed to call evaluator '${evalName}': ${detail ?? fallback}`)
305
+ })
306
+ }
307
+
250
308
  postExperimentEvents (experimentId, attributes) {
251
309
  return this.jsonApiRequest(
252
310
  'POST',
@@ -278,4 +336,10 @@ class ExperimentsClient {
278
336
  }
279
337
  }
280
338
 
281
- module.exports = { ExperimentsClient, apiHost, appHost, API_BASE_PATH }
339
+ module.exports = {
340
+ ExperimentsClient,
341
+ apiHost,
342
+ appHost,
343
+ API_BASE_PATH,
344
+ EVALUATOR_INFERENCE_API_BASE_PATH,
345
+ }
@@ -0,0 +1,138 @@
1
+ 'use strict'
2
+
3
+ const { validateEvaluatorName } = require('./util')
4
+
5
+ /**
6
+ * @param {object} evaluator
7
+ * @param {string | undefined} name
8
+ */
9
+ function resolveEvaluatorName (evaluator, name) {
10
+ const evaluatorName = name === undefined
11
+ ? evaluator.constructor.name
12
+ : typeof name === 'string' ? name.trim() : name
13
+ validateEvaluatorName(evaluatorName)
14
+ return evaluatorName
15
+ }
16
+
17
+ /**
18
+ * Context passed to a record-level class evaluator.
19
+ */
20
+ class EvaluatorContext {
21
+ /**
22
+ * @param {{inputData: unknown, outputData: unknown, expectedOutput?: unknown, metadata?: object,
23
+ * spanId?: string, traceId?: string}} options
24
+ */
25
+ constructor ({ inputData, outputData, expectedOutput, metadata = {}, spanId, traceId }) {
26
+ this.inputData = inputData
27
+ this.outputData = outputData
28
+ this.expectedOutput = expectedOutput
29
+ this.metadata = metadata
30
+ this.spanId = spanId
31
+ this.traceId = traceId
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Context passed to a summary class evaluator.
37
+ */
38
+ class SummaryEvaluatorContext {
39
+ /**
40
+ * @param {{inputs: unknown[], outputs: unknown[], expectedOutputs: unknown[], evaluationResults: object,
41
+ * metadata?: object[]}} options
42
+ */
43
+ constructor ({ inputs, outputs, expectedOutputs, evaluationResults, metadata = [] }) {
44
+ this.inputs = inputs
45
+ this.outputs = outputs
46
+ this.expectedOutputs = expectedOutputs
47
+ this.evaluationResults = evaluationResults
48
+ this.metadata = metadata
49
+ }
50
+ }
51
+
52
+ /**
53
+ * A metric value with optional evaluation details.
54
+ */
55
+ class EvaluatorResult {
56
+ /**
57
+ * @param {unknown} value
58
+ * @param {{reasoning?: string, assessment?: string, metadata?: object, tags?: object}} [options]
59
+ */
60
+ constructor (value, options = {}) {
61
+ this.value = value
62
+ this.reasoning = options.reasoning
63
+ this.assessment = options.assessment
64
+ this.metadata = options.metadata
65
+ this.tags = options.tags
66
+ }
67
+ }
68
+
69
+ /**
70
+ * A result that emits several named metrics from one evaluator invocation.
71
+ */
72
+ class MultiEvaluatorResult {
73
+ /**
74
+ * @param {Record<string, unknown>} values
75
+ * @param {boolean} [prefix]
76
+ */
77
+ constructor (values, prefix = true) {
78
+ if (values === null || typeof values !== 'object' || Array.isArray(values)) {
79
+ throw new TypeError('MultiEvaluatorResult.values must be an object')
80
+ }
81
+ const keys = Object.keys(values)
82
+ if (keys.length === 0) throw new Error('MultiEvaluatorResult.values must be a non-empty object')
83
+ for (const key of keys) validateEvaluatorName(key)
84
+ this.values = values
85
+ this.prefix = prefix
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Base class for reusable record-level evaluators.
91
+ *
92
+ * Subclasses may implement evaluate() synchronously or asynchronously.
93
+ */
94
+ class BaseEvaluator {
95
+ /**
96
+ * @param {string} [name] Evaluator name. Defaults to the subclass name.
97
+ */
98
+ constructor (name) {
99
+ this.name = resolveEvaluatorName(this, name)
100
+ }
101
+
102
+ /**
103
+ * @param {EvaluatorContext} _context
104
+ */
105
+ evaluate (_context) {
106
+ throw new Error('BaseEvaluator subclasses must implement evaluate(context)')
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Base class for reusable summary evaluators.
112
+ *
113
+ * Subclasses may implement evaluate() synchronously or asynchronously.
114
+ */
115
+ class BaseSummaryEvaluator {
116
+ /**
117
+ * @param {string} [name] Evaluator name. Defaults to the subclass name.
118
+ */
119
+ constructor (name) {
120
+ this.name = resolveEvaluatorName(this, name)
121
+ }
122
+
123
+ /**
124
+ * @param {SummaryEvaluatorContext} _context
125
+ */
126
+ evaluate (_context) {
127
+ throw new Error('BaseSummaryEvaluator subclasses must implement evaluate(context)')
128
+ }
129
+ }
130
+
131
+ module.exports = {
132
+ BaseEvaluator,
133
+ BaseSummaryEvaluator,
134
+ EvaluatorContext,
135
+ EvaluatorResult,
136
+ MultiEvaluatorResult,
137
+ SummaryEvaluatorContext,
138
+ }