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 +5 -4
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/run_trees.cjs +9 -3
- package/dist/run_trees.d.ts +2 -1
- package/dist/run_trees.js +9 -3
- package/dist/traceable.cjs +52 -16
- package/dist/traceable.d.ts +3 -1
- package/dist/traceable.js +52 -16
- package/dist/utils/messages.cjs +3 -1
- package/dist/utils/messages.js +3 -1
- package/dist/wrappers/index.cjs +17 -0
- package/dist/wrappers/index.d.ts +1 -0
- package/dist/wrappers/index.js +1 -0
- package/dist/wrappers/openai.cjs +215 -0
- package/dist/wrappers/openai.d.ts +83 -0
- package/dist/wrappers/openai.js +210 -0
- package/package.json +31 -9
- package/wrappers/openai.cjs +1 -0
- package/wrappers/openai.d.cts +1 -0
- package/wrappers/openai.d.ts +1 -0
- package/wrappers/openai.js +1 -0
- package/wrappers.cjs +1 -1
- package/wrappers.d.cts +1 -1
- package/wrappers.d.ts +1 -1
- package/wrappers.js +1 -1
- package/dist/wrappers.cjs +0 -54
- package/dist/wrappers.d.ts +0 -37
- package/dist/wrappers.js +0 -49
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?:
|
|
317
|
+
metadata?: RecordStringAny | null;
|
|
317
318
|
upsert?: boolean;
|
|
318
|
-
projectExtra?:
|
|
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?:
|
|
325
|
-
projectExtra?:
|
|
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.
|
|
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.
|
|
4
|
+
export declare const __version__ = "0.1.20";
|
package/dist/index.js
CHANGED
package/dist/run_trees.cjs
CHANGED
|
@@ -43,7 +43,7 @@ function convertToDottedOrderFormat(epoch, runId) {
|
|
|
43
43
|
}
|
|
44
44
|
exports.convertToDottedOrderFormat = convertToDottedOrderFormat;
|
|
45
45
|
class RunTree {
|
|
46
|
-
constructor(
|
|
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
|
|
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:
|
|
210
|
+
tags: dedupedTags,
|
|
205
211
|
extra: {
|
|
206
212
|
metadata: dedupedMetadata,
|
|
207
213
|
},
|
package/dist/run_trees.d.ts
CHANGED
|
@@ -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(
|
|
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(
|
|
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
|
|
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:
|
|
183
|
+
tags: dedupedTags,
|
|
178
184
|
extra: {
|
|
179
185
|
metadata: dedupedMetadata,
|
|
180
186
|
},
|
package/dist/traceable.cjs
CHANGED
|
@@ -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
|
-
...
|
|
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
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
83
|
-
|
|
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
|
|
92
|
-
await currentRunTree
|
|
123
|
+
if (initialOutputs === currentRunTree?.outputs) {
|
|
124
|
+
await currentRunTree?.end(outputs);
|
|
93
125
|
}
|
|
94
126
|
else {
|
|
95
|
-
currentRunTree
|
|
127
|
+
if (currentRunTree !== undefined) {
|
|
128
|
+
currentRunTree.end_time = Date.now();
|
|
129
|
+
}
|
|
96
130
|
}
|
|
97
|
-
await currentRunTree
|
|
131
|
+
await currentRunTree?.patchRun();
|
|
98
132
|
return resolve(rawOutput);
|
|
99
133
|
}
|
|
100
134
|
}
|
|
101
135
|
catch (error) {
|
|
102
|
-
if (initialError === currentRunTree
|
|
103
|
-
await currentRunTree
|
|
136
|
+
if (initialError === currentRunTree?.error) {
|
|
137
|
+
await currentRunTree?.end(initialOutputs, String(error));
|
|
104
138
|
}
|
|
105
139
|
else {
|
|
106
|
-
currentRunTree
|
|
140
|
+
if (currentRunTree !== undefined) {
|
|
141
|
+
currentRunTree.end_time = Date.now();
|
|
142
|
+
}
|
|
107
143
|
}
|
|
108
|
-
await currentRunTree
|
|
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:
|
|
151
|
+
value: runTreeConfig,
|
|
116
152
|
});
|
|
117
153
|
return traceableFunc;
|
|
118
154
|
}
|
package/dist/traceable.d.ts
CHANGED
|
@@ -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>
|
|
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
|
-
...
|
|
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
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
80
|
-
|
|
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
|
|
89
|
-
await currentRunTree
|
|
120
|
+
if (initialOutputs === currentRunTree?.outputs) {
|
|
121
|
+
await currentRunTree?.end(outputs);
|
|
90
122
|
}
|
|
91
123
|
else {
|
|
92
|
-
currentRunTree
|
|
124
|
+
if (currentRunTree !== undefined) {
|
|
125
|
+
currentRunTree.end_time = Date.now();
|
|
126
|
+
}
|
|
93
127
|
}
|
|
94
|
-
await currentRunTree
|
|
128
|
+
await currentRunTree?.patchRun();
|
|
95
129
|
return resolve(rawOutput);
|
|
96
130
|
}
|
|
97
131
|
}
|
|
98
132
|
catch (error) {
|
|
99
|
-
if (initialError === currentRunTree
|
|
100
|
-
await currentRunTree
|
|
133
|
+
if (initialError === currentRunTree?.error) {
|
|
134
|
+
await currentRunTree?.end(initialOutputs, String(error));
|
|
101
135
|
}
|
|
102
136
|
else {
|
|
103
|
-
currentRunTree
|
|
137
|
+
if (currentRunTree !== undefined) {
|
|
138
|
+
currentRunTree.end_time = Date.now();
|
|
139
|
+
}
|
|
104
140
|
}
|
|
105
|
-
await currentRunTree
|
|
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:
|
|
148
|
+
value: runTreeConfig,
|
|
113
149
|
});
|
|
114
150
|
return traceableFunc;
|
|
115
151
|
}
|
package/dist/utils/messages.cjs
CHANGED
|
@@ -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(
|
|
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;
|
package/dist/utils/messages.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export function isLangChainMessage(
|
|
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.
|
|
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
|
|
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.
|
|
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
|
-
"
|
|
98
|
-
"
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
"
|
|
102
|
-
|
|
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;
|
package/dist/wrappers.d.ts
DELETED
|
@@ -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
|
-
};
|