langsmith 0.1.40-rc.0 → 0.1.40

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/index.cjs CHANGED
@@ -6,4 +6,4 @@ Object.defineProperty(exports, "Client", { enumerable: true, get: function () {
6
6
  var run_trees_js_1 = require("./run_trees.cjs");
7
7
  Object.defineProperty(exports, "RunTree", { enumerable: true, get: function () { return run_trees_js_1.RunTree; } });
8
8
  // Update using yarn bump-version
9
- exports.__version__ = "0.1.39";
9
+ exports.__version__ = "0.1.40";
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Client } from "./client.js";
2
2
  export type { Dataset, Example, TracerSession, Run, Feedback, RetrieverOutput, } from "./schemas.js";
3
3
  export { RunTree, type RunTreeConfig } from "./run_trees.js";
4
- export declare const __version__ = "0.1.39";
4
+ export declare const __version__ = "0.1.40";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Client } from "./client.js";
2
2
  export { RunTree } from "./run_trees.js";
3
3
  // Update using yarn bump-version
4
- export const __version__ = "0.1.39";
4
+ export const __version__ = "0.1.40";
@@ -192,7 +192,7 @@ const convertSerializableArg = (arg) => {
192
192
  */
193
193
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
194
194
  function traceable(wrappedFunc, config) {
195
- const { aggregator, argsConfigPath, ...runTreeConfig } = config ?? {};
195
+ const { aggregator, argsConfigPath, __finalTracedIteratorKey, ...runTreeConfig } = config ?? {};
196
196
  const traceableFunc = (...args) => {
197
197
  let ensuredConfig;
198
198
  try {
@@ -294,6 +294,38 @@ function traceable(wrappedFunc, config) {
294
294
  }
295
295
  return chunks;
296
296
  }
297
+ function tapReadableStreamForTracing(stream, snapshot) {
298
+ const reader = stream.getReader();
299
+ let finished = false;
300
+ const chunks = [];
301
+ const tappedStream = new ReadableStream({
302
+ async start(controller) {
303
+ // eslint-disable-next-line no-constant-condition
304
+ while (true) {
305
+ const result = await (snapshot
306
+ ? snapshot(() => reader.read())
307
+ : reader.read());
308
+ if (result.done) {
309
+ finished = true;
310
+ await currentRunTree?.end(handleRunOutputs(await handleChunks(chunks)));
311
+ await handleEnd();
312
+ controller.close();
313
+ break;
314
+ }
315
+ chunks.push(result.value);
316
+ controller.enqueue(result.value);
317
+ }
318
+ },
319
+ async cancel(reason) {
320
+ if (!finished)
321
+ await currentRunTree?.end(undefined, "Cancelled");
322
+ await currentRunTree?.end(handleRunOutputs(await handleChunks(chunks)));
323
+ await handleEnd();
324
+ return reader.cancel(reason);
325
+ },
326
+ });
327
+ return tappedStream;
328
+ }
297
329
  async function* wrapAsyncIteratorForTracing(iterator, snapshot) {
298
330
  let finished = false;
299
331
  const chunks = [];
@@ -322,6 +354,9 @@ function traceable(wrappedFunc, config) {
322
354
  }
323
355
  }
324
356
  function wrapAsyncGeneratorForTracing(iterable, snapshot) {
357
+ if ((0, asserts_js_1.isReadableStream)(iterable)) {
358
+ return tapReadableStreamForTracing(iterable, snapshot);
359
+ }
325
360
  const iterator = iterable[Symbol.asyncIterator]();
326
361
  const wrappedIterator = wrapAsyncIteratorForTracing(iterator, snapshot);
327
362
  iterable[Symbol.asyncIterator] = () => wrappedIterator;
@@ -362,6 +397,17 @@ function traceable(wrappedFunc, config) {
362
397
  const snapshot = node_async_hooks_1.AsyncLocalStorage.snapshot();
363
398
  return wrapAsyncGeneratorForTracing(returnValue, snapshot);
364
399
  }
400
+ if (!Array.isArray(returnValue) &&
401
+ typeof returnValue === "object" &&
402
+ returnValue != null &&
403
+ __finalTracedIteratorKey !== undefined &&
404
+ (0, asserts_js_1.isAsyncIterable)(returnValue[__finalTracedIteratorKey])) {
405
+ const snapshot = node_async_hooks_1.AsyncLocalStorage.snapshot();
406
+ return {
407
+ ...returnValue,
408
+ [__finalTracedIteratorKey]: wrapAsyncGeneratorForTracing(returnValue[__finalTracedIteratorKey], snapshot),
409
+ };
410
+ }
365
411
  const tracedPromise = new Promise((resolve, reject) => {
366
412
  Promise.resolve(returnValue)
367
413
  .then(async (rawOutput) => {
@@ -369,6 +415,17 @@ function traceable(wrappedFunc, config) {
369
415
  const snapshot = node_async_hooks_1.AsyncLocalStorage.snapshot();
370
416
  return resolve(wrapAsyncGeneratorForTracing(rawOutput, snapshot));
371
417
  }
418
+ if (!Array.isArray(rawOutput) &&
419
+ typeof rawOutput === "object" &&
420
+ rawOutput != null &&
421
+ __finalTracedIteratorKey !== undefined &&
422
+ (0, asserts_js_1.isAsyncIterable)(rawOutput[__finalTracedIteratorKey])) {
423
+ const snapshot = node_async_hooks_1.AsyncLocalStorage.snapshot();
424
+ return {
425
+ ...rawOutput,
426
+ [__finalTracedIteratorKey]: wrapAsyncGeneratorForTracing(rawOutput[__finalTracedIteratorKey], snapshot),
427
+ };
428
+ }
372
429
  if ((0, asserts_js_1.isGenerator)(wrappedFunc) && (0, asserts_js_1.isIteratorLike)(rawOutput)) {
373
430
  const chunks = gatherAll(rawOutput);
374
431
  await currentRunTree?.end(handleRunOutputs(await handleChunks(chunks.reduce((memo, { value, done }) => {
@@ -18,6 +18,7 @@ import { TraceableFunction } from "./singletons/types.js";
18
18
  export declare function traceable<Func extends (...args: any[]) => any>(wrappedFunc: Func, config?: Partial<RunTreeConfig> & {
19
19
  aggregator?: (args: any[]) => any;
20
20
  argsConfigPath?: [number] | [number, string];
21
+ __finalTracedIteratorKey?: string;
21
22
  /**
22
23
  * Extract invocation parameters from the arguments of the traced function.
23
24
  * This is useful for LangSmith to properly track common metadata like
package/dist/traceable.js CHANGED
@@ -189,7 +189,7 @@ const convertSerializableArg = (arg) => {
189
189
  */
190
190
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
191
191
  export function traceable(wrappedFunc, config) {
192
- const { aggregator, argsConfigPath, ...runTreeConfig } = config ?? {};
192
+ const { aggregator, argsConfigPath, __finalTracedIteratorKey, ...runTreeConfig } = config ?? {};
193
193
  const traceableFunc = (...args) => {
194
194
  let ensuredConfig;
195
195
  try {
@@ -291,6 +291,38 @@ export function traceable(wrappedFunc, config) {
291
291
  }
292
292
  return chunks;
293
293
  }
294
+ function tapReadableStreamForTracing(stream, snapshot) {
295
+ const reader = stream.getReader();
296
+ let finished = false;
297
+ const chunks = [];
298
+ const tappedStream = new ReadableStream({
299
+ async start(controller) {
300
+ // eslint-disable-next-line no-constant-condition
301
+ while (true) {
302
+ const result = await (snapshot
303
+ ? snapshot(() => reader.read())
304
+ : reader.read());
305
+ if (result.done) {
306
+ finished = true;
307
+ await currentRunTree?.end(handleRunOutputs(await handleChunks(chunks)));
308
+ await handleEnd();
309
+ controller.close();
310
+ break;
311
+ }
312
+ chunks.push(result.value);
313
+ controller.enqueue(result.value);
314
+ }
315
+ },
316
+ async cancel(reason) {
317
+ if (!finished)
318
+ await currentRunTree?.end(undefined, "Cancelled");
319
+ await currentRunTree?.end(handleRunOutputs(await handleChunks(chunks)));
320
+ await handleEnd();
321
+ return reader.cancel(reason);
322
+ },
323
+ });
324
+ return tappedStream;
325
+ }
294
326
  async function* wrapAsyncIteratorForTracing(iterator, snapshot) {
295
327
  let finished = false;
296
328
  const chunks = [];
@@ -319,6 +351,9 @@ export function traceable(wrappedFunc, config) {
319
351
  }
320
352
  }
321
353
  function wrapAsyncGeneratorForTracing(iterable, snapshot) {
354
+ if (isReadableStream(iterable)) {
355
+ return tapReadableStreamForTracing(iterable, snapshot);
356
+ }
322
357
  const iterator = iterable[Symbol.asyncIterator]();
323
358
  const wrappedIterator = wrapAsyncIteratorForTracing(iterator, snapshot);
324
359
  iterable[Symbol.asyncIterator] = () => wrappedIterator;
@@ -359,6 +394,17 @@ export function traceable(wrappedFunc, config) {
359
394
  const snapshot = AsyncLocalStorage.snapshot();
360
395
  return wrapAsyncGeneratorForTracing(returnValue, snapshot);
361
396
  }
397
+ if (!Array.isArray(returnValue) &&
398
+ typeof returnValue === "object" &&
399
+ returnValue != null &&
400
+ __finalTracedIteratorKey !== undefined &&
401
+ isAsyncIterable(returnValue[__finalTracedIteratorKey])) {
402
+ const snapshot = AsyncLocalStorage.snapshot();
403
+ return {
404
+ ...returnValue,
405
+ [__finalTracedIteratorKey]: wrapAsyncGeneratorForTracing(returnValue[__finalTracedIteratorKey], snapshot),
406
+ };
407
+ }
362
408
  const tracedPromise = new Promise((resolve, reject) => {
363
409
  Promise.resolve(returnValue)
364
410
  .then(async (rawOutput) => {
@@ -366,6 +412,17 @@ export function traceable(wrappedFunc, config) {
366
412
  const snapshot = AsyncLocalStorage.snapshot();
367
413
  return resolve(wrapAsyncGeneratorForTracing(rawOutput, snapshot));
368
414
  }
415
+ if (!Array.isArray(rawOutput) &&
416
+ typeof rawOutput === "object" &&
417
+ rawOutput != null &&
418
+ __finalTracedIteratorKey !== undefined &&
419
+ isAsyncIterable(rawOutput[__finalTracedIteratorKey])) {
420
+ const snapshot = AsyncLocalStorage.snapshot();
421
+ return {
422
+ ...rawOutput,
423
+ [__finalTracedIteratorKey]: wrapAsyncGeneratorForTracing(rawOutput[__finalTracedIteratorKey], snapshot),
424
+ };
425
+ }
369
426
  if (isGenerator(wrappedFunc) && isIteratorLike(rawOutput)) {
370
427
  const chunks = gatherAll(rawOutput);
371
428
  await currentRunTree?.end(handleRunOutputs(await handleChunks(chunks.reduce((memo, { value, done }) => {
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.wrapSDK = exports._wrapClient = void 0;
4
+ const traceable_js_1 = require("../traceable.cjs");
5
+ const _wrapClient = (sdk, runName, options) => {
6
+ return new Proxy(sdk, {
7
+ get(target, propKey, receiver) {
8
+ const originalValue = target[propKey];
9
+ if (typeof originalValue === "function") {
10
+ return (0, traceable_js_1.traceable)(originalValue.bind(target), {
11
+ run_type: "llm",
12
+ ...options,
13
+ name: [runName, propKey.toString()].join("."),
14
+ });
15
+ }
16
+ else if (originalValue != null &&
17
+ !Array.isArray(originalValue) &&
18
+ // eslint-disable-next-line no-instanceof/no-instanceof
19
+ !(originalValue instanceof Date) &&
20
+ typeof originalValue === "object") {
21
+ return (0, exports._wrapClient)(originalValue, [runName, propKey.toString()].join("."), options);
22
+ }
23
+ else {
24
+ return Reflect.get(target, propKey, receiver);
25
+ }
26
+ },
27
+ });
28
+ };
29
+ exports._wrapClient = _wrapClient;
30
+ /**
31
+ * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
32
+ * Method signatures are unchanged.
33
+ *
34
+ * Note that this will wrap and trace ALL SDK methods, not just
35
+ * LLM completion methods. If the passed SDK contains other methods,
36
+ * we recommend using the wrapped instance for LLM calls only.
37
+ * @param sdk An arbitrary SDK instance.
38
+ * @param options LangSmith options.
39
+ * @returns
40
+ */
41
+ const wrapSDK = (sdk, options) => {
42
+ const traceableOptions = options ? { ...options } : undefined;
43
+ if (traceableOptions != null) {
44
+ delete traceableOptions.runName;
45
+ delete traceableOptions.name;
46
+ }
47
+ return (0, exports._wrapClient)(sdk, options?.name ?? options?.runName ?? sdk.constructor?.name, traceableOptions);
48
+ };
49
+ exports.wrapSDK = wrapSDK;
@@ -0,0 +1,21 @@
1
+ import type { RunTreeConfig } from "../index.js";
2
+ export declare const _wrapClient: <T extends object>(sdk: T, runName: string, options?: Omit<RunTreeConfig, "name">) => T;
3
+ type WrapSDKOptions = Partial<RunTreeConfig & {
4
+ /**
5
+ * @deprecated Use `name` instead.
6
+ */
7
+ runName: string;
8
+ }>;
9
+ /**
10
+ * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
11
+ * Method signatures are unchanged.
12
+ *
13
+ * Note that this will wrap and trace ALL SDK methods, not just
14
+ * LLM completion methods. If the passed SDK contains other methods,
15
+ * we recommend using the wrapped instance for LLM calls only.
16
+ * @param sdk An arbitrary SDK instance.
17
+ * @param options LangSmith options.
18
+ * @returns
19
+ */
20
+ export declare const wrapSDK: <T extends object>(sdk: T, options?: WrapSDKOptions) => T;
21
+ export {};
@@ -0,0 +1,44 @@
1
+ import { traceable } from "../traceable.js";
2
+ export const _wrapClient = (sdk, runName, options) => {
3
+ return new Proxy(sdk, {
4
+ get(target, propKey, receiver) {
5
+ const originalValue = target[propKey];
6
+ if (typeof originalValue === "function") {
7
+ return traceable(originalValue.bind(target), {
8
+ run_type: "llm",
9
+ ...options,
10
+ name: [runName, propKey.toString()].join("."),
11
+ });
12
+ }
13
+ else if (originalValue != null &&
14
+ !Array.isArray(originalValue) &&
15
+ // eslint-disable-next-line no-instanceof/no-instanceof
16
+ !(originalValue instanceof Date) &&
17
+ typeof originalValue === "object") {
18
+ return _wrapClient(originalValue, [runName, propKey.toString()].join("."), options);
19
+ }
20
+ else {
21
+ return Reflect.get(target, propKey, receiver);
22
+ }
23
+ },
24
+ });
25
+ };
26
+ /**
27
+ * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
28
+ * Method signatures are unchanged.
29
+ *
30
+ * Note that this will wrap and trace ALL SDK methods, not just
31
+ * LLM completion methods. If the passed SDK contains other methods,
32
+ * we recommend using the wrapped instance for LLM calls only.
33
+ * @param sdk An arbitrary SDK instance.
34
+ * @param options LangSmith options.
35
+ * @returns
36
+ */
37
+ export const wrapSDK = (sdk, options) => {
38
+ const traceableOptions = options ? { ...options } : undefined;
39
+ if (traceableOptions != null) {
40
+ delete traceableOptions.runName;
41
+ delete traceableOptions.name;
42
+ }
43
+ return _wrapClient(sdk, options?.name ?? options?.runName ?? sdk.constructor?.name, traceableOptions);
44
+ };
@@ -14,4 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.wrapSDK = void 0;
17
18
  __exportStar(require("./openai.cjs"), exports);
19
+ var generic_js_1 = require("./generic.cjs");
20
+ Object.defineProperty(exports, "wrapSDK", { enumerable: true, get: function () { return generic_js_1.wrapSDK; } });
@@ -1 +1,2 @@
1
1
  export * from "./openai.js";
2
+ export { wrapSDK } from "./generic.js";
@@ -1 +1,2 @@
1
1
  export * from "./openai.js";
2
+ export { wrapSDK } from "./generic.js";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.wrapSDK = exports.wrapOpenAI = void 0;
3
+ exports.wrapOpenAI = void 0;
4
4
  const traceable_js_1 = require("../traceable.cjs");
5
5
  function _combineChatCompletionChoices(choices
6
6
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -191,47 +191,3 @@ const wrapOpenAI = (openai, options) => {
191
191
  return openai;
192
192
  };
193
193
  exports.wrapOpenAI = wrapOpenAI;
194
- const _wrapClient = (sdk, runName, options) => {
195
- return new Proxy(sdk, {
196
- get(target, propKey, receiver) {
197
- const originalValue = target[propKey];
198
- if (typeof originalValue === "function") {
199
- return (0, traceable_js_1.traceable)(originalValue.bind(target), {
200
- run_type: "llm",
201
- ...options,
202
- name: [runName, propKey.toString()].join("."),
203
- });
204
- }
205
- else if (originalValue != null &&
206
- !Array.isArray(originalValue) &&
207
- // eslint-disable-next-line no-instanceof/no-instanceof
208
- !(originalValue instanceof Date) &&
209
- typeof originalValue === "object") {
210
- return _wrapClient(originalValue, [runName, propKey.toString()].join("."), options);
211
- }
212
- else {
213
- return Reflect.get(target, propKey, receiver);
214
- }
215
- },
216
- });
217
- };
218
- /**
219
- * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
220
- * Method signatures are unchanged.
221
- *
222
- * Note that this will wrap and trace ALL SDK methods, not just
223
- * LLM completion methods. If the passed SDK contains other methods,
224
- * we recommend using the wrapped instance for LLM calls only.
225
- * @param sdk An arbitrary SDK instance.
226
- * @param options LangSmith options.
227
- * @returns
228
- */
229
- const wrapSDK = (sdk, options) => {
230
- const traceableOptions = options ? { ...options } : undefined;
231
- if (traceableOptions != null) {
232
- delete traceableOptions.runName;
233
- delete traceableOptions.name;
234
- }
235
- return _wrapClient(sdk, options?.name ?? options?.runName ?? sdk.constructor?.name, traceableOptions);
236
- };
237
- exports.wrapSDK = wrapSDK;
@@ -63,22 +63,4 @@ type PatchedOpenAIClient<T extends OpenAIType> = T & {
63
63
  * ```
64
64
  */
65
65
  export declare const wrapOpenAI: <T extends OpenAIType>(openai: T, options?: Partial<RunTreeConfig>) => PatchedOpenAIClient<T>;
66
- type WrapSDKOptions = Partial<RunTreeConfig & {
67
- /**
68
- * @deprecated Use `name` instead.
69
- */
70
- runName: string;
71
- }>;
72
- /**
73
- * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
74
- * Method signatures are unchanged.
75
- *
76
- * Note that this will wrap and trace ALL SDK methods, not just
77
- * LLM completion methods. If the passed SDK contains other methods,
78
- * we recommend using the wrapped instance for LLM calls only.
79
- * @param sdk An arbitrary SDK instance.
80
- * @param options LangSmith options.
81
- * @returns
82
- */
83
- export declare const wrapSDK: <T extends object>(sdk: T, options?: WrapSDKOptions) => T;
84
66
  export {};
@@ -187,46 +187,3 @@ export const wrapOpenAI = (openai, options) => {
187
187
  });
188
188
  return openai;
189
189
  };
190
- const _wrapClient = (sdk, runName, options) => {
191
- return new Proxy(sdk, {
192
- get(target, propKey, receiver) {
193
- const originalValue = target[propKey];
194
- if (typeof originalValue === "function") {
195
- return traceable(originalValue.bind(target), {
196
- run_type: "llm",
197
- ...options,
198
- name: [runName, propKey.toString()].join("."),
199
- });
200
- }
201
- else if (originalValue != null &&
202
- !Array.isArray(originalValue) &&
203
- // eslint-disable-next-line no-instanceof/no-instanceof
204
- !(originalValue instanceof Date) &&
205
- typeof originalValue === "object") {
206
- return _wrapClient(originalValue, [runName, propKey.toString()].join("."), options);
207
- }
208
- else {
209
- return Reflect.get(target, propKey, receiver);
210
- }
211
- },
212
- });
213
- };
214
- /**
215
- * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
216
- * Method signatures are unchanged.
217
- *
218
- * Note that this will wrap and trace ALL SDK methods, not just
219
- * LLM completion methods. If the passed SDK contains other methods,
220
- * we recommend using the wrapped instance for LLM calls only.
221
- * @param sdk An arbitrary SDK instance.
222
- * @param options LangSmith options.
223
- * @returns
224
- */
225
- export const wrapSDK = (sdk, options) => {
226
- const traceableOptions = options ? { ...options } : undefined;
227
- if (traceableOptions != null) {
228
- delete traceableOptions.runName;
229
- delete traceableOptions.name;
230
- }
231
- return _wrapClient(sdk, options?.name ?? options?.runName ?? sdk.constructor?.name, traceableOptions);
232
- };
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.wrapAISDKModel = void 0;
4
+ const traceable_js_1 = require("../traceable.cjs");
5
+ const generic_js_1 = require("./generic.cjs");
6
+ /**
7
+ * Wrap a Vercel AI SDK model, enabling automatic LangSmith tracing.
8
+ * After wrapping a model, you can use it with the Vercel AI SDK Core
9
+ * methods as normal.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { anthropic } from "@ai-sdk/anthropic";
14
+ * import { streamText } from "ai";
15
+ * import { wrapAISDKModel } from "langsmith/wrappers/vercel";
16
+ *
17
+ * const anthropicModel = anthropic("claude-3-haiku-20240307");
18
+ *
19
+ * const modelWithTracing = wrapAISDKModel(anthropicModel);
20
+ *
21
+ * const { textStream } = await streamText({
22
+ * model: modelWithTracing,
23
+ * prompt: "Write a vegetarian lasagna recipe for 4 people.",
24
+ * });
25
+ *
26
+ * for await (const chunk of textStream) {
27
+ * console.log(chunk);
28
+ * }
29
+ * ```
30
+ * @param model An AI SDK model instance.
31
+ * @param options LangSmith options.
32
+ * @returns
33
+ */
34
+ const wrapAISDKModel = (model, options) => {
35
+ if (!("doStream" in model) ||
36
+ typeof model.doStream !== "function" ||
37
+ !("doGenerate" in model) ||
38
+ typeof model.doGenerate !== "function") {
39
+ throw new Error(`Received invalid input. This version of wrapAISDKModel only supports Vercel LanguageModelV1 instances.`);
40
+ }
41
+ const runName = options?.name ?? model.constructor?.name;
42
+ return new Proxy(model, {
43
+ get(target, propKey, receiver) {
44
+ const originalValue = target[propKey];
45
+ if (typeof originalValue === "function") {
46
+ let __finalTracedIteratorKey;
47
+ let aggregator;
48
+ if (propKey === "doStream") {
49
+ __finalTracedIteratorKey = "stream";
50
+ aggregator = (chunks) => {
51
+ return chunks.reduce((aggregated, chunk) => {
52
+ if (chunk.type === "text-delta") {
53
+ return {
54
+ ...aggregated,
55
+ text: aggregated.text + chunk.textDelta,
56
+ };
57
+ }
58
+ else if (chunk.type === "tool-call") {
59
+ return {
60
+ ...aggregated,
61
+ ...chunk,
62
+ };
63
+ }
64
+ else if (chunk.type === "finish") {
65
+ return {
66
+ ...aggregated,
67
+ usage: chunk.usage,
68
+ finishReason: chunk.finishReason,
69
+ };
70
+ }
71
+ else {
72
+ return aggregated;
73
+ }
74
+ }, {
75
+ text: "",
76
+ });
77
+ };
78
+ }
79
+ return (0, traceable_js_1.traceable)(originalValue.bind(target), {
80
+ run_type: "llm",
81
+ name: runName,
82
+ ...options,
83
+ __finalTracedIteratorKey,
84
+ aggregator,
85
+ });
86
+ }
87
+ else if (originalValue != null &&
88
+ !Array.isArray(originalValue) &&
89
+ // eslint-disable-next-line no-instanceof/no-instanceof
90
+ !(originalValue instanceof Date) &&
91
+ typeof originalValue === "object") {
92
+ return (0, generic_js_1._wrapClient)(originalValue, [runName, propKey.toString()].join("."), options);
93
+ }
94
+ else {
95
+ return Reflect.get(target, propKey, receiver);
96
+ }
97
+ },
98
+ });
99
+ };
100
+ exports.wrapAISDKModel = wrapAISDKModel;
@@ -0,0 +1,30 @@
1
+ import type { RunTreeConfig } from "../index.js";
2
+ /**
3
+ * Wrap a Vercel AI SDK model, enabling automatic LangSmith tracing.
4
+ * After wrapping a model, you can use it with the Vercel AI SDK Core
5
+ * methods as normal.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { anthropic } from "@ai-sdk/anthropic";
10
+ * import { streamText } from "ai";
11
+ * import { wrapAISDKModel } from "langsmith/wrappers/vercel";
12
+ *
13
+ * const anthropicModel = anthropic("claude-3-haiku-20240307");
14
+ *
15
+ * const modelWithTracing = wrapAISDKModel(anthropicModel);
16
+ *
17
+ * const { textStream } = await streamText({
18
+ * model: modelWithTracing,
19
+ * prompt: "Write a vegetarian lasagna recipe for 4 people.",
20
+ * });
21
+ *
22
+ * for await (const chunk of textStream) {
23
+ * console.log(chunk);
24
+ * }
25
+ * ```
26
+ * @param model An AI SDK model instance.
27
+ * @param options LangSmith options.
28
+ * @returns
29
+ */
30
+ export declare const wrapAISDKModel: <T extends object>(model: T, options?: Partial<RunTreeConfig>) => T;
@@ -0,0 +1,96 @@
1
+ import { traceable } from "../traceable.js";
2
+ import { _wrapClient } from "./generic.js";
3
+ /**
4
+ * Wrap a Vercel AI SDK model, enabling automatic LangSmith tracing.
5
+ * After wrapping a model, you can use it with the Vercel AI SDK Core
6
+ * methods as normal.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { anthropic } from "@ai-sdk/anthropic";
11
+ * import { streamText } from "ai";
12
+ * import { wrapAISDKModel } from "langsmith/wrappers/vercel";
13
+ *
14
+ * const anthropicModel = anthropic("claude-3-haiku-20240307");
15
+ *
16
+ * const modelWithTracing = wrapAISDKModel(anthropicModel);
17
+ *
18
+ * const { textStream } = await streamText({
19
+ * model: modelWithTracing,
20
+ * prompt: "Write a vegetarian lasagna recipe for 4 people.",
21
+ * });
22
+ *
23
+ * for await (const chunk of textStream) {
24
+ * console.log(chunk);
25
+ * }
26
+ * ```
27
+ * @param model An AI SDK model instance.
28
+ * @param options LangSmith options.
29
+ * @returns
30
+ */
31
+ export const wrapAISDKModel = (model, options) => {
32
+ if (!("doStream" in model) ||
33
+ typeof model.doStream !== "function" ||
34
+ !("doGenerate" in model) ||
35
+ typeof model.doGenerate !== "function") {
36
+ throw new Error(`Received invalid input. This version of wrapAISDKModel only supports Vercel LanguageModelV1 instances.`);
37
+ }
38
+ const runName = options?.name ?? model.constructor?.name;
39
+ return new Proxy(model, {
40
+ get(target, propKey, receiver) {
41
+ const originalValue = target[propKey];
42
+ if (typeof originalValue === "function") {
43
+ let __finalTracedIteratorKey;
44
+ let aggregator;
45
+ if (propKey === "doStream") {
46
+ __finalTracedIteratorKey = "stream";
47
+ aggregator = (chunks) => {
48
+ return chunks.reduce((aggregated, chunk) => {
49
+ if (chunk.type === "text-delta") {
50
+ return {
51
+ ...aggregated,
52
+ text: aggregated.text + chunk.textDelta,
53
+ };
54
+ }
55
+ else if (chunk.type === "tool-call") {
56
+ return {
57
+ ...aggregated,
58
+ ...chunk,
59
+ };
60
+ }
61
+ else if (chunk.type === "finish") {
62
+ return {
63
+ ...aggregated,
64
+ usage: chunk.usage,
65
+ finishReason: chunk.finishReason,
66
+ };
67
+ }
68
+ else {
69
+ return aggregated;
70
+ }
71
+ }, {
72
+ text: "",
73
+ });
74
+ };
75
+ }
76
+ return traceable(originalValue.bind(target), {
77
+ run_type: "llm",
78
+ name: runName,
79
+ ...options,
80
+ __finalTracedIteratorKey,
81
+ aggregator,
82
+ });
83
+ }
84
+ else if (originalValue != null &&
85
+ !Array.isArray(originalValue) &&
86
+ // eslint-disable-next-line no-instanceof/no-instanceof
87
+ !(originalValue instanceof Date) &&
88
+ typeof originalValue === "object") {
89
+ return _wrapClient(originalValue, [runName, propKey.toString()].join("."), options);
90
+ }
91
+ else {
92
+ return Reflect.get(target, propKey, receiver);
93
+ }
94
+ },
95
+ });
96
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.1.40-rc.0",
3
+ "version": "0.1.40",
4
4
  "description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.",
5
5
  "packageManager": "yarn@1.22.19",
6
6
  "files": [
@@ -45,6 +45,10 @@
45
45
  "wrappers/openai.js",
46
46
  "wrappers/openai.d.ts",
47
47
  "wrappers/openai.d.cts",
48
+ "wrappers/vercel.cjs",
49
+ "wrappers/vercel.js",
50
+ "wrappers/vercel.d.ts",
51
+ "wrappers/vercel.d.cts",
48
52
  "singletons/traceable.cjs",
49
53
  "singletons/traceable.js",
50
54
  "singletons/traceable.d.ts",
@@ -101,10 +105,10 @@
101
105
  "uuid": "^9.0.0"
102
106
  },
103
107
  "devDependencies": {
108
+ "@ai-sdk/openai": "^0.0.40",
104
109
  "@babel/preset-env": "^7.22.4",
105
110
  "@faker-js/faker": "^8.4.1",
106
111
  "@jest/globals": "^29.5.0",
107
- "langchain": "^0.2.10",
108
112
  "@langchain/core": "^0.2.17",
109
113
  "@langchain/langgraph": "^0.0.29",
110
114
  "@langchain/openai": "^0.2.5",
@@ -112,6 +116,7 @@
112
116
  "@types/jest": "^29.5.1",
113
117
  "@typescript-eslint/eslint-plugin": "^5.59.8",
114
118
  "@typescript-eslint/parser": "^5.59.8",
119
+ "ai": "^3.2.37",
115
120
  "babel-jest": "^29.5.0",
116
121
  "cross-env": "^7.0.3",
117
122
  "dotenv": "^16.1.3",
@@ -121,11 +126,13 @@
121
126
  "eslint-plugin-no-instanceof": "^1.0.1",
122
127
  "eslint-plugin-prettier": "^4.2.1",
123
128
  "jest": "^29.5.0",
129
+ "langchain": "^0.2.10",
124
130
  "openai": "^4.38.5",
125
131
  "prettier": "^2.8.8",
126
132
  "ts-jest": "^29.1.0",
127
133
  "ts-node": "^10.9.1",
128
- "typescript": "^5.4.5"
134
+ "typescript": "^5.4.5",
135
+ "zod": "^3.23.8"
129
136
  },
130
137
  "peerDependencies": {
131
138
  "@langchain/core": "*",
@@ -249,6 +256,15 @@
249
256
  "import": "./wrappers/openai.js",
250
257
  "require": "./wrappers/openai.cjs"
251
258
  },
259
+ "./wrappers/vercel": {
260
+ "types": {
261
+ "import": "./wrappers/vercel.d.ts",
262
+ "require": "./wrappers/vercel.d.cts",
263
+ "default": "./wrappers/vercel.d.ts"
264
+ },
265
+ "import": "./wrappers/vercel.js",
266
+ "require": "./wrappers/vercel.cjs"
267
+ },
252
268
  "./singletons/traceable": {
253
269
  "types": {
254
270
  "import": "./singletons/traceable.d.ts",
@@ -0,0 +1 @@
1
+ module.exports = require('../dist/wrappers/vercel.cjs');
@@ -0,0 +1 @@
1
+ export * from '../dist/wrappers/vercel.js'
@@ -0,0 +1 @@
1
+ export * from '../dist/wrappers/vercel.js'
@@ -0,0 +1 @@
1
+ export * from '../dist/wrappers/vercel.js'