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