dd-trace 6.0.0 → 6.1.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 +1 -2
- package/index.d.ts +21 -1
- package/package.json +32 -29
- package/packages/datadog-instrumentations/src/ai.js +45 -0
- package/packages/datadog-instrumentations/src/apollo-server.js +5 -13
- package/packages/datadog-instrumentations/src/child_process.js +3 -3
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +587 -0
- package/packages/datadog-instrumentations/src/cucumber.js +102 -43
- package/packages/datadog-instrumentations/src/cypress-config.js +11 -3
- package/packages/datadog-instrumentations/src/fastify.js +27 -8
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +7 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +6 -6
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/claude-agent-sdk.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/jest.js +713 -63
- package/packages/datadog-instrumentations/src/mocha/main.js +24 -3
- package/packages/datadog-instrumentations/src/mocha/utils.js +128 -22
- package/packages/datadog-instrumentations/src/mocha/worker.js +13 -0
- package/packages/datadog-instrumentations/src/mongodb.js +74 -0
- package/packages/datadog-instrumentations/src/mongoose.js +4 -5
- package/packages/datadog-instrumentations/src/playwright.js +13 -9
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +4 -0
- package/packages/datadog-instrumentations/src/vitest-main.js +28 -1
- package/packages/datadog-instrumentations/src/vitest-util.js +5 -0
- package/packages/datadog-instrumentations/src/vitest-worker.js +104 -34
- package/packages/datadog-plugin-ai/src/index.js +1 -1
- package/packages/datadog-plugin-ai/src/tracing.js +66 -3
- package/packages/datadog-plugin-ai/src/utils.js +17 -4
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +1 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +1 -0
- package/packages/datadog-plugin-child_process/src/index.js +13 -2
- package/packages/datadog-plugin-claude-agent-sdk/src/index.js +31 -0
- package/packages/datadog-plugin-claude-agent-sdk/src/tracing.js +107 -0
- package/packages/datadog-plugin-claude-agent-sdk/src/util.js +15 -0
- package/packages/datadog-plugin-cucumber/src/index.js +14 -23
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +351 -11
- package/packages/datadog-plugin-cypress/src/index.js +47 -2
- package/packages/datadog-plugin-cypress/src/plugin.js +1 -0
- package/packages/datadog-plugin-graphql/src/execute.js +21 -10
- package/packages/datadog-plugin-graphql/src/index.js +17 -1
- package/packages/datadog-plugin-graphql/src/utils.js +9 -2
- package/packages/datadog-plugin-graphql/src/validate.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +30 -14
- package/packages/datadog-plugin-mocha/src/index.js +39 -14
- package/packages/datadog-plugin-mongodb-core/src/bulk-write.js +43 -0
- package/packages/datadog-plugin-mongodb-core/src/index.js +8 -443
- package/packages/datadog-plugin-mongodb-core/src/query.js +452 -0
- package/packages/datadog-plugin-playwright/src/index.js +3 -2
- package/packages/datadog-plugin-vitest/src/index.js +51 -9
- package/packages/dd-trace/src/aiguard/index.js +9 -14
- package/packages/dd-trace/src/aiguard/integrations/index.js +34 -0
- package/packages/dd-trace/src/aiguard/integrations/openai.js +47 -33
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +42 -28
- package/packages/dd-trace/src/appsec/graphql.js +9 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +3 -10
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +26 -1
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +115 -24
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +3 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +3 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +75 -7
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +156 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +10 -0
- package/packages/dd-trace/src/config/supported-configurations.json +37 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -2
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +403 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +8 -395
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +27 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +363 -0
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +270 -0
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/utils.js +10 -0
- package/packages/dd-trace/src/opentelemetry/span.js +5 -0
- package/packages/dd-trace/src/plugin_manager.js +16 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +147 -7
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +4 -0
- package/packages/dd-trace/src/profiling/exporters/agent.js +28 -3
|
@@ -1,402 +1,15 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
3
|
+
const CompositePlugin = require('../../../plugins/composite')
|
|
4
|
+
const DdTelemetryPlugin = require('./ddTelemetry')
|
|
5
|
+
const VercelAiTelemetryPlugin = require('./vercelTelemetry')
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const { MODEL_NAME, MODEL_PROVIDER, NAME } = require('../../constants/tags')
|
|
11
|
-
const {
|
|
12
|
-
getSpanTags,
|
|
13
|
-
getOperation,
|
|
14
|
-
getUsage,
|
|
15
|
-
getJsonStringValue,
|
|
16
|
-
getModelMetadata,
|
|
17
|
-
getGenerationMetadata,
|
|
18
|
-
getToolNameFromTags,
|
|
19
|
-
getToolCallResultContent,
|
|
20
|
-
getLlmObsSpanName,
|
|
21
|
-
getTelemetryMetadata,
|
|
22
|
-
} = require('./util')
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* @typedef {Record<string, unknown> & { description?: string, id?: string }} AvailableToolArgs
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @typedef {string | number | boolean | null | undefined | string[] | number[] | boolean[]} TagValue
|
|
30
|
-
* @typedef {Record<string, TagValue>} SpanTags
|
|
31
|
-
*
|
|
32
|
-
* @typedef {{ name?: string, description?: string }} ToolForModel
|
|
33
|
-
*
|
|
34
|
-
* @typedef {{ type: 'text' | 'reasoning' | 'redacted-reasoning', text?: string, data?: string }} TextPart
|
|
35
|
-
* @typedef {{ type: 'tool-call', toolName: string, toolCallId: string, args?: unknown, input?: unknown }} ToolCallPart
|
|
36
|
-
* @typedef {(
|
|
37
|
-
* { type: 'tool-result', toolCallId: string, output?: { type: string, value?: unknown }, result?: unknown } &
|
|
38
|
-
* Record<string, unknown>
|
|
39
|
-
* )} ToolResultPart
|
|
40
|
-
*
|
|
41
|
-
* @typedef {{
|
|
42
|
-
* role: 'system',
|
|
43
|
-
* content: string
|
|
44
|
-
* } | {
|
|
45
|
-
* role: 'user',
|
|
46
|
-
* content: TextPart[]
|
|
47
|
-
* } | {
|
|
48
|
-
* role: 'assistant',
|
|
49
|
-
* content: Array<TextPart | ToolCallPart>
|
|
50
|
-
* } | {
|
|
51
|
-
* role: 'tool',
|
|
52
|
-
* content: ToolResultPart[]
|
|
53
|
-
* }} AiSdkMessage
|
|
54
|
-
*/
|
|
55
|
-
|
|
56
|
-
const SPAN_NAME_TO_KIND_MAPPING = {
|
|
57
|
-
// embeddings
|
|
58
|
-
embed: 'workflow',
|
|
59
|
-
embedMany: 'workflow',
|
|
60
|
-
doEmbed: 'embedding',
|
|
61
|
-
// object generation
|
|
62
|
-
generateObject: 'workflow',
|
|
63
|
-
streamObject: 'workflow',
|
|
64
|
-
// text generation
|
|
65
|
-
generateText: 'workflow',
|
|
66
|
-
streamText: 'workflow',
|
|
67
|
-
// llm operations
|
|
68
|
-
doGenerate: 'llm',
|
|
69
|
-
doStream: 'llm',
|
|
70
|
-
// tools
|
|
71
|
-
toolCall: 'tool',
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
class VercelAILLMObsPlugin extends BaseLLMObsPlugin {
|
|
75
|
-
static id = 'ai'
|
|
7
|
+
class VercelAILLMObsPlugin extends CompositePlugin {
|
|
8
|
+
static id = 'ai_llmobs'
|
|
76
9
|
static integration = 'ai'
|
|
77
|
-
static
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
* The available tools within the runtime scope of this integration.
|
|
81
|
-
* This essentially acts as a global registry for all tools made through the Vercel AI SDK.
|
|
82
|
-
* @type {Set<AvailableToolArgs>}
|
|
83
|
-
*/
|
|
84
|
-
#availableTools
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* A mapping of tool call IDs to tool names.
|
|
88
|
-
* This is used to map the tool call ID to the tool name for the output message.
|
|
89
|
-
* @type {Record<string, string>}
|
|
90
|
-
*/
|
|
91
|
-
#toolCallIdsToName
|
|
92
|
-
|
|
93
|
-
constructor (...args) {
|
|
94
|
-
super(...args)
|
|
95
|
-
|
|
96
|
-
this.#toolCallIdsToName = {}
|
|
97
|
-
this.#availableTools = new Set()
|
|
98
|
-
toolCreationCh.subscribe(ctx => {
|
|
99
|
-
const toolArgs = ctx.arguments
|
|
100
|
-
const tool = toolArgs[0] ?? {}
|
|
101
|
-
this.#availableTools.add(tool)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
setAttributesCh.subscribe(({ ctx, attributes }) => {
|
|
105
|
-
Object.assign(ctx.attributes, attributes)
|
|
106
|
-
})
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Does a best-effort attempt to find the right tool name for the given tool description.
|
|
111
|
-
* This is because the Vercel AI SDK does not tag tools by name properly, but
|
|
112
|
-
* rather by the index they were passed in. Tool names appear nowhere in the span tags.
|
|
113
|
-
*
|
|
114
|
-
* We use the tool description as the next best identifier for a tool.
|
|
115
|
-
*
|
|
116
|
-
* @param {string} toolName
|
|
117
|
-
* @param {string | undefined} toolDescription
|
|
118
|
-
* @returns {string | undefined}
|
|
119
|
-
*/
|
|
120
|
-
findToolName (toolName, toolDescription) {
|
|
121
|
-
if (Number.isNaN(Number.parseInt(toolName))) return toolName
|
|
122
|
-
|
|
123
|
-
for (const availableTool of this.#availableTools) {
|
|
124
|
-
const description = availableTool.description
|
|
125
|
-
if (description === toolDescription && availableTool.id) {
|
|
126
|
-
return availableTool.id
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* @override
|
|
133
|
-
*/
|
|
134
|
-
getLLMObsSpanRegisterOptions (ctx) {
|
|
135
|
-
const span = ctx.currentStore?.span
|
|
136
|
-
const operation = getOperation(span)
|
|
137
|
-
const kind = SPAN_NAME_TO_KIND_MAPPING[operation]
|
|
138
|
-
if (!kind) return
|
|
139
|
-
|
|
140
|
-
return { kind, name: getLlmObsSpanName(operation, ctx.attributes['ai.telemetry.functionId']) }
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* @override
|
|
145
|
-
*/
|
|
146
|
-
setLLMObsTags (ctx) {
|
|
147
|
-
const span = ctx.currentStore?.span
|
|
148
|
-
if (!span) return
|
|
149
|
-
|
|
150
|
-
const operation = getOperation(span)
|
|
151
|
-
const kind = SPAN_NAME_TO_KIND_MAPPING[operation]
|
|
152
|
-
if (!kind) return
|
|
153
|
-
|
|
154
|
-
const tags = getSpanTags(ctx)
|
|
155
|
-
|
|
156
|
-
if (['embedding', 'llm'].includes(kind)) {
|
|
157
|
-
this._tagger._setTag(span, MODEL_NAME, tags['ai.model.id'])
|
|
158
|
-
this._tagger._setTag(span, MODEL_PROVIDER, getModelProvider(tags))
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
switch (operation) {
|
|
162
|
-
case 'embed':
|
|
163
|
-
case 'embedMany':
|
|
164
|
-
this.setEmbeddingWorkflowTags(span, tags)
|
|
165
|
-
break
|
|
166
|
-
case 'doEmbed':
|
|
167
|
-
this.setEmbeddingTags(span, tags)
|
|
168
|
-
break
|
|
169
|
-
case 'generateObject':
|
|
170
|
-
case 'streamObject':
|
|
171
|
-
this.setObjectGenerationTags(span, tags)
|
|
172
|
-
break
|
|
173
|
-
case 'generateText':
|
|
174
|
-
case 'streamText':
|
|
175
|
-
this.setTextGenerationTags(span, tags)
|
|
176
|
-
break
|
|
177
|
-
case 'doGenerate':
|
|
178
|
-
case 'doStream':
|
|
179
|
-
this.setLLMOperationTags(span, tags)
|
|
180
|
-
break
|
|
181
|
-
case 'toolCall':
|
|
182
|
-
this.setToolTags(span, tags)
|
|
183
|
-
break
|
|
184
|
-
default:
|
|
185
|
-
break
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
setEmbeddingWorkflowTags (span, tags) {
|
|
190
|
-
const inputs = tags['ai.value'] ?? tags['ai.values']
|
|
191
|
-
const parsedInputs = Array.isArray(inputs)
|
|
192
|
-
? inputs.map(input => getJsonStringValue(input, ''))
|
|
193
|
-
: getJsonStringValue(inputs, '')
|
|
194
|
-
|
|
195
|
-
const embeddingsOutput = tags['ai.embedding'] ?? tags['ai.embeddings']
|
|
196
|
-
const isSingleEmbedding = !Array.isArray(embeddingsOutput)
|
|
197
|
-
const numberOfEmbeddings = isSingleEmbedding ? 1 : embeddingsOutput.length
|
|
198
|
-
const embeddingsLength = getJsonStringValue(isSingleEmbedding ? embeddingsOutput : embeddingsOutput?.[0], []).length
|
|
199
|
-
const output = `[${numberOfEmbeddings} embedding(s) returned with size ${embeddingsLength}]`
|
|
200
|
-
|
|
201
|
-
this._tagger.tagTextIO(span, parsedInputs, output)
|
|
202
|
-
|
|
203
|
-
const metadata = getGenerationMetadata(tags)
|
|
204
|
-
this._tagger.tagMetadata(span, metadata)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
setEmbeddingTags (span, tags) {
|
|
208
|
-
const inputs = tags['ai.values']
|
|
209
|
-
if (!Array.isArray(inputs)) return
|
|
210
|
-
|
|
211
|
-
const parsedInputs = inputs.map(input => getJsonStringValue(input, ''))
|
|
212
|
-
|
|
213
|
-
const embeddingsOutput = tags['ai.embeddings']
|
|
214
|
-
const numberOfEmbeddings = embeddingsOutput?.length
|
|
215
|
-
const embeddingsLength = getJsonStringValue(embeddingsOutput?.[0], []).length
|
|
216
|
-
const output = `[${numberOfEmbeddings} embedding(s) returned with size ${embeddingsLength}]`
|
|
217
|
-
|
|
218
|
-
this._tagger.tagEmbeddingIO(span, parsedInputs, output)
|
|
219
|
-
|
|
220
|
-
const metadata = getTelemetryMetadata(tags)
|
|
221
|
-
this._tagger.tagMetadata(span, metadata)
|
|
222
|
-
|
|
223
|
-
const usage = tags['ai.usage.tokens']
|
|
224
|
-
this._tagger.tagMetrics(span, {
|
|
225
|
-
inputTokens: usage,
|
|
226
|
-
totalTokens: usage,
|
|
227
|
-
})
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
setObjectGenerationTags (span, tags) {
|
|
231
|
-
const promptInfo = getJsonStringValue(tags['ai.prompt'], {})
|
|
232
|
-
const lastUserPrompt =
|
|
233
|
-
promptInfo.prompt ??
|
|
234
|
-
promptInfo.messages.reverse().find(message => message.role === 'user')?.content
|
|
235
|
-
const prompt = Array.isArray(lastUserPrompt) ? lastUserPrompt.map(part => part.text ?? '').join('') : lastUserPrompt
|
|
236
|
-
|
|
237
|
-
const output = tags['ai.response.object']
|
|
238
|
-
|
|
239
|
-
this._tagger.tagTextIO(span, prompt, output)
|
|
240
|
-
|
|
241
|
-
const metadata = getGenerationMetadata(tags)
|
|
242
|
-
metadata.schema = getJsonStringValue(tags['ai.schema'], {})
|
|
243
|
-
this._tagger.tagMetadata(span, metadata)
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
setTextGenerationTags (span, tags) {
|
|
247
|
-
const promptInfo = getJsonStringValue(tags['ai.prompt'], {})
|
|
248
|
-
const lastUserPrompt =
|
|
249
|
-
promptInfo.prompt ??
|
|
250
|
-
promptInfo.messages.reverse().find(message => message.role === 'user')?.content
|
|
251
|
-
const prompt = Array.isArray(lastUserPrompt) ? lastUserPrompt.map(part => part.text ?? '').join('') : lastUserPrompt
|
|
252
|
-
|
|
253
|
-
const output = tags['ai.response.text']
|
|
254
|
-
|
|
255
|
-
this._tagger.tagTextIO(span, prompt, output)
|
|
256
|
-
|
|
257
|
-
const metadata = getGenerationMetadata(tags)
|
|
258
|
-
this._tagger.tagMetadata(span, metadata)
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* @param {import('../../../opentracing/span')} span
|
|
263
|
-
* @param {SpanTags} tags
|
|
264
|
-
*/
|
|
265
|
-
setLLMOperationTags (span, tags) {
|
|
266
|
-
const toolsForModel = tags['ai.prompt.tools']?.map(getJsonStringValue)
|
|
267
|
-
|
|
268
|
-
const inputMessages = getJsonStringValue(tags['ai.prompt.messages'], [])
|
|
269
|
-
const parsedInputMessages = []
|
|
270
|
-
for (const message of inputMessages) {
|
|
271
|
-
const formattedMessages = this.formatMessage(message, toolsForModel)
|
|
272
|
-
parsedInputMessages.push(...formattedMessages)
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const outputMessage = this.formatOutputMessage(tags, toolsForModel)
|
|
276
|
-
|
|
277
|
-
this._tagger.tagLLMIO(span, parsedInputMessages, outputMessage)
|
|
278
|
-
|
|
279
|
-
const metadata = getModelMetadata(tags)
|
|
280
|
-
this._tagger.tagMetadata(span, metadata)
|
|
281
|
-
|
|
282
|
-
const usage = getUsage(tags)
|
|
283
|
-
this._tagger.tagMetrics(span, usage)
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
setToolTags (span, tags) {
|
|
287
|
-
const toolCallId = tags['ai.toolCall.id']
|
|
288
|
-
const name = getToolNameFromTags(tags) ?? this.#toolCallIdsToName[toolCallId]
|
|
289
|
-
if (name) this._tagger._setTag(span, NAME, name)
|
|
290
|
-
|
|
291
|
-
const input = tags['ai.toolCall.args']
|
|
292
|
-
const output = tags['ai.toolCall.result']
|
|
293
|
-
|
|
294
|
-
this._tagger.tagTextIO(span, input, output)
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
formatOutputMessage (tags, toolsForModel) {
|
|
298
|
-
const outputMessageText = tags['ai.response.text'] ?? tags['ai.response.object']
|
|
299
|
-
const outputMessageToolCalls = getJsonStringValue(tags['ai.response.toolCalls'], [])
|
|
300
|
-
|
|
301
|
-
const formattedToolCalls = []
|
|
302
|
-
for (const toolCall of outputMessageToolCalls) {
|
|
303
|
-
const toolArgs = toolCall.args ?? toolCall.input
|
|
304
|
-
const toolCallArgs = typeof toolArgs === 'string' ? getJsonStringValue(toolArgs, {}) : toolArgs
|
|
305
|
-
const toolDescription = toolsForModel?.find(tool => toolCall.toolName === tool.name)?.description
|
|
306
|
-
const name = this.findToolName(toolCall.toolName, toolDescription)
|
|
307
|
-
this.#toolCallIdsToName[toolCall.toolCallId] = name
|
|
308
|
-
|
|
309
|
-
formattedToolCalls.push({
|
|
310
|
-
arguments: toolCallArgs,
|
|
311
|
-
name,
|
|
312
|
-
toolId: toolCall.toolCallId,
|
|
313
|
-
type: toolCall.toolCallType ?? 'function',
|
|
314
|
-
})
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return {
|
|
318
|
-
role: 'assistant',
|
|
319
|
-
content: outputMessageText,
|
|
320
|
-
toolCalls: formattedToolCalls,
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Returns a list of formatted messages from a message object.
|
|
326
|
-
* Most of these will just be one entry, but in the case of a "tool" role,
|
|
327
|
-
* it is possible to have multiple tool call results in a single message that we
|
|
328
|
-
* need to split into multiple messages.
|
|
329
|
-
*
|
|
330
|
-
* @param {AiSdkMessage} message
|
|
331
|
-
* @param {ToolForModel[] | null | undefined} toolsForModel
|
|
332
|
-
* @returns {Array<{role: string, content: string, toolId?: string,
|
|
333
|
-
* toolCalls?: Array<{arguments: string, name: string, toolId: string, type: string}>}>}
|
|
334
|
-
*/
|
|
335
|
-
formatMessage (message, toolsForModel) {
|
|
336
|
-
const { role, content } = message
|
|
337
|
-
|
|
338
|
-
if (role === 'system') {
|
|
339
|
-
return [{ role, content }]
|
|
340
|
-
} else if (role === 'user') {
|
|
341
|
-
let finalContent = ''
|
|
342
|
-
for (const part of content) {
|
|
343
|
-
const { type } = part
|
|
344
|
-
if (type === 'text') {
|
|
345
|
-
finalContent += part.text
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return [{ role, content: finalContent }]
|
|
350
|
-
} else if (role === 'assistant') {
|
|
351
|
-
const toolCalls = []
|
|
352
|
-
let finalContent = ''
|
|
353
|
-
|
|
354
|
-
for (const part of content) {
|
|
355
|
-
const { type } = part
|
|
356
|
-
// TODO(sabrenner): do we want to include reasoning?
|
|
357
|
-
if (['text', 'reasoning', 'redacted-reasoning'].includes(type)) {
|
|
358
|
-
finalContent += part.text ?? part.data
|
|
359
|
-
} else if (type === 'tool-call') {
|
|
360
|
-
const toolDescription = toolsForModel?.find(tool => part.toolName === tool.name)?.description
|
|
361
|
-
const name = this.findToolName(part.toolName, toolDescription)
|
|
362
|
-
|
|
363
|
-
toolCalls.push({
|
|
364
|
-
arguments: part.args ?? part.input,
|
|
365
|
-
name,
|
|
366
|
-
toolId: part.toolCallId,
|
|
367
|
-
type: 'function',
|
|
368
|
-
})
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
const finalMessage = {
|
|
373
|
-
role,
|
|
374
|
-
content: finalContent,
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (toolCalls.length) {
|
|
378
|
-
finalMessage.toolCalls = toolCalls.length ? toolCalls : undefined
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return [finalMessage]
|
|
382
|
-
} else if (role === 'tool') {
|
|
383
|
-
const finalMessages = []
|
|
384
|
-
for (const part of content) {
|
|
385
|
-
if (part.type === 'tool-result') {
|
|
386
|
-
const safeResult = getToolCallResultContent(part)
|
|
387
|
-
|
|
388
|
-
finalMessages.push({
|
|
389
|
-
role,
|
|
390
|
-
content: safeResult,
|
|
391
|
-
toolId: part.toolCallId,
|
|
392
|
-
})
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
return finalMessages
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
return []
|
|
10
|
+
static plugins = {
|
|
11
|
+
dd: DdTelemetryPlugin,
|
|
12
|
+
ai: VercelAiTelemetryPlugin,
|
|
400
13
|
}
|
|
401
14
|
}
|
|
402
15
|
|
|
@@ -259,6 +259,32 @@ function getGenerationMetadata (tags) {
|
|
|
259
259
|
return Object.keys(metadata).length ? metadata : null
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Get the generation metadata from the span tags (maxSteps, maxRetries, etc.)
|
|
264
|
+
* Additionally, set telemetry metadata from manual telemetry tags.
|
|
265
|
+
* @param {Record<string, unknown>} event
|
|
266
|
+
* @returns {Record<string, unknown> | null}
|
|
267
|
+
*/
|
|
268
|
+
function getGenerationMetadataFromEvent (event) {
|
|
269
|
+
/** @type {Record<string, unknown>} */
|
|
270
|
+
const metadata = {}
|
|
271
|
+
|
|
272
|
+
for (const [key, value] of Object.entries(event)) {
|
|
273
|
+
const transformedKey = key.replaceAll(/[A-Z]/g, letter => '_' + letter.toLowerCase())
|
|
274
|
+
if (!MODEL_METADATA_KEYS.has(transformedKey)) {
|
|
275
|
+
if (key === 'runtimeContext') { // custom telemetry metadata
|
|
276
|
+
Object.assign(metadata, value)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
continue
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
metadata[transformedKey] = value
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return Object.keys(metadata).length ? metadata : null
|
|
286
|
+
}
|
|
287
|
+
|
|
262
288
|
/**
|
|
263
289
|
* Get the tool name from the span tags.
|
|
264
290
|
* If the tool name is a parsable number, or is not found, null is returned.
|
|
@@ -348,4 +374,5 @@ module.exports = {
|
|
|
348
374
|
getToolCallResultContent,
|
|
349
375
|
getLlmObsSpanName,
|
|
350
376
|
getTelemetryMetadata,
|
|
377
|
+
getGenerationMetadataFromEvent,
|
|
351
378
|
}
|