langsmith 0.1.20 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.cjs +2 -2
- package/dist/client.js +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/run_trees.cjs +4 -4
- package/dist/run_trees.d.ts +1 -1
- package/dist/run_trees.js +4 -4
- package/dist/traceable.cjs +176 -58
- package/dist/traceable.d.ts +5 -3
- package/dist/traceable.js +176 -58
- package/dist/utils/async_caller.cjs +17 -9
- package/dist/utils/async_caller.js +17 -9
- package/dist/wrappers/openai.cjs +53 -74
- package/dist/wrappers/openai.d.ts +10 -11
- package/dist/wrappers/openai.js +53 -74
- package/package.json +4 -4
package/dist/client.cjs
CHANGED
|
@@ -148,7 +148,7 @@ class Queue {
|
|
|
148
148
|
}
|
|
149
149
|
exports.Queue = Queue;
|
|
150
150
|
// 20 MB
|
|
151
|
-
exports.DEFAULT_BATCH_SIZE_LIMIT_BYTES =
|
|
151
|
+
exports.DEFAULT_BATCH_SIZE_LIMIT_BYTES = 20_971_520;
|
|
152
152
|
class Client {
|
|
153
153
|
constructor(config = {}) {
|
|
154
154
|
Object.defineProperty(this, "apiKey", {
|
|
@@ -276,7 +276,7 @@ class Client {
|
|
|
276
276
|
this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
|
|
277
277
|
this.apiKey = trimQuotes(config.apiKey ?? defaultConfig.apiKey);
|
|
278
278
|
this.webUrl = trimQuotes(config.webUrl ?? defaultConfig.webUrl);
|
|
279
|
-
this.timeout_ms = config.timeout_ms ??
|
|
279
|
+
this.timeout_ms = config.timeout_ms ?? 12_000;
|
|
280
280
|
this.caller = new async_caller_js_1.AsyncCaller(config.callerOptions ?? {});
|
|
281
281
|
this.batchIngestCaller = new async_caller_js_1.AsyncCaller({
|
|
282
282
|
...(config.callerOptions ?? {}),
|
package/dist/client.js
CHANGED
|
@@ -121,7 +121,7 @@ export class Queue {
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
// 20 MB
|
|
124
|
-
export const DEFAULT_BATCH_SIZE_LIMIT_BYTES =
|
|
124
|
+
export const DEFAULT_BATCH_SIZE_LIMIT_BYTES = 20_971_520;
|
|
125
125
|
export class Client {
|
|
126
126
|
constructor(config = {}) {
|
|
127
127
|
Object.defineProperty(this, "apiKey", {
|
|
@@ -249,7 +249,7 @@ export class Client {
|
|
|
249
249
|
this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
|
|
250
250
|
this.apiKey = trimQuotes(config.apiKey ?? defaultConfig.apiKey);
|
|
251
251
|
this.webUrl = trimQuotes(config.webUrl ?? defaultConfig.webUrl);
|
|
252
|
-
this.timeout_ms = config.timeout_ms ??
|
|
252
|
+
this.timeout_ms = config.timeout_ms ?? 12_000;
|
|
253
253
|
this.caller = new AsyncCaller(config.callerOptions ?? {});
|
|
254
254
|
this.batchIngestCaller = new AsyncCaller({
|
|
255
255
|
...(config.callerOptions ?? {}),
|
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.21";
|
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.21";
|
package/dist/index.js
CHANGED
package/dist/run_trees.cjs
CHANGED
|
@@ -232,7 +232,7 @@ class RunTree {
|
|
|
232
232
|
extra: {},
|
|
233
233
|
};
|
|
234
234
|
}
|
|
235
|
-
|
|
235
|
+
createChild(config) {
|
|
236
236
|
const child = new RunTree({
|
|
237
237
|
...config,
|
|
238
238
|
parent_run: this,
|
|
@@ -243,9 +243,9 @@ class RunTree {
|
|
|
243
243
|
return child;
|
|
244
244
|
}
|
|
245
245
|
async end(outputs, error, endTime = Date.now()) {
|
|
246
|
-
this.outputs = outputs;
|
|
247
|
-
this.error = error;
|
|
248
|
-
this.end_time = endTime;
|
|
246
|
+
this.outputs = this.outputs ?? outputs;
|
|
247
|
+
this.error = this.error ?? error;
|
|
248
|
+
this.end_time = this.end_time ?? endTime;
|
|
249
249
|
}
|
|
250
250
|
async _convertToCreate(run, excludeChildRuns = true) {
|
|
251
251
|
const runExtra = run.extra ?? {};
|
package/dist/run_trees.d.ts
CHANGED
|
@@ -65,7 +65,7 @@ export declare class RunTree implements BaseRun {
|
|
|
65
65
|
metadata?: KVMap;
|
|
66
66
|
}): RunTree;
|
|
67
67
|
private static getDefaultConfig;
|
|
68
|
-
createChild(config: RunTreeConfig):
|
|
68
|
+
createChild(config: RunTreeConfig): RunTree;
|
|
69
69
|
end(outputs?: KVMap, error?: string, endTime?: number): Promise<void>;
|
|
70
70
|
private _convertToCreate;
|
|
71
71
|
postRun(excludeChildRuns?: boolean): Promise<void>;
|
package/dist/run_trees.js
CHANGED
|
@@ -205,7 +205,7 @@ export class RunTree {
|
|
|
205
205
|
extra: {},
|
|
206
206
|
};
|
|
207
207
|
}
|
|
208
|
-
|
|
208
|
+
createChild(config) {
|
|
209
209
|
const child = new RunTree({
|
|
210
210
|
...config,
|
|
211
211
|
parent_run: this,
|
|
@@ -216,9 +216,9 @@ export class RunTree {
|
|
|
216
216
|
return child;
|
|
217
217
|
}
|
|
218
218
|
async end(outputs, error, endTime = Date.now()) {
|
|
219
|
-
this.outputs = outputs;
|
|
220
|
-
this.error = error;
|
|
221
|
-
this.end_time = endTime;
|
|
219
|
+
this.outputs = this.outputs ?? outputs;
|
|
220
|
+
this.error = this.error ?? error;
|
|
221
|
+
this.end_time = this.end_time ?? endTime;
|
|
222
222
|
}
|
|
223
223
|
async _convertToCreate(run, excludeChildRuns = true) {
|
|
224
224
|
const runExtra = run.extra ?? {};
|
package/dist/traceable.cjs
CHANGED
|
@@ -4,6 +4,12 @@ exports.isTraceableFunction = exports.getCurrentRunTree = exports.traceable = vo
|
|
|
4
4
|
const async_hooks_1 = require("async_hooks");
|
|
5
5
|
const run_trees_js_1 = require("./run_trees.cjs");
|
|
6
6
|
const env_js_1 = require("./utils/env.cjs");
|
|
7
|
+
function isPromiseMethod(x) {
|
|
8
|
+
if (x === "then" || x === "catch" || x === "finally") {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
7
13
|
const asyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
|
|
8
14
|
const isAsyncIterable = (x) => x != null &&
|
|
9
15
|
typeof x === "object" &&
|
|
@@ -33,14 +39,55 @@ const getTracingRunTree = (runTree) => {
|
|
|
33
39
|
*/
|
|
34
40
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
41
|
function traceable(wrappedFunc, config) {
|
|
36
|
-
const { aggregator, ...runTreeConfig } = config ?? {};
|
|
37
|
-
const traceableFunc =
|
|
42
|
+
const { aggregator, argsConfigPath, ...runTreeConfig } = config ?? {};
|
|
43
|
+
const traceableFunc = (...args) => {
|
|
38
44
|
let currentRunTree;
|
|
39
45
|
let rawInputs;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
let ensuredConfig;
|
|
47
|
+
try {
|
|
48
|
+
let runtimeConfig;
|
|
49
|
+
if (argsConfigPath) {
|
|
50
|
+
const [index, path] = argsConfigPath;
|
|
51
|
+
if (index === args.length - 1 && !path) {
|
|
52
|
+
runtimeConfig = args.pop();
|
|
53
|
+
}
|
|
54
|
+
else if (index <= args.length &&
|
|
55
|
+
typeof args[index] === "object" &&
|
|
56
|
+
args[index] !== null) {
|
|
57
|
+
if (path) {
|
|
58
|
+
const { [path]: extracted, ...rest } = args[index];
|
|
59
|
+
runtimeConfig = extracted;
|
|
60
|
+
args[index] = rest;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
runtimeConfig = args[index];
|
|
64
|
+
args.splice(index, 1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
ensuredConfig = {
|
|
69
|
+
name: wrappedFunc.name || "<lambda>",
|
|
70
|
+
...runTreeConfig,
|
|
71
|
+
...runtimeConfig,
|
|
72
|
+
tags: [
|
|
73
|
+
...new Set([
|
|
74
|
+
...(runTreeConfig?.tags ?? []),
|
|
75
|
+
...(runtimeConfig?.tags ?? []),
|
|
76
|
+
]),
|
|
77
|
+
],
|
|
78
|
+
metadata: {
|
|
79
|
+
...runTreeConfig?.metadata,
|
|
80
|
+
...runtimeConfig?.metadata,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
console.warn(`Failed to extract runtime config from args for ${runTreeConfig?.name ?? wrappedFunc.name}`, err);
|
|
86
|
+
ensuredConfig = {
|
|
87
|
+
name: wrappedFunc.name || "<lambda>",
|
|
88
|
+
...runTreeConfig,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
44
91
|
const previousRunTree = asyncLocalStorage.getStore();
|
|
45
92
|
if ((0, run_trees_js_1.isRunTree)(args[0])) {
|
|
46
93
|
currentRunTree = args[0];
|
|
@@ -51,7 +98,7 @@ function traceable(wrappedFunc, config) {
|
|
|
51
98
|
rawInputs = args.slice(1);
|
|
52
99
|
}
|
|
53
100
|
else if (previousRunTree !== undefined) {
|
|
54
|
-
currentRunTree =
|
|
101
|
+
currentRunTree = previousRunTree.createChild(ensuredConfig);
|
|
55
102
|
rawInputs = args;
|
|
56
103
|
}
|
|
57
104
|
else {
|
|
@@ -76,74 +123,145 @@ function traceable(wrappedFunc, config) {
|
|
|
76
123
|
if (currentRunTree) {
|
|
77
124
|
currentRunTree.inputs = inputs;
|
|
78
125
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
126
|
+
return asyncLocalStorage.run(currentRunTree, () => {
|
|
127
|
+
const postRunPromise = currentRunTree?.postRun();
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
129
|
+
let returnValue;
|
|
130
|
+
try {
|
|
131
|
+
returnValue = wrappedFunc(...rawInputs);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
returnValue = Promise.reject(err);
|
|
135
|
+
}
|
|
136
|
+
if (isAsyncIterable(returnValue)) {
|
|
137
|
+
// eslint-disable-next-line no-inner-declarations
|
|
138
|
+
async function* wrapOutputForTracing() {
|
|
139
|
+
let finished = false;
|
|
140
|
+
const chunks = [];
|
|
141
|
+
try {
|
|
142
|
+
for await (const chunk of returnValue) {
|
|
143
|
+
chunks.push(chunk);
|
|
144
|
+
yield chunk;
|
|
145
|
+
}
|
|
146
|
+
finished = true;
|
|
147
|
+
}
|
|
148
|
+
catch (e) {
|
|
149
|
+
await currentRunTree?.end(undefined, String(e));
|
|
150
|
+
throw e;
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
if (!finished) {
|
|
154
|
+
await currentRunTree?.end(undefined, "Cancelled");
|
|
155
|
+
}
|
|
156
|
+
let finalOutputs;
|
|
157
|
+
if (aggregator !== undefined) {
|
|
158
|
+
try {
|
|
159
|
+
finalOutputs = await aggregator(chunks);
|
|
160
|
+
}
|
|
161
|
+
catch (e) {
|
|
162
|
+
console.error(`[ERROR]: LangSmith aggregation failed: `, e);
|
|
163
|
+
finalOutputs = chunks;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
finalOutputs = chunks;
|
|
168
|
+
}
|
|
169
|
+
if (typeof finalOutputs === "object" &&
|
|
170
|
+
!Array.isArray(finalOutputs)) {
|
|
171
|
+
await currentRunTree?.end(finalOutputs);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
await currentRunTree?.end({ outputs: finalOutputs });
|
|
175
|
+
}
|
|
176
|
+
await postRunPromise;
|
|
177
|
+
await currentRunTree?.patchRun();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return wrapOutputForTracing();
|
|
181
|
+
}
|
|
182
|
+
const tracedPromise = new Promise((resolve, reject) => {
|
|
183
|
+
Promise.resolve(returnValue)
|
|
184
|
+
.then(
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
186
|
+
async (rawOutput) => {
|
|
86
187
|
if (isAsyncIterable(rawOutput)) {
|
|
87
188
|
// eslint-disable-next-line no-inner-declarations
|
|
88
189
|
async function* wrapOutputForTracing() {
|
|
190
|
+
let finished = false;
|
|
89
191
|
const chunks = [];
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
192
|
+
try {
|
|
193
|
+
// TypeScript thinks this is unsafe
|
|
194
|
+
for await (const chunk of rawOutput) {
|
|
195
|
+
chunks.push(chunk);
|
|
196
|
+
yield chunk;
|
|
197
|
+
}
|
|
198
|
+
finished = true;
|
|
199
|
+
}
|
|
200
|
+
catch (e) {
|
|
201
|
+
await currentRunTree?.end(undefined, String(e));
|
|
202
|
+
throw e;
|
|
94
203
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
finalOutputs = await aggregator(chunks);
|
|
204
|
+
finally {
|
|
205
|
+
if (!finished) {
|
|
206
|
+
await currentRunTree?.end(undefined, "Cancelled");
|
|
99
207
|
}
|
|
100
|
-
|
|
101
|
-
|
|
208
|
+
let finalOutputs;
|
|
209
|
+
if (aggregator !== undefined) {
|
|
210
|
+
try {
|
|
211
|
+
finalOutputs = await aggregator(chunks);
|
|
212
|
+
}
|
|
213
|
+
catch (e) {
|
|
214
|
+
console.error(`[ERROR]: LangSmith aggregation failed: `, e);
|
|
215
|
+
finalOutputs = chunks;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
102
219
|
finalOutputs = chunks;
|
|
103
220
|
}
|
|
221
|
+
if (typeof finalOutputs === "object" &&
|
|
222
|
+
!Array.isArray(finalOutputs)) {
|
|
223
|
+
await currentRunTree?.end(finalOutputs);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
await currentRunTree?.end({ outputs: finalOutputs });
|
|
227
|
+
}
|
|
228
|
+
await postRunPromise;
|
|
229
|
+
await currentRunTree?.patchRun();
|
|
104
230
|
}
|
|
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();
|
|
116
231
|
}
|
|
117
232
|
return resolve(wrapOutputForTracing());
|
|
118
233
|
}
|
|
119
234
|
else {
|
|
120
|
-
|
|
121
|
-
? rawOutput
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
await currentRunTree?.end(outputs);
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
if (currentRunTree !== undefined) {
|
|
128
|
-
currentRunTree.end_time = Date.now();
|
|
129
|
-
}
|
|
235
|
+
try {
|
|
236
|
+
await currentRunTree?.end(isKVMap(rawOutput) ? rawOutput : { outputs: rawOutput });
|
|
237
|
+
await postRunPromise;
|
|
238
|
+
await currentRunTree?.patchRun();
|
|
130
239
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
if (initialError === currentRunTree?.error) {
|
|
137
|
-
await currentRunTree?.end(initialOutputs, String(error));
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
if (currentRunTree !== undefined) {
|
|
141
|
-
currentRunTree.end_time = Date.now();
|
|
240
|
+
finally {
|
|
241
|
+
// eslint-disable-next-line no-unsafe-finally
|
|
242
|
+
return rawOutput;
|
|
142
243
|
}
|
|
143
244
|
}
|
|
245
|
+
},
|
|
246
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
247
|
+
async (error) => {
|
|
248
|
+
await currentRunTree?.end(undefined, String(error));
|
|
249
|
+
await postRunPromise;
|
|
144
250
|
await currentRunTree?.patchRun();
|
|
145
|
-
|
|
146
|
-
}
|
|
251
|
+
throw error;
|
|
252
|
+
})
|
|
253
|
+
.then(resolve, reject);
|
|
254
|
+
});
|
|
255
|
+
if (typeof returnValue !== "object" || returnValue === null) {
|
|
256
|
+
return tracedPromise;
|
|
257
|
+
}
|
|
258
|
+
return new Proxy(returnValue, {
|
|
259
|
+
get(target, prop, receiver) {
|
|
260
|
+
if (isPromiseMethod(prop)) {
|
|
261
|
+
return tracedPromise[prop].bind(tracedPromise);
|
|
262
|
+
}
|
|
263
|
+
return Reflect.get(target, prop, receiver);
|
|
264
|
+
},
|
|
147
265
|
});
|
|
148
266
|
});
|
|
149
267
|
};
|
package/dist/traceable.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { RunTree, RunTreeConfig, RunnableConfigLike } from "./run_trees.js";
|
|
2
2
|
export type RunTreeLike = RunTree;
|
|
3
|
+
type SmartPromise<T> = T extends AsyncGenerator ? T : T extends Promise<unknown> ? T : Promise<T>;
|
|
3
4
|
type WrapArgReturnPair<Pair> = Pair extends [
|
|
4
5
|
infer Args extends any[],
|
|
5
6
|
infer Return
|
|
6
7
|
] ? {
|
|
7
|
-
(...args: Args):
|
|
8
|
-
(...args: [runTree: RunTreeLike, ...rest: Args]):
|
|
9
|
-
(...args: [config: RunnableConfigLike, ...rest: Args]):
|
|
8
|
+
(...args: Args): SmartPromise<Return>;
|
|
9
|
+
(...args: [runTree: RunTreeLike, ...rest: Args]): SmartPromise<Return>;
|
|
10
|
+
(...args: [config: RunnableConfigLike, ...rest: Args]): SmartPromise<Return>;
|
|
10
11
|
} : never;
|
|
11
12
|
type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
|
|
12
13
|
export type TraceableFunction<Func extends (...args: any[]) => any> = Func extends {
|
|
@@ -46,6 +47,7 @@ export type TraceableFunction<Func extends (...args: any[]) => any> = Func exten
|
|
|
46
47
|
*/
|
|
47
48
|
export declare function traceable<Func extends (...args: any[]) => any>(wrappedFunc: Func, config?: Partial<RunTreeConfig> & {
|
|
48
49
|
aggregator?: (args: any[]) => any;
|
|
50
|
+
argsConfigPath?: [number] | [number, string];
|
|
49
51
|
}): TraceableFunction<Func>;
|
|
50
52
|
/**
|
|
51
53
|
* Return the current run tree from within a traceable-wrapped function.
|
package/dist/traceable.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "async_hooks";
|
|
2
2
|
import { RunTree, isRunTree, isRunnableConfigLike, } from "./run_trees.js";
|
|
3
3
|
import { getEnvironmentVariable } from "./utils/env.js";
|
|
4
|
+
function isPromiseMethod(x) {
|
|
5
|
+
if (x === "then" || x === "catch" || x === "finally") {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
4
10
|
const asyncLocalStorage = new AsyncLocalStorage();
|
|
5
11
|
const isAsyncIterable = (x) => x != null &&
|
|
6
12
|
typeof x === "object" &&
|
|
@@ -30,14 +36,55 @@ const getTracingRunTree = (runTree) => {
|
|
|
30
36
|
*/
|
|
31
37
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
38
|
export function traceable(wrappedFunc, config) {
|
|
33
|
-
const { aggregator, ...runTreeConfig } = config ?? {};
|
|
34
|
-
const traceableFunc =
|
|
39
|
+
const { aggregator, argsConfigPath, ...runTreeConfig } = config ?? {};
|
|
40
|
+
const traceableFunc = (...args) => {
|
|
35
41
|
let currentRunTree;
|
|
36
42
|
let rawInputs;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
let ensuredConfig;
|
|
44
|
+
try {
|
|
45
|
+
let runtimeConfig;
|
|
46
|
+
if (argsConfigPath) {
|
|
47
|
+
const [index, path] = argsConfigPath;
|
|
48
|
+
if (index === args.length - 1 && !path) {
|
|
49
|
+
runtimeConfig = args.pop();
|
|
50
|
+
}
|
|
51
|
+
else if (index <= args.length &&
|
|
52
|
+
typeof args[index] === "object" &&
|
|
53
|
+
args[index] !== null) {
|
|
54
|
+
if (path) {
|
|
55
|
+
const { [path]: extracted, ...rest } = args[index];
|
|
56
|
+
runtimeConfig = extracted;
|
|
57
|
+
args[index] = rest;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
runtimeConfig = args[index];
|
|
61
|
+
args.splice(index, 1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
ensuredConfig = {
|
|
66
|
+
name: wrappedFunc.name || "<lambda>",
|
|
67
|
+
...runTreeConfig,
|
|
68
|
+
...runtimeConfig,
|
|
69
|
+
tags: [
|
|
70
|
+
...new Set([
|
|
71
|
+
...(runTreeConfig?.tags ?? []),
|
|
72
|
+
...(runtimeConfig?.tags ?? []),
|
|
73
|
+
]),
|
|
74
|
+
],
|
|
75
|
+
metadata: {
|
|
76
|
+
...runTreeConfig?.metadata,
|
|
77
|
+
...runtimeConfig?.metadata,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
console.warn(`Failed to extract runtime config from args for ${runTreeConfig?.name ?? wrappedFunc.name}`, err);
|
|
83
|
+
ensuredConfig = {
|
|
84
|
+
name: wrappedFunc.name || "<lambda>",
|
|
85
|
+
...runTreeConfig,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
41
88
|
const previousRunTree = asyncLocalStorage.getStore();
|
|
42
89
|
if (isRunTree(args[0])) {
|
|
43
90
|
currentRunTree = args[0];
|
|
@@ -48,7 +95,7 @@ export function traceable(wrappedFunc, config) {
|
|
|
48
95
|
rawInputs = args.slice(1);
|
|
49
96
|
}
|
|
50
97
|
else if (previousRunTree !== undefined) {
|
|
51
|
-
currentRunTree =
|
|
98
|
+
currentRunTree = previousRunTree.createChild(ensuredConfig);
|
|
52
99
|
rawInputs = args;
|
|
53
100
|
}
|
|
54
101
|
else {
|
|
@@ -73,74 +120,145 @@ export function traceable(wrappedFunc, config) {
|
|
|
73
120
|
if (currentRunTree) {
|
|
74
121
|
currentRunTree.inputs = inputs;
|
|
75
122
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
123
|
+
return asyncLocalStorage.run(currentRunTree, () => {
|
|
124
|
+
const postRunPromise = currentRunTree?.postRun();
|
|
125
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
126
|
+
let returnValue;
|
|
127
|
+
try {
|
|
128
|
+
returnValue = wrappedFunc(...rawInputs);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
returnValue = Promise.reject(err);
|
|
132
|
+
}
|
|
133
|
+
if (isAsyncIterable(returnValue)) {
|
|
134
|
+
// eslint-disable-next-line no-inner-declarations
|
|
135
|
+
async function* wrapOutputForTracing() {
|
|
136
|
+
let finished = false;
|
|
137
|
+
const chunks = [];
|
|
138
|
+
try {
|
|
139
|
+
for await (const chunk of returnValue) {
|
|
140
|
+
chunks.push(chunk);
|
|
141
|
+
yield chunk;
|
|
142
|
+
}
|
|
143
|
+
finished = true;
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
await currentRunTree?.end(undefined, String(e));
|
|
147
|
+
throw e;
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
if (!finished) {
|
|
151
|
+
await currentRunTree?.end(undefined, "Cancelled");
|
|
152
|
+
}
|
|
153
|
+
let finalOutputs;
|
|
154
|
+
if (aggregator !== undefined) {
|
|
155
|
+
try {
|
|
156
|
+
finalOutputs = await aggregator(chunks);
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
console.error(`[ERROR]: LangSmith aggregation failed: `, e);
|
|
160
|
+
finalOutputs = chunks;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
finalOutputs = chunks;
|
|
165
|
+
}
|
|
166
|
+
if (typeof finalOutputs === "object" &&
|
|
167
|
+
!Array.isArray(finalOutputs)) {
|
|
168
|
+
await currentRunTree?.end(finalOutputs);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
await currentRunTree?.end({ outputs: finalOutputs });
|
|
172
|
+
}
|
|
173
|
+
await postRunPromise;
|
|
174
|
+
await currentRunTree?.patchRun();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return wrapOutputForTracing();
|
|
178
|
+
}
|
|
179
|
+
const tracedPromise = new Promise((resolve, reject) => {
|
|
180
|
+
Promise.resolve(returnValue)
|
|
181
|
+
.then(
|
|
182
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
183
|
+
async (rawOutput) => {
|
|
83
184
|
if (isAsyncIterable(rawOutput)) {
|
|
84
185
|
// eslint-disable-next-line no-inner-declarations
|
|
85
186
|
async function* wrapOutputForTracing() {
|
|
187
|
+
let finished = false;
|
|
86
188
|
const chunks = [];
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
189
|
+
try {
|
|
190
|
+
// TypeScript thinks this is unsafe
|
|
191
|
+
for await (const chunk of rawOutput) {
|
|
192
|
+
chunks.push(chunk);
|
|
193
|
+
yield chunk;
|
|
194
|
+
}
|
|
195
|
+
finished = true;
|
|
196
|
+
}
|
|
197
|
+
catch (e) {
|
|
198
|
+
await currentRunTree?.end(undefined, String(e));
|
|
199
|
+
throw e;
|
|
91
200
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
finalOutputs = await aggregator(chunks);
|
|
201
|
+
finally {
|
|
202
|
+
if (!finished) {
|
|
203
|
+
await currentRunTree?.end(undefined, "Cancelled");
|
|
96
204
|
}
|
|
97
|
-
|
|
98
|
-
|
|
205
|
+
let finalOutputs;
|
|
206
|
+
if (aggregator !== undefined) {
|
|
207
|
+
try {
|
|
208
|
+
finalOutputs = await aggregator(chunks);
|
|
209
|
+
}
|
|
210
|
+
catch (e) {
|
|
211
|
+
console.error(`[ERROR]: LangSmith aggregation failed: `, e);
|
|
212
|
+
finalOutputs = chunks;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
99
216
|
finalOutputs = chunks;
|
|
100
217
|
}
|
|
218
|
+
if (typeof finalOutputs === "object" &&
|
|
219
|
+
!Array.isArray(finalOutputs)) {
|
|
220
|
+
await currentRunTree?.end(finalOutputs);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
await currentRunTree?.end({ outputs: finalOutputs });
|
|
224
|
+
}
|
|
225
|
+
await postRunPromise;
|
|
226
|
+
await currentRunTree?.patchRun();
|
|
101
227
|
}
|
|
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();
|
|
113
228
|
}
|
|
114
229
|
return resolve(wrapOutputForTracing());
|
|
115
230
|
}
|
|
116
231
|
else {
|
|
117
|
-
|
|
118
|
-
? rawOutput
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
await currentRunTree?.end(outputs);
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
if (currentRunTree !== undefined) {
|
|
125
|
-
currentRunTree.end_time = Date.now();
|
|
126
|
-
}
|
|
232
|
+
try {
|
|
233
|
+
await currentRunTree?.end(isKVMap(rawOutput) ? rawOutput : { outputs: rawOutput });
|
|
234
|
+
await postRunPromise;
|
|
235
|
+
await currentRunTree?.patchRun();
|
|
127
236
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
catch (error) {
|
|
133
|
-
if (initialError === currentRunTree?.error) {
|
|
134
|
-
await currentRunTree?.end(initialOutputs, String(error));
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
if (currentRunTree !== undefined) {
|
|
138
|
-
currentRunTree.end_time = Date.now();
|
|
237
|
+
finally {
|
|
238
|
+
// eslint-disable-next-line no-unsafe-finally
|
|
239
|
+
return rawOutput;
|
|
139
240
|
}
|
|
140
241
|
}
|
|
242
|
+
},
|
|
243
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
244
|
+
async (error) => {
|
|
245
|
+
await currentRunTree?.end(undefined, String(error));
|
|
246
|
+
await postRunPromise;
|
|
141
247
|
await currentRunTree?.patchRun();
|
|
142
|
-
|
|
143
|
-
}
|
|
248
|
+
throw error;
|
|
249
|
+
})
|
|
250
|
+
.then(resolve, reject);
|
|
251
|
+
});
|
|
252
|
+
if (typeof returnValue !== "object" || returnValue === null) {
|
|
253
|
+
return tracedPromise;
|
|
254
|
+
}
|
|
255
|
+
return new Proxy(returnValue, {
|
|
256
|
+
get(target, prop, receiver) {
|
|
257
|
+
if (isPromiseMethod(prop)) {
|
|
258
|
+
return tracedPromise[prop].bind(tracedPromise);
|
|
259
|
+
}
|
|
260
|
+
return Reflect.get(target, prop, receiver);
|
|
261
|
+
},
|
|
144
262
|
});
|
|
145
263
|
});
|
|
146
264
|
};
|
|
@@ -7,13 +7,13 @@ exports.AsyncCaller = void 0;
|
|
|
7
7
|
const p_retry_1 = __importDefault(require("p-retry"));
|
|
8
8
|
const p_queue_1 = __importDefault(require("p-queue"));
|
|
9
9
|
const STATUS_NO_RETRY = [
|
|
10
|
-
400,
|
|
11
|
-
401,
|
|
12
|
-
403,
|
|
13
|
-
404,
|
|
14
|
-
405,
|
|
15
|
-
406,
|
|
16
|
-
407,
|
|
10
|
+
400, // Bad Request
|
|
11
|
+
401, // Unauthorized
|
|
12
|
+
403, // Forbidden
|
|
13
|
+
404, // Not Found
|
|
14
|
+
405, // Method Not Allowed
|
|
15
|
+
406, // Not Acceptable
|
|
16
|
+
407, // Proxy Authentication Required
|
|
17
17
|
408, // Request Timeout
|
|
18
18
|
];
|
|
19
19
|
const STATUS_IGNORE = [
|
|
@@ -60,8 +60,16 @@ class AsyncCaller {
|
|
|
60
60
|
});
|
|
61
61
|
this.maxConcurrency = params.maxConcurrency ?? Infinity;
|
|
62
62
|
this.maxRetries = params.maxRetries ?? 6;
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
if ("default" in p_queue_1.default) {
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
+
this.queue = new p_queue_1.default.default({
|
|
66
|
+
concurrency: this.maxConcurrency,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
71
|
+
this.queue = new p_queue_1.default({ concurrency: this.maxConcurrency });
|
|
72
|
+
}
|
|
65
73
|
this.onFailedResponseHook = params?.onFailedResponseHook;
|
|
66
74
|
}
|
|
67
75
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import pRetry from "p-retry";
|
|
2
2
|
import PQueueMod from "p-queue";
|
|
3
3
|
const STATUS_NO_RETRY = [
|
|
4
|
-
400,
|
|
5
|
-
401,
|
|
6
|
-
403,
|
|
7
|
-
404,
|
|
8
|
-
405,
|
|
9
|
-
406,
|
|
10
|
-
407,
|
|
4
|
+
400, // Bad Request
|
|
5
|
+
401, // Unauthorized
|
|
6
|
+
403, // Forbidden
|
|
7
|
+
404, // Not Found
|
|
8
|
+
405, // Method Not Allowed
|
|
9
|
+
406, // Not Acceptable
|
|
10
|
+
407, // Proxy Authentication Required
|
|
11
11
|
408, // Request Timeout
|
|
12
12
|
];
|
|
13
13
|
const STATUS_IGNORE = [
|
|
@@ -54,8 +54,16 @@ export class AsyncCaller {
|
|
|
54
54
|
});
|
|
55
55
|
this.maxConcurrency = params.maxConcurrency ?? Infinity;
|
|
56
56
|
this.maxRetries = params.maxRetries ?? 6;
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
if ("default" in PQueueMod) {
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
|
+
this.queue = new PQueueMod.default({
|
|
60
|
+
concurrency: this.maxConcurrency,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
+
this.queue = new PQueueMod({ concurrency: this.maxConcurrency });
|
|
66
|
+
}
|
|
59
67
|
this.onFailedResponseHook = params?.onFailedResponseHook;
|
|
60
68
|
}
|
|
61
69
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
package/dist/wrappers/openai.cjs
CHANGED
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.wrapSDK = exports.wrapOpenAI = void 0;
|
|
4
4
|
const traceable_js_1 = require("../traceable.cjs");
|
|
5
|
-
function _combineChatCompletionChoices(choices
|
|
5
|
+
function _combineChatCompletionChoices(choices
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
) {
|
|
6
8
|
const reversedChoices = choices.slice().reverse();
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
10
|
const message = {
|
|
8
11
|
role: "assistant",
|
|
9
12
|
content: "",
|
|
@@ -73,26 +76,43 @@ function _combineChatCompletionChoices(choices) {
|
|
|
73
76
|
message: message,
|
|
74
77
|
};
|
|
75
78
|
}
|
|
76
|
-
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
const chatAggregator = (chunks) => {
|
|
80
|
+
if (!chunks || chunks.length === 0) {
|
|
81
|
+
return { choices: [{ message: { role: "assistant", content: "" } }] };
|
|
82
|
+
}
|
|
83
|
+
const choicesByIndex = {};
|
|
84
|
+
for (const chunk of chunks) {
|
|
85
|
+
for (const choice of chunk.choices) {
|
|
86
|
+
if (choicesByIndex[choice.index] === undefined) {
|
|
87
|
+
choicesByIndex[choice.index] = [];
|
|
88
|
+
}
|
|
89
|
+
choicesByIndex[choice.index].push(choice);
|
|
87
90
|
}
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
}
|
|
92
|
+
const aggregatedOutput = chunks[chunks.length - 1];
|
|
93
|
+
aggregatedOutput.choices = Object.values(choicesByIndex).map((choices) => _combineChatCompletionChoices(choices));
|
|
94
|
+
return aggregatedOutput;
|
|
95
|
+
};
|
|
96
|
+
const textAggregator = (allChunks
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
98
|
+
) => {
|
|
99
|
+
if (allChunks.length === 0) {
|
|
100
|
+
return { choices: [{ text: "" }] };
|
|
101
|
+
}
|
|
102
|
+
const allContent = [];
|
|
103
|
+
for (const chunk of allChunks) {
|
|
104
|
+
const content = chunk.choices[0].text;
|
|
105
|
+
if (content != null) {
|
|
106
|
+
allContent.push(content);
|
|
90
107
|
}
|
|
91
|
-
return wrappedMethod(...finalArgs);
|
|
92
108
|
}
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
109
|
+
const content = allContent.join("");
|
|
110
|
+
const aggregatedOutput = allChunks[allChunks.length - 1];
|
|
111
|
+
aggregatedOutput.choices = [
|
|
112
|
+
{ ...aggregatedOutput.choices[0], text: content },
|
|
113
|
+
];
|
|
114
|
+
return aggregatedOutput;
|
|
115
|
+
};
|
|
96
116
|
/**
|
|
97
117
|
* Wraps an OpenAI client's completion methods, enabling automatic LangSmith
|
|
98
118
|
* tracing. Method signatures are unchanged, with the exception that you can pass
|
|
@@ -118,61 +138,20 @@ async function extractLangSmithExtraAndCall(openAIMethod, args, defaultRunConfig
|
|
|
118
138
|
* ```
|
|
119
139
|
*/
|
|
120
140
|
const wrapOpenAI = (openai, options) => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
};
|
|
141
|
+
openai.chat.completions.create = (0, traceable_js_1.traceable)(openai.chat.completions.create.bind(openai.chat.completions), {
|
|
142
|
+
name: "ChatOpenAI",
|
|
143
|
+
run_type: "llm",
|
|
144
|
+
aggregator: chatAggregator,
|
|
145
|
+
argsConfigPath: [1, "langsmithExtra"],
|
|
146
|
+
...options,
|
|
147
|
+
});
|
|
148
|
+
openai.completions.create = (0, traceable_js_1.traceable)(openai.completions.create.bind(openai.completions), {
|
|
149
|
+
name: "OpenAI",
|
|
150
|
+
run_type: "llm",
|
|
151
|
+
aggregator: textAggregator,
|
|
152
|
+
argsConfigPath: [1, "langsmithExtra"],
|
|
153
|
+
...options,
|
|
154
|
+
});
|
|
176
155
|
return openai;
|
|
177
156
|
};
|
|
178
157
|
exports.wrapOpenAI = wrapOpenAI;
|
|
@@ -181,7 +160,7 @@ const _wrapClient = (sdk, runName, options) => {
|
|
|
181
160
|
get(target, propKey, receiver) {
|
|
182
161
|
const originalValue = target[propKey];
|
|
183
162
|
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
|
|
163
|
+
return (0, traceable_js_1.traceable)(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options));
|
|
185
164
|
}
|
|
186
165
|
else if (originalValue != null &&
|
|
187
166
|
!Array.isArray(originalValue) &&
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { OpenAI } from "openai";
|
|
2
|
+
import type { APIPromise } from "openai/core";
|
|
2
3
|
import type { Client, RunTreeConfig } from "../index.js";
|
|
3
4
|
import { type RunnableConfigLike } from "../run_trees.js";
|
|
4
5
|
import { type RunTreeLike } from "../traceable.js";
|
|
@@ -12,31 +13,29 @@ type OpenAIType = {
|
|
|
12
13
|
create: (...args: any[]) => any;
|
|
13
14
|
};
|
|
14
15
|
};
|
|
15
|
-
type PatchedOpenAIClient<T extends OpenAIType> = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
chat: {
|
|
19
|
-
completions: {
|
|
16
|
+
type PatchedOpenAIClient<T extends OpenAIType> = T & {
|
|
17
|
+
chat: T["chat"] & {
|
|
18
|
+
completions: T["chat"]["completions"] & {
|
|
20
19
|
create: {
|
|
21
20
|
(arg: OpenAI.ChatCompletionCreateParamsStreaming, arg2?: OpenAI.RequestOptions & {
|
|
22
21
|
langsmithExtra?: RunnableConfigLike | RunTreeLike;
|
|
23
|
-
}):
|
|
22
|
+
}): APIPromise<AsyncGenerator<OpenAI.ChatCompletionChunk>>;
|
|
24
23
|
} & {
|
|
25
24
|
(arg: OpenAI.ChatCompletionCreateParamsNonStreaming, arg2?: OpenAI.RequestOptions & {
|
|
26
25
|
langsmithExtra?: RunnableConfigLike | RunTreeLike;
|
|
27
|
-
}):
|
|
26
|
+
}): APIPromise<OpenAI.ChatCompletionChunk>;
|
|
28
27
|
};
|
|
29
28
|
};
|
|
30
29
|
};
|
|
31
|
-
completions: {
|
|
30
|
+
completions: T["completions"] & {
|
|
32
31
|
create: {
|
|
33
32
|
(arg: OpenAI.CompletionCreateParamsStreaming, arg2?: OpenAI.RequestOptions & {
|
|
34
33
|
langsmithExtra?: RunnableConfigLike | RunTreeLike;
|
|
35
|
-
}):
|
|
34
|
+
}): APIPromise<AsyncGenerator<OpenAI.Completion>>;
|
|
36
35
|
} & {
|
|
37
36
|
(arg: OpenAI.CompletionCreateParamsNonStreaming, arg2?: OpenAI.RequestOptions & {
|
|
38
37
|
langsmithExtra?: RunnableConfigLike | RunTreeLike;
|
|
39
|
-
}):
|
|
38
|
+
}): APIPromise<OpenAI.Completion>;
|
|
40
39
|
};
|
|
41
40
|
};
|
|
42
41
|
};
|
package/dist/wrappers/openai.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { traceable } from "../traceable.js";
|
|
2
|
-
function _combineChatCompletionChoices(choices
|
|
2
|
+
function _combineChatCompletionChoices(choices
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4
|
+
) {
|
|
3
5
|
const reversedChoices = choices.slice().reverse();
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4
7
|
const message = {
|
|
5
8
|
role: "assistant",
|
|
6
9
|
content: "",
|
|
@@ -70,26 +73,43 @@ function _combineChatCompletionChoices(choices) {
|
|
|
70
73
|
message: message,
|
|
71
74
|
};
|
|
72
75
|
}
|
|
73
|
-
|
|
74
|
-
if (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
const chatAggregator = (chunks) => {
|
|
77
|
+
if (!chunks || chunks.length === 0) {
|
|
78
|
+
return { choices: [{ message: { role: "assistant", content: "" } }] };
|
|
79
|
+
}
|
|
80
|
+
const choicesByIndex = {};
|
|
81
|
+
for (const chunk of chunks) {
|
|
82
|
+
for (const choice of chunk.choices) {
|
|
83
|
+
if (choicesByIndex[choice.index] === undefined) {
|
|
84
|
+
choicesByIndex[choice.index] = [];
|
|
85
|
+
}
|
|
86
|
+
choicesByIndex[choice.index].push(choice);
|
|
84
87
|
}
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
}
|
|
89
|
+
const aggregatedOutput = chunks[chunks.length - 1];
|
|
90
|
+
aggregatedOutput.choices = Object.values(choicesByIndex).map((choices) => _combineChatCompletionChoices(choices));
|
|
91
|
+
return aggregatedOutput;
|
|
92
|
+
};
|
|
93
|
+
const textAggregator = (allChunks
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
95
|
+
) => {
|
|
96
|
+
if (allChunks.length === 0) {
|
|
97
|
+
return { choices: [{ text: "" }] };
|
|
98
|
+
}
|
|
99
|
+
const allContent = [];
|
|
100
|
+
for (const chunk of allChunks) {
|
|
101
|
+
const content = chunk.choices[0].text;
|
|
102
|
+
if (content != null) {
|
|
103
|
+
allContent.push(content);
|
|
87
104
|
}
|
|
88
|
-
return wrappedMethod(...finalArgs);
|
|
89
105
|
}
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
106
|
+
const content = allContent.join("");
|
|
107
|
+
const aggregatedOutput = allChunks[allChunks.length - 1];
|
|
108
|
+
aggregatedOutput.choices = [
|
|
109
|
+
{ ...aggregatedOutput.choices[0], text: content },
|
|
110
|
+
];
|
|
111
|
+
return aggregatedOutput;
|
|
112
|
+
};
|
|
93
113
|
/**
|
|
94
114
|
* Wraps an OpenAI client's completion methods, enabling automatic LangSmith
|
|
95
115
|
* tracing. Method signatures are unchanged, with the exception that you can pass
|
|
@@ -115,61 +135,20 @@ async function extractLangSmithExtraAndCall(openAIMethod, args, defaultRunConfig
|
|
|
115
135
|
* ```
|
|
116
136
|
*/
|
|
117
137
|
export const wrapOpenAI = (openai, options) => {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
};
|
|
138
|
+
openai.chat.completions.create = traceable(openai.chat.completions.create.bind(openai.chat.completions), {
|
|
139
|
+
name: "ChatOpenAI",
|
|
140
|
+
run_type: "llm",
|
|
141
|
+
aggregator: chatAggregator,
|
|
142
|
+
argsConfigPath: [1, "langsmithExtra"],
|
|
143
|
+
...options,
|
|
144
|
+
});
|
|
145
|
+
openai.completions.create = traceable(openai.completions.create.bind(openai.completions), {
|
|
146
|
+
name: "OpenAI",
|
|
147
|
+
run_type: "llm",
|
|
148
|
+
aggregator: textAggregator,
|
|
149
|
+
argsConfigPath: [1, "langsmithExtra"],
|
|
150
|
+
...options,
|
|
151
|
+
});
|
|
173
152
|
return openai;
|
|
174
153
|
};
|
|
175
154
|
const _wrapClient = (sdk, runName, options) => {
|
|
@@ -177,7 +156,7 @@ const _wrapClient = (sdk, runName, options) => {
|
|
|
177
156
|
get(target, propKey, receiver) {
|
|
178
157
|
const originalValue = target[propKey];
|
|
179
158
|
if (typeof originalValue === "function") {
|
|
180
|
-
return traceable(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options
|
|
159
|
+
return traceable(originalValue.bind(target), Object.assign({ name: [runName, propKey.toString()].join("."), run_type: "llm" }, options));
|
|
181
160
|
}
|
|
182
161
|
else if (originalValue != null &&
|
|
183
162
|
!Array.isArray(originalValue) &&
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "langsmith",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
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": [
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"check-version": "node scripts/check-version.js",
|
|
48
48
|
"check-npm-version": "node scripts/check-npm-version.js",
|
|
49
49
|
"clean": "rm -rf dist/ && node scripts/create-entrypoints.js clean",
|
|
50
|
-
"build:esm": "tsc --outDir dist/ && rm -rf dist/tests dist/**/tests",
|
|
51
|
-
"build:cjs": "tsc --outDir dist-cjs/ -p tsconfig.cjs.json && node scripts/move-cjs-to-dist.js && rm -r dist-cjs",
|
|
50
|
+
"build:esm": "rm -f src/package.json && tsc --outDir dist/ && rm -rf dist/tests dist/**/tests",
|
|
51
|
+
"build:cjs": "echo '{}' > src/package.json && tsc --outDir dist-cjs/ -p tsconfig.cjs.json && node scripts/move-cjs-to-dist.js && rm -r dist-cjs src/package.json",
|
|
52
52
|
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests --testPathIgnorePatterns='\\.int\\.test.[tj]s' --testTimeout 30000",
|
|
53
53
|
"test:integration": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --testPathPattern=\\.int\\.test.ts --testTimeout 100000",
|
|
54
54
|
"test:single": "NODE_OPTIONS=--experimental-vm-modules yarn run jest --config jest.config.cjs --testTimeout 100000",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"prettier": "^2.8.8",
|
|
105
105
|
"ts-jest": "^29.1.0",
|
|
106
106
|
"ts-node": "^10.9.1",
|
|
107
|
-
"typescript": "^5.
|
|
107
|
+
"typescript": "^5.4.5"
|
|
108
108
|
},
|
|
109
109
|
"peerDependencies": {
|
|
110
110
|
"openai": "*"
|