langsmith 0.1.18 → 0.1.20

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.d.ts CHANGED
@@ -138,6 +138,7 @@ interface ProjectOptions {
138
138
  projectName?: string;
139
139
  projectId?: string;
140
140
  }
141
+ type RecordStringAny = Record<string, any>;
141
142
  export type FeedbackSourceType = "model" | "api" | "app";
142
143
  export type CreateExampleOptions = {
143
144
  datasetId?: string;
@@ -313,16 +314,16 @@ export declare class Client {
313
314
  createProject({ projectName, description, metadata, upsert, projectExtra, referenceDatasetId, }: {
314
315
  projectName: string;
315
316
  description?: string | null;
316
- metadata?: Record<string, any> | null;
317
+ metadata?: RecordStringAny | null;
317
318
  upsert?: boolean;
318
- projectExtra?: Record<string, any> | null;
319
+ projectExtra?: RecordStringAny | null;
319
320
  referenceDatasetId?: string | null;
320
321
  }): Promise<TracerSession>;
321
322
  updateProject(projectId: string, { name, description, metadata, projectExtra, endTime, }: {
322
323
  name?: string | null;
323
324
  description?: string | null;
324
- metadata?: Record<string, any> | null;
325
- projectExtra?: Record<string, any> | null;
325
+ metadata?: RecordStringAny | null;
326
+ projectExtra?: RecordStringAny | null;
326
327
  endTime?: string | null;
327
328
  }): Promise<TracerSession>;
328
329
  hasProject({ projectId, projectName, }: {
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.18";
9
+ exports.__version__ = "0.1.20";
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, } from "./schemas.js";
3
3
  export { RunTree, type RunTreeConfig } from "./run_trees.js";
4
- export declare const __version__ = "0.1.18";
4
+ export declare const __version__ = "0.1.20";
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.18";
4
+ export const __version__ = "0.1.20";
@@ -43,7 +43,7 @@ function convertToDottedOrderFormat(epoch, runId) {
43
43
  }
44
44
  exports.convertToDottedOrderFormat = convertToDottedOrderFormat;
45
45
  class RunTree {
46
- constructor(config) {
46
+ constructor(originalConfig) {
47
47
  Object.defineProperty(this, "id", {
48
48
  enumerable: true,
49
49
  configurable: true,
@@ -159,7 +159,13 @@ class RunTree {
159
159
  value: void 0
160
160
  });
161
161
  const defaultConfig = RunTree.getDefaultConfig();
162
+ const { metadata, ...config } = originalConfig;
162
163
  const client = config.client ?? new client_js_1.Client();
164
+ const dedupedMetadata = {
165
+ ...metadata,
166
+ ...config?.extra?.metadata,
167
+ };
168
+ config.extra = { ...config.extra, metadata: dedupedMetadata };
163
169
  Object.assign(this, { ...defaultConfig, ...config, client });
164
170
  if (!this.trace_id) {
165
171
  if (this.parent_run) {
@@ -191,7 +197,7 @@ class RunTree {
191
197
  parentRun = langChainTracer?.getRun?.(parentRunId);
192
198
  projectName = langChainTracer?.projectName;
193
199
  }
194
- const deduppedTags = [
200
+ const dedupedTags = [
195
201
  ...new Set((parentRun?.tags ?? []).concat(config?.tags ?? [])),
196
202
  ];
197
203
  const dedupedMetadata = {
@@ -201,7 +207,7 @@ class RunTree {
201
207
  const rt = new RunTree({
202
208
  name: props?.name ?? "<lambda>",
203
209
  parent_run: parentRun,
204
- tags: deduppedTags,
210
+ tags: dedupedTags,
205
211
  extra: {
206
212
  metadata: dedupedMetadata,
207
213
  },
@@ -12,6 +12,7 @@ export interface RunTreeConfig {
12
12
  start_time?: number;
13
13
  end_time?: number;
14
14
  extra?: KVMap;
15
+ metadata?: KVMap;
15
16
  tags?: string[];
16
17
  error?: string;
17
18
  serialized?: object;
@@ -57,7 +58,7 @@ export declare class RunTree implements BaseRun {
57
58
  events?: KVMap[] | undefined;
58
59
  trace_id: string;
59
60
  dotted_order: string;
60
- constructor(config: RunTreeConfig);
61
+ constructor(originalConfig: RunTreeConfig);
61
62
  static fromRunnableConfig(config: RunnableConfigLike, props: {
62
63
  name: string;
63
64
  tags?: string[];
package/dist/run_trees.js CHANGED
@@ -16,7 +16,7 @@ export function convertToDottedOrderFormat(epoch, runId) {
16
16
  runId);
17
17
  }
18
18
  export class RunTree {
19
- constructor(config) {
19
+ constructor(originalConfig) {
20
20
  Object.defineProperty(this, "id", {
21
21
  enumerable: true,
22
22
  configurable: true,
@@ -132,7 +132,13 @@ export class RunTree {
132
132
  value: void 0
133
133
  });
134
134
  const defaultConfig = RunTree.getDefaultConfig();
135
+ const { metadata, ...config } = originalConfig;
135
136
  const client = config.client ?? new Client();
137
+ const dedupedMetadata = {
138
+ ...metadata,
139
+ ...config?.extra?.metadata,
140
+ };
141
+ config.extra = { ...config.extra, metadata: dedupedMetadata };
136
142
  Object.assign(this, { ...defaultConfig, ...config, client });
137
143
  if (!this.trace_id) {
138
144
  if (this.parent_run) {
@@ -164,7 +170,7 @@ export class RunTree {
164
170
  parentRun = langChainTracer?.getRun?.(parentRunId);
165
171
  projectName = langChainTracer?.projectName;
166
172
  }
167
- const deduppedTags = [
173
+ const dedupedTags = [
168
174
  ...new Set((parentRun?.tags ?? []).concat(config?.tags ?? [])),
169
175
  ];
170
176
  const dedupedMetadata = {
@@ -174,7 +180,7 @@ export class RunTree {
174
180
  const rt = new RunTree({
175
181
  name: props?.name ?? "<lambda>",
176
182
  parent_run: parentRun,
177
- tags: deduppedTags,
183
+ tags: dedupedTags,
178
184
  extra: {
179
185
  metadata: dedupedMetadata,
180
186
  },
@@ -3,11 +3,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isTraceableFunction = exports.getCurrentRunTree = exports.traceable = void 0;
4
4
  const async_hooks_1 = require("async_hooks");
5
5
  const run_trees_js_1 = require("./run_trees.cjs");
6
+ const env_js_1 = require("./utils/env.cjs");
6
7
  const asyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
7
8
  const isAsyncIterable = (x) => x != null &&
8
9
  typeof x === "object" &&
9
10
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
11
  typeof x[Symbol.asyncIterator] === "function";
12
+ const getTracingRunTree = (runTree) => {
13
+ const tracingEnabled = (0, env_js_1.getEnvironmentVariable)("LANGSMITH_TRACING_V2") === "true" ||
14
+ (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_TRACING_V2") === "true";
15
+ if (!tracingEnabled) {
16
+ return undefined;
17
+ }
18
+ return runTree;
19
+ };
11
20
  /**
12
21
  * Higher-order function that takes function as input and returns a
13
22
  * "TraceableFunction" - a wrapped version of the input that
@@ -24,12 +33,13 @@ const isAsyncIterable = (x) => x != null &&
24
33
  */
25
34
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
35
  function traceable(wrappedFunc, config) {
36
+ const { aggregator, ...runTreeConfig } = config ?? {};
27
37
  const traceableFunc = async (...args) => {
28
38
  let currentRunTree;
29
39
  let rawInputs;
30
40
  const ensuredConfig = {
31
41
  name: wrappedFunc.name || "<lambda>",
32
- ...config,
42
+ ...runTreeConfig,
33
43
  };
34
44
  const previousRunTree = asyncLocalStorage.getStore();
35
45
  if ((0, run_trees_js_1.isRunTree)(args[0])) {
@@ -48,6 +58,7 @@ function traceable(wrappedFunc, config) {
48
58
  currentRunTree = new run_trees_js_1.RunTree(ensuredConfig);
49
59
  rawInputs = args;
50
60
  }
61
+ currentRunTree = getTracingRunTree(currentRunTree);
51
62
  let inputs;
52
63
  const firstInput = rawInputs[0];
53
64
  if (firstInput == null) {
@@ -62,10 +73,12 @@ function traceable(wrappedFunc, config) {
62
73
  else {
63
74
  inputs = { input: firstInput };
64
75
  }
65
- currentRunTree.inputs = inputs;
66
- const initialOutputs = currentRunTree.outputs;
67
- const initialError = currentRunTree.error;
68
- await currentRunTree.postRun();
76
+ if (currentRunTree) {
77
+ currentRunTree.inputs = inputs;
78
+ }
79
+ const initialOutputs = currentRunTree?.outputs;
80
+ const initialError = currentRunTree?.error;
81
+ await currentRunTree?.postRun();
69
82
  return new Promise((resolve, reject) => {
70
83
  void asyncLocalStorage.run(currentRunTree, async () => {
71
84
  try {
@@ -79,8 +92,27 @@ function traceable(wrappedFunc, config) {
79
92
  chunks.push(chunk);
80
93
  yield chunk;
81
94
  }
82
- await currentRunTree.end({ outputs: chunks });
83
- await currentRunTree.patchRun();
95
+ let finalOutputs;
96
+ if (aggregator !== undefined) {
97
+ try {
98
+ finalOutputs = await aggregator(chunks);
99
+ }
100
+ catch (e) {
101
+ console.error(`[ERROR]: LangSmith aggregation failed: `, e);
102
+ finalOutputs = chunks;
103
+ }
104
+ }
105
+ else {
106
+ finalOutputs = chunks;
107
+ }
108
+ if (typeof finalOutputs === "object" &&
109
+ !Array.isArray(finalOutputs)) {
110
+ await currentRunTree?.end(finalOutputs);
111
+ }
112
+ else {
113
+ await currentRunTree?.end({ outputs: finalOutputs });
114
+ }
115
+ await currentRunTree?.patchRun();
84
116
  }
85
117
  return resolve(wrapOutputForTracing());
86
118
  }
@@ -88,31 +120,35 @@ function traceable(wrappedFunc, config) {
88
120
  const outputs = isKVMap(rawOutput)
89
121
  ? rawOutput
90
122
  : { outputs: rawOutput };
91
- if (initialOutputs === currentRunTree.outputs) {
92
- await currentRunTree.end(outputs);
123
+ if (initialOutputs === currentRunTree?.outputs) {
124
+ await currentRunTree?.end(outputs);
93
125
  }
94
126
  else {
95
- currentRunTree.end_time = Date.now();
127
+ if (currentRunTree !== undefined) {
128
+ currentRunTree.end_time = Date.now();
129
+ }
96
130
  }
97
- await currentRunTree.patchRun();
131
+ await currentRunTree?.patchRun();
98
132
  return resolve(rawOutput);
99
133
  }
100
134
  }
101
135
  catch (error) {
102
- if (initialError === currentRunTree.error) {
103
- await currentRunTree.end(initialOutputs, String(error));
136
+ if (initialError === currentRunTree?.error) {
137
+ await currentRunTree?.end(initialOutputs, String(error));
104
138
  }
105
139
  else {
106
- currentRunTree.end_time = Date.now();
140
+ if (currentRunTree !== undefined) {
141
+ currentRunTree.end_time = Date.now();
142
+ }
107
143
  }
108
- await currentRunTree.patchRun();
144
+ await currentRunTree?.patchRun();
109
145
  reject(error);
110
146
  }
111
147
  });
112
148
  });
113
149
  };
114
150
  Object.defineProperty(traceableFunc, "langsmith:traceable", {
115
- value: config,
151
+ value: runTreeConfig,
116
152
  });
117
153
  return traceableFunc;
118
154
  }
@@ -44,7 +44,9 @@ export type TraceableFunction<Func extends (...args: any[]) => any> = Func exten
44
44
  * @param config Additional metadata such as name, tags or providing
45
45
  * a custom LangSmith client instance
46
46
  */
47
- export declare function traceable<Func extends (...args: any[]) => any>(wrappedFunc: Func, config?: Partial<RunTreeConfig>): TraceableFunction<Func>;
47
+ export declare function traceable<Func extends (...args: any[]) => any>(wrappedFunc: Func, config?: Partial<RunTreeConfig> & {
48
+ aggregator?: (args: any[]) => any;
49
+ }): TraceableFunction<Func>;
48
50
  /**
49
51
  * Return the current run tree from within a traceable-wrapped function.
50
52
  * Will throw an error if called outside of a traceable function.
package/dist/traceable.js CHANGED
@@ -1,10 +1,19 @@
1
1
  import { AsyncLocalStorage } from "async_hooks";
2
2
  import { RunTree, isRunTree, isRunnableConfigLike, } from "./run_trees.js";
3
+ import { getEnvironmentVariable } from "./utils/env.js";
3
4
  const asyncLocalStorage = new AsyncLocalStorage();
4
5
  const isAsyncIterable = (x) => x != null &&
5
6
  typeof x === "object" &&
6
7
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
8
  typeof x[Symbol.asyncIterator] === "function";
9
+ const getTracingRunTree = (runTree) => {
10
+ const tracingEnabled = getEnvironmentVariable("LANGSMITH_TRACING_V2") === "true" ||
11
+ getEnvironmentVariable("LANGCHAIN_TRACING_V2") === "true";
12
+ if (!tracingEnabled) {
13
+ return undefined;
14
+ }
15
+ return runTree;
16
+ };
8
17
  /**
9
18
  * Higher-order function that takes function as input and returns a
10
19
  * "TraceableFunction" - a wrapped version of the input that
@@ -21,12 +30,13 @@ const isAsyncIterable = (x) => x != null &&
21
30
  */
22
31
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
32
  export function traceable(wrappedFunc, config) {
33
+ const { aggregator, ...runTreeConfig } = config ?? {};
24
34
  const traceableFunc = async (...args) => {
25
35
  let currentRunTree;
26
36
  let rawInputs;
27
37
  const ensuredConfig = {
28
38
  name: wrappedFunc.name || "<lambda>",
29
- ...config,
39
+ ...runTreeConfig,
30
40
  };
31
41
  const previousRunTree = asyncLocalStorage.getStore();
32
42
  if (isRunTree(args[0])) {
@@ -45,6 +55,7 @@ export function traceable(wrappedFunc, config) {
45
55
  currentRunTree = new RunTree(ensuredConfig);
46
56
  rawInputs = args;
47
57
  }
58
+ currentRunTree = getTracingRunTree(currentRunTree);
48
59
  let inputs;
49
60
  const firstInput = rawInputs[0];
50
61
  if (firstInput == null) {
@@ -59,10 +70,12 @@ export function traceable(wrappedFunc, config) {
59
70
  else {
60
71
  inputs = { input: firstInput };
61
72
  }
62
- currentRunTree.inputs = inputs;
63
- const initialOutputs = currentRunTree.outputs;
64
- const initialError = currentRunTree.error;
65
- await currentRunTree.postRun();
73
+ if (currentRunTree) {
74
+ currentRunTree.inputs = inputs;
75
+ }
76
+ const initialOutputs = currentRunTree?.outputs;
77
+ const initialError = currentRunTree?.error;
78
+ await currentRunTree?.postRun();
66
79
  return new Promise((resolve, reject) => {
67
80
  void asyncLocalStorage.run(currentRunTree, async () => {
68
81
  try {
@@ -76,8 +89,27 @@ export function traceable(wrappedFunc, config) {
76
89
  chunks.push(chunk);
77
90
  yield chunk;
78
91
  }
79
- await currentRunTree.end({ outputs: chunks });
80
- await currentRunTree.patchRun();
92
+ let finalOutputs;
93
+ if (aggregator !== undefined) {
94
+ try {
95
+ finalOutputs = await aggregator(chunks);
96
+ }
97
+ catch (e) {
98
+ console.error(`[ERROR]: LangSmith aggregation failed: `, e);
99
+ finalOutputs = chunks;
100
+ }
101
+ }
102
+ else {
103
+ finalOutputs = chunks;
104
+ }
105
+ if (typeof finalOutputs === "object" &&
106
+ !Array.isArray(finalOutputs)) {
107
+ await currentRunTree?.end(finalOutputs);
108
+ }
109
+ else {
110
+ await currentRunTree?.end({ outputs: finalOutputs });
111
+ }
112
+ await currentRunTree?.patchRun();
81
113
  }
82
114
  return resolve(wrapOutputForTracing());
83
115
  }
@@ -85,31 +117,35 @@ export function traceable(wrappedFunc, config) {
85
117
  const outputs = isKVMap(rawOutput)
86
118
  ? rawOutput
87
119
  : { outputs: rawOutput };
88
- if (initialOutputs === currentRunTree.outputs) {
89
- await currentRunTree.end(outputs);
120
+ if (initialOutputs === currentRunTree?.outputs) {
121
+ await currentRunTree?.end(outputs);
90
122
  }
91
123
  else {
92
- currentRunTree.end_time = Date.now();
124
+ if (currentRunTree !== undefined) {
125
+ currentRunTree.end_time = Date.now();
126
+ }
93
127
  }
94
- await currentRunTree.patchRun();
128
+ await currentRunTree?.patchRun();
95
129
  return resolve(rawOutput);
96
130
  }
97
131
  }
98
132
  catch (error) {
99
- if (initialError === currentRunTree.error) {
100
- await currentRunTree.end(initialOutputs, String(error));
133
+ if (initialError === currentRunTree?.error) {
134
+ await currentRunTree?.end(initialOutputs, String(error));
101
135
  }
102
136
  else {
103
- currentRunTree.end_time = Date.now();
137
+ if (currentRunTree !== undefined) {
138
+ currentRunTree.end_time = Date.now();
139
+ }
104
140
  }
105
- await currentRunTree.patchRun();
141
+ await currentRunTree?.patchRun();
106
142
  reject(error);
107
143
  }
108
144
  });
109
145
  });
110
146
  };
111
147
  Object.defineProperty(traceableFunc, "langsmith:traceable", {
112
- value: config,
148
+ value: runTreeConfig,
113
149
  });
114
150
  return traceableFunc;
115
151
  }
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.convertLangChainMessageToExample = exports.isLangChainMessage = void 0;
4
- function isLangChainMessage(message) {
4
+ function isLangChainMessage(
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ message) {
5
7
  return typeof message?._getType === "function";
6
8
  }
7
9
  exports.isLangChainMessage = isLangChainMessage;
@@ -1,4 +1,6 @@
1
- export function isLangChainMessage(message) {
1
+ export function isLangChainMessage(
2
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
+ message) {
2
4
  return typeof message?._getType === "function";
3
5
  }
4
6
  export function convertLangChainMessageToExample(message) {
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./openai.cjs"), exports);
@@ -0,0 +1 @@
1
+ export * from "./openai.js";
@@ -0,0 +1 @@
1
+ export * from "./openai.js";
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.wrapSDK = exports.wrapOpenAI = void 0;
4
+ const traceable_js_1 = require("../traceable.cjs");
5
+ function _combineChatCompletionChoices(choices) {
6
+ const reversedChoices = choices.slice().reverse();
7
+ const message = {
8
+ role: "assistant",
9
+ content: "",
10
+ };
11
+ for (const c of reversedChoices) {
12
+ if (c.delta.role) {
13
+ message["role"] = c.delta.role;
14
+ break;
15
+ }
16
+ }
17
+ const toolCalls = {};
18
+ for (const c of choices) {
19
+ if (c.delta.content) {
20
+ message.content = message.content.concat(c.delta.content);
21
+ }
22
+ if (c.delta.function_call) {
23
+ if (!message.function_call) {
24
+ message.function_call = { name: "", arguments: "" };
25
+ }
26
+ if (c.delta.function_call.name) {
27
+ message.function_call.name += c.delta.function_call.name;
28
+ }
29
+ if (c.delta.function_call.arguments) {
30
+ message.function_call.arguments += c.delta.function_call.arguments;
31
+ }
32
+ }
33
+ if (c.delta.tool_calls) {
34
+ for (const tool_call of c.delta.tool_calls) {
35
+ if (!toolCalls[c.index]) {
36
+ toolCalls[c.index] = [];
37
+ }
38
+ toolCalls[c.index].push(tool_call);
39
+ }
40
+ }
41
+ }
42
+ if (Object.keys(toolCalls).length > 0) {
43
+ message.tool_calls = [...Array(Object.keys(toolCalls).length)];
44
+ for (const [index, toolCallChunks] of Object.entries(toolCalls)) {
45
+ const idx = parseInt(index);
46
+ message.tool_calls[idx] = {
47
+ index: idx,
48
+ id: toolCallChunks.find((c) => c.id)?.id || null,
49
+ type: toolCallChunks.find((c) => c.type)?.type || null,
50
+ };
51
+ for (const chunk of toolCallChunks) {
52
+ if (chunk.function) {
53
+ if (!message.tool_calls[idx].function) {
54
+ message.tool_calls[idx].function = {
55
+ name: "",
56
+ arguments: "",
57
+ };
58
+ }
59
+ if (chunk.function.name) {
60
+ message.tool_calls[idx].function.name += chunk.function.name;
61
+ }
62
+ if (chunk.function.arguments) {
63
+ message.tool_calls[idx].function.arguments +=
64
+ chunk.function.arguments;
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+ return {
71
+ index: choices[0].index,
72
+ finish_reason: reversedChoices.find((c) => c.finish_reason) || null,
73
+ message: message,
74
+ };
75
+ }
76
+ async function extractLangSmithExtraAndCall(openAIMethod, args, defaultRunConfig) {
77
+ if (args[1]?.langsmithExtra !== undefined) {
78
+ const { langsmithExtra, ...openAIOptions } = args[1];
79
+ const wrappedMethod = (0, traceable_js_1.traceable)(openAIMethod, {
80
+ ...defaultRunConfig,
81
+ ...langsmithExtra,
82
+ });
83
+ const finalArgs = [args[0]];
84
+ if (args.length > 2) {
85
+ finalArgs.push(openAIOptions);
86
+ finalArgs.push(args.slice(2));
87
+ }
88
+ else if (Object.keys(openAIOptions).length !== 0) {
89
+ finalArgs.push(openAIOptions);
90
+ }
91
+ return wrappedMethod(...finalArgs);
92
+ }
93
+ const wrappedMethod = (0, traceable_js_1.traceable)(openAIMethod, defaultRunConfig);
94
+ return wrappedMethod(...args);
95
+ }
96
+ /**
97
+ * Wraps an OpenAI client's completion methods, enabling automatic LangSmith
98
+ * tracing. Method signatures are unchanged, with the exception that you can pass
99
+ * an additional and optional "langsmithExtra" field within the second parameter.
100
+ * @param openai An OpenAI client instance.
101
+ * @param options LangSmith options.
102
+ * @example
103
+ * ```ts
104
+ * const patchedStream = await patchedClient.chat.completions.create(
105
+ * {
106
+ * messages: [{ role: "user", content: `Say 'foo'` }],
107
+ * model: "gpt-3.5-turbo",
108
+ * stream: true,
109
+ * },
110
+ * {
111
+ * langsmithExtra: {
112
+ * metadata: {
113
+ * additional_data: "bar",
114
+ * },
115
+ * },
116
+ * },
117
+ * );
118
+ * ```
119
+ */
120
+ const wrapOpenAI = (openai, options) => {
121
+ const originalChatCompletionsFn = openai.chat.completions.create.bind(openai.chat.completions);
122
+ openai.chat.completions.create = async (...args) => {
123
+ const aggregator = (chunks) => {
124
+ if (!chunks || chunks.length === 0) {
125
+ return { choices: [{ message: { role: "assistant", content: "" } }] };
126
+ }
127
+ const choicesByIndex = {};
128
+ for (const chunk of chunks) {
129
+ for (const choice of chunk.choices) {
130
+ if (choicesByIndex[choice.index] === undefined) {
131
+ choicesByIndex[choice.index] = [];
132
+ }
133
+ choicesByIndex[choice.index].push(choice);
134
+ }
135
+ }
136
+ const aggregatedOutput = chunks[chunks.length - 1];
137
+ aggregatedOutput.choices = Object.values(choicesByIndex).map((choices) => _combineChatCompletionChoices(choices));
138
+ return aggregatedOutput;
139
+ };
140
+ const defaultRunConfig = {
141
+ name: "ChatOpenAI",
142
+ run_type: "llm",
143
+ aggregator,
144
+ ...options,
145
+ };
146
+ return extractLangSmithExtraAndCall(originalChatCompletionsFn, args, defaultRunConfig);
147
+ };
148
+ const originalCompletionsFn = openai.completions.create.bind(openai.chat.completions);
149
+ openai.completions.create = async (...args) => {
150
+ const aggregator = (allChunks) => {
151
+ if (allChunks.length === 0) {
152
+ return { choices: [{ text: "" }] };
153
+ }
154
+ const allContent = [];
155
+ for (const chunk of allChunks) {
156
+ const content = chunk.choices[0].text;
157
+ if (content != null) {
158
+ allContent.push(content);
159
+ }
160
+ }
161
+ const content = allContent.join("");
162
+ const aggregatedOutput = allChunks[allChunks.length - 1];
163
+ aggregatedOutput.choices = [
164
+ { ...aggregatedOutput.choices[0], text: content },
165
+ ];
166
+ return aggregatedOutput;
167
+ };
168
+ const defaultRunConfig = {
169
+ name: "OpenAI",
170
+ run_type: "llm",
171
+ aggregator,
172
+ ...options,
173
+ };
174
+ return extractLangSmithExtraAndCall(originalCompletionsFn, args, defaultRunConfig);
175
+ };
176
+ return openai;
177
+ };
178
+ exports.wrapOpenAI = wrapOpenAI;
179
+ const _wrapClient = (sdk, runName, options) => {
180
+ return new Proxy(sdk, {
181
+ get(target, propKey, receiver) {
182
+ const originalValue = target[propKey];
183
+ if (typeof originalValue === "function") {
184
+ return (0, traceable_js_1.traceable)(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options?.client));
185
+ }
186
+ else if (originalValue != null &&
187
+ !Array.isArray(originalValue) &&
188
+ // eslint-disable-next-line no-instanceof/no-instanceof
189
+ !(originalValue instanceof Date) &&
190
+ typeof originalValue === "object") {
191
+ return _wrapClient(originalValue, [runName, propKey.toString()].join("."), options);
192
+ }
193
+ else {
194
+ return Reflect.get(target, propKey, receiver);
195
+ }
196
+ },
197
+ });
198
+ };
199
+ /**
200
+ * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
201
+ * Method signatures are unchanged.
202
+ *
203
+ * Note that this will wrap and trace ALL SDK methods, not just
204
+ * LLM completion methods. If the passed SDK contains other methods,
205
+ * we recommend using the wrapped instance for LLM calls only.
206
+ * @param sdk An arbitrary SDK instance.
207
+ * @param options LangSmith options.
208
+ * @returns
209
+ */
210
+ const wrapSDK = (sdk, options) => {
211
+ return _wrapClient(sdk, options?.runName ?? sdk.constructor?.name, {
212
+ client: options?.client,
213
+ });
214
+ };
215
+ exports.wrapSDK = wrapSDK;
@@ -0,0 +1,83 @@
1
+ import type { OpenAI } from "openai";
2
+ import type { Client, RunTreeConfig } from "../index.js";
3
+ import { type RunnableConfigLike } from "../run_trees.js";
4
+ import { type RunTreeLike } from "../traceable.js";
5
+ type OpenAIType = {
6
+ chat: {
7
+ completions: {
8
+ create: (...args: any[]) => any;
9
+ };
10
+ };
11
+ completions: {
12
+ create: (...args: any[]) => any;
13
+ };
14
+ };
15
+ type PatchedOpenAIClient<T extends OpenAIType> = {
16
+ [P in keyof T]: T[P];
17
+ } & {
18
+ chat: {
19
+ completions: {
20
+ create: {
21
+ (arg: OpenAI.ChatCompletionCreateParamsStreaming, arg2?: OpenAI.RequestOptions & {
22
+ langsmithExtra?: RunnableConfigLike | RunTreeLike;
23
+ }): Promise<AsyncGenerator<OpenAI.ChatCompletionChunk>>;
24
+ } & {
25
+ (arg: OpenAI.ChatCompletionCreateParamsNonStreaming, arg2?: OpenAI.RequestOptions & {
26
+ langsmithExtra?: RunnableConfigLike | RunTreeLike;
27
+ }): Promise<OpenAI.ChatCompletionChunk>;
28
+ };
29
+ };
30
+ };
31
+ completions: {
32
+ create: {
33
+ (arg: OpenAI.CompletionCreateParamsStreaming, arg2?: OpenAI.RequestOptions & {
34
+ langsmithExtra?: RunnableConfigLike | RunTreeLike;
35
+ }): Promise<AsyncGenerator<OpenAI.Completion>>;
36
+ } & {
37
+ (arg: OpenAI.CompletionCreateParamsNonStreaming, arg2?: OpenAI.RequestOptions & {
38
+ langsmithExtra?: RunnableConfigLike | RunTreeLike;
39
+ }): Promise<OpenAI.Completion>;
40
+ };
41
+ };
42
+ };
43
+ /**
44
+ * Wraps an OpenAI client's completion methods, enabling automatic LangSmith
45
+ * tracing. Method signatures are unchanged, with the exception that you can pass
46
+ * an additional and optional "langsmithExtra" field within the second parameter.
47
+ * @param openai An OpenAI client instance.
48
+ * @param options LangSmith options.
49
+ * @example
50
+ * ```ts
51
+ * const patchedStream = await patchedClient.chat.completions.create(
52
+ * {
53
+ * messages: [{ role: "user", content: `Say 'foo'` }],
54
+ * model: "gpt-3.5-turbo",
55
+ * stream: true,
56
+ * },
57
+ * {
58
+ * langsmithExtra: {
59
+ * metadata: {
60
+ * additional_data: "bar",
61
+ * },
62
+ * },
63
+ * },
64
+ * );
65
+ * ```
66
+ */
67
+ export declare const wrapOpenAI: <T extends OpenAIType>(openai: T, options?: Partial<RunTreeConfig>) => PatchedOpenAIClient<T>;
68
+ /**
69
+ * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
70
+ * Method signatures are unchanged.
71
+ *
72
+ * Note that this will wrap and trace ALL SDK methods, not just
73
+ * LLM completion methods. If the passed SDK contains other methods,
74
+ * we recommend using the wrapped instance for LLM calls only.
75
+ * @param sdk An arbitrary SDK instance.
76
+ * @param options LangSmith options.
77
+ * @returns
78
+ */
79
+ export declare const wrapSDK: <T extends object>(sdk: T, options?: {
80
+ client?: Client;
81
+ runName?: string;
82
+ }) => T;
83
+ export {};
@@ -0,0 +1,210 @@
1
+ import { traceable } from "../traceable.js";
2
+ function _combineChatCompletionChoices(choices) {
3
+ const reversedChoices = choices.slice().reverse();
4
+ const message = {
5
+ role: "assistant",
6
+ content: "",
7
+ };
8
+ for (const c of reversedChoices) {
9
+ if (c.delta.role) {
10
+ message["role"] = c.delta.role;
11
+ break;
12
+ }
13
+ }
14
+ const toolCalls = {};
15
+ for (const c of choices) {
16
+ if (c.delta.content) {
17
+ message.content = message.content.concat(c.delta.content);
18
+ }
19
+ if (c.delta.function_call) {
20
+ if (!message.function_call) {
21
+ message.function_call = { name: "", arguments: "" };
22
+ }
23
+ if (c.delta.function_call.name) {
24
+ message.function_call.name += c.delta.function_call.name;
25
+ }
26
+ if (c.delta.function_call.arguments) {
27
+ message.function_call.arguments += c.delta.function_call.arguments;
28
+ }
29
+ }
30
+ if (c.delta.tool_calls) {
31
+ for (const tool_call of c.delta.tool_calls) {
32
+ if (!toolCalls[c.index]) {
33
+ toolCalls[c.index] = [];
34
+ }
35
+ toolCalls[c.index].push(tool_call);
36
+ }
37
+ }
38
+ }
39
+ if (Object.keys(toolCalls).length > 0) {
40
+ message.tool_calls = [...Array(Object.keys(toolCalls).length)];
41
+ for (const [index, toolCallChunks] of Object.entries(toolCalls)) {
42
+ const idx = parseInt(index);
43
+ message.tool_calls[idx] = {
44
+ index: idx,
45
+ id: toolCallChunks.find((c) => c.id)?.id || null,
46
+ type: toolCallChunks.find((c) => c.type)?.type || null,
47
+ };
48
+ for (const chunk of toolCallChunks) {
49
+ if (chunk.function) {
50
+ if (!message.tool_calls[idx].function) {
51
+ message.tool_calls[idx].function = {
52
+ name: "",
53
+ arguments: "",
54
+ };
55
+ }
56
+ if (chunk.function.name) {
57
+ message.tool_calls[idx].function.name += chunk.function.name;
58
+ }
59
+ if (chunk.function.arguments) {
60
+ message.tool_calls[idx].function.arguments +=
61
+ chunk.function.arguments;
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ return {
68
+ index: choices[0].index,
69
+ finish_reason: reversedChoices.find((c) => c.finish_reason) || null,
70
+ message: message,
71
+ };
72
+ }
73
+ async function extractLangSmithExtraAndCall(openAIMethod, args, defaultRunConfig) {
74
+ if (args[1]?.langsmithExtra !== undefined) {
75
+ const { langsmithExtra, ...openAIOptions } = args[1];
76
+ const wrappedMethod = traceable(openAIMethod, {
77
+ ...defaultRunConfig,
78
+ ...langsmithExtra,
79
+ });
80
+ const finalArgs = [args[0]];
81
+ if (args.length > 2) {
82
+ finalArgs.push(openAIOptions);
83
+ finalArgs.push(args.slice(2));
84
+ }
85
+ else if (Object.keys(openAIOptions).length !== 0) {
86
+ finalArgs.push(openAIOptions);
87
+ }
88
+ return wrappedMethod(...finalArgs);
89
+ }
90
+ const wrappedMethod = traceable(openAIMethod, defaultRunConfig);
91
+ return wrappedMethod(...args);
92
+ }
93
+ /**
94
+ * Wraps an OpenAI client's completion methods, enabling automatic LangSmith
95
+ * tracing. Method signatures are unchanged, with the exception that you can pass
96
+ * an additional and optional "langsmithExtra" field within the second parameter.
97
+ * @param openai An OpenAI client instance.
98
+ * @param options LangSmith options.
99
+ * @example
100
+ * ```ts
101
+ * const patchedStream = await patchedClient.chat.completions.create(
102
+ * {
103
+ * messages: [{ role: "user", content: `Say 'foo'` }],
104
+ * model: "gpt-3.5-turbo",
105
+ * stream: true,
106
+ * },
107
+ * {
108
+ * langsmithExtra: {
109
+ * metadata: {
110
+ * additional_data: "bar",
111
+ * },
112
+ * },
113
+ * },
114
+ * );
115
+ * ```
116
+ */
117
+ export const wrapOpenAI = (openai, options) => {
118
+ const originalChatCompletionsFn = openai.chat.completions.create.bind(openai.chat.completions);
119
+ openai.chat.completions.create = async (...args) => {
120
+ const aggregator = (chunks) => {
121
+ if (!chunks || chunks.length === 0) {
122
+ return { choices: [{ message: { role: "assistant", content: "" } }] };
123
+ }
124
+ const choicesByIndex = {};
125
+ for (const chunk of chunks) {
126
+ for (const choice of chunk.choices) {
127
+ if (choicesByIndex[choice.index] === undefined) {
128
+ choicesByIndex[choice.index] = [];
129
+ }
130
+ choicesByIndex[choice.index].push(choice);
131
+ }
132
+ }
133
+ const aggregatedOutput = chunks[chunks.length - 1];
134
+ aggregatedOutput.choices = Object.values(choicesByIndex).map((choices) => _combineChatCompletionChoices(choices));
135
+ return aggregatedOutput;
136
+ };
137
+ const defaultRunConfig = {
138
+ name: "ChatOpenAI",
139
+ run_type: "llm",
140
+ aggregator,
141
+ ...options,
142
+ };
143
+ return extractLangSmithExtraAndCall(originalChatCompletionsFn, args, defaultRunConfig);
144
+ };
145
+ const originalCompletionsFn = openai.completions.create.bind(openai.chat.completions);
146
+ openai.completions.create = async (...args) => {
147
+ const aggregator = (allChunks) => {
148
+ if (allChunks.length === 0) {
149
+ return { choices: [{ text: "" }] };
150
+ }
151
+ const allContent = [];
152
+ for (const chunk of allChunks) {
153
+ const content = chunk.choices[0].text;
154
+ if (content != null) {
155
+ allContent.push(content);
156
+ }
157
+ }
158
+ const content = allContent.join("");
159
+ const aggregatedOutput = allChunks[allChunks.length - 1];
160
+ aggregatedOutput.choices = [
161
+ { ...aggregatedOutput.choices[0], text: content },
162
+ ];
163
+ return aggregatedOutput;
164
+ };
165
+ const defaultRunConfig = {
166
+ name: "OpenAI",
167
+ run_type: "llm",
168
+ aggregator,
169
+ ...options,
170
+ };
171
+ return extractLangSmithExtraAndCall(originalCompletionsFn, args, defaultRunConfig);
172
+ };
173
+ return openai;
174
+ };
175
+ const _wrapClient = (sdk, runName, options) => {
176
+ return new Proxy(sdk, {
177
+ get(target, propKey, receiver) {
178
+ const originalValue = target[propKey];
179
+ if (typeof originalValue === "function") {
180
+ return traceable(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options?.client));
181
+ }
182
+ else if (originalValue != null &&
183
+ !Array.isArray(originalValue) &&
184
+ // eslint-disable-next-line no-instanceof/no-instanceof
185
+ !(originalValue instanceof Date) &&
186
+ typeof originalValue === "object") {
187
+ return _wrapClient(originalValue, [runName, propKey.toString()].join("."), options);
188
+ }
189
+ else {
190
+ return Reflect.get(target, propKey, receiver);
191
+ }
192
+ },
193
+ });
194
+ };
195
+ /**
196
+ * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
197
+ * Method signatures are unchanged.
198
+ *
199
+ * Note that this will wrap and trace ALL SDK methods, not just
200
+ * LLM completion methods. If the passed SDK contains other methods,
201
+ * we recommend using the wrapped instance for LLM calls only.
202
+ * @param sdk An arbitrary SDK instance.
203
+ * @param options LangSmith options.
204
+ * @returns
205
+ */
206
+ export const wrapSDK = (sdk, options) => {
207
+ return _wrapClient(sdk, options?.runName ?? sdk.constructor?.name, {
208
+ client: options?.client,
209
+ });
210
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
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": [
@@ -29,6 +29,10 @@
29
29
  "wrappers.js",
30
30
  "wrappers.d.ts",
31
31
  "wrappers.d.cts",
32
+ "wrappers/openai.cjs",
33
+ "wrappers/openai.js",
34
+ "wrappers/openai.d.ts",
35
+ "wrappers/openai.d.cts",
32
36
  "index.cjs",
33
37
  "index.js",
34
38
  "index.d.ts",
@@ -48,7 +52,8 @@
48
52
  "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests --testPathIgnorePatterns='\\.int\\.test.[tj]s' --testTimeout 30000",
49
53
  "test:integration": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --testPathPattern=\\.int\\.test.ts --testTimeout 100000",
50
54
  "test:single": "NODE_OPTIONS=--experimental-vm-modules yarn run jest --config jest.config.cjs --testTimeout 100000",
51
- "lint": "eslint 'src/**/*.{ts,tsx}' --quiet --fix",
55
+ "lint": "NODE_OPTIONS=--max-old-space-size=4096 eslint --cache --ext .ts,.js src/",
56
+ "lint:fix": "yarn lint --fix",
52
57
  "format": "prettier --write 'src/**/*.{ts,tsx}'",
53
58
  "format:check": "prettier --check 'src/**/*.{ts,tsx}'",
54
59
  "precommit": "lint-staged",
@@ -70,6 +75,13 @@
70
75
  "url": "https://github.com/langchain-ai/langsmith-sdk/issues"
71
76
  },
72
77
  "homepage": "https://github.com/langchain-ai/langsmith-sdk#readme",
78
+ "dependencies": {
79
+ "@types/uuid": "^9.0.1",
80
+ "commander": "^10.0.1",
81
+ "p-queue": "^6.6.2",
82
+ "p-retry": "4",
83
+ "uuid": "^9.0.0"
84
+ },
73
85
  "devDependencies": {
74
86
  "@babel/preset-env": "^7.22.4",
75
87
  "@jest/globals": "^29.5.0",
@@ -88,18 +100,19 @@
88
100
  "eslint-plugin-no-instanceof": "^1.0.1",
89
101
  "eslint-plugin-prettier": "^4.2.1",
90
102
  "jest": "^29.5.0",
91
- "openai": "^4.28.0",
103
+ "openai": "^4.38.5",
92
104
  "prettier": "^2.8.8",
93
105
  "ts-jest": "^29.1.0",
94
106
  "ts-node": "^10.9.1",
95
107
  "typescript": "^5.0.4"
96
108
  },
97
- "dependencies": {
98
- "@types/uuid": "^9.0.1",
99
- "commander": "^10.0.1",
100
- "p-queue": "^6.6.2",
101
- "p-retry": "4",
102
- "uuid": "^9.0.0"
109
+ "peerDependencies": {
110
+ "openai": "*"
111
+ },
112
+ "peerDependenciesMeta": {
113
+ "openai": {
114
+ "optional": true
115
+ }
103
116
  },
104
117
  "lint-staged": {
105
118
  "**/*.{ts,tsx}": [
@@ -171,6 +184,15 @@
171
184
  "import": "./wrappers.js",
172
185
  "require": "./wrappers.cjs"
173
186
  },
187
+ "./wrappers/openai": {
188
+ "types": {
189
+ "import": "./wrappers/openai.d.ts",
190
+ "require": "./wrappers/openai.d.cts",
191
+ "default": "./wrappers/openai.d.ts"
192
+ },
193
+ "import": "./wrappers/openai.js",
194
+ "require": "./wrappers/openai.cjs"
195
+ },
174
196
  "./package.json": "./package.json"
175
197
  }
176
198
  }
@@ -0,0 +1 @@
1
+ module.exports = require('../dist/wrappers/openai.cjs');
@@ -0,0 +1 @@
1
+ export * from '../dist/wrappers/openai.js'
@@ -0,0 +1 @@
1
+ export * from '../dist/wrappers/openai.js'
@@ -0,0 +1 @@
1
+ export * from '../dist/wrappers/openai.js'
package/wrappers.cjs CHANGED
@@ -1 +1 @@
1
- module.exports = require('./dist/wrappers.cjs');
1
+ module.exports = require('./dist/wrappers/index.cjs');
package/wrappers.d.cts CHANGED
@@ -1 +1 @@
1
- export * from './dist/wrappers.js'
1
+ export * from './dist/wrappers/index.js'
package/wrappers.d.ts CHANGED
@@ -1 +1 @@
1
- export * from './dist/wrappers.js'
1
+ export * from './dist/wrappers/index.js'
package/wrappers.js CHANGED
@@ -1 +1 @@
1
- export * from './dist/wrappers.js'
1
+ export * from './dist/wrappers/index.js'
package/dist/wrappers.cjs DELETED
@@ -1,54 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.wrapSDK = exports.wrapOpenAI = void 0;
4
- const traceable_js_1 = require("./traceable.cjs");
5
- /**
6
- * Wraps an OpenAI client's completion methods, enabling automatic LangSmith
7
- * tracing. Method signatures are unchanged.
8
- * @param openai An OpenAI client instance.
9
- * @param options LangSmith options.
10
- * @returns
11
- */
12
- const wrapOpenAI = (openai, options) => {
13
- openai.chat.completions.create = (0, traceable_js_1.traceable)(openai.chat.completions.create.bind(openai.chat.completions), Object.assign({ name: "ChatOpenAI", run_type: "llm" }, options?.client));
14
- openai.completions.create = (0, traceable_js_1.traceable)(openai.completions.create.bind(openai.completions), Object.assign({ name: "OpenAI", run_type: "llm" }, options?.client));
15
- return openai;
16
- };
17
- exports.wrapOpenAI = wrapOpenAI;
18
- const _wrapClient = (sdk, runName, options) => {
19
- return new Proxy(sdk, {
20
- get(target, propKey, receiver) {
21
- const originalValue = target[propKey];
22
- if (typeof originalValue === "function") {
23
- return (0, traceable_js_1.traceable)(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options?.client));
24
- }
25
- else if (originalValue != null &&
26
- !Array.isArray(originalValue) &&
27
- // eslint-disable-next-line no-instanceof/no-instanceof
28
- !(originalValue instanceof Date) &&
29
- typeof originalValue === "object") {
30
- return _wrapClient(originalValue, [runName, propKey.toString()].join("."), options);
31
- }
32
- else {
33
- return Reflect.get(target, propKey, receiver);
34
- }
35
- },
36
- });
37
- };
38
- /**
39
- * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
40
- * Method signatures are unchanged.
41
- *
42
- * Note that this will wrap and trace ALL SDK methods, not just
43
- * LLM completion methods. If the passed SDK contains other methods,
44
- * we recommend using the wrapped instance for LLM calls only.
45
- * @param sdk An arbitrary SDK instance.
46
- * @param options LangSmith options.
47
- * @returns
48
- */
49
- const wrapSDK = (sdk, options) => {
50
- return _wrapClient(sdk, options?.runName ?? sdk.constructor?.name, {
51
- client: options?.client,
52
- });
53
- };
54
- exports.wrapSDK = wrapSDK;
@@ -1,37 +0,0 @@
1
- import type { Client } from "./index.js";
2
- type OpenAIType = {
3
- chat: {
4
- completions: {
5
- create: (...args: any[]) => any;
6
- };
7
- };
8
- completions: {
9
- create: (...args: any[]) => any;
10
- };
11
- };
12
- /**
13
- * Wraps an OpenAI client's completion methods, enabling automatic LangSmith
14
- * tracing. Method signatures are unchanged.
15
- * @param openai An OpenAI client instance.
16
- * @param options LangSmith options.
17
- * @returns
18
- */
19
- export declare const wrapOpenAI: <T extends OpenAIType>(openai: T, options?: {
20
- client?: Client;
21
- }) => T;
22
- /**
23
- * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
24
- * Method signatures are unchanged.
25
- *
26
- * Note that this will wrap and trace ALL SDK methods, not just
27
- * LLM completion methods. If the passed SDK contains other methods,
28
- * we recommend using the wrapped instance for LLM calls only.
29
- * @param sdk An arbitrary SDK instance.
30
- * @param options LangSmith options.
31
- * @returns
32
- */
33
- export declare const wrapSDK: <T extends object>(sdk: T, options?: {
34
- client?: Client;
35
- runName?: string;
36
- }) => T;
37
- export {};
package/dist/wrappers.js DELETED
@@ -1,49 +0,0 @@
1
- import { traceable } from "./traceable.js";
2
- /**
3
- * Wraps an OpenAI client's completion methods, enabling automatic LangSmith
4
- * tracing. Method signatures are unchanged.
5
- * @param openai An OpenAI client instance.
6
- * @param options LangSmith options.
7
- * @returns
8
- */
9
- export const wrapOpenAI = (openai, options) => {
10
- openai.chat.completions.create = traceable(openai.chat.completions.create.bind(openai.chat.completions), Object.assign({ name: "ChatOpenAI", run_type: "llm" }, options?.client));
11
- openai.completions.create = traceable(openai.completions.create.bind(openai.completions), Object.assign({ name: "OpenAI", run_type: "llm" }, options?.client));
12
- return openai;
13
- };
14
- const _wrapClient = (sdk, runName, options) => {
15
- return new Proxy(sdk, {
16
- get(target, propKey, receiver) {
17
- const originalValue = target[propKey];
18
- if (typeof originalValue === "function") {
19
- return traceable(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options?.client));
20
- }
21
- else if (originalValue != null &&
22
- !Array.isArray(originalValue) &&
23
- // eslint-disable-next-line no-instanceof/no-instanceof
24
- !(originalValue instanceof Date) &&
25
- typeof originalValue === "object") {
26
- return _wrapClient(originalValue, [runName, propKey.toString()].join("."), options);
27
- }
28
- else {
29
- return Reflect.get(target, propKey, receiver);
30
- }
31
- },
32
- });
33
- };
34
- /**
35
- * Wrap an arbitrary SDK, enabling automatic LangSmith tracing.
36
- * Method signatures are unchanged.
37
- *
38
- * Note that this will wrap and trace ALL SDK methods, not just
39
- * LLM completion methods. If the passed SDK contains other methods,
40
- * we recommend using the wrapped instance for LLM calls only.
41
- * @param sdk An arbitrary SDK instance.
42
- * @param options LangSmith options.
43
- * @returns
44
- */
45
- export const wrapSDK = (sdk, options) => {
46
- return _wrapClient(sdk, options?.runName ?? sdk.constructor?.name, {
47
- client: options?.client,
48
- });
49
- };