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
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
import { LangSmithMiddleware, } from "./middleware.js";
|
|
2
|
+
import { convertMessageToTracedFormat } from "./utils.js";
|
|
3
|
+
import { isTraceableFunction, traceable, getCurrentRunTree, } from "../../traceable.js";
|
|
4
|
+
const _getModelDisplayName = (model) => {
|
|
5
|
+
if (typeof model === "string") {
|
|
6
|
+
return model;
|
|
7
|
+
}
|
|
8
|
+
if (model.config != null &&
|
|
9
|
+
typeof model.config === "object" &&
|
|
10
|
+
"provider" in model.config &&
|
|
11
|
+
typeof model.config.provider === "string") {
|
|
12
|
+
return model.config.provider;
|
|
13
|
+
}
|
|
14
|
+
if (model.modelId != null && typeof model.modelId === "string") {
|
|
15
|
+
return model.modelId;
|
|
16
|
+
}
|
|
17
|
+
return "unknown";
|
|
18
|
+
};
|
|
19
|
+
const _getModelId = (model) => {
|
|
20
|
+
if (typeof model === "string") {
|
|
21
|
+
return model;
|
|
22
|
+
}
|
|
23
|
+
return typeof model.modelId === "string" ? model.modelId : undefined;
|
|
24
|
+
};
|
|
25
|
+
const _wrapTools = (tools, lsConfig) => {
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
|
+
const wrappedTools = {};
|
|
28
|
+
if (tools) {
|
|
29
|
+
for (const [key, tool] of Object.entries(tools)) {
|
|
30
|
+
wrappedTools[key] = Object.assign(Object.create(Object.getPrototypeOf(tool)), tool);
|
|
31
|
+
if (wrappedTools[key] != null &&
|
|
32
|
+
typeof wrappedTools[key] === "object" &&
|
|
33
|
+
"execute" in wrappedTools[key] &&
|
|
34
|
+
typeof wrappedTools[key].execute === "function" &&
|
|
35
|
+
!isTraceableFunction(wrappedTools[key].execute)) {
|
|
36
|
+
wrappedTools[key].execute = traceable(wrappedTools[key].execute.bind(wrappedTools[key]), {
|
|
37
|
+
...lsConfig,
|
|
38
|
+
name: key,
|
|
39
|
+
run_type: "tool",
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return wrappedTools;
|
|
45
|
+
};
|
|
46
|
+
const _formatTracedInputs = async (params) => {
|
|
47
|
+
const { prompt, messages, model, tools, output, ...rest } = params;
|
|
48
|
+
let processedInputs = {};
|
|
49
|
+
if (Array.isArray(prompt)) {
|
|
50
|
+
processedInputs = {
|
|
51
|
+
...rest,
|
|
52
|
+
messages: prompt.map((message) => convertMessageToTracedFormat(message)),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
else if (Array.isArray(messages)) {
|
|
56
|
+
processedInputs = {
|
|
57
|
+
...rest,
|
|
58
|
+
messages: messages.map((message) => convertMessageToTracedFormat(message)),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
processedInputs = { ...rest, prompt, messages };
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
if (output != null &&
|
|
66
|
+
typeof output === "object" &&
|
|
67
|
+
"responseFormat" in output) {
|
|
68
|
+
const responseFormat = await output.responseFormat;
|
|
69
|
+
processedInputs.output = responseFormat;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
processedInputs.output = output;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Could not extract response format from output for tracing
|
|
77
|
+
processedInputs.output = output;
|
|
78
|
+
}
|
|
79
|
+
return processedInputs;
|
|
80
|
+
};
|
|
81
|
+
const _mergeConfig = (baseConfig, runtimeConfig) => {
|
|
82
|
+
return {
|
|
83
|
+
...baseConfig,
|
|
84
|
+
...runtimeConfig,
|
|
85
|
+
metadata: {
|
|
86
|
+
ls_integration: "vercel-ai-sdk",
|
|
87
|
+
...baseConfig?.metadata,
|
|
88
|
+
...runtimeConfig?.metadata,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
const _extractChildRunConfig = (lsConfig) => {
|
|
93
|
+
const { id, name, parent_run_id, start_time, end_time, attachments, dotted_order, processInputs, processOutputs, processChildLLMRunInputs, processChildLLMRunOutputs, ...inheritedConfig } = lsConfig ?? {};
|
|
94
|
+
const childConfig = inheritedConfig;
|
|
95
|
+
if (processChildLLMRunInputs) {
|
|
96
|
+
childConfig.processInputs = processChildLLMRunInputs;
|
|
97
|
+
}
|
|
98
|
+
if (processChildLLMRunOutputs) {
|
|
99
|
+
// TODO: Fix this typing on minor bump
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
101
|
+
childConfig.processOutputs = processChildLLMRunOutputs;
|
|
102
|
+
}
|
|
103
|
+
return childConfig;
|
|
104
|
+
};
|
|
105
|
+
const _resolveConfigs = (baseLsConfig, runtimeLsConfig) => {
|
|
106
|
+
const baseChildRunConfig = _extractChildRunConfig(baseLsConfig);
|
|
107
|
+
const runtimeChildLLMRunConfig = _extractChildRunConfig(runtimeLsConfig);
|
|
108
|
+
const resolvedLsConfig = _mergeConfig(baseLsConfig, runtimeLsConfig);
|
|
109
|
+
const resolvedChildLLMRunConfig = _mergeConfig(baseChildRunConfig, runtimeChildLLMRunConfig);
|
|
110
|
+
const { processInputs: _processInputs, processOutputs: _processOutputs, ...resolvedToolConfig } = resolvedChildLLMRunConfig;
|
|
111
|
+
return {
|
|
112
|
+
resolvedLsConfig,
|
|
113
|
+
resolvedChildLLMRunConfig,
|
|
114
|
+
resolvedToolConfig,
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
const _getLsAgentType = () => {
|
|
118
|
+
const parentRun = getCurrentRunTree(true);
|
|
119
|
+
if (parentRun != null && parentRun.run_type === "tool") {
|
|
120
|
+
return "subagent";
|
|
121
|
+
}
|
|
122
|
+
return "root";
|
|
123
|
+
};
|
|
124
|
+
const _getGenerateTextWrapperConfig = ({ model, runName, aiSdkMethodName, resolvedLsConfig, hasExplicitOutput, hasExplicitExperimentalOutput, traceResponseMetadata, }) => {
|
|
125
|
+
return {
|
|
126
|
+
name: runName ?? _getModelDisplayName(model),
|
|
127
|
+
...resolvedLsConfig,
|
|
128
|
+
metadata: {
|
|
129
|
+
ls_agent_type: _getLsAgentType(),
|
|
130
|
+
ai_sdk_method: aiSdkMethodName ?? "ai.generateText",
|
|
131
|
+
...resolvedLsConfig?.metadata,
|
|
132
|
+
},
|
|
133
|
+
processInputs: async (inputs) => {
|
|
134
|
+
const inputFormatter = resolvedLsConfig?.processInputs ?? _formatTracedInputs;
|
|
135
|
+
return inputFormatter(inputs);
|
|
136
|
+
},
|
|
137
|
+
processOutputs: async (outputs) => {
|
|
138
|
+
if (resolvedLsConfig?.processOutputs) {
|
|
139
|
+
const processedOutputs = await resolvedLsConfig.processOutputs(
|
|
140
|
+
// TODO: Fix this typing on minor bump
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
142
|
+
outputs);
|
|
143
|
+
return processedOutputs;
|
|
144
|
+
}
|
|
145
|
+
if (outputs.outputs == null || typeof outputs.outputs !== "object") {
|
|
146
|
+
return outputs;
|
|
147
|
+
}
|
|
148
|
+
// If output or experimental_output (legacy) was explicitly provided, return it directly at top level (like generateObject)
|
|
149
|
+
// Note: In AI SDK 6, experimental_output/output is always available as a getter, so we need to check if it was explicitly provided
|
|
150
|
+
if (hasExplicitOutput) {
|
|
151
|
+
try {
|
|
152
|
+
// Try new 'output' property first, then fall back to 'experimental_output' for backwards compatibility
|
|
153
|
+
if ("output" in outputs.outputs) {
|
|
154
|
+
const output = outputs.outputs.output;
|
|
155
|
+
if (output != null && typeof output === "object") {
|
|
156
|
+
if (Array.isArray(output)) {
|
|
157
|
+
return { outputs: output };
|
|
158
|
+
}
|
|
159
|
+
return output;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// output not accessible, continue with normal processing
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else if (hasExplicitExperimentalOutput) {
|
|
168
|
+
try {
|
|
169
|
+
if ("experimental_output" in outputs.outputs) {
|
|
170
|
+
const experimentalOutput = outputs.outputs.experimental_output;
|
|
171
|
+
if (experimentalOutput != null) {
|
|
172
|
+
return experimentalOutput;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// experimental_output not accessible, continue with normal processing
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const { steps } = outputs.outputs;
|
|
181
|
+
if (Array.isArray(steps)) {
|
|
182
|
+
const lastStep = steps.at(-1);
|
|
183
|
+
if (lastStep == null || typeof lastStep !== "object") {
|
|
184
|
+
return outputs;
|
|
185
|
+
}
|
|
186
|
+
const { content } = lastStep;
|
|
187
|
+
return convertMessageToTracedFormat({
|
|
188
|
+
content: content ?? outputs.outputs.text,
|
|
189
|
+
role: "assistant",
|
|
190
|
+
}, (resolvedLsConfig?.traceResponseMetadata ?? traceResponseMetadata)
|
|
191
|
+
? { steps }
|
|
192
|
+
: undefined);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
return outputs;
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
const _getStreamTextWrapperConfig = ({ model, runName, aiSdkMethodName, resolvedLsConfig, hasExplicitOutput, hasExplicitExperimentalOutput, traceResponseMetadata, }) => {
|
|
201
|
+
return {
|
|
202
|
+
name: runName ?? _getModelDisplayName(model),
|
|
203
|
+
...resolvedLsConfig,
|
|
204
|
+
metadata: {
|
|
205
|
+
ls_agent_type: _getLsAgentType(),
|
|
206
|
+
ai_sdk_method: aiSdkMethodName ?? "ai.streamText",
|
|
207
|
+
...resolvedLsConfig?.metadata,
|
|
208
|
+
},
|
|
209
|
+
processInputs: async (inputs) => {
|
|
210
|
+
const inputFormatter = resolvedLsConfig?.processInputs ?? _formatTracedInputs;
|
|
211
|
+
return inputFormatter(inputs);
|
|
212
|
+
},
|
|
213
|
+
processOutputs: async (outputs) => {
|
|
214
|
+
try {
|
|
215
|
+
if (resolvedLsConfig?.processOutputs) {
|
|
216
|
+
const processedOutputs = await resolvedLsConfig.processOutputs(
|
|
217
|
+
// TODO: Fix this typing on minor bump
|
|
218
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
219
|
+
outputs);
|
|
220
|
+
return processedOutputs;
|
|
221
|
+
}
|
|
222
|
+
if (outputs.outputs == null || typeof outputs.outputs !== "object") {
|
|
223
|
+
return outputs;
|
|
224
|
+
}
|
|
225
|
+
// Important: Even accessing this property creates a promise.
|
|
226
|
+
// This must be awaited.
|
|
227
|
+
let content = await outputs.outputs.content;
|
|
228
|
+
if (content == null) {
|
|
229
|
+
// AI SDK 4 shim
|
|
230
|
+
content = await outputs.outputs.text;
|
|
231
|
+
}
|
|
232
|
+
if (content == null || !["object", "string"].includes(typeof content)) {
|
|
233
|
+
return outputs;
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
if (hasExplicitOutput || hasExplicitExperimentalOutput) {
|
|
237
|
+
const textContent = await outputs.outputs.text;
|
|
238
|
+
return JSON.parse(textContent);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// experimental_partialOutputStream not specified, continue with normal processing
|
|
243
|
+
}
|
|
244
|
+
let responseMetadata = undefined;
|
|
245
|
+
if (resolvedLsConfig?.traceResponseMetadata ?? traceResponseMetadata) {
|
|
246
|
+
try {
|
|
247
|
+
const steps = await outputs.outputs.steps;
|
|
248
|
+
responseMetadata = { steps };
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
// Do nothing if step parsing fails
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return convertMessageToTracedFormat({
|
|
255
|
+
content,
|
|
256
|
+
role: "assistant",
|
|
257
|
+
}, responseMetadata);
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// Handle parsing failures without a log
|
|
261
|
+
return outputs;
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Wraps LangSmith config in a way that matches AI SDK provider types.
|
|
268
|
+
*
|
|
269
|
+
* ```ts
|
|
270
|
+
* import { createLangSmithProviderOptions } from "langsmith/experimental/vercel";
|
|
271
|
+
* import * as ai from "ai";
|
|
272
|
+
*
|
|
273
|
+
* const lsConfig = createLangSmithProviderOptions<typeof ai.generateText>({
|
|
274
|
+
* // Will have appropriate typing
|
|
275
|
+
* processInputs: (inputs) => {
|
|
276
|
+
* const { messages } = inputs;
|
|
277
|
+
* return {
|
|
278
|
+
* messages: messages?.map((message) => ({
|
|
279
|
+
* ...message,
|
|
280
|
+
* content: "REDACTED",
|
|
281
|
+
* })),
|
|
282
|
+
* prompt: "REDACTED",
|
|
283
|
+
* };
|
|
284
|
+
* },
|
|
285
|
+
* });
|
|
286
|
+
* ```
|
|
287
|
+
*
|
|
288
|
+
* Note: AI SDK expects only JSON values in an object for
|
|
289
|
+
* provider options, but LangSmith's config may contain non-JSON values.
|
|
290
|
+
* These are not passed to the underlying AI SDK model, so it is safe to
|
|
291
|
+
* cast the typing here.
|
|
292
|
+
*/
|
|
293
|
+
export const createLangSmithProviderOptions = (lsConfig) => {
|
|
294
|
+
return (lsConfig ?? {});
|
|
295
|
+
};
|
|
296
|
+
/**
|
|
297
|
+
* Wraps Vercel AI SDK 6 or AI SDK 5 functions with LangSmith tracing capabilities.
|
|
298
|
+
*
|
|
299
|
+
* @param methods - Object containing AI SDK methods to wrap
|
|
300
|
+
* @param methods.wrapLanguageModel - AI SDK's wrapLanguageModel function
|
|
301
|
+
* @param methods.generateText - AI SDK's generateText function
|
|
302
|
+
* @param methods.streamText - AI SDK's streamText function
|
|
303
|
+
* @param methods.streamObject - AI SDK's streamObject function
|
|
304
|
+
* @param methods.generateObject - AI SDK's generateObject function
|
|
305
|
+
*
|
|
306
|
+
* @returns Object containing wrapped versions of the AI SDK functions with LangSmith tracing
|
|
307
|
+
* @returns returns.generateText - Wrapped generateText function that traces calls to LangSmith
|
|
308
|
+
* @returns returns.generateObject - Wrapped generateObject function that traces calls to LangSmith
|
|
309
|
+
* @returns returns.streamText - Wrapped streamText function that traces calls to LangSmith
|
|
310
|
+
* @returns returns.streamObject - Wrapped streamObject function that traces calls to LangSmith
|
|
311
|
+
*/
|
|
312
|
+
const wrapAISDK = (ai, baseLsConfig) => {
|
|
313
|
+
/**
|
|
314
|
+
* Wrapped version of AI SDK's generateText with LangSmith tracing.
|
|
315
|
+
*
|
|
316
|
+
* This function has the same signature and behavior as the original generateText,
|
|
317
|
+
* but adds automatic tracing to LangSmith for observability.
|
|
318
|
+
*
|
|
319
|
+
* ```ts
|
|
320
|
+
* import * as ai from "ai";
|
|
321
|
+
* import { wrapAISDK } from "langsmith/experimental/vercel";
|
|
322
|
+
*
|
|
323
|
+
* const { generateText } = wrapAISDK(ai);
|
|
324
|
+
* const { text } = await generateText(...);
|
|
325
|
+
* ```
|
|
326
|
+
*
|
|
327
|
+
* @see {@link https://sdk.vercel.ai/docs/ai-sdk-core/generating-text} Original generateText documentation
|
|
328
|
+
* @param params - Same parameters as the original generateText function
|
|
329
|
+
* @returns Promise resolving to the same result as generateText, with tracing applied
|
|
330
|
+
*/
|
|
331
|
+
const wrappedGenerateText = async (...args) => {
|
|
332
|
+
const params = args[0];
|
|
333
|
+
const { langsmith: runtimeLsConfig, ...providerOptions } = params.providerOptions ?? {};
|
|
334
|
+
const { resolvedLsConfig, resolvedChildLLMRunConfig, resolvedToolConfig } = _resolveConfigs(baseLsConfig, runtimeLsConfig);
|
|
335
|
+
const hasExplicitOutput = "output" in params;
|
|
336
|
+
const hasExplicitExperimentalOutput = "experimental_output" in params;
|
|
337
|
+
const traceableFunc = traceable(async (...args) => {
|
|
338
|
+
const [params, ...rest] = args;
|
|
339
|
+
const wrappedModel = ai.wrapLanguageModel({
|
|
340
|
+
model: params.model,
|
|
341
|
+
middleware: LangSmithMiddleware({
|
|
342
|
+
name: _getModelDisplayName(params.model),
|
|
343
|
+
modelId: _getModelId(params.model),
|
|
344
|
+
// TODO: Fix this typing on minor bump
|
|
345
|
+
lsConfig: resolvedChildLLMRunConfig,
|
|
346
|
+
}),
|
|
347
|
+
});
|
|
348
|
+
return ai.generateText({
|
|
349
|
+
...params,
|
|
350
|
+
providerOptions,
|
|
351
|
+
tools: _wrapTools(params.tools, resolvedToolConfig),
|
|
352
|
+
model: wrappedModel,
|
|
353
|
+
}, ...rest);
|
|
354
|
+
}, _getGenerateTextWrapperConfig({
|
|
355
|
+
model: params.model,
|
|
356
|
+
resolvedLsConfig,
|
|
357
|
+
hasExplicitOutput,
|
|
358
|
+
hasExplicitExperimentalOutput,
|
|
359
|
+
}));
|
|
360
|
+
return traceableFunc(...args);
|
|
361
|
+
};
|
|
362
|
+
let wrappedGenerateObject;
|
|
363
|
+
if (typeof ai.generateObject === "function") {
|
|
364
|
+
const generateObject = ai.generateObject;
|
|
365
|
+
/**
|
|
366
|
+
* Wrapped version of AI SDK's generateObject with LangSmith tracing.
|
|
367
|
+
*
|
|
368
|
+
* This function has the same signature and behavior as the original generateObject,
|
|
369
|
+
* but adds automatic tracing to LangSmith for observability.
|
|
370
|
+
*
|
|
371
|
+
* ```ts
|
|
372
|
+
* import * as ai from "ai";
|
|
373
|
+
* import { wrapAISDK } from "langsmith/experimental/vercel";
|
|
374
|
+
*
|
|
375
|
+
* const { generateObject } = wrapAISDK(ai);
|
|
376
|
+
* const { object } = await generateObject(...);
|
|
377
|
+
* ```
|
|
378
|
+
*
|
|
379
|
+
* @see {@link https://sdk.vercel.ai/docs/ai-sdk-core/generating-structured-data} Original generateObject documentation
|
|
380
|
+
* @param params - Same parameters as the original generateObject function
|
|
381
|
+
* @returns Promise resolving to the same result as generateObject, with tracing applied
|
|
382
|
+
*/
|
|
383
|
+
wrappedGenerateObject = async (...args) => {
|
|
384
|
+
const params = args[0];
|
|
385
|
+
const { langsmith: runtimeLsConfig, ...providerOptions } = params.providerOptions ?? {};
|
|
386
|
+
const { resolvedLsConfig, resolvedChildLLMRunConfig } = _resolveConfigs(baseLsConfig, runtimeLsConfig);
|
|
387
|
+
const traceableFunc = traceable(async (...args) => {
|
|
388
|
+
const [params, ...rest] = args;
|
|
389
|
+
const wrappedModel = ai.wrapLanguageModel({
|
|
390
|
+
model: params.model,
|
|
391
|
+
middleware: LangSmithMiddleware({
|
|
392
|
+
name: _getModelDisplayName(params.model),
|
|
393
|
+
modelId: _getModelId(params.model),
|
|
394
|
+
// TODO: Fix this typing on minor bump
|
|
395
|
+
lsConfig: resolvedChildLLMRunConfig,
|
|
396
|
+
}),
|
|
397
|
+
});
|
|
398
|
+
return generateObject({
|
|
399
|
+
...params,
|
|
400
|
+
providerOptions,
|
|
401
|
+
model: wrappedModel,
|
|
402
|
+
}, ...rest);
|
|
403
|
+
}, {
|
|
404
|
+
name: _getModelDisplayName(params.model),
|
|
405
|
+
...resolvedLsConfig,
|
|
406
|
+
metadata: {
|
|
407
|
+
ls_agent_type: _getLsAgentType(),
|
|
408
|
+
ai_sdk_method: "ai.generateObject",
|
|
409
|
+
...resolvedLsConfig?.metadata,
|
|
410
|
+
},
|
|
411
|
+
processInputs: async (inputs) => {
|
|
412
|
+
const inputFormatter = resolvedLsConfig?.processInputs ?? _formatTracedInputs;
|
|
413
|
+
return inputFormatter(inputs);
|
|
414
|
+
},
|
|
415
|
+
processOutputs: async (outputs) => {
|
|
416
|
+
if (resolvedLsConfig?.processOutputs) {
|
|
417
|
+
const processedOutputs = await resolvedLsConfig.processOutputs(
|
|
418
|
+
// TODO: Fix this typing on minor bump
|
|
419
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
420
|
+
outputs);
|
|
421
|
+
return processedOutputs;
|
|
422
|
+
}
|
|
423
|
+
if (outputs.outputs == null ||
|
|
424
|
+
typeof outputs.outputs !== "object") {
|
|
425
|
+
return outputs;
|
|
426
|
+
}
|
|
427
|
+
return outputs.outputs.object ?? outputs;
|
|
428
|
+
},
|
|
429
|
+
});
|
|
430
|
+
return traceableFunc(...args);
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Wrapped version of AI SDK's streamText with LangSmith tracing.
|
|
435
|
+
*
|
|
436
|
+
* Must be called with `await`, but otherwise behaves the same as the
|
|
437
|
+
* original streamText and adds adds automatic tracing to LangSmith
|
|
438
|
+
* for observability.
|
|
439
|
+
*
|
|
440
|
+
* ```ts
|
|
441
|
+
* import * as ai from "ai";
|
|
442
|
+
* import { wrapAISDK } from "langsmith/experimental/vercel";
|
|
443
|
+
*
|
|
444
|
+
* const { streamText } = wrapAISDK(ai);
|
|
445
|
+
* const { textStream } = await streamText(...);
|
|
446
|
+
* ```
|
|
447
|
+
*
|
|
448
|
+
* @see {@link https://sdk.vercel.ai/docs/ai-sdk-core/generating-text} Original streamText documentation
|
|
449
|
+
* @param params - Same parameters as the original streamText function
|
|
450
|
+
* @returns Promise resolving to the same result as streamText, with tracing applied
|
|
451
|
+
*/
|
|
452
|
+
const wrappedStreamText = (...args) => {
|
|
453
|
+
const params = args[0];
|
|
454
|
+
const { langsmith: runtimeLsConfig, ...providerOptions } = params.providerOptions ?? {};
|
|
455
|
+
const { resolvedLsConfig, resolvedChildLLMRunConfig, resolvedToolConfig } = _resolveConfigs(baseLsConfig, runtimeLsConfig);
|
|
456
|
+
const hasExplicitOutput = "output" in params;
|
|
457
|
+
const hasExplicitExperimentalOutput = "experimental_output" in params;
|
|
458
|
+
const traceableFunc = traceable((...args) => {
|
|
459
|
+
const [params, ...rest] = args;
|
|
460
|
+
const wrappedModel = ai.wrapLanguageModel({
|
|
461
|
+
model: params.model,
|
|
462
|
+
middleware: LangSmithMiddleware({
|
|
463
|
+
name: _getModelDisplayName(params.model),
|
|
464
|
+
modelId: _getModelId(params.model),
|
|
465
|
+
// TODO: Fix this typing on minor bump
|
|
466
|
+
lsConfig: resolvedChildLLMRunConfig,
|
|
467
|
+
}),
|
|
468
|
+
});
|
|
469
|
+
return ai.streamText({
|
|
470
|
+
...params,
|
|
471
|
+
providerOptions,
|
|
472
|
+
tools: _wrapTools(params.tools, resolvedToolConfig),
|
|
473
|
+
model: wrappedModel,
|
|
474
|
+
}, ...rest);
|
|
475
|
+
}, _getStreamTextWrapperConfig({
|
|
476
|
+
model: params.model,
|
|
477
|
+
resolvedLsConfig,
|
|
478
|
+
hasExplicitOutput,
|
|
479
|
+
hasExplicitExperimentalOutput,
|
|
480
|
+
}));
|
|
481
|
+
return traceableFunc(...args);
|
|
482
|
+
};
|
|
483
|
+
let wrappedStreamObject;
|
|
484
|
+
if (typeof ai.streamObject === "function") {
|
|
485
|
+
const streamObject = ai.streamObject;
|
|
486
|
+
/**
|
|
487
|
+
* Wrapped version of AI SDK's streamObject with LangSmith tracing.
|
|
488
|
+
*
|
|
489
|
+
* Must be called with `await`, but otherwise behaves the same as the
|
|
490
|
+
* original streamObject and adds adds automatic tracing to LangSmith
|
|
491
|
+
* for observability.
|
|
492
|
+
*
|
|
493
|
+
* ```ts
|
|
494
|
+
* import * as ai from "ai";
|
|
495
|
+
* import { wrapAISDK } from "langsmith/experimental/vercel";
|
|
496
|
+
*
|
|
497
|
+
* const { streamObject } = wrapAISDK(ai);
|
|
498
|
+
* const { partialObjectStream } = await streamObject(...);
|
|
499
|
+
* ```
|
|
500
|
+
*
|
|
501
|
+
* @see {@link https://sdk.vercel.ai/docs/ai-sdk-core/generating-structured-data} Original streamObject documentation
|
|
502
|
+
* @param params - Same parameters as the original streamObject function
|
|
503
|
+
* @returns Promise resolving to the same result as streamObject, with tracing applied
|
|
504
|
+
*/
|
|
505
|
+
wrappedStreamObject = (...args) => {
|
|
506
|
+
const params = args[0];
|
|
507
|
+
const { langsmith: runtimeLsConfig, ...providerOptions } = params.providerOptions ?? {};
|
|
508
|
+
const { resolvedLsConfig, resolvedChildLLMRunConfig } = _resolveConfigs(baseLsConfig, runtimeLsConfig);
|
|
509
|
+
const traceableFunc = traceable((...args) => {
|
|
510
|
+
const [params, ...rest] = args;
|
|
511
|
+
const wrappedModel = ai.wrapLanguageModel({
|
|
512
|
+
model: params.model,
|
|
513
|
+
middleware: LangSmithMiddleware({
|
|
514
|
+
name: _getModelDisplayName(params.model),
|
|
515
|
+
modelId: _getModelId(params.model),
|
|
516
|
+
// TODO: Fix this typing on minor bump
|
|
517
|
+
lsConfig: resolvedChildLLMRunConfig,
|
|
518
|
+
}),
|
|
519
|
+
});
|
|
520
|
+
return streamObject({
|
|
521
|
+
...params,
|
|
522
|
+
providerOptions,
|
|
523
|
+
model: wrappedModel,
|
|
524
|
+
}, ...rest);
|
|
525
|
+
}, {
|
|
526
|
+
name: _getModelDisplayName(params.model),
|
|
527
|
+
...resolvedLsConfig,
|
|
528
|
+
metadata: {
|
|
529
|
+
ls_agent_type: _getLsAgentType(),
|
|
530
|
+
ai_sdk_method: "ai.streamObject",
|
|
531
|
+
...resolvedLsConfig?.metadata,
|
|
532
|
+
},
|
|
533
|
+
processInputs: async (inputs) => {
|
|
534
|
+
const inputFormatter = resolvedLsConfig?.processInputs ?? _formatTracedInputs;
|
|
535
|
+
return inputFormatter(inputs);
|
|
536
|
+
},
|
|
537
|
+
processOutputs: async (outputs) => {
|
|
538
|
+
try {
|
|
539
|
+
if (resolvedLsConfig?.processOutputs) {
|
|
540
|
+
const processedOutputs = await resolvedLsConfig.processOutputs(
|
|
541
|
+
// TODO: Fix this typing on minor bump
|
|
542
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
543
|
+
outputs);
|
|
544
|
+
return processedOutputs;
|
|
545
|
+
}
|
|
546
|
+
if (outputs.outputs == null ||
|
|
547
|
+
typeof outputs.outputs !== "object") {
|
|
548
|
+
return outputs;
|
|
549
|
+
}
|
|
550
|
+
const object = await outputs.outputs.object;
|
|
551
|
+
if (object == null || typeof object !== "object") {
|
|
552
|
+
return outputs;
|
|
553
|
+
}
|
|
554
|
+
return object;
|
|
555
|
+
}
|
|
556
|
+
catch {
|
|
557
|
+
// Handle parsing failures without a log
|
|
558
|
+
return outputs;
|
|
559
|
+
}
|
|
560
|
+
},
|
|
561
|
+
});
|
|
562
|
+
return traceableFunc(...args);
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
let wrappedToolLoopAgentClass;
|
|
566
|
+
if (ai.ToolLoopAgent != null) {
|
|
567
|
+
try {
|
|
568
|
+
const wrapToolLoopAgent = (ToolLoopAgent) => {
|
|
569
|
+
return new Proxy(ToolLoopAgent, {
|
|
570
|
+
construct(ToolLoopAgent, args) {
|
|
571
|
+
const params = args[0] ?? {};
|
|
572
|
+
const { langsmith: runtimeLsConfig } = params.providerOptions ?? {};
|
|
573
|
+
const { resolvedLsConfig, resolvedChildLLMRunConfig, resolvedToolConfig, } = _resolveConfigs(baseLsConfig, runtimeLsConfig);
|
|
574
|
+
let wrappedModel = params.model;
|
|
575
|
+
if (wrappedModel != null) {
|
|
576
|
+
wrappedModel = ai.wrapLanguageModel({
|
|
577
|
+
model: params.model,
|
|
578
|
+
middleware: LangSmithMiddleware({
|
|
579
|
+
name: _getModelDisplayName(params.model),
|
|
580
|
+
modelId: _getModelId(params.model),
|
|
581
|
+
// TODO: Fix this typing on minor bump
|
|
582
|
+
lsConfig: resolvedChildLLMRunConfig,
|
|
583
|
+
}),
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
let wrappedTools = params.tools;
|
|
587
|
+
if (wrappedTools != null) {
|
|
588
|
+
wrappedTools = _wrapTools(params.tools, resolvedToolConfig);
|
|
589
|
+
}
|
|
590
|
+
const instance = new ToolLoopAgent(...[
|
|
591
|
+
{ ...params, model: wrappedModel, tools: wrappedTools },
|
|
592
|
+
...args.slice(1),
|
|
593
|
+
]);
|
|
594
|
+
if (typeof instance.generate === "function") {
|
|
595
|
+
instance.generate = traceable(instance.generate.bind(instance), _getGenerateTextWrapperConfig({
|
|
596
|
+
model: wrappedModel,
|
|
597
|
+
runName: "ToolLoopAgent",
|
|
598
|
+
aiSdkMethodName: "ai.ToolLoopAgent.generate",
|
|
599
|
+
resolvedLsConfig,
|
|
600
|
+
hasExplicitOutput: "output" in params && params.output != null,
|
|
601
|
+
traceResponseMetadata: true,
|
|
602
|
+
}));
|
|
603
|
+
}
|
|
604
|
+
if (typeof instance.stream === "function") {
|
|
605
|
+
instance.stream = traceable(instance.stream.bind(instance), _getStreamTextWrapperConfig({
|
|
606
|
+
model: wrappedModel,
|
|
607
|
+
runName: "ToolLoopAgent",
|
|
608
|
+
aiSdkMethodName: "ai.ToolLoopAgent.stream",
|
|
609
|
+
resolvedLsConfig,
|
|
610
|
+
hasExplicitOutput: "output" in params && params.output != null,
|
|
611
|
+
traceResponseMetadata: true,
|
|
612
|
+
}));
|
|
613
|
+
}
|
|
614
|
+
return instance;
|
|
615
|
+
},
|
|
616
|
+
});
|
|
617
|
+
};
|
|
618
|
+
wrappedToolLoopAgentClass = wrapToolLoopAgent(ai.ToolLoopAgent);
|
|
619
|
+
}
|
|
620
|
+
catch (e) {
|
|
621
|
+
console.error("Failed to wrap passed ToolLoopAgent:", e);
|
|
622
|
+
wrappedToolLoopAgentClass = ai.ToolLoopAgent;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return {
|
|
626
|
+
...ai,
|
|
627
|
+
generateText: wrappedGenerateText,
|
|
628
|
+
generateObject: wrappedGenerateObject,
|
|
629
|
+
streamText: wrappedStreamText,
|
|
630
|
+
streamObject: wrappedStreamObject,
|
|
631
|
+
ToolLoopAgent: wrappedToolLoopAgentClass,
|
|
632
|
+
};
|
|
633
|
+
};
|
|
634
|
+
export { wrapAISDK };
|
|
635
|
+
export { convertMessageToTracedFormat };
|
package/dist/index.cjs
CHANGED
|
@@ -18,4 +18,4 @@ Object.defineProperty(exports, "PromptCache", { enumerable: true, get: function
|
|
|
18
18
|
Object.defineProperty(exports, "configureGlobalPromptCache", { enumerable: true, get: function () { return index_js_1.configureGlobalPromptCache; } });
|
|
19
19
|
Object.defineProperty(exports, "promptCacheSingleton", { enumerable: true, get: function () { return index_js_1.promptCacheSingleton; } });
|
|
20
20
|
// Update using pnpm bump-version
|
|
21
|
-
exports.__version__ = "0.7.
|
|
21
|
+
exports.__version__ = "0.7.2";
|
package/dist/index.d.ts
CHANGED
|
@@ -5,4 +5,4 @@ export { overrideFetchImplementation } from "./singletons/fetch.js";
|
|
|
5
5
|
export { getDefaultProjectName } from "./utils/project.js";
|
|
6
6
|
export { uuid7, uuid7FromTime } from "./uuid.js";
|
|
7
7
|
export { Cache, PromptCache, type CacheConfig, type CacheMetrics, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
|
|
8
|
-
export declare const __version__ = "0.7.
|
|
8
|
+
export declare const __version__ = "0.7.2";
|
package/dist/index.js
CHANGED
|
@@ -5,4 +5,4 @@ export { getDefaultProjectName } from "./utils/project.js";
|
|
|
5
5
|
export { uuid7, uuid7FromTime } from "./uuid.js";
|
|
6
6
|
export { Cache, PromptCache, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
|
|
7
7
|
// Update using pnpm bump-version
|
|
8
|
-
export const __version__ = "0.7.
|
|
8
|
+
export const __version__ = "0.7.2";
|