langsmith 0.7.1 → 0.7.2
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/dist/client.cjs +1 -1
- package/dist/client.js +1 -1
- package/dist/experimental/vercel/index.cjs +18 -637
- package/dist/experimental/vercel/index.d.ts +3 -257
- package/dist/experimental/vercel/index.js +2 -635
- package/dist/experimental/vercel/middleware.cjs +2 -78
- package/dist/experimental/vercel/middleware.js +1 -77
- package/dist/experimental/vercel/telemetry.cjs +462 -0
- package/dist/experimental/vercel/telemetry.d.ts +89 -0
- package/dist/experimental/vercel/telemetry.js +459 -0
- package/dist/experimental/vercel/utils.cjs +142 -35
- package/dist/experimental/vercel/utils.d.ts +28 -3
- package/dist/experimental/vercel/utils.js +140 -34
- package/dist/experimental/vercel/wrap.cjs +639 -0
- package/dist/experimental/vercel/wrap.d.ts +257 -0
- package/dist/experimental/vercel/wrap.js +635 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/sandbox/client.cjs +21 -0
- package/dist/sandbox/client.d.ts +1 -0
- package/dist/sandbox/client.js +21 -0
- package/dist/sandbox/sandbox.cjs +12 -1
- package/dist/sandbox/sandbox.js +12 -1
- package/dist/sandbox/types.d.ts +12 -0
- package/dist/sandbox/ws_execute.cjs +11 -7
- package/dist/sandbox/ws_execute.d.ts +2 -1
- package/dist/sandbox/ws_execute.js +11 -7
- package/dist/utils/types.cjs +13 -0
- package/dist/utils/types.d.ts +2 -0
- package/dist/utils/types.js +8 -0
- package/dist/utils/vercel.cjs +68 -10
- package/dist/utils/vercel.d.ts +17 -2
- package/dist/utils/vercel.js +68 -10
- package/package.json +9 -7
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { RunTreeConfig } from "../../run_trees.js";
|
|
2
|
+
import type { KVMap } from "../../schemas.js";
|
|
3
|
+
/**
|
|
4
|
+
* Configuration options for creating a LangSmith telemetry integration
|
|
5
|
+
* for the Vercel AI SDK.
|
|
6
|
+
*/
|
|
7
|
+
export interface LangSmithTelemetryConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Custom name for the root span. If not provided, defaults to the
|
|
10
|
+
* model display name or "generateText"/"streamText".
|
|
11
|
+
*/
|
|
12
|
+
name?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Run type for the root span. Defaults to "chain".
|
|
15
|
+
*/
|
|
16
|
+
runType?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Additional metadata to attach to all spans.
|
|
19
|
+
*/
|
|
20
|
+
metadata?: KVMap;
|
|
21
|
+
/**
|
|
22
|
+
* Tags to attach to all spans.
|
|
23
|
+
*/
|
|
24
|
+
tags?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Custom LangSmith client configuration.
|
|
27
|
+
*/
|
|
28
|
+
client?: RunTreeConfig["client"];
|
|
29
|
+
/**
|
|
30
|
+
* Project name to log runs to.
|
|
31
|
+
*/
|
|
32
|
+
projectName?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Transform inputs before logging on the root span.
|
|
35
|
+
*/
|
|
36
|
+
processInputs?: (inputs: KVMap) => KVMap;
|
|
37
|
+
/**
|
|
38
|
+
* Transform outputs before logging on the root span.
|
|
39
|
+
*/
|
|
40
|
+
processOutputs?: (outputs: KVMap) => KVMap;
|
|
41
|
+
/**
|
|
42
|
+
* Transform inputs before logging on child LLM step spans.
|
|
43
|
+
*/
|
|
44
|
+
processChildLLMRunInputs?: (inputs: KVMap) => KVMap;
|
|
45
|
+
/**
|
|
46
|
+
* Transform outputs before logging on child LLM step spans.
|
|
47
|
+
*/
|
|
48
|
+
processChildLLMRunOutputs?: (outputs: KVMap) => KVMap;
|
|
49
|
+
/**
|
|
50
|
+
* Whether to include intermediate step details in the output.
|
|
51
|
+
*/
|
|
52
|
+
traceResponseMetadata?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Whether to include raw HTTP request/response bodies.
|
|
55
|
+
*/
|
|
56
|
+
traceRawHttp?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Additional RunTree configuration to pass through.
|
|
59
|
+
*/
|
|
60
|
+
extra?: KVMap;
|
|
61
|
+
/**
|
|
62
|
+
* Whether to enable tracing.
|
|
63
|
+
* @default true if LANGSMITH_TRACING is set to "true"
|
|
64
|
+
*/
|
|
65
|
+
tracingEnabled?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Creates a LangSmith `Telemetry` for the Vercel AI SDK.
|
|
69
|
+
*
|
|
70
|
+
* This adapter implements the Vercel AI SDK's `Telemetry` interface
|
|
71
|
+
* and maps lifecycle events to LangSmith traces. It creates a root span for
|
|
72
|
+
* the entire generation, child LLM spans for each step, and tool spans for
|
|
73
|
+
* tool calls.
|
|
74
|
+
*
|
|
75
|
+
* ```ts
|
|
76
|
+
* import { generateText, registerTelemetry } from "ai";
|
|
77
|
+
* import { LangSmithTelemetry } from "langsmith/experimental/vercel";
|
|
78
|
+
*
|
|
79
|
+
* registerTelemetry(LangSmithTelemetry());
|
|
80
|
+
*
|
|
81
|
+
* const result = await generateText({
|
|
82
|
+
* model: openai("gpt-4o"),
|
|
83
|
+
* prompt: "Hello!",
|
|
84
|
+
* });
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @experimental Only available in Vercel AI SDK 7.
|
|
88
|
+
*/
|
|
89
|
+
export declare function LangSmithTelemetry(config?: LangSmithTelemetryConfig): any;
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { isRunTree, RunTree } from "../../run_trees.js";
|
|
2
|
+
import { getCurrentRunTree, withRunTree } from "../../singletons/traceable.js";
|
|
3
|
+
import { isTracingEnabled } from "../../env.js";
|
|
4
|
+
import { convertMessageToTracedFormat } from "./utils.js";
|
|
5
|
+
import { setUsageMetadataOnRunTree } from "./utils.js";
|
|
6
|
+
import { isPrimitive, isRecord } from "../../utils/types.js";
|
|
7
|
+
function _formatMessages(messages) {
|
|
8
|
+
if (!Array.isArray(messages))
|
|
9
|
+
return messages;
|
|
10
|
+
return messages.map((msg) => convertMessageToTracedFormat(msg));
|
|
11
|
+
}
|
|
12
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
13
|
+
function _formatToolCalls(toolCalls) {
|
|
14
|
+
return toolCalls.map((tc) => ({
|
|
15
|
+
id: tc.toolCallId,
|
|
16
|
+
type: "function",
|
|
17
|
+
function: {
|
|
18
|
+
name: tc.toolName,
|
|
19
|
+
arguments: isPrimitive(tc.input)
|
|
20
|
+
? String(tc.input)
|
|
21
|
+
: JSON.stringify(tc.input),
|
|
22
|
+
},
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
function _formatStepOutput(
|
|
26
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
27
|
+
event, traceRawHttp) {
|
|
28
|
+
// Build an assistant-style message from the step result
|
|
29
|
+
const output = { role: "assistant" };
|
|
30
|
+
// Text content
|
|
31
|
+
if (event.content != null) {
|
|
32
|
+
output.content = event.content;
|
|
33
|
+
}
|
|
34
|
+
else if (event.text != null) {
|
|
35
|
+
output.content = event.text;
|
|
36
|
+
}
|
|
37
|
+
// Tool calls
|
|
38
|
+
if (Array.isArray(event.toolCalls) && event.toolCalls.length > 0) {
|
|
39
|
+
output.tool_calls = _formatToolCalls(event.toolCalls);
|
|
40
|
+
}
|
|
41
|
+
if (event.finishReason != null) {
|
|
42
|
+
output.finish_reason = event.finishReason;
|
|
43
|
+
}
|
|
44
|
+
if (traceRawHttp) {
|
|
45
|
+
if (event.request != null)
|
|
46
|
+
output.request = event.request;
|
|
47
|
+
if (event.response != null)
|
|
48
|
+
output.response = event.response;
|
|
49
|
+
}
|
|
50
|
+
return convertMessageToTracedFormat(output);
|
|
51
|
+
}
|
|
52
|
+
function _getLsAgentType(parentRunTree) {
|
|
53
|
+
if (isRunTree(parentRunTree) && parentRunTree.run_type === "tool") {
|
|
54
|
+
return "subagent";
|
|
55
|
+
}
|
|
56
|
+
return "root";
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Creates a LangSmith `Telemetry` for the Vercel AI SDK.
|
|
60
|
+
*
|
|
61
|
+
* This adapter implements the Vercel AI SDK's `Telemetry` interface
|
|
62
|
+
* and maps lifecycle events to LangSmith traces. It creates a root span for
|
|
63
|
+
* the entire generation, child LLM spans for each step, and tool spans for
|
|
64
|
+
* tool calls.
|
|
65
|
+
*
|
|
66
|
+
* ```ts
|
|
67
|
+
* import { generateText, registerTelemetry } from "ai";
|
|
68
|
+
* import { LangSmithTelemetry } from "langsmith/experimental/vercel";
|
|
69
|
+
*
|
|
70
|
+
* registerTelemetry(LangSmithTelemetry());
|
|
71
|
+
*
|
|
72
|
+
* const result = await generateText({
|
|
73
|
+
* model: openai("gpt-4o"),
|
|
74
|
+
* prompt: "Hello!",
|
|
75
|
+
* });
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @experimental Only available in Vercel AI SDK 7.
|
|
79
|
+
*/
|
|
80
|
+
export function LangSmithTelemetry(config) {
|
|
81
|
+
const { name: customName, runType = "chain", metadata: customMetadata, tags: customTags, client, projectName, processInputs, processOutputs, processChildLLMRunInputs, processChildLLMRunOutputs, traceResponseMetadata, traceRawHttp, tracingEnabled, extra: customExtra, } = config ?? {};
|
|
82
|
+
function getOpenStepOrRoot(state) {
|
|
83
|
+
let openStep;
|
|
84
|
+
state.stepRunTrees.forEach((stepRt) => {
|
|
85
|
+
if (stepRt.end_time == null) {
|
|
86
|
+
openStep = stepRt;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return openStep ?? state.rootRunTree;
|
|
90
|
+
}
|
|
91
|
+
async function finalizeOpenToolRuns(state, opts) {
|
|
92
|
+
const entries = Array.from(state.toolRunTrees.entries());
|
|
93
|
+
for (let i = 0; i < entries.length; i++) {
|
|
94
|
+
const [, toolRt] = entries[i];
|
|
95
|
+
if (toolRt.end_time == null) {
|
|
96
|
+
if (opts?.error != null) {
|
|
97
|
+
await toolRt.end(undefined, opts.error);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
await toolRt.end(opts?.note != null ? { note: opts.note } : undefined);
|
|
101
|
+
}
|
|
102
|
+
await toolRt.patchRun({ excludeInputs: true });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
state.toolRunTrees.clear();
|
|
106
|
+
}
|
|
107
|
+
/** Per-generation state keyed by AI SDK `callId` (stable across nested calls). */
|
|
108
|
+
const invocationsByCallId = new Map();
|
|
109
|
+
const onStart = async (event) => {
|
|
110
|
+
if (!isTracingEnabled(tracingEnabled))
|
|
111
|
+
return;
|
|
112
|
+
if (!("callId" in event) || typeof event.callId !== "string")
|
|
113
|
+
return;
|
|
114
|
+
// If called within an existing traceable context, nest under it
|
|
115
|
+
const parentRunTree = getCurrentRunTree(true);
|
|
116
|
+
let inputs = {};
|
|
117
|
+
if (event.recordInputs !== false) {
|
|
118
|
+
if ("messages" in event && event.messages != null) {
|
|
119
|
+
inputs.messages = _formatMessages(event.messages);
|
|
120
|
+
}
|
|
121
|
+
if ("prompt" in event && event.prompt != null) {
|
|
122
|
+
inputs.prompt = event.prompt;
|
|
123
|
+
}
|
|
124
|
+
if ("instructions" in event && event.instructions != null) {
|
|
125
|
+
inputs.instructions = event.instructions;
|
|
126
|
+
}
|
|
127
|
+
if ("system" in event && event.system != null) {
|
|
128
|
+
inputs.system = event.system;
|
|
129
|
+
}
|
|
130
|
+
if ("tools" in event && event.tools != null) {
|
|
131
|
+
inputs.tools = Object.keys(event.tools);
|
|
132
|
+
}
|
|
133
|
+
if ("runtimeContext" in event && event.runtimeContext != null) {
|
|
134
|
+
inputs.runtimeContext = event.runtimeContext;
|
|
135
|
+
}
|
|
136
|
+
if ("toolsContext" in event && event.toolsContext != null) {
|
|
137
|
+
inputs.toolsContext = event.toolsContext;
|
|
138
|
+
}
|
|
139
|
+
// Apply user-provided input processing
|
|
140
|
+
if (processInputs) {
|
|
141
|
+
try {
|
|
142
|
+
inputs = processInputs(inputs);
|
|
143
|
+
}
|
|
144
|
+
catch (e) {
|
|
145
|
+
console.error("Error in processInputs, using raw inputs:", e);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const runTreeConfig = {
|
|
150
|
+
name: customName ?? event.functionId ?? event.provider,
|
|
151
|
+
run_type: runType,
|
|
152
|
+
inputs,
|
|
153
|
+
tracingEnabled: true,
|
|
154
|
+
extra: {
|
|
155
|
+
...customExtra,
|
|
156
|
+
metadata: {
|
|
157
|
+
...customMetadata,
|
|
158
|
+
ai_sdk_method: event.operationId,
|
|
159
|
+
ls_agent_type: _getLsAgentType(parentRunTree),
|
|
160
|
+
ls_model_name: event.modelId,
|
|
161
|
+
ls_provider: event.provider,
|
|
162
|
+
ls_integration: "vercel-ai-sdk-telemetry",
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
tags: customTags,
|
|
166
|
+
...(client ? { client } : {}),
|
|
167
|
+
...(projectName ? { project_name: projectName } : {}),
|
|
168
|
+
};
|
|
169
|
+
let rootRunTree;
|
|
170
|
+
if (isRunTree(parentRunTree)) {
|
|
171
|
+
rootRunTree = parentRunTree.createChild(runTreeConfig);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
rootRunTree = new RunTree(runTreeConfig);
|
|
175
|
+
}
|
|
176
|
+
await rootRunTree.postRun();
|
|
177
|
+
invocationsByCallId.set(event.callId, {
|
|
178
|
+
rootRunTree,
|
|
179
|
+
stepRunTrees: new Map(),
|
|
180
|
+
toolRunTrees: new Map(),
|
|
181
|
+
});
|
|
182
|
+
};
|
|
183
|
+
const onStepStart = async (event) => {
|
|
184
|
+
const state = invocationsByCallId.get(event.callId);
|
|
185
|
+
if (!state)
|
|
186
|
+
return;
|
|
187
|
+
const stepNumber = event.stepNumber ?? 0;
|
|
188
|
+
let inputs = {};
|
|
189
|
+
if (event.recordInputs !== false) {
|
|
190
|
+
if ("messages" in event && event.messages != null) {
|
|
191
|
+
inputs.messages = _formatMessages(event.messages);
|
|
192
|
+
}
|
|
193
|
+
if ("runtimeContext" in event && event.runtimeContext != null) {
|
|
194
|
+
inputs.runtimeContext = event.runtimeContext;
|
|
195
|
+
}
|
|
196
|
+
if ("toolsContext" in event && event.toolsContext != null) {
|
|
197
|
+
inputs.toolsContext = event.toolsContext;
|
|
198
|
+
}
|
|
199
|
+
if (processChildLLMRunInputs) {
|
|
200
|
+
try {
|
|
201
|
+
inputs = processChildLLMRunInputs(inputs);
|
|
202
|
+
}
|
|
203
|
+
catch (e) {
|
|
204
|
+
console.error("Error in processChildLLMRunInputs, using raw inputs:", e);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const stepRunTree = state.rootRunTree.createChild({
|
|
209
|
+
name: event.provider,
|
|
210
|
+
run_type: "llm",
|
|
211
|
+
inputs,
|
|
212
|
+
extra: { metadata: { step_number: stepNumber } },
|
|
213
|
+
});
|
|
214
|
+
state.stepRunTrees.set(stepNumber, stepRunTree);
|
|
215
|
+
await stepRunTree.postRun();
|
|
216
|
+
};
|
|
217
|
+
const onLanguageModelCallStart = async (event) => {
|
|
218
|
+
const state = invocationsByCallId.get(event.callId);
|
|
219
|
+
if (!state)
|
|
220
|
+
return;
|
|
221
|
+
const stepRunTree = getOpenStepOrRoot(state);
|
|
222
|
+
if (stepRunTree.run_type !== "llm")
|
|
223
|
+
return;
|
|
224
|
+
const prevParams = isRecord(stepRunTree.extra?.invocation_params)
|
|
225
|
+
? stepRunTree.extra.invocation_params
|
|
226
|
+
: {};
|
|
227
|
+
const nextParams = { ...event };
|
|
228
|
+
// Remove properties that are already in the step run tree
|
|
229
|
+
delete nextParams.messages;
|
|
230
|
+
delete nextParams.provider;
|
|
231
|
+
delete nextParams.modelId;
|
|
232
|
+
// Remove telemetry options (except functionId)
|
|
233
|
+
delete nextParams.recordInputs;
|
|
234
|
+
delete nextParams.recordOutputs;
|
|
235
|
+
delete nextParams.includeToolsContext;
|
|
236
|
+
// Massage tools for LangSmith to render schema nicely
|
|
237
|
+
nextParams.tools = nextParams.tools?.map((tool) => {
|
|
238
|
+
const newTool = { ...tool };
|
|
239
|
+
if ("inputSchema" in newTool) {
|
|
240
|
+
newTool.input_schema = newTool.inputSchema;
|
|
241
|
+
delete newTool.inputSchema;
|
|
242
|
+
}
|
|
243
|
+
return newTool;
|
|
244
|
+
});
|
|
245
|
+
stepRunTree.extra = {
|
|
246
|
+
...stepRunTree.extra,
|
|
247
|
+
invocation_params: { ...prevParams, ...nextParams },
|
|
248
|
+
};
|
|
249
|
+
};
|
|
250
|
+
const onToolExecutionStart = async (event) => {
|
|
251
|
+
const state = invocationsByCallId.get(event.callId);
|
|
252
|
+
if (!state)
|
|
253
|
+
return;
|
|
254
|
+
const parentRunTree = getOpenStepOrRoot(state);
|
|
255
|
+
let inputs = {};
|
|
256
|
+
if (event.recordInputs !== false) {
|
|
257
|
+
if (isRecord(event.toolCall.input)) {
|
|
258
|
+
inputs = { ...event.toolCall.input };
|
|
259
|
+
}
|
|
260
|
+
else if (typeof event.toolCall.input !== "undefined") {
|
|
261
|
+
inputs = { input: event.toolCall.input };
|
|
262
|
+
}
|
|
263
|
+
if ("toolContext" in event && event.toolContext != null) {
|
|
264
|
+
inputs.toolContext = event.toolContext;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
inputs = {};
|
|
269
|
+
}
|
|
270
|
+
const toolRunTree = parentRunTree.createChild({
|
|
271
|
+
name: event.toolCall.toolName,
|
|
272
|
+
run_type: "tool",
|
|
273
|
+
inputs,
|
|
274
|
+
extra: {
|
|
275
|
+
metadata: {
|
|
276
|
+
tool_call_id: event.toolCall.toolCallId,
|
|
277
|
+
ai_sdk_call_id: event.callId,
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
await toolRunTree.postRun();
|
|
282
|
+
state.toolRunTrees.set(event.toolCall.toolCallId, toolRunTree);
|
|
283
|
+
};
|
|
284
|
+
const onToolExecutionEnd = async (event) => {
|
|
285
|
+
const state = invocationsByCallId.get(event.callId);
|
|
286
|
+
if (!state)
|
|
287
|
+
return;
|
|
288
|
+
const toolRunTree = state.toolRunTrees.get(event.toolCall.toolCallId);
|
|
289
|
+
if (!toolRunTree)
|
|
290
|
+
return;
|
|
291
|
+
state.toolRunTrees.delete(event.toolCall.toolCallId);
|
|
292
|
+
let outputs;
|
|
293
|
+
let error;
|
|
294
|
+
if (event.recordOutputs !== false) {
|
|
295
|
+
if (event.toolOutput.type === "tool-result") {
|
|
296
|
+
outputs = { output: event.toolOutput.output };
|
|
297
|
+
}
|
|
298
|
+
else if (event.toolOutput.type === "tool-error") {
|
|
299
|
+
const err = event.toolOutput.error;
|
|
300
|
+
error = err instanceof Error ? err.message : String(err);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
outputs = {};
|
|
305
|
+
}
|
|
306
|
+
await toolRunTree.end(outputs, error, Math.floor(toolRunTree.start_time + event.toolExecutionMs));
|
|
307
|
+
await toolRunTree.patchRun({ excludeInputs: true });
|
|
308
|
+
};
|
|
309
|
+
const onStepFinish = async (event) => {
|
|
310
|
+
const state = invocationsByCallId.get(event.callId);
|
|
311
|
+
if (!state)
|
|
312
|
+
return;
|
|
313
|
+
const stepNumber = event.stepNumber ?? 0;
|
|
314
|
+
const stepRunTree = state.stepRunTrees.get(stepNumber);
|
|
315
|
+
if (!stepRunTree)
|
|
316
|
+
return;
|
|
317
|
+
let outputs = {};
|
|
318
|
+
if (event.recordOutputs !== false) {
|
|
319
|
+
outputs = _formatStepOutput(event, traceRawHttp);
|
|
320
|
+
if (processChildLLMRunOutputs) {
|
|
321
|
+
try {
|
|
322
|
+
outputs = processChildLLMRunOutputs(outputs);
|
|
323
|
+
}
|
|
324
|
+
catch (e) {
|
|
325
|
+
console.error("Error in processChildLLMRunOutputs, using raw outputs:", e);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// Set usage metadata
|
|
330
|
+
// @ts-expect-error SharedV4ProviderMetadata is not assignable to SharedV2ProviderMetadata
|
|
331
|
+
setUsageMetadataOnRunTree(event, stepRunTree);
|
|
332
|
+
await stepRunTree.end(outputs);
|
|
333
|
+
await stepRunTree.patchRun({ excludeInputs: true });
|
|
334
|
+
state.stepRunTrees.delete(stepNumber);
|
|
335
|
+
};
|
|
336
|
+
const onEnd = async (event) => {
|
|
337
|
+
if (!("callId" in event) || typeof event.callId !== "string")
|
|
338
|
+
return;
|
|
339
|
+
const state = invocationsByCallId.get(event.callId);
|
|
340
|
+
if (!state)
|
|
341
|
+
return;
|
|
342
|
+
const { rootRunTree } = state;
|
|
343
|
+
await finalizeOpenToolRuns(state, { note: "closed on finish" });
|
|
344
|
+
// Ensure any remaining step runs are closed
|
|
345
|
+
const remainingSteps = Array.from(state.stepRunTrees.entries());
|
|
346
|
+
for (let i = 0; i < remainingSteps.length; i++) {
|
|
347
|
+
const [stepNumber, stepRt] = remainingSteps[i];
|
|
348
|
+
if (stepRt.end_time == null) {
|
|
349
|
+
await stepRt.end({ note: "closed on finish" });
|
|
350
|
+
await stepRt.patchRun({ excludeInputs: true });
|
|
351
|
+
}
|
|
352
|
+
state.stepRunTrees.delete(stepNumber);
|
|
353
|
+
}
|
|
354
|
+
let outputs = {};
|
|
355
|
+
if (event.recordOutputs !== false) {
|
|
356
|
+
// Final result output
|
|
357
|
+
if ("text" in event && event.text != null) {
|
|
358
|
+
outputs.content = event.text;
|
|
359
|
+
}
|
|
360
|
+
else if ("content" in event && event.content != null) {
|
|
361
|
+
outputs.content = event.content;
|
|
362
|
+
}
|
|
363
|
+
if (outputs.content != null) {
|
|
364
|
+
outputs.role = "assistant";
|
|
365
|
+
}
|
|
366
|
+
if ("object" in event && event.object != null) {
|
|
367
|
+
outputs.object = event.object;
|
|
368
|
+
}
|
|
369
|
+
if ("toolCalls" in event &&
|
|
370
|
+
Array.isArray(event.toolCalls) &&
|
|
371
|
+
event.toolCalls.length > 0) {
|
|
372
|
+
outputs.tool_calls = _formatToolCalls(event.toolCalls);
|
|
373
|
+
}
|
|
374
|
+
if ("finishReason" in event && event.finishReason != null) {
|
|
375
|
+
outputs.finish_reason = event.finishReason;
|
|
376
|
+
}
|
|
377
|
+
if (traceResponseMetadata &&
|
|
378
|
+
"steps" in event &&
|
|
379
|
+
Array.isArray(event.steps)) {
|
|
380
|
+
outputs.steps = event.steps.map((step, idx) => ({
|
|
381
|
+
step_number: idx,
|
|
382
|
+
..._formatStepOutput(step, traceRawHttp),
|
|
383
|
+
}));
|
|
384
|
+
}
|
|
385
|
+
if (processOutputs) {
|
|
386
|
+
try {
|
|
387
|
+
outputs = processOutputs(outputs);
|
|
388
|
+
}
|
|
389
|
+
catch (e) {
|
|
390
|
+
console.error("Error in processOutputs, using raw outputs:", e);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// Set aggregated usage on root
|
|
395
|
+
if ("totalUsage" in event && event.totalUsage != null) {
|
|
396
|
+
setUsageMetadataOnRunTree(
|
|
397
|
+
// @ts-expect-error SharedV4ProviderMetadata is not assignable to SharedV2ProviderMetadata
|
|
398
|
+
{ usage: event.totalUsage, providerMetadata: event.providerMetadata }, rootRunTree);
|
|
399
|
+
}
|
|
400
|
+
else if ("usage" in event && event.usage != null) {
|
|
401
|
+
// @ts-expect-error SharedV4ProviderMetadata is not assignable to SharedV2ProviderMetadata
|
|
402
|
+
setUsageMetadataOnRunTree(event, rootRunTree);
|
|
403
|
+
}
|
|
404
|
+
await rootRunTree.end(outputs);
|
|
405
|
+
await rootRunTree.patchRun({ excludeInputs: true });
|
|
406
|
+
invocationsByCallId.delete(event.callId);
|
|
407
|
+
};
|
|
408
|
+
const onError = async (payload) => {
|
|
409
|
+
const callId = typeof payload === "object" &&
|
|
410
|
+
payload !== null &&
|
|
411
|
+
"callId" in payload &&
|
|
412
|
+
typeof payload.callId === "string"
|
|
413
|
+
? payload.callId
|
|
414
|
+
: undefined;
|
|
415
|
+
const error = typeof payload === "object" && payload !== null && "error" in payload
|
|
416
|
+
? payload.error
|
|
417
|
+
: payload;
|
|
418
|
+
if (callId === undefined)
|
|
419
|
+
return;
|
|
420
|
+
const state = invocationsByCallId.get(callId);
|
|
421
|
+
if (!state)
|
|
422
|
+
return;
|
|
423
|
+
const { rootRunTree } = state;
|
|
424
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
425
|
+
await finalizeOpenToolRuns(state, { error: errorMsg });
|
|
426
|
+
// Close any open step runs with error
|
|
427
|
+
const errorSteps = Array.from(state.stepRunTrees.entries());
|
|
428
|
+
for (let i = 0; i < errorSteps.length; i++) {
|
|
429
|
+
const [stepNumber, stepRt] = errorSteps[i];
|
|
430
|
+
if (stepRt.end_time == null) {
|
|
431
|
+
await stepRt.end(undefined, errorMsg);
|
|
432
|
+
await stepRt.patchRun({ excludeInputs: true });
|
|
433
|
+
}
|
|
434
|
+
state.stepRunTrees.delete(stepNumber);
|
|
435
|
+
}
|
|
436
|
+
await rootRunTree.end(undefined, errorMsg);
|
|
437
|
+
await rootRunTree.patchRun({ excludeInputs: true });
|
|
438
|
+
invocationsByCallId.delete(callId);
|
|
439
|
+
};
|
|
440
|
+
const executeTool = async (params) => {
|
|
441
|
+
const state = invocationsByCallId.get(params.callId);
|
|
442
|
+
const toolRunTree = state?.toolRunTrees.get(params.toolCallId);
|
|
443
|
+
if (toolRunTree != null) {
|
|
444
|
+
return withRunTree(toolRunTree, () => params.execute());
|
|
445
|
+
}
|
|
446
|
+
return params.execute();
|
|
447
|
+
};
|
|
448
|
+
return {
|
|
449
|
+
onStart,
|
|
450
|
+
onStepStart,
|
|
451
|
+
onLanguageModelCallStart,
|
|
452
|
+
onToolExecutionStart,
|
|
453
|
+
onToolExecutionEnd,
|
|
454
|
+
onStepFinish,
|
|
455
|
+
onEnd,
|
|
456
|
+
onError,
|
|
457
|
+
executeTool,
|
|
458
|
+
};
|
|
459
|
+
}
|