@rpascene/mcp 0.30.11
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/README.md +2 -0
- package/dist/251.js +24942 -0
- package/dist/251.js.LICENSE.txt +1 -0
- package/dist/290.js +4026 -0
- package/dist/328.js +456 -0
- package/dist/79.js +40 -0
- package/dist/940.js +1156 -0
- package/dist/api.mdx +1167 -0
- package/dist/index.js +252260 -0
- package/dist/index.js.LICENSE.txt +522 -0
- package/package.json +44 -0
package/dist/290.js
ADDED
|
@@ -0,0 +1,4026 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
exports.ids = [
|
|
3
|
+
"290"
|
|
4
|
+
];
|
|
5
|
+
exports.modules = {
|
|
6
|
+
"../../node_modules/.pnpm/langsmith@0.3.7_openai@4.81.0_ws@8.18.3_zod@3.24.3_/node_modules/langsmith/wrappers.js": function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
|
|
7
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
8
|
+
wrapOpenAI: ()=>wrapOpenAI
|
|
9
|
+
});
|
|
10
|
+
var external_node_async_hooks_ = __webpack_require__("node:async_hooks");
|
|
11
|
+
var v4 = __webpack_require__("../../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/v4.js");
|
|
12
|
+
var p_retry = __webpack_require__("../../node_modules/.pnpm/p-retry@4.6.2/node_modules/p-retry/index.js");
|
|
13
|
+
var dist = __webpack_require__("../../node_modules/.pnpm/p-queue@6.6.2/node_modules/p-queue/dist/index.js");
|
|
14
|
+
const DEFAULT_FETCH_IMPLEMENTATION = (...args)=>fetch(...args);
|
|
15
|
+
const LANGSMITH_FETCH_IMPLEMENTATION_KEY = Symbol.for("ls:fetch_implementation");
|
|
16
|
+
const _getFetchImplementation = ()=>globalThis[LANGSMITH_FETCH_IMPLEMENTATION_KEY] ?? DEFAULT_FETCH_IMPLEMENTATION;
|
|
17
|
+
const STATUS_NO_RETRY = [
|
|
18
|
+
400,
|
|
19
|
+
401,
|
|
20
|
+
403,
|
|
21
|
+
404,
|
|
22
|
+
405,
|
|
23
|
+
406,
|
|
24
|
+
407,
|
|
25
|
+
408
|
|
26
|
+
];
|
|
27
|
+
const STATUS_IGNORE = [
|
|
28
|
+
409
|
|
29
|
+
];
|
|
30
|
+
class AsyncCaller {
|
|
31
|
+
constructor(params){
|
|
32
|
+
Object.defineProperty(this, "maxConcurrency", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: void 0
|
|
37
|
+
});
|
|
38
|
+
Object.defineProperty(this, "maxRetries", {
|
|
39
|
+
enumerable: true,
|
|
40
|
+
configurable: true,
|
|
41
|
+
writable: true,
|
|
42
|
+
value: void 0
|
|
43
|
+
});
|
|
44
|
+
Object.defineProperty(this, "queue", {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
configurable: true,
|
|
47
|
+
writable: true,
|
|
48
|
+
value: void 0
|
|
49
|
+
});
|
|
50
|
+
Object.defineProperty(this, "onFailedResponseHook", {
|
|
51
|
+
enumerable: true,
|
|
52
|
+
configurable: true,
|
|
53
|
+
writable: true,
|
|
54
|
+
value: void 0
|
|
55
|
+
});
|
|
56
|
+
this.maxConcurrency = params.maxConcurrency ?? 1 / 0;
|
|
57
|
+
this.maxRetries = params.maxRetries ?? 6;
|
|
58
|
+
if ("default" in dist) this.queue = new dist["default"]({
|
|
59
|
+
concurrency: this.maxConcurrency
|
|
60
|
+
});
|
|
61
|
+
else this.queue = new dist({
|
|
62
|
+
concurrency: this.maxConcurrency
|
|
63
|
+
});
|
|
64
|
+
this.onFailedResponseHook = params?.onFailedResponseHook;
|
|
65
|
+
}
|
|
66
|
+
call(callable, ...args) {
|
|
67
|
+
const onFailedResponseHook = this.onFailedResponseHook;
|
|
68
|
+
return this.queue.add(()=>p_retry(()=>callable(...args).catch((error)=>{
|
|
69
|
+
if (error instanceof Error) throw error;
|
|
70
|
+
throw new Error(error);
|
|
71
|
+
}), {
|
|
72
|
+
async onFailedAttempt (error) {
|
|
73
|
+
if (error.message.startsWith("Cancel") || error.message.startsWith("TimeoutError") || error.message.startsWith("AbortError")) throw error;
|
|
74
|
+
if (error?.code === "ECONNABORTED") throw error;
|
|
75
|
+
const response = error?.response;
|
|
76
|
+
const status = response?.status;
|
|
77
|
+
if (status) {
|
|
78
|
+
if (STATUS_NO_RETRY.includes(+status)) throw error;
|
|
79
|
+
if (STATUS_IGNORE.includes(+status)) return;
|
|
80
|
+
if (onFailedResponseHook) await onFailedResponseHook(response);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
retries: this.maxRetries,
|
|
84
|
+
randomize: true
|
|
85
|
+
}), {
|
|
86
|
+
throwOnTimeout: true
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
callWithOptions(options, callable, ...args) {
|
|
90
|
+
if (options.signal) return Promise.race([
|
|
91
|
+
this.call(callable, ...args),
|
|
92
|
+
new Promise((_, reject)=>{
|
|
93
|
+
options.signal?.addEventListener("abort", ()=>{
|
|
94
|
+
reject(new Error("AbortError"));
|
|
95
|
+
});
|
|
96
|
+
})
|
|
97
|
+
]);
|
|
98
|
+
return this.call(callable, ...args);
|
|
99
|
+
}
|
|
100
|
+
fetch(...args) {
|
|
101
|
+
return this.call(()=>_getFetchImplementation()(...args).then((res)=>res.ok ? res : Promise.reject(res)));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function isLangChainMessage(message) {
|
|
105
|
+
return "function" == typeof message?._getType;
|
|
106
|
+
}
|
|
107
|
+
function convertLangChainMessageToExample(message) {
|
|
108
|
+
const converted = {
|
|
109
|
+
type: message._getType(),
|
|
110
|
+
data: {
|
|
111
|
+
content: message.content
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
if (message?.additional_kwargs && Object.keys(message.additional_kwargs).length > 0) converted.data.additional_kwargs = {
|
|
115
|
+
...message.additional_kwargs
|
|
116
|
+
};
|
|
117
|
+
return converted;
|
|
118
|
+
}
|
|
119
|
+
var validate = __webpack_require__("../../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/validate.js");
|
|
120
|
+
function assertUuid(str, which) {
|
|
121
|
+
if (!validate.Z(str)) {
|
|
122
|
+
const msg = void 0 !== which ? `Invalid UUID for ${which}: ${str}` : `Invalid UUID: ${str}`;
|
|
123
|
+
throw new Error(msg);
|
|
124
|
+
}
|
|
125
|
+
return str;
|
|
126
|
+
}
|
|
127
|
+
const warnedMessages = {};
|
|
128
|
+
function warnOnce(message) {
|
|
129
|
+
if (!warnedMessages[message]) {
|
|
130
|
+
console.warn(message);
|
|
131
|
+
warnedMessages[message] = true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
__webpack_require__("../../node_modules/.pnpm/semver@7.7.2/node_modules/semver/index.js");
|
|
135
|
+
function parsePromptIdentifier(identifier) {
|
|
136
|
+
if (!identifier || identifier.split("/").length > 2 || identifier.startsWith("/") || identifier.endsWith("/") || identifier.split(":").length > 2) throw new Error(`Invalid identifier format: ${identifier}`);
|
|
137
|
+
const [ownerNamePart, commitPart] = identifier.split(":");
|
|
138
|
+
const commit = commitPart || "latest";
|
|
139
|
+
if (ownerNamePart.includes("/")) {
|
|
140
|
+
const [owner, name] = ownerNamePart.split("/", 2);
|
|
141
|
+
if (!owner || !name) throw new Error(`Invalid identifier format: ${identifier}`);
|
|
142
|
+
return [
|
|
143
|
+
owner,
|
|
144
|
+
name,
|
|
145
|
+
commit
|
|
146
|
+
];
|
|
147
|
+
}
|
|
148
|
+
if (!ownerNamePart) throw new Error(`Invalid identifier format: ${identifier}`);
|
|
149
|
+
return [
|
|
150
|
+
"-",
|
|
151
|
+
ownerNamePart,
|
|
152
|
+
commit
|
|
153
|
+
];
|
|
154
|
+
}
|
|
155
|
+
class LangSmithConflictError extends Error {
|
|
156
|
+
constructor(message){
|
|
157
|
+
super(message);
|
|
158
|
+
this.name = "LangSmithConflictError";
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function raiseForStatus(response, context, consume) {
|
|
162
|
+
let errorBody;
|
|
163
|
+
if (response.ok) {
|
|
164
|
+
if (consume) errorBody = await response.text();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
errorBody = await response.text();
|
|
168
|
+
const fullMessage = `Failed to ${context}. Received status [${response.status}]: ${response.statusText}. Server response: ${errorBody}`;
|
|
169
|
+
if (409 === response.status) throw new LangSmithConflictError(fullMessage);
|
|
170
|
+
throw new Error(fullMessage);
|
|
171
|
+
}
|
|
172
|
+
var LIMIT_REPLACE_NODE = "[...]";
|
|
173
|
+
var CIRCULAR_REPLACE_NODE = {
|
|
174
|
+
result: "[Circular]"
|
|
175
|
+
};
|
|
176
|
+
var arr = [];
|
|
177
|
+
var replacerStack = [];
|
|
178
|
+
const encoder = new TextEncoder();
|
|
179
|
+
function defaultOptions() {
|
|
180
|
+
return {
|
|
181
|
+
depthLimit: Number.MAX_SAFE_INTEGER,
|
|
182
|
+
edgesLimit: Number.MAX_SAFE_INTEGER
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function encodeString(str) {
|
|
186
|
+
return encoder.encode(str);
|
|
187
|
+
}
|
|
188
|
+
function serialize(obj, replacer, spacer, options) {
|
|
189
|
+
try {
|
|
190
|
+
const str = JSON.stringify(obj, replacer, spacer);
|
|
191
|
+
return encodeString(str);
|
|
192
|
+
} catch (e) {
|
|
193
|
+
if (!e.message?.includes("Converting circular structure to JSON")) {
|
|
194
|
+
console.warn("[WARNING]: LangSmith received unserializable value.");
|
|
195
|
+
return encodeString("[Unserializable]");
|
|
196
|
+
}
|
|
197
|
+
console.warn("[WARNING]: LangSmith received circular JSON. This will decrease tracer performance.");
|
|
198
|
+
if (void 0 === options) options = defaultOptions();
|
|
199
|
+
decirc(obj, "", 0, [], void 0, 0, options);
|
|
200
|
+
let res;
|
|
201
|
+
try {
|
|
202
|
+
res = 0 === replacerStack.length ? JSON.stringify(obj, replacer, spacer) : JSON.stringify(obj, replaceGetterValues(replacer), spacer);
|
|
203
|
+
} catch (_) {
|
|
204
|
+
return encodeString("[unable to serialize, circular reference is too complex to analyze]");
|
|
205
|
+
} finally{
|
|
206
|
+
while(0 !== arr.length){
|
|
207
|
+
const part = arr.pop();
|
|
208
|
+
if (4 === part.length) Object.defineProperty(part[0], part[1], part[3]);
|
|
209
|
+
else part[0][part[1]] = part[2];
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return encodeString(res);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function setReplace(replace, val, k, parent) {
|
|
216
|
+
var propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k);
|
|
217
|
+
if (void 0 !== propertyDescriptor.get) if (propertyDescriptor.configurable) {
|
|
218
|
+
Object.defineProperty(parent, k, {
|
|
219
|
+
value: replace
|
|
220
|
+
});
|
|
221
|
+
arr.push([
|
|
222
|
+
parent,
|
|
223
|
+
k,
|
|
224
|
+
val,
|
|
225
|
+
propertyDescriptor
|
|
226
|
+
]);
|
|
227
|
+
} else replacerStack.push([
|
|
228
|
+
val,
|
|
229
|
+
k,
|
|
230
|
+
replace
|
|
231
|
+
]);
|
|
232
|
+
else {
|
|
233
|
+
parent[k] = replace;
|
|
234
|
+
arr.push([
|
|
235
|
+
parent,
|
|
236
|
+
k,
|
|
237
|
+
val
|
|
238
|
+
]);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function decirc(val, k, edgeIndex, stack, parent, depth, options) {
|
|
242
|
+
depth += 1;
|
|
243
|
+
var i;
|
|
244
|
+
if ("object" == typeof val && null !== val) {
|
|
245
|
+
for(i = 0; i < stack.length; i++)if (stack[i] === val) return void setReplace(CIRCULAR_REPLACE_NODE, val, k, parent);
|
|
246
|
+
if (void 0 !== options.depthLimit && depth > options.depthLimit) return void setReplace(LIMIT_REPLACE_NODE, val, k, parent);
|
|
247
|
+
if (void 0 !== options.edgesLimit && edgeIndex + 1 > options.edgesLimit) return void setReplace(LIMIT_REPLACE_NODE, val, k, parent);
|
|
248
|
+
stack.push(val);
|
|
249
|
+
if (Array.isArray(val)) for(i = 0; i < val.length; i++)decirc(val[i], i, i, stack, val, depth, options);
|
|
250
|
+
else {
|
|
251
|
+
var keys = Object.keys(val);
|
|
252
|
+
for(i = 0; i < keys.length; i++){
|
|
253
|
+
var key = keys[i];
|
|
254
|
+
decirc(val[key], key, i, stack, val, depth, options);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
stack.pop();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function replaceGetterValues(replacer) {
|
|
261
|
+
replacer = void 0 !== replacer ? replacer : function(k, v) {
|
|
262
|
+
return v;
|
|
263
|
+
};
|
|
264
|
+
return function(key, val) {
|
|
265
|
+
if (replacerStack.length > 0) for(var i = 0; i < replacerStack.length; i++){
|
|
266
|
+
var part = replacerStack[i];
|
|
267
|
+
if (part[1] === key && part[0] === val) {
|
|
268
|
+
val = part[2];
|
|
269
|
+
replacerStack.splice(i, 1);
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return replacer.call(this, key, val);
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function mergeRuntimeEnvIntoRunCreate(run) {
|
|
277
|
+
const runtimeEnv = getRuntimeEnvironment();
|
|
278
|
+
const envVars = getLangChainEnvVarsMetadata();
|
|
279
|
+
const extra = run.extra ?? {};
|
|
280
|
+
const metadata = extra.metadata;
|
|
281
|
+
run.extra = {
|
|
282
|
+
...extra,
|
|
283
|
+
runtime: {
|
|
284
|
+
...runtimeEnv,
|
|
285
|
+
...extra?.runtime
|
|
286
|
+
},
|
|
287
|
+
metadata: {
|
|
288
|
+
...envVars,
|
|
289
|
+
...envVars.revision_id || run.revision_id ? {
|
|
290
|
+
revision_id: run.revision_id ?? envVars.revision_id
|
|
291
|
+
} : {},
|
|
292
|
+
...metadata
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
return run;
|
|
296
|
+
}
|
|
297
|
+
const getTracingSamplingRate = ()=>{
|
|
298
|
+
const samplingRateStr = getLangSmithEnvironmentVariable("TRACING_SAMPLING_RATE");
|
|
299
|
+
if (void 0 === samplingRateStr) return;
|
|
300
|
+
const samplingRate = parseFloat(samplingRateStr);
|
|
301
|
+
if (samplingRate < 0 || samplingRate > 1) throw new Error(`LANGSMITH_TRACING_SAMPLING_RATE must be between 0 and 1 if set. Got: ${samplingRate}`);
|
|
302
|
+
return samplingRate;
|
|
303
|
+
};
|
|
304
|
+
const isLocalhost = (url)=>{
|
|
305
|
+
const strippedUrl = url.replace("http://", "").replace("https://", "");
|
|
306
|
+
const hostname = strippedUrl.split("/")[0].split(":")[0];
|
|
307
|
+
return "localhost" === hostname || "127.0.0.1" === hostname || "::1" === hostname;
|
|
308
|
+
};
|
|
309
|
+
async function toArray(iterable) {
|
|
310
|
+
const result = [];
|
|
311
|
+
for await (const item of iterable)result.push(item);
|
|
312
|
+
return result;
|
|
313
|
+
}
|
|
314
|
+
function trimQuotes(str) {
|
|
315
|
+
if (void 0 === str) return;
|
|
316
|
+
return str.trim().replace(/^"(.*)"$/, "$1").replace(/^'(.*)'$/, "$1");
|
|
317
|
+
}
|
|
318
|
+
const handle429 = async (response)=>{
|
|
319
|
+
if (response?.status === 429) {
|
|
320
|
+
const retryAfter = 1000 * parseInt(response.headers.get("retry-after") ?? "30", 10);
|
|
321
|
+
if (retryAfter > 0) {
|
|
322
|
+
await new Promise((resolve)=>setTimeout(resolve, retryAfter));
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return false;
|
|
327
|
+
};
|
|
328
|
+
class AutoBatchQueue {
|
|
329
|
+
constructor(){
|
|
330
|
+
Object.defineProperty(this, "items", {
|
|
331
|
+
enumerable: true,
|
|
332
|
+
configurable: true,
|
|
333
|
+
writable: true,
|
|
334
|
+
value: []
|
|
335
|
+
});
|
|
336
|
+
Object.defineProperty(this, "sizeBytes", {
|
|
337
|
+
enumerable: true,
|
|
338
|
+
configurable: true,
|
|
339
|
+
writable: true,
|
|
340
|
+
value: 0
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
peek() {
|
|
344
|
+
return this.items[0];
|
|
345
|
+
}
|
|
346
|
+
push(item) {
|
|
347
|
+
let itemPromiseResolve;
|
|
348
|
+
const itemPromise = new Promise((resolve)=>{
|
|
349
|
+
itemPromiseResolve = resolve;
|
|
350
|
+
});
|
|
351
|
+
const size = serialize(item.item).length;
|
|
352
|
+
this.items.push({
|
|
353
|
+
action: item.action,
|
|
354
|
+
payload: item.item,
|
|
355
|
+
itemPromiseResolve: itemPromiseResolve,
|
|
356
|
+
itemPromise,
|
|
357
|
+
size
|
|
358
|
+
});
|
|
359
|
+
this.sizeBytes += size;
|
|
360
|
+
return itemPromise;
|
|
361
|
+
}
|
|
362
|
+
pop(upToSizeBytes) {
|
|
363
|
+
if (upToSizeBytes < 1) throw new Error("Number of bytes to pop off may not be less than 1.");
|
|
364
|
+
const popped = [];
|
|
365
|
+
let poppedSizeBytes = 0;
|
|
366
|
+
while(poppedSizeBytes + (this.peek()?.size ?? 0) < upToSizeBytes && this.items.length > 0){
|
|
367
|
+
const item = this.items.shift();
|
|
368
|
+
if (item) {
|
|
369
|
+
popped.push(item);
|
|
370
|
+
poppedSizeBytes += item.size;
|
|
371
|
+
this.sizeBytes -= item.size;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (0 === popped.length && this.items.length > 0) {
|
|
375
|
+
const item = this.items.shift();
|
|
376
|
+
popped.push(item);
|
|
377
|
+
poppedSizeBytes += item.size;
|
|
378
|
+
this.sizeBytes -= item.size;
|
|
379
|
+
}
|
|
380
|
+
return [
|
|
381
|
+
popped.map((it)=>({
|
|
382
|
+
action: it.action,
|
|
383
|
+
item: it.payload
|
|
384
|
+
})),
|
|
385
|
+
()=>popped.forEach((it)=>it.itemPromiseResolve())
|
|
386
|
+
];
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
const DEFAULT_BATCH_SIZE_LIMIT_BYTES = 20971520;
|
|
390
|
+
const SERVER_INFO_REQUEST_TIMEOUT = 2500;
|
|
391
|
+
class Client {
|
|
392
|
+
constructor(config = {}){
|
|
393
|
+
Object.defineProperty(this, "apiKey", {
|
|
394
|
+
enumerable: true,
|
|
395
|
+
configurable: true,
|
|
396
|
+
writable: true,
|
|
397
|
+
value: void 0
|
|
398
|
+
});
|
|
399
|
+
Object.defineProperty(this, "apiUrl", {
|
|
400
|
+
enumerable: true,
|
|
401
|
+
configurable: true,
|
|
402
|
+
writable: true,
|
|
403
|
+
value: void 0
|
|
404
|
+
});
|
|
405
|
+
Object.defineProperty(this, "webUrl", {
|
|
406
|
+
enumerable: true,
|
|
407
|
+
configurable: true,
|
|
408
|
+
writable: true,
|
|
409
|
+
value: void 0
|
|
410
|
+
});
|
|
411
|
+
Object.defineProperty(this, "caller", {
|
|
412
|
+
enumerable: true,
|
|
413
|
+
configurable: true,
|
|
414
|
+
writable: true,
|
|
415
|
+
value: void 0
|
|
416
|
+
});
|
|
417
|
+
Object.defineProperty(this, "batchIngestCaller", {
|
|
418
|
+
enumerable: true,
|
|
419
|
+
configurable: true,
|
|
420
|
+
writable: true,
|
|
421
|
+
value: void 0
|
|
422
|
+
});
|
|
423
|
+
Object.defineProperty(this, "timeout_ms", {
|
|
424
|
+
enumerable: true,
|
|
425
|
+
configurable: true,
|
|
426
|
+
writable: true,
|
|
427
|
+
value: void 0
|
|
428
|
+
});
|
|
429
|
+
Object.defineProperty(this, "_tenantId", {
|
|
430
|
+
enumerable: true,
|
|
431
|
+
configurable: true,
|
|
432
|
+
writable: true,
|
|
433
|
+
value: null
|
|
434
|
+
});
|
|
435
|
+
Object.defineProperty(this, "hideInputs", {
|
|
436
|
+
enumerable: true,
|
|
437
|
+
configurable: true,
|
|
438
|
+
writable: true,
|
|
439
|
+
value: void 0
|
|
440
|
+
});
|
|
441
|
+
Object.defineProperty(this, "hideOutputs", {
|
|
442
|
+
enumerable: true,
|
|
443
|
+
configurable: true,
|
|
444
|
+
writable: true,
|
|
445
|
+
value: void 0
|
|
446
|
+
});
|
|
447
|
+
Object.defineProperty(this, "tracingSampleRate", {
|
|
448
|
+
enumerable: true,
|
|
449
|
+
configurable: true,
|
|
450
|
+
writable: true,
|
|
451
|
+
value: void 0
|
|
452
|
+
});
|
|
453
|
+
Object.defineProperty(this, "filteredPostUuids", {
|
|
454
|
+
enumerable: true,
|
|
455
|
+
configurable: true,
|
|
456
|
+
writable: true,
|
|
457
|
+
value: new Set()
|
|
458
|
+
});
|
|
459
|
+
Object.defineProperty(this, "autoBatchTracing", {
|
|
460
|
+
enumerable: true,
|
|
461
|
+
configurable: true,
|
|
462
|
+
writable: true,
|
|
463
|
+
value: true
|
|
464
|
+
});
|
|
465
|
+
Object.defineProperty(this, "autoBatchQueue", {
|
|
466
|
+
enumerable: true,
|
|
467
|
+
configurable: true,
|
|
468
|
+
writable: true,
|
|
469
|
+
value: new AutoBatchQueue()
|
|
470
|
+
});
|
|
471
|
+
Object.defineProperty(this, "autoBatchTimeout", {
|
|
472
|
+
enumerable: true,
|
|
473
|
+
configurable: true,
|
|
474
|
+
writable: true,
|
|
475
|
+
value: void 0
|
|
476
|
+
});
|
|
477
|
+
Object.defineProperty(this, "autoBatchAggregationDelayMs", {
|
|
478
|
+
enumerable: true,
|
|
479
|
+
configurable: true,
|
|
480
|
+
writable: true,
|
|
481
|
+
value: 250
|
|
482
|
+
});
|
|
483
|
+
Object.defineProperty(this, "batchSizeBytesLimit", {
|
|
484
|
+
enumerable: true,
|
|
485
|
+
configurable: true,
|
|
486
|
+
writable: true,
|
|
487
|
+
value: void 0
|
|
488
|
+
});
|
|
489
|
+
Object.defineProperty(this, "fetchOptions", {
|
|
490
|
+
enumerable: true,
|
|
491
|
+
configurable: true,
|
|
492
|
+
writable: true,
|
|
493
|
+
value: void 0
|
|
494
|
+
});
|
|
495
|
+
Object.defineProperty(this, "settings", {
|
|
496
|
+
enumerable: true,
|
|
497
|
+
configurable: true,
|
|
498
|
+
writable: true,
|
|
499
|
+
value: void 0
|
|
500
|
+
});
|
|
501
|
+
Object.defineProperty(this, "blockOnRootRunFinalization", {
|
|
502
|
+
enumerable: true,
|
|
503
|
+
configurable: true,
|
|
504
|
+
writable: true,
|
|
505
|
+
value: "false" === getEnvironmentVariable("LANGSMITH_TRACING_BACKGROUND")
|
|
506
|
+
});
|
|
507
|
+
Object.defineProperty(this, "traceBatchConcurrency", {
|
|
508
|
+
enumerable: true,
|
|
509
|
+
configurable: true,
|
|
510
|
+
writable: true,
|
|
511
|
+
value: 5
|
|
512
|
+
});
|
|
513
|
+
Object.defineProperty(this, "_serverInfo", {
|
|
514
|
+
enumerable: true,
|
|
515
|
+
configurable: true,
|
|
516
|
+
writable: true,
|
|
517
|
+
value: void 0
|
|
518
|
+
});
|
|
519
|
+
Object.defineProperty(this, "_getServerInfoPromise", {
|
|
520
|
+
enumerable: true,
|
|
521
|
+
configurable: true,
|
|
522
|
+
writable: true,
|
|
523
|
+
value: void 0
|
|
524
|
+
});
|
|
525
|
+
Object.defineProperty(this, "manualFlushMode", {
|
|
526
|
+
enumerable: true,
|
|
527
|
+
configurable: true,
|
|
528
|
+
writable: true,
|
|
529
|
+
value: false
|
|
530
|
+
});
|
|
531
|
+
const defaultConfig = Client.getDefaultClientConfig();
|
|
532
|
+
this.tracingSampleRate = getTracingSamplingRate();
|
|
533
|
+
this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
|
|
534
|
+
if (this.apiUrl.endsWith("/")) this.apiUrl = this.apiUrl.slice(0, -1);
|
|
535
|
+
this.apiKey = trimQuotes(config.apiKey ?? defaultConfig.apiKey);
|
|
536
|
+
this.webUrl = trimQuotes(config.webUrl ?? defaultConfig.webUrl);
|
|
537
|
+
if (this.webUrl?.endsWith("/")) this.webUrl = this.webUrl.slice(0, -1);
|
|
538
|
+
this.timeout_ms = config.timeout_ms ?? 90000;
|
|
539
|
+
this.caller = new AsyncCaller(config.callerOptions ?? {});
|
|
540
|
+
this.traceBatchConcurrency = config.traceBatchConcurrency ?? this.traceBatchConcurrency;
|
|
541
|
+
if (this.traceBatchConcurrency < 1) throw new Error("Trace batch concurrency must be positive.");
|
|
542
|
+
this.batchIngestCaller = new AsyncCaller({
|
|
543
|
+
maxRetries: 2,
|
|
544
|
+
maxConcurrency: this.traceBatchConcurrency,
|
|
545
|
+
...config.callerOptions ?? {},
|
|
546
|
+
onFailedResponseHook: handle429
|
|
547
|
+
});
|
|
548
|
+
this.hideInputs = config.hideInputs ?? config.anonymizer ?? defaultConfig.hideInputs;
|
|
549
|
+
this.hideOutputs = config.hideOutputs ?? config.anonymizer ?? defaultConfig.hideOutputs;
|
|
550
|
+
this.autoBatchTracing = config.autoBatchTracing ?? this.autoBatchTracing;
|
|
551
|
+
this.blockOnRootRunFinalization = config.blockOnRootRunFinalization ?? this.blockOnRootRunFinalization;
|
|
552
|
+
this.batchSizeBytesLimit = config.batchSizeBytesLimit;
|
|
553
|
+
this.fetchOptions = config.fetchOptions || {};
|
|
554
|
+
this.manualFlushMode = config.manualFlushMode ?? this.manualFlushMode;
|
|
555
|
+
}
|
|
556
|
+
static getDefaultClientConfig() {
|
|
557
|
+
const apiKey = getLangSmithEnvironmentVariable("API_KEY");
|
|
558
|
+
const apiUrl = getLangSmithEnvironmentVariable("ENDPOINT") ?? "https://api.smith.langchain.com";
|
|
559
|
+
const hideInputs = "true" === getLangSmithEnvironmentVariable("HIDE_INPUTS");
|
|
560
|
+
const hideOutputs = "true" === getLangSmithEnvironmentVariable("HIDE_OUTPUTS");
|
|
561
|
+
return {
|
|
562
|
+
apiUrl: apiUrl,
|
|
563
|
+
apiKey: apiKey,
|
|
564
|
+
webUrl: void 0,
|
|
565
|
+
hideInputs: hideInputs,
|
|
566
|
+
hideOutputs: hideOutputs
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
getHostUrl() {
|
|
570
|
+
if (this.webUrl) return this.webUrl;
|
|
571
|
+
if (isLocalhost(this.apiUrl)) {
|
|
572
|
+
this.webUrl = "http://localhost:3000";
|
|
573
|
+
return this.webUrl;
|
|
574
|
+
}
|
|
575
|
+
if (this.apiUrl.endsWith("/api/v1")) {
|
|
576
|
+
this.webUrl = this.apiUrl.replace("/api/v1", "");
|
|
577
|
+
return this.webUrl;
|
|
578
|
+
}
|
|
579
|
+
if (this.apiUrl.includes("/api") && !this.apiUrl.split(".", 1)[0].endsWith("api")) {
|
|
580
|
+
this.webUrl = this.apiUrl.replace("/api", "");
|
|
581
|
+
return this.webUrl;
|
|
582
|
+
}
|
|
583
|
+
if (this.apiUrl.split(".", 1)[0].includes("dev")) {
|
|
584
|
+
this.webUrl = "https://dev.smith.langchain.com";
|
|
585
|
+
return this.webUrl;
|
|
586
|
+
} else if (this.apiUrl.split(".", 1)[0].includes("eu")) {
|
|
587
|
+
this.webUrl = "https://eu.smith.langchain.com";
|
|
588
|
+
return this.webUrl;
|
|
589
|
+
} else if (this.apiUrl.split(".", 1)[0].includes("beta")) {
|
|
590
|
+
this.webUrl = "https://beta.smith.langchain.com";
|
|
591
|
+
return this.webUrl;
|
|
592
|
+
} else {
|
|
593
|
+
this.webUrl = "https://smith.langchain.com";
|
|
594
|
+
return this.webUrl;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
get headers() {
|
|
598
|
+
const headers = {
|
|
599
|
+
"User-Agent": `langsmith-js/${__version__}`
|
|
600
|
+
};
|
|
601
|
+
if (this.apiKey) headers["x-api-key"] = `${this.apiKey}`;
|
|
602
|
+
return headers;
|
|
603
|
+
}
|
|
604
|
+
processInputs(inputs) {
|
|
605
|
+
if (false === this.hideInputs) return inputs;
|
|
606
|
+
if (true === this.hideInputs) return {};
|
|
607
|
+
if ("function" == typeof this.hideInputs) return this.hideInputs(inputs);
|
|
608
|
+
return inputs;
|
|
609
|
+
}
|
|
610
|
+
processOutputs(outputs) {
|
|
611
|
+
if (false === this.hideOutputs) return outputs;
|
|
612
|
+
if (true === this.hideOutputs) return {};
|
|
613
|
+
if ("function" == typeof this.hideOutputs) return this.hideOutputs(outputs);
|
|
614
|
+
return outputs;
|
|
615
|
+
}
|
|
616
|
+
prepareRunCreateOrUpdateInputs(run) {
|
|
617
|
+
const runParams = {
|
|
618
|
+
...run
|
|
619
|
+
};
|
|
620
|
+
if (void 0 !== runParams.inputs) runParams.inputs = this.processInputs(runParams.inputs);
|
|
621
|
+
if (void 0 !== runParams.outputs) runParams.outputs = this.processOutputs(runParams.outputs);
|
|
622
|
+
return runParams;
|
|
623
|
+
}
|
|
624
|
+
async _getResponse(path, queryParams) {
|
|
625
|
+
const paramsString = queryParams?.toString() ?? "";
|
|
626
|
+
const url = `${this.apiUrl}${path}?${paramsString}`;
|
|
627
|
+
const response = await this.caller.call(_getFetchImplementation(), url, {
|
|
628
|
+
method: "GET",
|
|
629
|
+
headers: this.headers,
|
|
630
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
631
|
+
...this.fetchOptions
|
|
632
|
+
});
|
|
633
|
+
await raiseForStatus(response, `Failed to fetch ${path}`);
|
|
634
|
+
return response;
|
|
635
|
+
}
|
|
636
|
+
async _get(path, queryParams) {
|
|
637
|
+
const response = await this._getResponse(path, queryParams);
|
|
638
|
+
return response.json();
|
|
639
|
+
}
|
|
640
|
+
async *_getPaginated(path, queryParams = new URLSearchParams(), transform) {
|
|
641
|
+
let offset = Number(queryParams.get("offset")) || 0;
|
|
642
|
+
const limit = Number(queryParams.get("limit")) || 100;
|
|
643
|
+
while(true){
|
|
644
|
+
queryParams.set("offset", String(offset));
|
|
645
|
+
queryParams.set("limit", String(limit));
|
|
646
|
+
const url = `${this.apiUrl}${path}?${queryParams}`;
|
|
647
|
+
const response = await this.caller.call(_getFetchImplementation(), url, {
|
|
648
|
+
method: "GET",
|
|
649
|
+
headers: this.headers,
|
|
650
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
651
|
+
...this.fetchOptions
|
|
652
|
+
});
|
|
653
|
+
await raiseForStatus(response, `Failed to fetch ${path}`);
|
|
654
|
+
const items = transform ? transform(await response.json()) : await response.json();
|
|
655
|
+
if (0 === items.length) break;
|
|
656
|
+
yield items;
|
|
657
|
+
if (items.length < limit) break;
|
|
658
|
+
offset += items.length;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
async *_getCursorPaginatedList(path, body = null, requestMethod = "POST", dataKey = "runs") {
|
|
662
|
+
const bodyParams = body ? {
|
|
663
|
+
...body
|
|
664
|
+
} : {};
|
|
665
|
+
while(true){
|
|
666
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}${path}`, {
|
|
667
|
+
method: requestMethod,
|
|
668
|
+
headers: {
|
|
669
|
+
...this.headers,
|
|
670
|
+
"Content-Type": "application/json"
|
|
671
|
+
},
|
|
672
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
673
|
+
...this.fetchOptions,
|
|
674
|
+
body: JSON.stringify(bodyParams)
|
|
675
|
+
});
|
|
676
|
+
const responseBody = await response.json();
|
|
677
|
+
if (!responseBody) break;
|
|
678
|
+
if (!responseBody[dataKey]) break;
|
|
679
|
+
yield responseBody[dataKey];
|
|
680
|
+
const cursors = responseBody.cursors;
|
|
681
|
+
if (!cursors) break;
|
|
682
|
+
if (!cursors.next) break;
|
|
683
|
+
bodyParams.cursor = cursors.next;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
_filterForSampling(runs, patch = false) {
|
|
687
|
+
if (void 0 === this.tracingSampleRate) return runs;
|
|
688
|
+
if (patch) {
|
|
689
|
+
const sampled = [];
|
|
690
|
+
for (const run of runs)if (this.filteredPostUuids.has(run.id)) this.filteredPostUuids.delete(run.id);
|
|
691
|
+
else sampled.push(run);
|
|
692
|
+
return sampled;
|
|
693
|
+
}
|
|
694
|
+
{
|
|
695
|
+
const sampled = [];
|
|
696
|
+
for (const run of runs)if (run.id !== run.trace_id && !this.filteredPostUuids.has(run.trace_id) || Math.random() < this.tracingSampleRate) sampled.push(run);
|
|
697
|
+
else this.filteredPostUuids.add(run.id);
|
|
698
|
+
return sampled;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
async _getBatchSizeLimitBytes() {
|
|
702
|
+
const serverInfo = await this._ensureServerInfo();
|
|
703
|
+
return this.batchSizeBytesLimit ?? serverInfo.batch_ingest_config?.size_limit_bytes ?? DEFAULT_BATCH_SIZE_LIMIT_BYTES;
|
|
704
|
+
}
|
|
705
|
+
async _getMultiPartSupport() {
|
|
706
|
+
const serverInfo = await this._ensureServerInfo();
|
|
707
|
+
return serverInfo.instance_flags?.dataset_examples_multipart_enabled ?? false;
|
|
708
|
+
}
|
|
709
|
+
drainAutoBatchQueue(batchSizeLimit) {
|
|
710
|
+
const promises = [];
|
|
711
|
+
while(this.autoBatchQueue.items.length > 0){
|
|
712
|
+
const [batch, done] = this.autoBatchQueue.pop(batchSizeLimit);
|
|
713
|
+
if (!batch.length) {
|
|
714
|
+
done();
|
|
715
|
+
break;
|
|
716
|
+
}
|
|
717
|
+
const batchPromise = this._processBatch(batch, done).catch(console.error);
|
|
718
|
+
promises.push(batchPromise);
|
|
719
|
+
}
|
|
720
|
+
return Promise.all(promises);
|
|
721
|
+
}
|
|
722
|
+
async _processBatch(batch, done) {
|
|
723
|
+
if (!batch.length) return void done();
|
|
724
|
+
try {
|
|
725
|
+
const ingestParams = {
|
|
726
|
+
runCreates: batch.filter((item)=>"create" === item.action).map((item)=>item.item),
|
|
727
|
+
runUpdates: batch.filter((item)=>"update" === item.action).map((item)=>item.item)
|
|
728
|
+
};
|
|
729
|
+
const serverInfo = await this._ensureServerInfo();
|
|
730
|
+
if (serverInfo?.batch_ingest_config?.use_multipart_endpoint) await this.multipartIngestRuns(ingestParams);
|
|
731
|
+
else await this.batchIngestRuns(ingestParams);
|
|
732
|
+
} finally{
|
|
733
|
+
done();
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async processRunOperation(item) {
|
|
737
|
+
clearTimeout(this.autoBatchTimeout);
|
|
738
|
+
this.autoBatchTimeout = void 0;
|
|
739
|
+
if ("create" === item.action) item.item = mergeRuntimeEnvIntoRunCreate(item.item);
|
|
740
|
+
const itemPromise = this.autoBatchQueue.push(item);
|
|
741
|
+
if (this.manualFlushMode) return itemPromise;
|
|
742
|
+
const sizeLimitBytes = await this._getBatchSizeLimitBytes();
|
|
743
|
+
if (this.autoBatchQueue.sizeBytes > sizeLimitBytes) this.drainAutoBatchQueue(sizeLimitBytes);
|
|
744
|
+
if (this.autoBatchQueue.items.length > 0) this.autoBatchTimeout = setTimeout(()=>{
|
|
745
|
+
this.autoBatchTimeout = void 0;
|
|
746
|
+
this.drainAutoBatchQueue(sizeLimitBytes);
|
|
747
|
+
}, this.autoBatchAggregationDelayMs);
|
|
748
|
+
return itemPromise;
|
|
749
|
+
}
|
|
750
|
+
async _getServerInfo() {
|
|
751
|
+
const response = await _getFetchImplementation()(`${this.apiUrl}/info`, {
|
|
752
|
+
method: "GET",
|
|
753
|
+
headers: {
|
|
754
|
+
Accept: "application/json"
|
|
755
|
+
},
|
|
756
|
+
signal: AbortSignal.timeout(SERVER_INFO_REQUEST_TIMEOUT),
|
|
757
|
+
...this.fetchOptions
|
|
758
|
+
});
|
|
759
|
+
await raiseForStatus(response, "get server info");
|
|
760
|
+
return response.json();
|
|
761
|
+
}
|
|
762
|
+
async _ensureServerInfo() {
|
|
763
|
+
if (void 0 === this._getServerInfoPromise) this._getServerInfoPromise = (async ()=>{
|
|
764
|
+
if (void 0 === this._serverInfo) try {
|
|
765
|
+
this._serverInfo = await this._getServerInfo();
|
|
766
|
+
} catch (e) {
|
|
767
|
+
console.warn("[WARNING]: LangSmith failed to fetch info on supported operations. Falling back to batch operations and default limits.");
|
|
768
|
+
}
|
|
769
|
+
return this._serverInfo ?? {};
|
|
770
|
+
})();
|
|
771
|
+
return this._getServerInfoPromise.then((serverInfo)=>{
|
|
772
|
+
if (void 0 === this._serverInfo) this._getServerInfoPromise = void 0;
|
|
773
|
+
return serverInfo;
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
async _getSettings() {
|
|
777
|
+
if (!this.settings) this.settings = this._get("/settings");
|
|
778
|
+
return await this.settings;
|
|
779
|
+
}
|
|
780
|
+
async flush() {
|
|
781
|
+
const sizeLimitBytes = await this._getBatchSizeLimitBytes();
|
|
782
|
+
await this.drainAutoBatchQueue(sizeLimitBytes);
|
|
783
|
+
}
|
|
784
|
+
async createRun(run) {
|
|
785
|
+
if (!this._filterForSampling([
|
|
786
|
+
run
|
|
787
|
+
]).length) return;
|
|
788
|
+
const headers = {
|
|
789
|
+
...this.headers,
|
|
790
|
+
"Content-Type": "application/json"
|
|
791
|
+
};
|
|
792
|
+
const session_name = run.project_name;
|
|
793
|
+
delete run.project_name;
|
|
794
|
+
const runCreate = this.prepareRunCreateOrUpdateInputs({
|
|
795
|
+
session_name,
|
|
796
|
+
...run,
|
|
797
|
+
start_time: run.start_time ?? Date.now()
|
|
798
|
+
});
|
|
799
|
+
if (this.autoBatchTracing && void 0 !== runCreate.trace_id && void 0 !== runCreate.dotted_order) return void this.processRunOperation({
|
|
800
|
+
action: "create",
|
|
801
|
+
item: runCreate
|
|
802
|
+
}).catch(console.error);
|
|
803
|
+
const mergedRunCreateParam = mergeRuntimeEnvIntoRunCreate(runCreate);
|
|
804
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/runs`, {
|
|
805
|
+
method: "POST",
|
|
806
|
+
headers,
|
|
807
|
+
body: serialize(mergedRunCreateParam),
|
|
808
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
809
|
+
...this.fetchOptions
|
|
810
|
+
});
|
|
811
|
+
await raiseForStatus(response, "create run", true);
|
|
812
|
+
}
|
|
813
|
+
async batchIngestRuns({ runCreates, runUpdates }) {
|
|
814
|
+
if (void 0 === runCreates && void 0 === runUpdates) return;
|
|
815
|
+
let preparedCreateParams = runCreates?.map((create)=>this.prepareRunCreateOrUpdateInputs(create)) ?? [];
|
|
816
|
+
let preparedUpdateParams = runUpdates?.map((update)=>this.prepareRunCreateOrUpdateInputs(update)) ?? [];
|
|
817
|
+
if (preparedCreateParams.length > 0 && preparedUpdateParams.length > 0) {
|
|
818
|
+
const createById = preparedCreateParams.reduce((params, run)=>{
|
|
819
|
+
if (!run.id) return params;
|
|
820
|
+
params[run.id] = run;
|
|
821
|
+
return params;
|
|
822
|
+
}, {});
|
|
823
|
+
const standaloneUpdates = [];
|
|
824
|
+
for (const updateParam of preparedUpdateParams)if (void 0 !== updateParam.id && createById[updateParam.id]) createById[updateParam.id] = {
|
|
825
|
+
...createById[updateParam.id],
|
|
826
|
+
...updateParam
|
|
827
|
+
};
|
|
828
|
+
else standaloneUpdates.push(updateParam);
|
|
829
|
+
preparedCreateParams = Object.values(createById);
|
|
830
|
+
preparedUpdateParams = standaloneUpdates;
|
|
831
|
+
}
|
|
832
|
+
const rawBatch = {
|
|
833
|
+
post: this._filterForSampling(preparedCreateParams),
|
|
834
|
+
patch: this._filterForSampling(preparedUpdateParams, true)
|
|
835
|
+
};
|
|
836
|
+
if (!rawBatch.post.length && !rawBatch.patch.length) return;
|
|
837
|
+
const batchChunks = {
|
|
838
|
+
post: [],
|
|
839
|
+
patch: []
|
|
840
|
+
};
|
|
841
|
+
for (const k of [
|
|
842
|
+
"post",
|
|
843
|
+
"patch"
|
|
844
|
+
]){
|
|
845
|
+
const key = k;
|
|
846
|
+
const batchItems = rawBatch[key].reverse();
|
|
847
|
+
let batchItem = batchItems.pop();
|
|
848
|
+
while(void 0 !== batchItem){
|
|
849
|
+
batchChunks[key].push(batchItem);
|
|
850
|
+
batchItem = batchItems.pop();
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
if (batchChunks.post.length > 0 || batchChunks.patch.length > 0) await this._postBatchIngestRuns(serialize(batchChunks));
|
|
854
|
+
}
|
|
855
|
+
async _postBatchIngestRuns(body) {
|
|
856
|
+
const headers = {
|
|
857
|
+
...this.headers,
|
|
858
|
+
"Content-Type": "application/json",
|
|
859
|
+
Accept: "application/json"
|
|
860
|
+
};
|
|
861
|
+
const response = await this.batchIngestCaller.call(_getFetchImplementation(), `${this.apiUrl}/runs/batch`, {
|
|
862
|
+
method: "POST",
|
|
863
|
+
headers,
|
|
864
|
+
body: body,
|
|
865
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
866
|
+
...this.fetchOptions
|
|
867
|
+
});
|
|
868
|
+
await raiseForStatus(response, "batch create run", true);
|
|
869
|
+
}
|
|
870
|
+
async multipartIngestRuns({ runCreates, runUpdates }) {
|
|
871
|
+
if (void 0 === runCreates && void 0 === runUpdates) return;
|
|
872
|
+
const allAttachments = {};
|
|
873
|
+
let preparedCreateParams = [];
|
|
874
|
+
for (const create of runCreates ?? []){
|
|
875
|
+
const preparedCreate = this.prepareRunCreateOrUpdateInputs(create);
|
|
876
|
+
if (void 0 !== preparedCreate.id && void 0 !== preparedCreate.attachments) allAttachments[preparedCreate.id] = preparedCreate.attachments;
|
|
877
|
+
delete preparedCreate.attachments;
|
|
878
|
+
preparedCreateParams.push(preparedCreate);
|
|
879
|
+
}
|
|
880
|
+
let preparedUpdateParams = [];
|
|
881
|
+
for (const update of runUpdates ?? [])preparedUpdateParams.push(this.prepareRunCreateOrUpdateInputs(update));
|
|
882
|
+
const invalidRunCreate = preparedCreateParams.find((runCreate)=>void 0 === runCreate.trace_id || void 0 === runCreate.dotted_order);
|
|
883
|
+
if (void 0 !== invalidRunCreate) throw new Error('Multipart ingest requires "trace_id" and "dotted_order" to be set when creating a run');
|
|
884
|
+
const invalidRunUpdate = preparedUpdateParams.find((runUpdate)=>void 0 === runUpdate.trace_id || void 0 === runUpdate.dotted_order);
|
|
885
|
+
if (void 0 !== invalidRunUpdate) throw new Error('Multipart ingest requires "trace_id" and "dotted_order" to be set when updating a run');
|
|
886
|
+
if (preparedCreateParams.length > 0 && preparedUpdateParams.length > 0) {
|
|
887
|
+
const createById = preparedCreateParams.reduce((params, run)=>{
|
|
888
|
+
if (!run.id) return params;
|
|
889
|
+
params[run.id] = run;
|
|
890
|
+
return params;
|
|
891
|
+
}, {});
|
|
892
|
+
const standaloneUpdates = [];
|
|
893
|
+
for (const updateParam of preparedUpdateParams)if (void 0 !== updateParam.id && createById[updateParam.id]) createById[updateParam.id] = {
|
|
894
|
+
...createById[updateParam.id],
|
|
895
|
+
...updateParam
|
|
896
|
+
};
|
|
897
|
+
else standaloneUpdates.push(updateParam);
|
|
898
|
+
preparedCreateParams = Object.values(createById);
|
|
899
|
+
preparedUpdateParams = standaloneUpdates;
|
|
900
|
+
}
|
|
901
|
+
if (0 === preparedCreateParams.length && 0 === preparedUpdateParams.length) return;
|
|
902
|
+
const accumulatedContext = [];
|
|
903
|
+
const accumulatedParts = [];
|
|
904
|
+
for (const [method, payloads] of [
|
|
905
|
+
[
|
|
906
|
+
"post",
|
|
907
|
+
preparedCreateParams
|
|
908
|
+
],
|
|
909
|
+
[
|
|
910
|
+
"patch",
|
|
911
|
+
preparedUpdateParams
|
|
912
|
+
]
|
|
913
|
+
])for (const originalPayload of payloads){
|
|
914
|
+
const { inputs, outputs, events, attachments, ...payload } = originalPayload;
|
|
915
|
+
const fields = {
|
|
916
|
+
inputs,
|
|
917
|
+
outputs,
|
|
918
|
+
events
|
|
919
|
+
};
|
|
920
|
+
const stringifiedPayload = serialize(payload);
|
|
921
|
+
accumulatedParts.push({
|
|
922
|
+
name: `${method}.${payload.id}`,
|
|
923
|
+
payload: new Blob([
|
|
924
|
+
stringifiedPayload
|
|
925
|
+
], {
|
|
926
|
+
type: `application/json; length=${stringifiedPayload.length}`
|
|
927
|
+
})
|
|
928
|
+
});
|
|
929
|
+
for (const [key, value] of Object.entries(fields)){
|
|
930
|
+
if (void 0 === value) continue;
|
|
931
|
+
const stringifiedValue = serialize(value);
|
|
932
|
+
accumulatedParts.push({
|
|
933
|
+
name: `${method}.${payload.id}.${key}`,
|
|
934
|
+
payload: new Blob([
|
|
935
|
+
stringifiedValue
|
|
936
|
+
], {
|
|
937
|
+
type: `application/json; length=${stringifiedValue.length}`
|
|
938
|
+
})
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
if (void 0 !== payload.id) {
|
|
942
|
+
const attachments = allAttachments[payload.id];
|
|
943
|
+
if (attachments) {
|
|
944
|
+
delete allAttachments[payload.id];
|
|
945
|
+
for (const [name, attachment] of Object.entries(attachments)){
|
|
946
|
+
let contentType;
|
|
947
|
+
let content;
|
|
948
|
+
if (Array.isArray(attachment)) [contentType, content] = attachment;
|
|
949
|
+
else {
|
|
950
|
+
contentType = attachment.mimeType;
|
|
951
|
+
content = attachment.data;
|
|
952
|
+
}
|
|
953
|
+
if (name.includes(".")) {
|
|
954
|
+
console.warn(`Skipping attachment '${name}' for run ${payload.id}: Invalid attachment name. Attachment names must not contain periods ('.'). Please rename the attachment and try again.`);
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
957
|
+
accumulatedParts.push({
|
|
958
|
+
name: `attachment.${payload.id}.${name}`,
|
|
959
|
+
payload: new Blob([
|
|
960
|
+
content
|
|
961
|
+
], {
|
|
962
|
+
type: `${contentType}; length=${content.byteLength}`
|
|
963
|
+
})
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
accumulatedContext.push(`trace=${payload.trace_id},id=${payload.id}`);
|
|
969
|
+
}
|
|
970
|
+
await this._sendMultipartRequest(accumulatedParts, accumulatedContext.join("; "));
|
|
971
|
+
}
|
|
972
|
+
async _sendMultipartRequest(parts, context) {
|
|
973
|
+
try {
|
|
974
|
+
const boundary = "----LangSmithFormBoundary" + Math.random().toString(36).slice(2);
|
|
975
|
+
const chunks = [];
|
|
976
|
+
for (const part of parts){
|
|
977
|
+
chunks.push(new Blob([
|
|
978
|
+
`--${boundary}\r\n`
|
|
979
|
+
]));
|
|
980
|
+
chunks.push(new Blob([
|
|
981
|
+
`Content-Disposition: form-data; name="${part.name}"\r\n`,
|
|
982
|
+
`Content-Type: ${part.payload.type}\r\n\r\n`
|
|
983
|
+
]));
|
|
984
|
+
chunks.push(part.payload);
|
|
985
|
+
chunks.push(new Blob([
|
|
986
|
+
"\r\n"
|
|
987
|
+
]));
|
|
988
|
+
}
|
|
989
|
+
chunks.push(new Blob([
|
|
990
|
+
`--${boundary}--\r\n`
|
|
991
|
+
]));
|
|
992
|
+
const body = new Blob(chunks);
|
|
993
|
+
const arrayBuffer = await body.arrayBuffer();
|
|
994
|
+
const res = await this.batchIngestCaller.call(_getFetchImplementation(), `${this.apiUrl}/runs/multipart`, {
|
|
995
|
+
method: "POST",
|
|
996
|
+
headers: {
|
|
997
|
+
...this.headers,
|
|
998
|
+
"Content-Type": `multipart/form-data; boundary=${boundary}`
|
|
999
|
+
},
|
|
1000
|
+
body: arrayBuffer,
|
|
1001
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1002
|
+
...this.fetchOptions
|
|
1003
|
+
});
|
|
1004
|
+
await raiseForStatus(res, "ingest multipart runs", true);
|
|
1005
|
+
} catch (e) {
|
|
1006
|
+
console.warn(`${e.message.trim()}\n\nContext: ${context}`);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
async updateRun(runId, run) {
|
|
1010
|
+
assertUuid(runId);
|
|
1011
|
+
if (run.inputs) run.inputs = this.processInputs(run.inputs);
|
|
1012
|
+
if (run.outputs) run.outputs = this.processOutputs(run.outputs);
|
|
1013
|
+
const data = {
|
|
1014
|
+
...run,
|
|
1015
|
+
id: runId
|
|
1016
|
+
};
|
|
1017
|
+
if (!this._filterForSampling([
|
|
1018
|
+
data
|
|
1019
|
+
], true).length) return;
|
|
1020
|
+
if (this.autoBatchTracing && void 0 !== data.trace_id && void 0 !== data.dotted_order) {
|
|
1021
|
+
if (void 0 !== run.end_time && void 0 === data.parent_run_id && this.blockOnRootRunFinalization && !this.manualFlushMode) return void await this.processRunOperation({
|
|
1022
|
+
action: "update",
|
|
1023
|
+
item: data
|
|
1024
|
+
}).catch(console.error);
|
|
1025
|
+
this.processRunOperation({
|
|
1026
|
+
action: "update",
|
|
1027
|
+
item: data
|
|
1028
|
+
}).catch(console.error);
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
const headers = {
|
|
1032
|
+
...this.headers,
|
|
1033
|
+
"Content-Type": "application/json"
|
|
1034
|
+
};
|
|
1035
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/runs/${runId}`, {
|
|
1036
|
+
method: "PATCH",
|
|
1037
|
+
headers,
|
|
1038
|
+
body: serialize(run),
|
|
1039
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1040
|
+
...this.fetchOptions
|
|
1041
|
+
});
|
|
1042
|
+
await raiseForStatus(response, "update run", true);
|
|
1043
|
+
}
|
|
1044
|
+
async readRun(runId, { loadChildRuns } = {
|
|
1045
|
+
loadChildRuns: false
|
|
1046
|
+
}) {
|
|
1047
|
+
assertUuid(runId);
|
|
1048
|
+
let run = await this._get(`/runs/${runId}`);
|
|
1049
|
+
if (loadChildRuns && run.child_run_ids) run = await this._loadChildRuns(run);
|
|
1050
|
+
return run;
|
|
1051
|
+
}
|
|
1052
|
+
async getRunUrl({ runId, run, projectOpts }) {
|
|
1053
|
+
if (void 0 !== run) {
|
|
1054
|
+
let sessionId;
|
|
1055
|
+
if (run.session_id) sessionId = run.session_id;
|
|
1056
|
+
else if (projectOpts?.projectName) sessionId = (await this.readProject({
|
|
1057
|
+
projectName: projectOpts?.projectName
|
|
1058
|
+
})).id;
|
|
1059
|
+
else if (projectOpts?.projectId) sessionId = projectOpts?.projectId;
|
|
1060
|
+
else {
|
|
1061
|
+
const project = await this.readProject({
|
|
1062
|
+
projectName: getLangSmithEnvironmentVariable("PROJECT") || "default"
|
|
1063
|
+
});
|
|
1064
|
+
sessionId = project.id;
|
|
1065
|
+
}
|
|
1066
|
+
const tenantId = await this._getTenantId();
|
|
1067
|
+
return `${this.getHostUrl()}/o/${tenantId}/projects/p/${sessionId}/r/${run.id}?poll=true`;
|
|
1068
|
+
}
|
|
1069
|
+
if (void 0 !== runId) {
|
|
1070
|
+
const run_ = await this.readRun(runId);
|
|
1071
|
+
if (!run_.app_path) throw new Error(`Run ${runId} has no app_path`);
|
|
1072
|
+
const baseUrl = this.getHostUrl();
|
|
1073
|
+
return `${baseUrl}${run_.app_path}`;
|
|
1074
|
+
}
|
|
1075
|
+
throw new Error("Must provide either runId or run");
|
|
1076
|
+
}
|
|
1077
|
+
async _loadChildRuns(run) {
|
|
1078
|
+
const childRuns = await toArray(this.listRuns({
|
|
1079
|
+
id: run.child_run_ids
|
|
1080
|
+
}));
|
|
1081
|
+
const treemap = {};
|
|
1082
|
+
const runs = {};
|
|
1083
|
+
childRuns.sort((a, b)=>(a?.dotted_order ?? "").localeCompare(b?.dotted_order ?? ""));
|
|
1084
|
+
for (const childRun of childRuns){
|
|
1085
|
+
if (null === childRun.parent_run_id || void 0 === childRun.parent_run_id) throw new Error(`Child run ${childRun.id} has no parent`);
|
|
1086
|
+
if (!(childRun.parent_run_id in treemap)) treemap[childRun.parent_run_id] = [];
|
|
1087
|
+
treemap[childRun.parent_run_id].push(childRun);
|
|
1088
|
+
runs[childRun.id] = childRun;
|
|
1089
|
+
}
|
|
1090
|
+
run.child_runs = treemap[run.id] || [];
|
|
1091
|
+
for(const runId in treemap)if (runId !== run.id) runs[runId].child_runs = treemap[runId];
|
|
1092
|
+
return run;
|
|
1093
|
+
}
|
|
1094
|
+
async *listRuns(props) {
|
|
1095
|
+
const { projectId, projectName, parentRunId, traceId, referenceExampleId, startTime, executionOrder, isRoot, runType, error, id, query, filter, traceFilter, treeFilter, limit, select } = props;
|
|
1096
|
+
let projectIds = [];
|
|
1097
|
+
if (projectId) projectIds = Array.isArray(projectId) ? projectId : [
|
|
1098
|
+
projectId
|
|
1099
|
+
];
|
|
1100
|
+
if (projectName) {
|
|
1101
|
+
const projectNames = Array.isArray(projectName) ? projectName : [
|
|
1102
|
+
projectName
|
|
1103
|
+
];
|
|
1104
|
+
const projectIds_ = await Promise.all(projectNames.map((name)=>this.readProject({
|
|
1105
|
+
projectName: name
|
|
1106
|
+
}).then((project)=>project.id)));
|
|
1107
|
+
projectIds.push(...projectIds_);
|
|
1108
|
+
}
|
|
1109
|
+
const default_select = [
|
|
1110
|
+
"app_path",
|
|
1111
|
+
"child_run_ids",
|
|
1112
|
+
"completion_cost",
|
|
1113
|
+
"completion_tokens",
|
|
1114
|
+
"dotted_order",
|
|
1115
|
+
"end_time",
|
|
1116
|
+
"error",
|
|
1117
|
+
"events",
|
|
1118
|
+
"extra",
|
|
1119
|
+
"feedback_stats",
|
|
1120
|
+
"first_token_time",
|
|
1121
|
+
"id",
|
|
1122
|
+
"inputs",
|
|
1123
|
+
"name",
|
|
1124
|
+
"outputs",
|
|
1125
|
+
"parent_run_id",
|
|
1126
|
+
"parent_run_ids",
|
|
1127
|
+
"prompt_cost",
|
|
1128
|
+
"prompt_tokens",
|
|
1129
|
+
"reference_example_id",
|
|
1130
|
+
"run_type",
|
|
1131
|
+
"session_id",
|
|
1132
|
+
"start_time",
|
|
1133
|
+
"status",
|
|
1134
|
+
"tags",
|
|
1135
|
+
"total_cost",
|
|
1136
|
+
"total_tokens",
|
|
1137
|
+
"trace_id"
|
|
1138
|
+
];
|
|
1139
|
+
const body = {
|
|
1140
|
+
session: projectIds.length ? projectIds : null,
|
|
1141
|
+
run_type: runType,
|
|
1142
|
+
reference_example: referenceExampleId,
|
|
1143
|
+
query,
|
|
1144
|
+
filter,
|
|
1145
|
+
trace_filter: traceFilter,
|
|
1146
|
+
tree_filter: treeFilter,
|
|
1147
|
+
execution_order: executionOrder,
|
|
1148
|
+
parent_run: parentRunId,
|
|
1149
|
+
start_time: startTime ? startTime.toISOString() : null,
|
|
1150
|
+
error,
|
|
1151
|
+
id,
|
|
1152
|
+
limit,
|
|
1153
|
+
trace: traceId,
|
|
1154
|
+
select: select ? select : default_select,
|
|
1155
|
+
is_root: isRoot
|
|
1156
|
+
};
|
|
1157
|
+
let runsYielded = 0;
|
|
1158
|
+
for await (const runs of this._getCursorPaginatedList("/runs/query", body))if (limit) {
|
|
1159
|
+
if (runsYielded >= limit) break;
|
|
1160
|
+
if (runs.length + runsYielded > limit) {
|
|
1161
|
+
const newRuns = runs.slice(0, limit - runsYielded);
|
|
1162
|
+
yield* newRuns;
|
|
1163
|
+
break;
|
|
1164
|
+
}
|
|
1165
|
+
runsYielded += runs.length;
|
|
1166
|
+
yield* runs;
|
|
1167
|
+
} else yield* runs;
|
|
1168
|
+
}
|
|
1169
|
+
async getRunStats({ id, trace, parentRun, runType, projectNames, projectIds, referenceExampleIds, startTime, endTime, error, query, filter, traceFilter, treeFilter, isRoot, dataSourceType }) {
|
|
1170
|
+
let projectIds_ = projectIds || [];
|
|
1171
|
+
if (projectNames) projectIds_ = [
|
|
1172
|
+
...projectIds || [],
|
|
1173
|
+
...await Promise.all(projectNames.map((name)=>this.readProject({
|
|
1174
|
+
projectName: name
|
|
1175
|
+
}).then((project)=>project.id)))
|
|
1176
|
+
];
|
|
1177
|
+
const payload = {
|
|
1178
|
+
id,
|
|
1179
|
+
trace,
|
|
1180
|
+
parent_run: parentRun,
|
|
1181
|
+
run_type: runType,
|
|
1182
|
+
session: projectIds_,
|
|
1183
|
+
reference_example: referenceExampleIds,
|
|
1184
|
+
start_time: startTime,
|
|
1185
|
+
end_time: endTime,
|
|
1186
|
+
error,
|
|
1187
|
+
query,
|
|
1188
|
+
filter,
|
|
1189
|
+
trace_filter: traceFilter,
|
|
1190
|
+
tree_filter: treeFilter,
|
|
1191
|
+
is_root: isRoot,
|
|
1192
|
+
data_source_type: dataSourceType
|
|
1193
|
+
};
|
|
1194
|
+
const filteredPayload = Object.fromEntries(Object.entries(payload).filter(([_, value])=>void 0 !== value));
|
|
1195
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/runs/stats`, {
|
|
1196
|
+
method: "POST",
|
|
1197
|
+
headers: this.headers,
|
|
1198
|
+
body: JSON.stringify(filteredPayload),
|
|
1199
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1200
|
+
...this.fetchOptions
|
|
1201
|
+
});
|
|
1202
|
+
const result = await response.json();
|
|
1203
|
+
return result;
|
|
1204
|
+
}
|
|
1205
|
+
async shareRun(runId, { shareId } = {}) {
|
|
1206
|
+
const data = {
|
|
1207
|
+
run_id: runId,
|
|
1208
|
+
share_token: shareId || v4.Z()
|
|
1209
|
+
};
|
|
1210
|
+
assertUuid(runId);
|
|
1211
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/runs/${runId}/share`, {
|
|
1212
|
+
method: "PUT",
|
|
1213
|
+
headers: this.headers,
|
|
1214
|
+
body: JSON.stringify(data),
|
|
1215
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1216
|
+
...this.fetchOptions
|
|
1217
|
+
});
|
|
1218
|
+
const result = await response.json();
|
|
1219
|
+
if (null === result || !("share_token" in result)) throw new Error("Invalid response from server");
|
|
1220
|
+
return `${this.getHostUrl()}/public/${result["share_token"]}/r`;
|
|
1221
|
+
}
|
|
1222
|
+
async unshareRun(runId) {
|
|
1223
|
+
assertUuid(runId);
|
|
1224
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/runs/${runId}/share`, {
|
|
1225
|
+
method: "DELETE",
|
|
1226
|
+
headers: this.headers,
|
|
1227
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1228
|
+
...this.fetchOptions
|
|
1229
|
+
});
|
|
1230
|
+
await raiseForStatus(response, "unshare run", true);
|
|
1231
|
+
}
|
|
1232
|
+
async readRunSharedLink(runId) {
|
|
1233
|
+
assertUuid(runId);
|
|
1234
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/runs/${runId}/share`, {
|
|
1235
|
+
method: "GET",
|
|
1236
|
+
headers: this.headers,
|
|
1237
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1238
|
+
...this.fetchOptions
|
|
1239
|
+
});
|
|
1240
|
+
const result = await response.json();
|
|
1241
|
+
if (null === result || !("share_token" in result)) return;
|
|
1242
|
+
return `${this.getHostUrl()}/public/${result["share_token"]}/r`;
|
|
1243
|
+
}
|
|
1244
|
+
async listSharedRuns(shareToken, { runIds } = {}) {
|
|
1245
|
+
const queryParams = new URLSearchParams({
|
|
1246
|
+
share_token: shareToken
|
|
1247
|
+
});
|
|
1248
|
+
if (void 0 !== runIds) for (const runId of runIds)queryParams.append("id", runId);
|
|
1249
|
+
assertUuid(shareToken);
|
|
1250
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/public/${shareToken}/runs${queryParams}`, {
|
|
1251
|
+
method: "GET",
|
|
1252
|
+
headers: this.headers,
|
|
1253
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1254
|
+
...this.fetchOptions
|
|
1255
|
+
});
|
|
1256
|
+
const runs = await response.json();
|
|
1257
|
+
return runs;
|
|
1258
|
+
}
|
|
1259
|
+
async readDatasetSharedSchema(datasetId, datasetName) {
|
|
1260
|
+
if (!datasetId && !datasetName) throw new Error("Either datasetId or datasetName must be given");
|
|
1261
|
+
if (!datasetId) {
|
|
1262
|
+
const dataset = await this.readDataset({
|
|
1263
|
+
datasetName
|
|
1264
|
+
});
|
|
1265
|
+
datasetId = dataset.id;
|
|
1266
|
+
}
|
|
1267
|
+
assertUuid(datasetId);
|
|
1268
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/datasets/${datasetId}/share`, {
|
|
1269
|
+
method: "GET",
|
|
1270
|
+
headers: this.headers,
|
|
1271
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1272
|
+
...this.fetchOptions
|
|
1273
|
+
});
|
|
1274
|
+
const shareSchema = await response.json();
|
|
1275
|
+
shareSchema.url = `${this.getHostUrl()}/public/${shareSchema.share_token}/d`;
|
|
1276
|
+
return shareSchema;
|
|
1277
|
+
}
|
|
1278
|
+
async shareDataset(datasetId, datasetName) {
|
|
1279
|
+
if (!datasetId && !datasetName) throw new Error("Either datasetId or datasetName must be given");
|
|
1280
|
+
if (!datasetId) {
|
|
1281
|
+
const dataset = await this.readDataset({
|
|
1282
|
+
datasetName
|
|
1283
|
+
});
|
|
1284
|
+
datasetId = dataset.id;
|
|
1285
|
+
}
|
|
1286
|
+
const data = {
|
|
1287
|
+
dataset_id: datasetId
|
|
1288
|
+
};
|
|
1289
|
+
assertUuid(datasetId);
|
|
1290
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/datasets/${datasetId}/share`, {
|
|
1291
|
+
method: "PUT",
|
|
1292
|
+
headers: this.headers,
|
|
1293
|
+
body: JSON.stringify(data),
|
|
1294
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1295
|
+
...this.fetchOptions
|
|
1296
|
+
});
|
|
1297
|
+
const shareSchema = await response.json();
|
|
1298
|
+
shareSchema.url = `${this.getHostUrl()}/public/${shareSchema.share_token}/d`;
|
|
1299
|
+
return shareSchema;
|
|
1300
|
+
}
|
|
1301
|
+
async unshareDataset(datasetId) {
|
|
1302
|
+
assertUuid(datasetId);
|
|
1303
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/datasets/${datasetId}/share`, {
|
|
1304
|
+
method: "DELETE",
|
|
1305
|
+
headers: this.headers,
|
|
1306
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1307
|
+
...this.fetchOptions
|
|
1308
|
+
});
|
|
1309
|
+
await raiseForStatus(response, "unshare dataset", true);
|
|
1310
|
+
}
|
|
1311
|
+
async readSharedDataset(shareToken) {
|
|
1312
|
+
assertUuid(shareToken);
|
|
1313
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/public/${shareToken}/datasets`, {
|
|
1314
|
+
method: "GET",
|
|
1315
|
+
headers: this.headers,
|
|
1316
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1317
|
+
...this.fetchOptions
|
|
1318
|
+
});
|
|
1319
|
+
const dataset = await response.json();
|
|
1320
|
+
return dataset;
|
|
1321
|
+
}
|
|
1322
|
+
async listSharedExamples(shareToken, options) {
|
|
1323
|
+
const params = {};
|
|
1324
|
+
if (options?.exampleIds) params.id = options.exampleIds;
|
|
1325
|
+
const urlParams = new URLSearchParams();
|
|
1326
|
+
Object.entries(params).forEach(([key, value])=>{
|
|
1327
|
+
if (Array.isArray(value)) value.forEach((v)=>urlParams.append(key, v));
|
|
1328
|
+
else urlParams.append(key, value);
|
|
1329
|
+
});
|
|
1330
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/public/${shareToken}/examples?${urlParams.toString()}`, {
|
|
1331
|
+
method: "GET",
|
|
1332
|
+
headers: this.headers,
|
|
1333
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1334
|
+
...this.fetchOptions
|
|
1335
|
+
});
|
|
1336
|
+
const result = await response.json();
|
|
1337
|
+
if (!response.ok) {
|
|
1338
|
+
if ("detail" in result) throw new Error(`Failed to list shared examples.\nStatus: ${response.status}\nMessage: ${result.detail.join("\n")}`);
|
|
1339
|
+
throw new Error(`Failed to list shared examples: ${response.status} ${response.statusText}`);
|
|
1340
|
+
}
|
|
1341
|
+
return result.map((example)=>({
|
|
1342
|
+
...example,
|
|
1343
|
+
_hostUrl: this.getHostUrl()
|
|
1344
|
+
}));
|
|
1345
|
+
}
|
|
1346
|
+
async createProject({ projectName, description = null, metadata = null, upsert = false, projectExtra = null, referenceDatasetId = null }) {
|
|
1347
|
+
const upsert_ = upsert ? "?upsert=true" : "";
|
|
1348
|
+
const endpoint = `${this.apiUrl}/sessions${upsert_}`;
|
|
1349
|
+
const extra = projectExtra || {};
|
|
1350
|
+
if (metadata) extra["metadata"] = metadata;
|
|
1351
|
+
const body = {
|
|
1352
|
+
name: projectName,
|
|
1353
|
+
extra,
|
|
1354
|
+
description
|
|
1355
|
+
};
|
|
1356
|
+
if (null !== referenceDatasetId) body["reference_dataset_id"] = referenceDatasetId;
|
|
1357
|
+
const response = await this.caller.call(_getFetchImplementation(), endpoint, {
|
|
1358
|
+
method: "POST",
|
|
1359
|
+
headers: {
|
|
1360
|
+
...this.headers,
|
|
1361
|
+
"Content-Type": "application/json"
|
|
1362
|
+
},
|
|
1363
|
+
body: JSON.stringify(body),
|
|
1364
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1365
|
+
...this.fetchOptions
|
|
1366
|
+
});
|
|
1367
|
+
await raiseForStatus(response, "create project");
|
|
1368
|
+
const result = await response.json();
|
|
1369
|
+
return result;
|
|
1370
|
+
}
|
|
1371
|
+
async updateProject(projectId, { name = null, description = null, metadata = null, projectExtra = null, endTime = null }) {
|
|
1372
|
+
const endpoint = `${this.apiUrl}/sessions/${projectId}`;
|
|
1373
|
+
let extra = projectExtra;
|
|
1374
|
+
if (metadata) extra = {
|
|
1375
|
+
...extra || {},
|
|
1376
|
+
metadata
|
|
1377
|
+
};
|
|
1378
|
+
const body = {
|
|
1379
|
+
name,
|
|
1380
|
+
extra,
|
|
1381
|
+
description,
|
|
1382
|
+
end_time: endTime ? new Date(endTime).toISOString() : null
|
|
1383
|
+
};
|
|
1384
|
+
const response = await this.caller.call(_getFetchImplementation(), endpoint, {
|
|
1385
|
+
method: "PATCH",
|
|
1386
|
+
headers: {
|
|
1387
|
+
...this.headers,
|
|
1388
|
+
"Content-Type": "application/json"
|
|
1389
|
+
},
|
|
1390
|
+
body: JSON.stringify(body),
|
|
1391
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1392
|
+
...this.fetchOptions
|
|
1393
|
+
});
|
|
1394
|
+
await raiseForStatus(response, "update project");
|
|
1395
|
+
const result = await response.json();
|
|
1396
|
+
return result;
|
|
1397
|
+
}
|
|
1398
|
+
async hasProject({ projectId, projectName }) {
|
|
1399
|
+
let path = "/sessions";
|
|
1400
|
+
const params = new URLSearchParams();
|
|
1401
|
+
if (void 0 !== projectId && void 0 !== projectName) throw new Error("Must provide either projectName or projectId, not both");
|
|
1402
|
+
if (void 0 !== projectId) {
|
|
1403
|
+
assertUuid(projectId);
|
|
1404
|
+
path += `/${projectId}`;
|
|
1405
|
+
} else if (void 0 !== projectName) params.append("name", projectName);
|
|
1406
|
+
else throw new Error("Must provide projectName or projectId");
|
|
1407
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}${path}?${params}`, {
|
|
1408
|
+
method: "GET",
|
|
1409
|
+
headers: this.headers,
|
|
1410
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1411
|
+
...this.fetchOptions
|
|
1412
|
+
});
|
|
1413
|
+
try {
|
|
1414
|
+
const result = await response.json();
|
|
1415
|
+
if (!response.ok) return false;
|
|
1416
|
+
if (Array.isArray(result)) return result.length > 0;
|
|
1417
|
+
return true;
|
|
1418
|
+
} catch (e) {
|
|
1419
|
+
return false;
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
async readProject({ projectId, projectName, includeStats }) {
|
|
1423
|
+
let path = "/sessions";
|
|
1424
|
+
const params = new URLSearchParams();
|
|
1425
|
+
if (void 0 !== projectId && void 0 !== projectName) throw new Error("Must provide either projectName or projectId, not both");
|
|
1426
|
+
if (void 0 !== projectId) {
|
|
1427
|
+
assertUuid(projectId);
|
|
1428
|
+
path += `/${projectId}`;
|
|
1429
|
+
} else if (void 0 !== projectName) params.append("name", projectName);
|
|
1430
|
+
else throw new Error("Must provide projectName or projectId");
|
|
1431
|
+
if (void 0 !== includeStats) params.append("include_stats", includeStats.toString());
|
|
1432
|
+
const response = await this._get(path, params);
|
|
1433
|
+
let result;
|
|
1434
|
+
if (Array.isArray(response)) {
|
|
1435
|
+
if (0 === response.length) throw new Error(`Project[id=${projectId}, name=${projectName}] not found`);
|
|
1436
|
+
result = response[0];
|
|
1437
|
+
} else result = response;
|
|
1438
|
+
return result;
|
|
1439
|
+
}
|
|
1440
|
+
async getProjectUrl({ projectId, projectName }) {
|
|
1441
|
+
if (void 0 === projectId && void 0 === projectName) throw new Error("Must provide either projectName or projectId");
|
|
1442
|
+
const project = await this.readProject({
|
|
1443
|
+
projectId,
|
|
1444
|
+
projectName
|
|
1445
|
+
});
|
|
1446
|
+
const tenantId = await this._getTenantId();
|
|
1447
|
+
return `${this.getHostUrl()}/o/${tenantId}/projects/p/${project.id}`;
|
|
1448
|
+
}
|
|
1449
|
+
async getDatasetUrl({ datasetId, datasetName }) {
|
|
1450
|
+
if (void 0 === datasetId && void 0 === datasetName) throw new Error("Must provide either datasetName or datasetId");
|
|
1451
|
+
const dataset = await this.readDataset({
|
|
1452
|
+
datasetId,
|
|
1453
|
+
datasetName
|
|
1454
|
+
});
|
|
1455
|
+
const tenantId = await this._getTenantId();
|
|
1456
|
+
return `${this.getHostUrl()}/o/${tenantId}/datasets/${dataset.id}`;
|
|
1457
|
+
}
|
|
1458
|
+
async _getTenantId() {
|
|
1459
|
+
if (null !== this._tenantId) return this._tenantId;
|
|
1460
|
+
const queryParams = new URLSearchParams({
|
|
1461
|
+
limit: "1"
|
|
1462
|
+
});
|
|
1463
|
+
for await (const projects of this._getPaginated("/sessions", queryParams)){
|
|
1464
|
+
this._tenantId = projects[0].tenant_id;
|
|
1465
|
+
return projects[0].tenant_id;
|
|
1466
|
+
}
|
|
1467
|
+
throw new Error("No projects found to resolve tenant.");
|
|
1468
|
+
}
|
|
1469
|
+
async *listProjects({ projectIds, name, nameContains, referenceDatasetId, referenceDatasetName, referenceFree, metadata } = {}) {
|
|
1470
|
+
const params = new URLSearchParams();
|
|
1471
|
+
if (void 0 !== projectIds) for (const projectId of projectIds)params.append("id", projectId);
|
|
1472
|
+
if (void 0 !== name) params.append("name", name);
|
|
1473
|
+
if (void 0 !== nameContains) params.append("name_contains", nameContains);
|
|
1474
|
+
if (void 0 !== referenceDatasetId) params.append("reference_dataset", referenceDatasetId);
|
|
1475
|
+
else if (void 0 !== referenceDatasetName) {
|
|
1476
|
+
const dataset = await this.readDataset({
|
|
1477
|
+
datasetName: referenceDatasetName
|
|
1478
|
+
});
|
|
1479
|
+
params.append("reference_dataset", dataset.id);
|
|
1480
|
+
}
|
|
1481
|
+
if (void 0 !== referenceFree) params.append("reference_free", referenceFree.toString());
|
|
1482
|
+
if (void 0 !== metadata) params.append("metadata", JSON.stringify(metadata));
|
|
1483
|
+
for await (const projects of this._getPaginated("/sessions", params))yield* projects;
|
|
1484
|
+
}
|
|
1485
|
+
async deleteProject({ projectId, projectName }) {
|
|
1486
|
+
let projectId_;
|
|
1487
|
+
if (void 0 === projectId && void 0 === projectName) throw new Error("Must provide projectName or projectId");
|
|
1488
|
+
if (void 0 !== projectId && void 0 !== projectName) throw new Error("Must provide either projectName or projectId, not both");
|
|
1489
|
+
projectId_ = void 0 === projectId ? (await this.readProject({
|
|
1490
|
+
projectName
|
|
1491
|
+
})).id : projectId;
|
|
1492
|
+
assertUuid(projectId_);
|
|
1493
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/sessions/${projectId_}`, {
|
|
1494
|
+
method: "DELETE",
|
|
1495
|
+
headers: this.headers,
|
|
1496
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1497
|
+
...this.fetchOptions
|
|
1498
|
+
});
|
|
1499
|
+
await raiseForStatus(response, `delete session ${projectId_} (${projectName})`, true);
|
|
1500
|
+
}
|
|
1501
|
+
async uploadCsv({ csvFile, fileName, inputKeys, outputKeys, description, dataType, name }) {
|
|
1502
|
+
const url = `${this.apiUrl}/datasets/upload`;
|
|
1503
|
+
const formData = new FormData();
|
|
1504
|
+
formData.append("file", csvFile, fileName);
|
|
1505
|
+
inputKeys.forEach((key)=>{
|
|
1506
|
+
formData.append("input_keys", key);
|
|
1507
|
+
});
|
|
1508
|
+
outputKeys.forEach((key)=>{
|
|
1509
|
+
formData.append("output_keys", key);
|
|
1510
|
+
});
|
|
1511
|
+
if (description) formData.append("description", description);
|
|
1512
|
+
if (dataType) formData.append("data_type", dataType);
|
|
1513
|
+
if (name) formData.append("name", name);
|
|
1514
|
+
const response = await this.caller.call(_getFetchImplementation(), url, {
|
|
1515
|
+
method: "POST",
|
|
1516
|
+
headers: this.headers,
|
|
1517
|
+
body: formData,
|
|
1518
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1519
|
+
...this.fetchOptions
|
|
1520
|
+
});
|
|
1521
|
+
await raiseForStatus(response, "upload CSV");
|
|
1522
|
+
const result = await response.json();
|
|
1523
|
+
return result;
|
|
1524
|
+
}
|
|
1525
|
+
async createDataset(name, { description, dataType, inputsSchema, outputsSchema, metadata } = {}) {
|
|
1526
|
+
const body = {
|
|
1527
|
+
name,
|
|
1528
|
+
description,
|
|
1529
|
+
extra: metadata ? {
|
|
1530
|
+
metadata
|
|
1531
|
+
} : void 0
|
|
1532
|
+
};
|
|
1533
|
+
if (dataType) body.data_type = dataType;
|
|
1534
|
+
if (inputsSchema) body.inputs_schema_definition = inputsSchema;
|
|
1535
|
+
if (outputsSchema) body.outputs_schema_definition = outputsSchema;
|
|
1536
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/datasets`, {
|
|
1537
|
+
method: "POST",
|
|
1538
|
+
headers: {
|
|
1539
|
+
...this.headers,
|
|
1540
|
+
"Content-Type": "application/json"
|
|
1541
|
+
},
|
|
1542
|
+
body: JSON.stringify(body),
|
|
1543
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1544
|
+
...this.fetchOptions
|
|
1545
|
+
});
|
|
1546
|
+
await raiseForStatus(response, "create dataset");
|
|
1547
|
+
const result = await response.json();
|
|
1548
|
+
return result;
|
|
1549
|
+
}
|
|
1550
|
+
async readDataset({ datasetId, datasetName }) {
|
|
1551
|
+
let path = "/datasets";
|
|
1552
|
+
const params = new URLSearchParams({
|
|
1553
|
+
limit: "1"
|
|
1554
|
+
});
|
|
1555
|
+
if (void 0 !== datasetId && void 0 !== datasetName) throw new Error("Must provide either datasetName or datasetId, not both");
|
|
1556
|
+
if (void 0 !== datasetId) {
|
|
1557
|
+
assertUuid(datasetId);
|
|
1558
|
+
path += `/${datasetId}`;
|
|
1559
|
+
} else if (void 0 !== datasetName) params.append("name", datasetName);
|
|
1560
|
+
else throw new Error("Must provide datasetName or datasetId");
|
|
1561
|
+
const response = await this._get(path, params);
|
|
1562
|
+
let result;
|
|
1563
|
+
if (Array.isArray(response)) {
|
|
1564
|
+
if (0 === response.length) throw new Error(`Dataset[id=${datasetId}, name=${datasetName}] not found`);
|
|
1565
|
+
result = response[0];
|
|
1566
|
+
} else result = response;
|
|
1567
|
+
return result;
|
|
1568
|
+
}
|
|
1569
|
+
async hasDataset({ datasetId, datasetName }) {
|
|
1570
|
+
try {
|
|
1571
|
+
await this.readDataset({
|
|
1572
|
+
datasetId,
|
|
1573
|
+
datasetName
|
|
1574
|
+
});
|
|
1575
|
+
return true;
|
|
1576
|
+
} catch (e) {
|
|
1577
|
+
if (e instanceof Error && e.message.toLocaleLowerCase().includes("not found")) return false;
|
|
1578
|
+
throw e;
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
async diffDatasetVersions({ datasetId, datasetName, fromVersion, toVersion }) {
|
|
1582
|
+
let datasetId_ = datasetId;
|
|
1583
|
+
if (void 0 === datasetId_ && void 0 === datasetName) throw new Error("Must provide either datasetName or datasetId");
|
|
1584
|
+
if (void 0 !== datasetId_ && void 0 !== datasetName) throw new Error("Must provide either datasetName or datasetId, not both");
|
|
1585
|
+
if (void 0 === datasetId_) {
|
|
1586
|
+
const dataset = await this.readDataset({
|
|
1587
|
+
datasetName
|
|
1588
|
+
});
|
|
1589
|
+
datasetId_ = dataset.id;
|
|
1590
|
+
}
|
|
1591
|
+
const urlParams = new URLSearchParams({
|
|
1592
|
+
from_version: "string" == typeof fromVersion ? fromVersion : fromVersion.toISOString(),
|
|
1593
|
+
to_version: "string" == typeof toVersion ? toVersion : toVersion.toISOString()
|
|
1594
|
+
});
|
|
1595
|
+
const response = await this._get(`/datasets/${datasetId_}/versions/diff`, urlParams);
|
|
1596
|
+
return response;
|
|
1597
|
+
}
|
|
1598
|
+
async readDatasetOpenaiFinetuning({ datasetId, datasetName }) {
|
|
1599
|
+
const path = "/datasets";
|
|
1600
|
+
if (void 0 !== datasetId) ;
|
|
1601
|
+
else if (void 0 !== datasetName) datasetId = (await this.readDataset({
|
|
1602
|
+
datasetName
|
|
1603
|
+
})).id;
|
|
1604
|
+
else throw new Error("Must provide datasetName or datasetId");
|
|
1605
|
+
const response = await this._getResponse(`${path}/${datasetId}/openai_ft`);
|
|
1606
|
+
const datasetText = await response.text();
|
|
1607
|
+
const dataset = datasetText.trim().split("\n").map((line)=>JSON.parse(line));
|
|
1608
|
+
return dataset;
|
|
1609
|
+
}
|
|
1610
|
+
async *listDatasets({ limit = 100, offset = 0, datasetIds, datasetName, datasetNameContains, metadata } = {}) {
|
|
1611
|
+
const path = "/datasets";
|
|
1612
|
+
const params = new URLSearchParams({
|
|
1613
|
+
limit: limit.toString(),
|
|
1614
|
+
offset: offset.toString()
|
|
1615
|
+
});
|
|
1616
|
+
if (void 0 !== datasetIds) for (const id_ of datasetIds)params.append("id", id_);
|
|
1617
|
+
if (void 0 !== datasetName) params.append("name", datasetName);
|
|
1618
|
+
if (void 0 !== datasetNameContains) params.append("name_contains", datasetNameContains);
|
|
1619
|
+
if (void 0 !== metadata) params.append("metadata", JSON.stringify(metadata));
|
|
1620
|
+
for await (const datasets of this._getPaginated(path, params))yield* datasets;
|
|
1621
|
+
}
|
|
1622
|
+
async updateDataset(props) {
|
|
1623
|
+
const { datasetId, datasetName, ...update } = props;
|
|
1624
|
+
if (!datasetId && !datasetName) throw new Error("Must provide either datasetName or datasetId");
|
|
1625
|
+
const _datasetId = datasetId ?? (await this.readDataset({
|
|
1626
|
+
datasetName
|
|
1627
|
+
})).id;
|
|
1628
|
+
assertUuid(_datasetId);
|
|
1629
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/datasets/${_datasetId}`, {
|
|
1630
|
+
method: "PATCH",
|
|
1631
|
+
headers: {
|
|
1632
|
+
...this.headers,
|
|
1633
|
+
"Content-Type": "application/json"
|
|
1634
|
+
},
|
|
1635
|
+
body: JSON.stringify(update),
|
|
1636
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1637
|
+
...this.fetchOptions
|
|
1638
|
+
});
|
|
1639
|
+
await raiseForStatus(response, "update dataset");
|
|
1640
|
+
return await response.json();
|
|
1641
|
+
}
|
|
1642
|
+
async updateDatasetTag(props) {
|
|
1643
|
+
const { datasetId, datasetName, asOf, tag } = props;
|
|
1644
|
+
if (!datasetId && !datasetName) throw new Error("Must provide either datasetName or datasetId");
|
|
1645
|
+
const _datasetId = datasetId ?? (await this.readDataset({
|
|
1646
|
+
datasetName
|
|
1647
|
+
})).id;
|
|
1648
|
+
assertUuid(_datasetId);
|
|
1649
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/datasets/${_datasetId}/tags`, {
|
|
1650
|
+
method: "PUT",
|
|
1651
|
+
headers: {
|
|
1652
|
+
...this.headers,
|
|
1653
|
+
"Content-Type": "application/json"
|
|
1654
|
+
},
|
|
1655
|
+
body: JSON.stringify({
|
|
1656
|
+
as_of: "string" == typeof asOf ? asOf : asOf.toISOString(),
|
|
1657
|
+
tag
|
|
1658
|
+
}),
|
|
1659
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1660
|
+
...this.fetchOptions
|
|
1661
|
+
});
|
|
1662
|
+
await raiseForStatus(response, "update dataset tags");
|
|
1663
|
+
}
|
|
1664
|
+
async deleteDataset({ datasetId, datasetName }) {
|
|
1665
|
+
let path = "/datasets";
|
|
1666
|
+
let datasetId_ = datasetId;
|
|
1667
|
+
if (void 0 !== datasetId && void 0 !== datasetName) throw new Error("Must provide either datasetName or datasetId, not both");
|
|
1668
|
+
if (void 0 !== datasetName) {
|
|
1669
|
+
const dataset = await this.readDataset({
|
|
1670
|
+
datasetName
|
|
1671
|
+
});
|
|
1672
|
+
datasetId_ = dataset.id;
|
|
1673
|
+
}
|
|
1674
|
+
if (void 0 !== datasetId_) {
|
|
1675
|
+
assertUuid(datasetId_);
|
|
1676
|
+
path += `/${datasetId_}`;
|
|
1677
|
+
} else throw new Error("Must provide datasetName or datasetId");
|
|
1678
|
+
const response = await this.caller.call(_getFetchImplementation(), this.apiUrl + path, {
|
|
1679
|
+
method: "DELETE",
|
|
1680
|
+
headers: this.headers,
|
|
1681
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1682
|
+
...this.fetchOptions
|
|
1683
|
+
});
|
|
1684
|
+
await raiseForStatus(response, `delete ${path}`);
|
|
1685
|
+
await response.json();
|
|
1686
|
+
}
|
|
1687
|
+
async indexDataset({ datasetId, datasetName, tag }) {
|
|
1688
|
+
let datasetId_ = datasetId;
|
|
1689
|
+
if (datasetId_ || datasetName) {
|
|
1690
|
+
if (datasetId_ && datasetName) throw new Error("Must provide either datasetName or datasetId, not both");
|
|
1691
|
+
else if (!datasetId_) {
|
|
1692
|
+
const dataset = await this.readDataset({
|
|
1693
|
+
datasetName
|
|
1694
|
+
});
|
|
1695
|
+
datasetId_ = dataset.id;
|
|
1696
|
+
}
|
|
1697
|
+
} else throw new Error("Must provide either datasetName or datasetId");
|
|
1698
|
+
assertUuid(datasetId_);
|
|
1699
|
+
const data = {
|
|
1700
|
+
tag: tag
|
|
1701
|
+
};
|
|
1702
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/datasets/${datasetId_}/index`, {
|
|
1703
|
+
method: "POST",
|
|
1704
|
+
headers: {
|
|
1705
|
+
...this.headers,
|
|
1706
|
+
"Content-Type": "application/json"
|
|
1707
|
+
},
|
|
1708
|
+
body: JSON.stringify(data),
|
|
1709
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1710
|
+
...this.fetchOptions
|
|
1711
|
+
});
|
|
1712
|
+
await raiseForStatus(response, "index dataset");
|
|
1713
|
+
await response.json();
|
|
1714
|
+
}
|
|
1715
|
+
async similarExamples(inputs, datasetId, limit, { filter } = {}) {
|
|
1716
|
+
const data = {
|
|
1717
|
+
limit: limit,
|
|
1718
|
+
inputs: inputs
|
|
1719
|
+
};
|
|
1720
|
+
if (void 0 !== filter) data["filter"] = filter;
|
|
1721
|
+
assertUuid(datasetId);
|
|
1722
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/datasets/${datasetId}/search`, {
|
|
1723
|
+
method: "POST",
|
|
1724
|
+
headers: {
|
|
1725
|
+
...this.headers,
|
|
1726
|
+
"Content-Type": "application/json"
|
|
1727
|
+
},
|
|
1728
|
+
body: JSON.stringify(data),
|
|
1729
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1730
|
+
...this.fetchOptions
|
|
1731
|
+
});
|
|
1732
|
+
await raiseForStatus(response, "fetch similar examples");
|
|
1733
|
+
const result = await response.json();
|
|
1734
|
+
return result["examples"];
|
|
1735
|
+
}
|
|
1736
|
+
async createExample(inputs, outputs, { datasetId, datasetName, createdAt, exampleId, metadata, split, sourceRunId }) {
|
|
1737
|
+
let datasetId_ = datasetId;
|
|
1738
|
+
if (void 0 === datasetId_ && void 0 === datasetName) throw new Error("Must provide either datasetName or datasetId");
|
|
1739
|
+
if (void 0 !== datasetId_ && void 0 !== datasetName) throw new Error("Must provide either datasetName or datasetId, not both");
|
|
1740
|
+
if (void 0 === datasetId_) {
|
|
1741
|
+
const dataset = await this.readDataset({
|
|
1742
|
+
datasetName
|
|
1743
|
+
});
|
|
1744
|
+
datasetId_ = dataset.id;
|
|
1745
|
+
}
|
|
1746
|
+
const createdAt_ = createdAt || new Date();
|
|
1747
|
+
const data = {
|
|
1748
|
+
dataset_id: datasetId_,
|
|
1749
|
+
inputs,
|
|
1750
|
+
outputs,
|
|
1751
|
+
created_at: createdAt_?.toISOString(),
|
|
1752
|
+
id: exampleId,
|
|
1753
|
+
metadata,
|
|
1754
|
+
split,
|
|
1755
|
+
source_run_id: sourceRunId
|
|
1756
|
+
};
|
|
1757
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/examples`, {
|
|
1758
|
+
method: "POST",
|
|
1759
|
+
headers: {
|
|
1760
|
+
...this.headers,
|
|
1761
|
+
"Content-Type": "application/json"
|
|
1762
|
+
},
|
|
1763
|
+
body: JSON.stringify(data),
|
|
1764
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1765
|
+
...this.fetchOptions
|
|
1766
|
+
});
|
|
1767
|
+
await raiseForStatus(response, "create example");
|
|
1768
|
+
const result = await response.json();
|
|
1769
|
+
return result;
|
|
1770
|
+
}
|
|
1771
|
+
async createExamples(props) {
|
|
1772
|
+
const { inputs, outputs, metadata, sourceRunIds, exampleIds, datasetId, datasetName } = props;
|
|
1773
|
+
let datasetId_ = datasetId;
|
|
1774
|
+
if (void 0 === datasetId_ && void 0 === datasetName) throw new Error("Must provide either datasetName or datasetId");
|
|
1775
|
+
if (void 0 !== datasetId_ && void 0 !== datasetName) throw new Error("Must provide either datasetName or datasetId, not both");
|
|
1776
|
+
if (void 0 === datasetId_) {
|
|
1777
|
+
const dataset = await this.readDataset({
|
|
1778
|
+
datasetName
|
|
1779
|
+
});
|
|
1780
|
+
datasetId_ = dataset.id;
|
|
1781
|
+
}
|
|
1782
|
+
const formattedExamples = inputs.map((input, idx)=>({
|
|
1783
|
+
dataset_id: datasetId_,
|
|
1784
|
+
inputs: input,
|
|
1785
|
+
outputs: outputs ? outputs[idx] : void 0,
|
|
1786
|
+
metadata: metadata ? metadata[idx] : void 0,
|
|
1787
|
+
split: props.splits ? props.splits[idx] : void 0,
|
|
1788
|
+
id: exampleIds ? exampleIds[idx] : void 0,
|
|
1789
|
+
source_run_id: sourceRunIds ? sourceRunIds[idx] : void 0
|
|
1790
|
+
}));
|
|
1791
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/examples/bulk`, {
|
|
1792
|
+
method: "POST",
|
|
1793
|
+
headers: {
|
|
1794
|
+
...this.headers,
|
|
1795
|
+
"Content-Type": "application/json"
|
|
1796
|
+
},
|
|
1797
|
+
body: JSON.stringify(formattedExamples),
|
|
1798
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1799
|
+
...this.fetchOptions
|
|
1800
|
+
});
|
|
1801
|
+
await raiseForStatus(response, "create examples");
|
|
1802
|
+
const result = await response.json();
|
|
1803
|
+
return result;
|
|
1804
|
+
}
|
|
1805
|
+
async createLLMExample(input, generation, options) {
|
|
1806
|
+
return this.createExample({
|
|
1807
|
+
input
|
|
1808
|
+
}, {
|
|
1809
|
+
output: generation
|
|
1810
|
+
}, options);
|
|
1811
|
+
}
|
|
1812
|
+
async createChatExample(input, generations, options) {
|
|
1813
|
+
const finalInput = input.map((message)=>{
|
|
1814
|
+
if (isLangChainMessage(message)) return convertLangChainMessageToExample(message);
|
|
1815
|
+
return message;
|
|
1816
|
+
});
|
|
1817
|
+
const finalOutput = isLangChainMessage(generations) ? convertLangChainMessageToExample(generations) : generations;
|
|
1818
|
+
return this.createExample({
|
|
1819
|
+
input: finalInput
|
|
1820
|
+
}, {
|
|
1821
|
+
output: finalOutput
|
|
1822
|
+
}, options);
|
|
1823
|
+
}
|
|
1824
|
+
async readExample(exampleId) {
|
|
1825
|
+
assertUuid(exampleId);
|
|
1826
|
+
const path = `/examples/${exampleId}`;
|
|
1827
|
+
const rawExample = await this._get(path);
|
|
1828
|
+
const { attachment_urls, ...rest } = rawExample;
|
|
1829
|
+
const example = rest;
|
|
1830
|
+
if (attachment_urls) example.attachments = Object.entries(attachment_urls).reduce((acc, [key, value])=>{
|
|
1831
|
+
acc[key.slice(11)] = {
|
|
1832
|
+
presigned_url: value.presigned_url,
|
|
1833
|
+
mime_type: value.mime_type
|
|
1834
|
+
};
|
|
1835
|
+
return acc;
|
|
1836
|
+
}, {});
|
|
1837
|
+
return example;
|
|
1838
|
+
}
|
|
1839
|
+
async *listExamples({ datasetId, datasetName, exampleIds, asOf, splits, inlineS3Urls, metadata, limit, offset, filter, includeAttachments } = {}) {
|
|
1840
|
+
let datasetId_;
|
|
1841
|
+
if (void 0 !== datasetId && void 0 !== datasetName) throw new Error("Must provide either datasetName or datasetId, not both");
|
|
1842
|
+
if (void 0 !== datasetId) datasetId_ = datasetId;
|
|
1843
|
+
else if (void 0 !== datasetName) {
|
|
1844
|
+
const dataset = await this.readDataset({
|
|
1845
|
+
datasetName
|
|
1846
|
+
});
|
|
1847
|
+
datasetId_ = dataset.id;
|
|
1848
|
+
} else throw new Error("Must provide a datasetName or datasetId");
|
|
1849
|
+
const params = new URLSearchParams({
|
|
1850
|
+
dataset: datasetId_
|
|
1851
|
+
});
|
|
1852
|
+
const dataset_version = asOf ? "string" == typeof asOf ? asOf : asOf?.toISOString() : void 0;
|
|
1853
|
+
if (dataset_version) params.append("as_of", dataset_version);
|
|
1854
|
+
const inlineS3Urls_ = inlineS3Urls ?? true;
|
|
1855
|
+
params.append("inline_s3_urls", inlineS3Urls_.toString());
|
|
1856
|
+
if (void 0 !== exampleIds) for (const id_ of exampleIds)params.append("id", id_);
|
|
1857
|
+
if (void 0 !== splits) for (const split of splits)params.append("splits", split);
|
|
1858
|
+
if (void 0 !== metadata) {
|
|
1859
|
+
const serializedMetadata = JSON.stringify(metadata);
|
|
1860
|
+
params.append("metadata", serializedMetadata);
|
|
1861
|
+
}
|
|
1862
|
+
if (void 0 !== limit) params.append("limit", limit.toString());
|
|
1863
|
+
if (void 0 !== offset) params.append("offset", offset.toString());
|
|
1864
|
+
if (void 0 !== filter) params.append("filter", filter);
|
|
1865
|
+
if (true === includeAttachments) [
|
|
1866
|
+
"attachment_urls",
|
|
1867
|
+
"outputs",
|
|
1868
|
+
"metadata"
|
|
1869
|
+
].forEach((field)=>params.append("select", field));
|
|
1870
|
+
let i = 0;
|
|
1871
|
+
for await (const rawExamples of this._getPaginated("/examples", params)){
|
|
1872
|
+
for (const rawExample of rawExamples){
|
|
1873
|
+
const { attachment_urls, ...rest } = rawExample;
|
|
1874
|
+
const example = rest;
|
|
1875
|
+
if (attachment_urls) example.attachments = Object.entries(attachment_urls).reduce((acc, [key, value])=>{
|
|
1876
|
+
acc[key.slice(11)] = {
|
|
1877
|
+
presigned_url: value.presigned_url,
|
|
1878
|
+
mime_type: value.mime_type || void 0
|
|
1879
|
+
};
|
|
1880
|
+
return acc;
|
|
1881
|
+
}, {});
|
|
1882
|
+
yield example;
|
|
1883
|
+
i++;
|
|
1884
|
+
}
|
|
1885
|
+
if (void 0 !== limit && i >= limit) break;
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
async deleteExample(exampleId) {
|
|
1889
|
+
assertUuid(exampleId);
|
|
1890
|
+
const path = `/examples/${exampleId}`;
|
|
1891
|
+
const response = await this.caller.call(_getFetchImplementation(), this.apiUrl + path, {
|
|
1892
|
+
method: "DELETE",
|
|
1893
|
+
headers: this.headers,
|
|
1894
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1895
|
+
...this.fetchOptions
|
|
1896
|
+
});
|
|
1897
|
+
await raiseForStatus(response, `delete ${path}`);
|
|
1898
|
+
await response.json();
|
|
1899
|
+
}
|
|
1900
|
+
async updateExample(exampleId, update) {
|
|
1901
|
+
assertUuid(exampleId);
|
|
1902
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/examples/${exampleId}`, {
|
|
1903
|
+
method: "PATCH",
|
|
1904
|
+
headers: {
|
|
1905
|
+
...this.headers,
|
|
1906
|
+
"Content-Type": "application/json"
|
|
1907
|
+
},
|
|
1908
|
+
body: JSON.stringify(update),
|
|
1909
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1910
|
+
...this.fetchOptions
|
|
1911
|
+
});
|
|
1912
|
+
await raiseForStatus(response, "update example");
|
|
1913
|
+
const result = await response.json();
|
|
1914
|
+
return result;
|
|
1915
|
+
}
|
|
1916
|
+
async updateExamples(update) {
|
|
1917
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/examples/bulk`, {
|
|
1918
|
+
method: "PATCH",
|
|
1919
|
+
headers: {
|
|
1920
|
+
...this.headers,
|
|
1921
|
+
"Content-Type": "application/json"
|
|
1922
|
+
},
|
|
1923
|
+
body: JSON.stringify(update),
|
|
1924
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1925
|
+
...this.fetchOptions
|
|
1926
|
+
});
|
|
1927
|
+
await raiseForStatus(response, "update examples");
|
|
1928
|
+
const result = await response.json();
|
|
1929
|
+
return result;
|
|
1930
|
+
}
|
|
1931
|
+
async readDatasetVersion({ datasetId, datasetName, asOf, tag }) {
|
|
1932
|
+
let resolvedDatasetId;
|
|
1933
|
+
if (datasetId) resolvedDatasetId = datasetId;
|
|
1934
|
+
else {
|
|
1935
|
+
const dataset = await this.readDataset({
|
|
1936
|
+
datasetName
|
|
1937
|
+
});
|
|
1938
|
+
resolvedDatasetId = dataset.id;
|
|
1939
|
+
}
|
|
1940
|
+
assertUuid(resolvedDatasetId);
|
|
1941
|
+
if (asOf && tag || !asOf && !tag) throw new Error("Exactly one of asOf and tag must be specified.");
|
|
1942
|
+
const params = new URLSearchParams();
|
|
1943
|
+
if (void 0 !== asOf) params.append("as_of", "string" == typeof asOf ? asOf : asOf.toISOString());
|
|
1944
|
+
if (void 0 !== tag) params.append("tag", tag);
|
|
1945
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/datasets/${resolvedDatasetId}/version?${params.toString()}`, {
|
|
1946
|
+
method: "GET",
|
|
1947
|
+
headers: {
|
|
1948
|
+
...this.headers
|
|
1949
|
+
},
|
|
1950
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1951
|
+
...this.fetchOptions
|
|
1952
|
+
});
|
|
1953
|
+
await raiseForStatus(response, "read dataset version");
|
|
1954
|
+
return await response.json();
|
|
1955
|
+
}
|
|
1956
|
+
async listDatasetSplits({ datasetId, datasetName, asOf }) {
|
|
1957
|
+
let datasetId_;
|
|
1958
|
+
if (void 0 === datasetId && void 0 === datasetName) throw new Error("Must provide dataset name or ID");
|
|
1959
|
+
if (void 0 !== datasetId && void 0 !== datasetName) throw new Error("Must provide either datasetName or datasetId, not both");
|
|
1960
|
+
if (void 0 === datasetId) {
|
|
1961
|
+
const dataset = await this.readDataset({
|
|
1962
|
+
datasetName
|
|
1963
|
+
});
|
|
1964
|
+
datasetId_ = dataset.id;
|
|
1965
|
+
} else datasetId_ = datasetId;
|
|
1966
|
+
assertUuid(datasetId_);
|
|
1967
|
+
const params = new URLSearchParams();
|
|
1968
|
+
const dataset_version = asOf ? "string" == typeof asOf ? asOf : asOf?.toISOString() : void 0;
|
|
1969
|
+
if (dataset_version) params.append("as_of", dataset_version);
|
|
1970
|
+
const response = await this._get(`/datasets/${datasetId_}/splits`, params);
|
|
1971
|
+
return response;
|
|
1972
|
+
}
|
|
1973
|
+
async updateDatasetSplits({ datasetId, datasetName, splitName, exampleIds, remove = false }) {
|
|
1974
|
+
let datasetId_;
|
|
1975
|
+
if (void 0 === datasetId && void 0 === datasetName) throw new Error("Must provide dataset name or ID");
|
|
1976
|
+
if (void 0 !== datasetId && void 0 !== datasetName) throw new Error("Must provide either datasetName or datasetId, not both");
|
|
1977
|
+
if (void 0 === datasetId) {
|
|
1978
|
+
const dataset = await this.readDataset({
|
|
1979
|
+
datasetName
|
|
1980
|
+
});
|
|
1981
|
+
datasetId_ = dataset.id;
|
|
1982
|
+
} else datasetId_ = datasetId;
|
|
1983
|
+
assertUuid(datasetId_);
|
|
1984
|
+
const data = {
|
|
1985
|
+
split_name: splitName,
|
|
1986
|
+
examples: exampleIds.map((id)=>{
|
|
1987
|
+
assertUuid(id);
|
|
1988
|
+
return id;
|
|
1989
|
+
}),
|
|
1990
|
+
remove
|
|
1991
|
+
};
|
|
1992
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/datasets/${datasetId_}/splits`, {
|
|
1993
|
+
method: "PUT",
|
|
1994
|
+
headers: {
|
|
1995
|
+
...this.headers,
|
|
1996
|
+
"Content-Type": "application/json"
|
|
1997
|
+
},
|
|
1998
|
+
body: JSON.stringify(data),
|
|
1999
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2000
|
+
...this.fetchOptions
|
|
2001
|
+
});
|
|
2002
|
+
await raiseForStatus(response, "update dataset splits", true);
|
|
2003
|
+
}
|
|
2004
|
+
async evaluateRun(run, evaluator, { sourceInfo, loadChildRuns, referenceExample } = {
|
|
2005
|
+
loadChildRuns: false
|
|
2006
|
+
}) {
|
|
2007
|
+
warnOnce("This method is deprecated and will be removed in future LangSmith versions, use `evaluate` from `langsmith/evaluation` instead.");
|
|
2008
|
+
let run_;
|
|
2009
|
+
if ("string" == typeof run) run_ = await this.readRun(run, {
|
|
2010
|
+
loadChildRuns
|
|
2011
|
+
});
|
|
2012
|
+
else if ("object" == typeof run && "id" in run) run_ = run;
|
|
2013
|
+
else throw new Error(`Invalid run type: ${typeof run}`);
|
|
2014
|
+
if (null !== run_.reference_example_id && void 0 !== run_.reference_example_id) referenceExample = await this.readExample(run_.reference_example_id);
|
|
2015
|
+
const feedbackResult = await evaluator.evaluateRun(run_, referenceExample);
|
|
2016
|
+
const [_, feedbacks] = await this._logEvaluationFeedback(feedbackResult, run_, sourceInfo);
|
|
2017
|
+
return feedbacks[0];
|
|
2018
|
+
}
|
|
2019
|
+
async createFeedback(runId, key, { score, value, correction, comment, sourceInfo, feedbackSourceType = "api", sourceRunId, feedbackId, feedbackConfig, projectId, comparativeExperimentId }) {
|
|
2020
|
+
if (!runId && !projectId) throw new Error("One of runId or projectId must be provided");
|
|
2021
|
+
if (runId && projectId) throw new Error("Only one of runId or projectId can be provided");
|
|
2022
|
+
const feedback_source = {
|
|
2023
|
+
type: feedbackSourceType ?? "api",
|
|
2024
|
+
metadata: sourceInfo ?? {}
|
|
2025
|
+
};
|
|
2026
|
+
if (void 0 !== sourceRunId && feedback_source?.metadata !== void 0 && !feedback_source.metadata["__run"]) feedback_source.metadata["__run"] = {
|
|
2027
|
+
run_id: sourceRunId
|
|
2028
|
+
};
|
|
2029
|
+
if (feedback_source?.metadata !== void 0 && feedback_source.metadata["__run"]?.run_id !== void 0) assertUuid(feedback_source.metadata["__run"].run_id);
|
|
2030
|
+
const feedback = {
|
|
2031
|
+
id: feedbackId ?? v4.Z(),
|
|
2032
|
+
run_id: runId,
|
|
2033
|
+
key,
|
|
2034
|
+
score,
|
|
2035
|
+
value,
|
|
2036
|
+
correction,
|
|
2037
|
+
comment,
|
|
2038
|
+
feedback_source: feedback_source,
|
|
2039
|
+
comparative_experiment_id: comparativeExperimentId,
|
|
2040
|
+
feedbackConfig,
|
|
2041
|
+
session_id: projectId
|
|
2042
|
+
};
|
|
2043
|
+
const url = `${this.apiUrl}/feedback`;
|
|
2044
|
+
const response = await this.caller.call(_getFetchImplementation(), url, {
|
|
2045
|
+
method: "POST",
|
|
2046
|
+
headers: {
|
|
2047
|
+
...this.headers,
|
|
2048
|
+
"Content-Type": "application/json"
|
|
2049
|
+
},
|
|
2050
|
+
body: JSON.stringify(feedback),
|
|
2051
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2052
|
+
...this.fetchOptions
|
|
2053
|
+
});
|
|
2054
|
+
await raiseForStatus(response, "create feedback", true);
|
|
2055
|
+
return feedback;
|
|
2056
|
+
}
|
|
2057
|
+
async updateFeedback(feedbackId, { score, value, correction, comment }) {
|
|
2058
|
+
const feedbackUpdate = {};
|
|
2059
|
+
if (null != score) feedbackUpdate["score"] = score;
|
|
2060
|
+
if (null != value) feedbackUpdate["value"] = value;
|
|
2061
|
+
if (null != correction) feedbackUpdate["correction"] = correction;
|
|
2062
|
+
if (null != comment) feedbackUpdate["comment"] = comment;
|
|
2063
|
+
assertUuid(feedbackId);
|
|
2064
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/feedback/${feedbackId}`, {
|
|
2065
|
+
method: "PATCH",
|
|
2066
|
+
headers: {
|
|
2067
|
+
...this.headers,
|
|
2068
|
+
"Content-Type": "application/json"
|
|
2069
|
+
},
|
|
2070
|
+
body: JSON.stringify(feedbackUpdate),
|
|
2071
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2072
|
+
...this.fetchOptions
|
|
2073
|
+
});
|
|
2074
|
+
await raiseForStatus(response, "update feedback", true);
|
|
2075
|
+
}
|
|
2076
|
+
async readFeedback(feedbackId) {
|
|
2077
|
+
assertUuid(feedbackId);
|
|
2078
|
+
const path = `/feedback/${feedbackId}`;
|
|
2079
|
+
const response = await this._get(path);
|
|
2080
|
+
return response;
|
|
2081
|
+
}
|
|
2082
|
+
async deleteFeedback(feedbackId) {
|
|
2083
|
+
assertUuid(feedbackId);
|
|
2084
|
+
const path = `/feedback/${feedbackId}`;
|
|
2085
|
+
const response = await this.caller.call(_getFetchImplementation(), this.apiUrl + path, {
|
|
2086
|
+
method: "DELETE",
|
|
2087
|
+
headers: this.headers,
|
|
2088
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2089
|
+
...this.fetchOptions
|
|
2090
|
+
});
|
|
2091
|
+
await raiseForStatus(response, `delete ${path}`);
|
|
2092
|
+
await response.json();
|
|
2093
|
+
}
|
|
2094
|
+
async *listFeedback({ runIds, feedbackKeys, feedbackSourceTypes } = {}) {
|
|
2095
|
+
const queryParams = new URLSearchParams();
|
|
2096
|
+
if (runIds) queryParams.append("run", runIds.join(","));
|
|
2097
|
+
if (feedbackKeys) for (const key of feedbackKeys)queryParams.append("key", key);
|
|
2098
|
+
if (feedbackSourceTypes) for (const type of feedbackSourceTypes)queryParams.append("source", type);
|
|
2099
|
+
for await (const feedbacks of this._getPaginated("/feedback", queryParams))yield* feedbacks;
|
|
2100
|
+
}
|
|
2101
|
+
async createPresignedFeedbackToken(runId, feedbackKey, { expiration, feedbackConfig } = {}) {
|
|
2102
|
+
const body = {
|
|
2103
|
+
run_id: runId,
|
|
2104
|
+
feedback_key: feedbackKey,
|
|
2105
|
+
feedback_config: feedbackConfig
|
|
2106
|
+
};
|
|
2107
|
+
if (expiration) {
|
|
2108
|
+
if ("string" == typeof expiration) body["expires_at"] = expiration;
|
|
2109
|
+
else if (expiration?.hours || expiration?.minutes || expiration?.days) body["expires_in"] = expiration;
|
|
2110
|
+
} else body["expires_in"] = {
|
|
2111
|
+
hours: 3
|
|
2112
|
+
};
|
|
2113
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/feedback/tokens`, {
|
|
2114
|
+
method: "POST",
|
|
2115
|
+
headers: {
|
|
2116
|
+
...this.headers,
|
|
2117
|
+
"Content-Type": "application/json"
|
|
2118
|
+
},
|
|
2119
|
+
body: JSON.stringify(body),
|
|
2120
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2121
|
+
...this.fetchOptions
|
|
2122
|
+
});
|
|
2123
|
+
const result = await response.json();
|
|
2124
|
+
return result;
|
|
2125
|
+
}
|
|
2126
|
+
async createComparativeExperiment({ name, experimentIds, referenceDatasetId, createdAt, description, metadata, id }) {
|
|
2127
|
+
if (0 === experimentIds.length) throw new Error("At least one experiment is required");
|
|
2128
|
+
if (!referenceDatasetId) referenceDatasetId = (await this.readProject({
|
|
2129
|
+
projectId: experimentIds[0]
|
|
2130
|
+
})).reference_dataset_id;
|
|
2131
|
+
if (null == !referenceDatasetId) throw new Error("A reference dataset is required");
|
|
2132
|
+
const body = {
|
|
2133
|
+
id,
|
|
2134
|
+
name,
|
|
2135
|
+
experiment_ids: experimentIds,
|
|
2136
|
+
reference_dataset_id: referenceDatasetId,
|
|
2137
|
+
description,
|
|
2138
|
+
created_at: (createdAt ?? new Date())?.toISOString(),
|
|
2139
|
+
extra: {}
|
|
2140
|
+
};
|
|
2141
|
+
if (metadata) body.extra["metadata"] = metadata;
|
|
2142
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/datasets/comparative`, {
|
|
2143
|
+
method: "POST",
|
|
2144
|
+
headers: {
|
|
2145
|
+
...this.headers,
|
|
2146
|
+
"Content-Type": "application/json"
|
|
2147
|
+
},
|
|
2148
|
+
body: JSON.stringify(body),
|
|
2149
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2150
|
+
...this.fetchOptions
|
|
2151
|
+
});
|
|
2152
|
+
return await response.json();
|
|
2153
|
+
}
|
|
2154
|
+
async *listPresignedFeedbackTokens(runId) {
|
|
2155
|
+
assertUuid(runId);
|
|
2156
|
+
const params = new URLSearchParams({
|
|
2157
|
+
run_id: runId
|
|
2158
|
+
});
|
|
2159
|
+
for await (const tokens of this._getPaginated("/feedback/tokens", params))yield* tokens;
|
|
2160
|
+
}
|
|
2161
|
+
_selectEvalResults(results) {
|
|
2162
|
+
let results_;
|
|
2163
|
+
results_ = "results" in results ? results.results : [
|
|
2164
|
+
results
|
|
2165
|
+
];
|
|
2166
|
+
return results_;
|
|
2167
|
+
}
|
|
2168
|
+
async _logEvaluationFeedback(evaluatorResponse, run, sourceInfo) {
|
|
2169
|
+
const evalResults = this._selectEvalResults(evaluatorResponse);
|
|
2170
|
+
const feedbacks = [];
|
|
2171
|
+
for (const res of evalResults){
|
|
2172
|
+
let sourceInfo_ = sourceInfo || {};
|
|
2173
|
+
if (res.evaluatorInfo) sourceInfo_ = {
|
|
2174
|
+
...res.evaluatorInfo,
|
|
2175
|
+
...sourceInfo_
|
|
2176
|
+
};
|
|
2177
|
+
let runId_ = null;
|
|
2178
|
+
if (res.targetRunId) runId_ = res.targetRunId;
|
|
2179
|
+
else if (run) runId_ = run.id;
|
|
2180
|
+
feedbacks.push(await this.createFeedback(runId_, res.key, {
|
|
2181
|
+
score: res.score,
|
|
2182
|
+
value: res.value,
|
|
2183
|
+
comment: res.comment,
|
|
2184
|
+
correction: res.correction,
|
|
2185
|
+
sourceInfo: sourceInfo_,
|
|
2186
|
+
sourceRunId: res.sourceRunId,
|
|
2187
|
+
feedbackConfig: res.feedbackConfig,
|
|
2188
|
+
feedbackSourceType: "model"
|
|
2189
|
+
}));
|
|
2190
|
+
}
|
|
2191
|
+
return [
|
|
2192
|
+
evalResults,
|
|
2193
|
+
feedbacks
|
|
2194
|
+
];
|
|
2195
|
+
}
|
|
2196
|
+
async logEvaluationFeedback(evaluatorResponse, run, sourceInfo) {
|
|
2197
|
+
const [results] = await this._logEvaluationFeedback(evaluatorResponse, run, sourceInfo);
|
|
2198
|
+
return results;
|
|
2199
|
+
}
|
|
2200
|
+
async *listAnnotationQueues(options = {}) {
|
|
2201
|
+
const { queueIds, name, nameContains, limit } = options;
|
|
2202
|
+
const params = new URLSearchParams();
|
|
2203
|
+
if (queueIds) queueIds.forEach((id, i)=>{
|
|
2204
|
+
assertUuid(id, `queueIds[${i}]`);
|
|
2205
|
+
params.append("ids", id);
|
|
2206
|
+
});
|
|
2207
|
+
if (name) params.append("name", name);
|
|
2208
|
+
if (nameContains) params.append("name_contains", nameContains);
|
|
2209
|
+
params.append("limit", (void 0 !== limit ? Math.min(limit, 100) : 100).toString());
|
|
2210
|
+
let count = 0;
|
|
2211
|
+
for await (const queues of this._getPaginated("/annotation-queues", params)){
|
|
2212
|
+
yield* queues;
|
|
2213
|
+
count++;
|
|
2214
|
+
if (void 0 !== limit && count >= limit) break;
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
async createAnnotationQueue(options) {
|
|
2218
|
+
const { name, description, queueId } = options;
|
|
2219
|
+
const body = {
|
|
2220
|
+
name,
|
|
2221
|
+
description,
|
|
2222
|
+
id: queueId || v4.Z()
|
|
2223
|
+
};
|
|
2224
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/annotation-queues`, {
|
|
2225
|
+
method: "POST",
|
|
2226
|
+
headers: {
|
|
2227
|
+
...this.headers,
|
|
2228
|
+
"Content-Type": "application/json"
|
|
2229
|
+
},
|
|
2230
|
+
body: JSON.stringify(Object.fromEntries(Object.entries(body).filter(([_, v])=>void 0 !== v))),
|
|
2231
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2232
|
+
...this.fetchOptions
|
|
2233
|
+
});
|
|
2234
|
+
await raiseForStatus(response, "create annotation queue");
|
|
2235
|
+
const data = await response.json();
|
|
2236
|
+
return data;
|
|
2237
|
+
}
|
|
2238
|
+
async readAnnotationQueue(queueId) {
|
|
2239
|
+
const queueIteratorResult = await this.listAnnotationQueues({
|
|
2240
|
+
queueIds: [
|
|
2241
|
+
queueId
|
|
2242
|
+
]
|
|
2243
|
+
}).next();
|
|
2244
|
+
if (queueIteratorResult.done) throw new Error(`Annotation queue with ID ${queueId} not found`);
|
|
2245
|
+
return queueIteratorResult.value;
|
|
2246
|
+
}
|
|
2247
|
+
async updateAnnotationQueue(queueId, options) {
|
|
2248
|
+
const { name, description } = options;
|
|
2249
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/annotation-queues/${assertUuid(queueId, "queueId")}`, {
|
|
2250
|
+
method: "PATCH",
|
|
2251
|
+
headers: {
|
|
2252
|
+
...this.headers,
|
|
2253
|
+
"Content-Type": "application/json"
|
|
2254
|
+
},
|
|
2255
|
+
body: JSON.stringify({
|
|
2256
|
+
name,
|
|
2257
|
+
description
|
|
2258
|
+
}),
|
|
2259
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2260
|
+
...this.fetchOptions
|
|
2261
|
+
});
|
|
2262
|
+
await raiseForStatus(response, "update annotation queue");
|
|
2263
|
+
}
|
|
2264
|
+
async deleteAnnotationQueue(queueId) {
|
|
2265
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/annotation-queues/${assertUuid(queueId, "queueId")}`, {
|
|
2266
|
+
method: "DELETE",
|
|
2267
|
+
headers: {
|
|
2268
|
+
...this.headers,
|
|
2269
|
+
Accept: "application/json"
|
|
2270
|
+
},
|
|
2271
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2272
|
+
...this.fetchOptions
|
|
2273
|
+
});
|
|
2274
|
+
await raiseForStatus(response, "delete annotation queue");
|
|
2275
|
+
}
|
|
2276
|
+
async addRunsToAnnotationQueue(queueId, runIds) {
|
|
2277
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/annotation-queues/${assertUuid(queueId, "queueId")}/runs`, {
|
|
2278
|
+
method: "POST",
|
|
2279
|
+
headers: {
|
|
2280
|
+
...this.headers,
|
|
2281
|
+
"Content-Type": "application/json"
|
|
2282
|
+
},
|
|
2283
|
+
body: JSON.stringify(runIds.map((id, i)=>assertUuid(id, `runIds[${i}]`).toString())),
|
|
2284
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2285
|
+
...this.fetchOptions
|
|
2286
|
+
});
|
|
2287
|
+
await raiseForStatus(response, "add runs to annotation queue");
|
|
2288
|
+
}
|
|
2289
|
+
async getRunFromAnnotationQueue(queueId, index) {
|
|
2290
|
+
const baseUrl = `/annotation-queues/${assertUuid(queueId, "queueId")}/run`;
|
|
2291
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}${baseUrl}/${index}`, {
|
|
2292
|
+
method: "GET",
|
|
2293
|
+
headers: this.headers,
|
|
2294
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2295
|
+
...this.fetchOptions
|
|
2296
|
+
});
|
|
2297
|
+
await raiseForStatus(response, "get run from annotation queue");
|
|
2298
|
+
return await response.json();
|
|
2299
|
+
}
|
|
2300
|
+
async deleteRunFromAnnotationQueue(queueId, queueRunId) {
|
|
2301
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/annotation-queues/${assertUuid(queueId, "queueId")}/runs/${assertUuid(queueRunId, "queueRunId")}`, {
|
|
2302
|
+
method: "DELETE",
|
|
2303
|
+
headers: {
|
|
2304
|
+
...this.headers,
|
|
2305
|
+
Accept: "application/json"
|
|
2306
|
+
},
|
|
2307
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2308
|
+
...this.fetchOptions
|
|
2309
|
+
});
|
|
2310
|
+
await raiseForStatus(response, "delete run from annotation queue");
|
|
2311
|
+
}
|
|
2312
|
+
async getSizeFromAnnotationQueue(queueId) {
|
|
2313
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/annotation-queues/${assertUuid(queueId, "queueId")}/size`, {
|
|
2314
|
+
method: "GET",
|
|
2315
|
+
headers: this.headers,
|
|
2316
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2317
|
+
...this.fetchOptions
|
|
2318
|
+
});
|
|
2319
|
+
await raiseForStatus(response, "get size from annotation queue");
|
|
2320
|
+
return await response.json();
|
|
2321
|
+
}
|
|
2322
|
+
async _currentTenantIsOwner(owner) {
|
|
2323
|
+
const settings = await this._getSettings();
|
|
2324
|
+
return "-" == owner || settings.tenant_handle === owner;
|
|
2325
|
+
}
|
|
2326
|
+
async _ownerConflictError(action, owner) {
|
|
2327
|
+
const settings = await this._getSettings();
|
|
2328
|
+
return new Error(`Cannot ${action} for another tenant.\n
|
|
2329
|
+
Current tenant: ${settings.tenant_handle}\n
|
|
2330
|
+
Requested tenant: ${owner}`);
|
|
2331
|
+
}
|
|
2332
|
+
async _getLatestCommitHash(promptOwnerAndName) {
|
|
2333
|
+
const res = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/commits/${promptOwnerAndName}/?limit=1&offset=0`, {
|
|
2334
|
+
method: "GET",
|
|
2335
|
+
headers: this.headers,
|
|
2336
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2337
|
+
...this.fetchOptions
|
|
2338
|
+
});
|
|
2339
|
+
const json = await res.json();
|
|
2340
|
+
if (!res.ok) {
|
|
2341
|
+
const detail = "string" == typeof json.detail ? json.detail : JSON.stringify(json.detail);
|
|
2342
|
+
const error = new Error(`Error ${res.status}: ${res.statusText}\n${detail}`);
|
|
2343
|
+
error.statusCode = res.status;
|
|
2344
|
+
throw error;
|
|
2345
|
+
}
|
|
2346
|
+
if (0 === json.commits.length) return;
|
|
2347
|
+
return json.commits[0].commit_hash;
|
|
2348
|
+
}
|
|
2349
|
+
async _likeOrUnlikePrompt(promptIdentifier, like) {
|
|
2350
|
+
const [owner, promptName, _] = parsePromptIdentifier(promptIdentifier);
|
|
2351
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/likes/${owner}/${promptName}`, {
|
|
2352
|
+
method: "POST",
|
|
2353
|
+
body: JSON.stringify({
|
|
2354
|
+
like: like
|
|
2355
|
+
}),
|
|
2356
|
+
headers: {
|
|
2357
|
+
...this.headers,
|
|
2358
|
+
"Content-Type": "application/json"
|
|
2359
|
+
},
|
|
2360
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2361
|
+
...this.fetchOptions
|
|
2362
|
+
});
|
|
2363
|
+
await raiseForStatus(response, `${like ? "like" : "unlike"} prompt`);
|
|
2364
|
+
return await response.json();
|
|
2365
|
+
}
|
|
2366
|
+
async _getPromptUrl(promptIdentifier) {
|
|
2367
|
+
const [owner, promptName, commitHash] = parsePromptIdentifier(promptIdentifier);
|
|
2368
|
+
if (await this._currentTenantIsOwner(owner)) {
|
|
2369
|
+
const settings = await this._getSettings();
|
|
2370
|
+
if ("latest" !== commitHash) return `${this.getHostUrl()}/prompts/${promptName}/${commitHash.substring(0, 8)}?organizationId=${settings.id}`;
|
|
2371
|
+
return `${this.getHostUrl()}/prompts/${promptName}?organizationId=${settings.id}`;
|
|
2372
|
+
}
|
|
2373
|
+
if ("latest" !== commitHash) return `${this.getHostUrl()}/hub/${owner}/${promptName}/${commitHash.substring(0, 8)}`;
|
|
2374
|
+
return `${this.getHostUrl()}/hub/${owner}/${promptName}`;
|
|
2375
|
+
}
|
|
2376
|
+
async promptExists(promptIdentifier) {
|
|
2377
|
+
const prompt = await this.getPrompt(promptIdentifier);
|
|
2378
|
+
return !!prompt;
|
|
2379
|
+
}
|
|
2380
|
+
async likePrompt(promptIdentifier) {
|
|
2381
|
+
return this._likeOrUnlikePrompt(promptIdentifier, true);
|
|
2382
|
+
}
|
|
2383
|
+
async unlikePrompt(promptIdentifier) {
|
|
2384
|
+
return this._likeOrUnlikePrompt(promptIdentifier, false);
|
|
2385
|
+
}
|
|
2386
|
+
async *listCommits(promptOwnerAndName) {
|
|
2387
|
+
for await (const commits of this._getPaginated(`/commits/${promptOwnerAndName}/`, new URLSearchParams(), (res)=>res.commits))yield* commits;
|
|
2388
|
+
}
|
|
2389
|
+
async *listPrompts(options) {
|
|
2390
|
+
const params = new URLSearchParams();
|
|
2391
|
+
params.append("sort_field", options?.sortField ?? "updated_at");
|
|
2392
|
+
params.append("sort_direction", "desc");
|
|
2393
|
+
params.append("is_archived", (!!options?.isArchived).toString());
|
|
2394
|
+
if (options?.isPublic !== void 0) params.append("is_public", options.isPublic.toString());
|
|
2395
|
+
if (options?.query) params.append("query", options.query);
|
|
2396
|
+
for await (const prompts of this._getPaginated("/repos", params, (res)=>res.repos))yield* prompts;
|
|
2397
|
+
}
|
|
2398
|
+
async getPrompt(promptIdentifier) {
|
|
2399
|
+
const [owner, promptName, _] = parsePromptIdentifier(promptIdentifier);
|
|
2400
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/repos/${owner}/${promptName}`, {
|
|
2401
|
+
method: "GET",
|
|
2402
|
+
headers: this.headers,
|
|
2403
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2404
|
+
...this.fetchOptions
|
|
2405
|
+
});
|
|
2406
|
+
if (404 === response.status) return null;
|
|
2407
|
+
await raiseForStatus(response, "get prompt");
|
|
2408
|
+
const result = await response.json();
|
|
2409
|
+
if (result.repo) return result.repo;
|
|
2410
|
+
return null;
|
|
2411
|
+
}
|
|
2412
|
+
async createPrompt(promptIdentifier, options) {
|
|
2413
|
+
const settings = await this._getSettings();
|
|
2414
|
+
if (options?.isPublic && !settings.tenant_handle) throw new Error(`Cannot create a public prompt without first\n
|
|
2415
|
+
creating a LangChain Hub handle.
|
|
2416
|
+
You can add a handle by creating a public prompt at:\n
|
|
2417
|
+
https://smith.langchain.com/prompts`);
|
|
2418
|
+
const [owner, promptName, _] = parsePromptIdentifier(promptIdentifier);
|
|
2419
|
+
if (!await this._currentTenantIsOwner(owner)) throw await this._ownerConflictError("create a prompt", owner);
|
|
2420
|
+
const data = {
|
|
2421
|
+
repo_handle: promptName,
|
|
2422
|
+
...options?.description && {
|
|
2423
|
+
description: options.description
|
|
2424
|
+
},
|
|
2425
|
+
...options?.readme && {
|
|
2426
|
+
readme: options.readme
|
|
2427
|
+
},
|
|
2428
|
+
...options?.tags && {
|
|
2429
|
+
tags: options.tags
|
|
2430
|
+
},
|
|
2431
|
+
is_public: !!options?.isPublic
|
|
2432
|
+
};
|
|
2433
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/repos/`, {
|
|
2434
|
+
method: "POST",
|
|
2435
|
+
headers: {
|
|
2436
|
+
...this.headers,
|
|
2437
|
+
"Content-Type": "application/json"
|
|
2438
|
+
},
|
|
2439
|
+
body: JSON.stringify(data),
|
|
2440
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2441
|
+
...this.fetchOptions
|
|
2442
|
+
});
|
|
2443
|
+
await raiseForStatus(response, "create prompt");
|
|
2444
|
+
const { repo } = await response.json();
|
|
2445
|
+
return repo;
|
|
2446
|
+
}
|
|
2447
|
+
async createCommit(promptIdentifier, object, options) {
|
|
2448
|
+
if (!await this.promptExists(promptIdentifier)) throw new Error("Prompt does not exist, you must create it first.");
|
|
2449
|
+
const [owner, promptName, _] = parsePromptIdentifier(promptIdentifier);
|
|
2450
|
+
const resolvedParentCommitHash = options?.parentCommitHash !== "latest" && options?.parentCommitHash ? options?.parentCommitHash : await this._getLatestCommitHash(`${owner}/${promptName}`);
|
|
2451
|
+
const payload = {
|
|
2452
|
+
manifest: JSON.parse(JSON.stringify(object)),
|
|
2453
|
+
parent_commit: resolvedParentCommitHash
|
|
2454
|
+
};
|
|
2455
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/commits/${owner}/${promptName}`, {
|
|
2456
|
+
method: "POST",
|
|
2457
|
+
headers: {
|
|
2458
|
+
...this.headers,
|
|
2459
|
+
"Content-Type": "application/json"
|
|
2460
|
+
},
|
|
2461
|
+
body: JSON.stringify(payload),
|
|
2462
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2463
|
+
...this.fetchOptions
|
|
2464
|
+
});
|
|
2465
|
+
await raiseForStatus(response, "create commit");
|
|
2466
|
+
const result = await response.json();
|
|
2467
|
+
return this._getPromptUrl(`${owner}/${promptName}${result.commit_hash ? `:${result.commit_hash}` : ""}`);
|
|
2468
|
+
}
|
|
2469
|
+
async updateExamplesMultipart(datasetId, updates = []) {
|
|
2470
|
+
if (!await this._getMultiPartSupport()) throw new Error("Your LangSmith version does not allow using the multipart examples endpoint, please update to the latest version.");
|
|
2471
|
+
const formData = new FormData();
|
|
2472
|
+
for (const example of updates){
|
|
2473
|
+
const exampleId = example.id;
|
|
2474
|
+
const exampleBody = {
|
|
2475
|
+
...example.metadata && {
|
|
2476
|
+
metadata: example.metadata
|
|
2477
|
+
},
|
|
2478
|
+
...example.split && {
|
|
2479
|
+
split: example.split
|
|
2480
|
+
}
|
|
2481
|
+
};
|
|
2482
|
+
const stringifiedExample = serialize(exampleBody);
|
|
2483
|
+
const exampleBlob = new Blob([
|
|
2484
|
+
stringifiedExample
|
|
2485
|
+
], {
|
|
2486
|
+
type: "application/json"
|
|
2487
|
+
});
|
|
2488
|
+
formData.append(exampleId, exampleBlob);
|
|
2489
|
+
if (example.inputs) {
|
|
2490
|
+
const stringifiedInputs = serialize(example.inputs);
|
|
2491
|
+
const inputsBlob = new Blob([
|
|
2492
|
+
stringifiedInputs
|
|
2493
|
+
], {
|
|
2494
|
+
type: "application/json"
|
|
2495
|
+
});
|
|
2496
|
+
formData.append(`${exampleId}.inputs`, inputsBlob);
|
|
2497
|
+
}
|
|
2498
|
+
if (example.outputs) {
|
|
2499
|
+
const stringifiedOutputs = serialize(example.outputs);
|
|
2500
|
+
const outputsBlob = new Blob([
|
|
2501
|
+
stringifiedOutputs
|
|
2502
|
+
], {
|
|
2503
|
+
type: "application/json"
|
|
2504
|
+
});
|
|
2505
|
+
formData.append(`${exampleId}.outputs`, outputsBlob);
|
|
2506
|
+
}
|
|
2507
|
+
if (example.attachments) for (const [name, attachment] of Object.entries(example.attachments)){
|
|
2508
|
+
let mimeType;
|
|
2509
|
+
let data;
|
|
2510
|
+
if (Array.isArray(attachment)) [mimeType, data] = attachment;
|
|
2511
|
+
else {
|
|
2512
|
+
mimeType = attachment.mimeType;
|
|
2513
|
+
data = attachment.data;
|
|
2514
|
+
}
|
|
2515
|
+
const attachmentBlob = new Blob([
|
|
2516
|
+
data
|
|
2517
|
+
], {
|
|
2518
|
+
type: `${mimeType}; length=${data.byteLength}`
|
|
2519
|
+
});
|
|
2520
|
+
formData.append(`${exampleId}.attachment.${name}`, attachmentBlob);
|
|
2521
|
+
}
|
|
2522
|
+
if (example.attachments_operations) {
|
|
2523
|
+
const stringifiedAttachmentsOperations = serialize(example.attachments_operations);
|
|
2524
|
+
const attachmentsOperationsBlob = new Blob([
|
|
2525
|
+
stringifiedAttachmentsOperations
|
|
2526
|
+
], {
|
|
2527
|
+
type: "application/json"
|
|
2528
|
+
});
|
|
2529
|
+
formData.append(`${exampleId}.attachments_operations`, attachmentsOperationsBlob);
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/v1/platform/datasets/${datasetId}/examples`, {
|
|
2533
|
+
method: "PATCH",
|
|
2534
|
+
headers: this.headers,
|
|
2535
|
+
body: formData
|
|
2536
|
+
});
|
|
2537
|
+
const result = await response.json();
|
|
2538
|
+
return result;
|
|
2539
|
+
}
|
|
2540
|
+
async uploadExamplesMultipart(datasetId, uploads = []) {
|
|
2541
|
+
if (!await this._getMultiPartSupport()) throw new Error("Your LangSmith version does not allow using the multipart examples endpoint, please update to the latest version.");
|
|
2542
|
+
const formData = new FormData();
|
|
2543
|
+
for (const example of uploads){
|
|
2544
|
+
const exampleId = (example.id ?? v4.Z()).toString();
|
|
2545
|
+
const exampleBody = {
|
|
2546
|
+
created_at: example.created_at,
|
|
2547
|
+
...example.metadata && {
|
|
2548
|
+
metadata: example.metadata
|
|
2549
|
+
},
|
|
2550
|
+
...example.split && {
|
|
2551
|
+
split: example.split
|
|
2552
|
+
}
|
|
2553
|
+
};
|
|
2554
|
+
const stringifiedExample = serialize(exampleBody);
|
|
2555
|
+
const exampleBlob = new Blob([
|
|
2556
|
+
stringifiedExample
|
|
2557
|
+
], {
|
|
2558
|
+
type: "application/json"
|
|
2559
|
+
});
|
|
2560
|
+
formData.append(exampleId, exampleBlob);
|
|
2561
|
+
const stringifiedInputs = serialize(example.inputs);
|
|
2562
|
+
const inputsBlob = new Blob([
|
|
2563
|
+
stringifiedInputs
|
|
2564
|
+
], {
|
|
2565
|
+
type: "application/json"
|
|
2566
|
+
});
|
|
2567
|
+
formData.append(`${exampleId}.inputs`, inputsBlob);
|
|
2568
|
+
if (example.outputs) {
|
|
2569
|
+
const stringifiedOutputs = serialize(example.outputs);
|
|
2570
|
+
const outputsBlob = new Blob([
|
|
2571
|
+
stringifiedOutputs
|
|
2572
|
+
], {
|
|
2573
|
+
type: "application/json"
|
|
2574
|
+
});
|
|
2575
|
+
formData.append(`${exampleId}.outputs`, outputsBlob);
|
|
2576
|
+
}
|
|
2577
|
+
if (example.attachments) for (const [name, attachment] of Object.entries(example.attachments)){
|
|
2578
|
+
let mimeType;
|
|
2579
|
+
let data;
|
|
2580
|
+
if (Array.isArray(attachment)) [mimeType, data] = attachment;
|
|
2581
|
+
else {
|
|
2582
|
+
mimeType = attachment.mimeType;
|
|
2583
|
+
data = attachment.data;
|
|
2584
|
+
}
|
|
2585
|
+
const attachmentBlob = new Blob([
|
|
2586
|
+
data
|
|
2587
|
+
], {
|
|
2588
|
+
type: `${mimeType}; length=${data.byteLength}`
|
|
2589
|
+
});
|
|
2590
|
+
formData.append(`${exampleId}.attachment.${name}`, attachmentBlob);
|
|
2591
|
+
}
|
|
2592
|
+
}
|
|
2593
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/v1/platform/datasets/${datasetId}/examples`, {
|
|
2594
|
+
method: "POST",
|
|
2595
|
+
headers: this.headers,
|
|
2596
|
+
body: formData
|
|
2597
|
+
});
|
|
2598
|
+
const result = await response.json();
|
|
2599
|
+
return result;
|
|
2600
|
+
}
|
|
2601
|
+
async updatePrompt(promptIdentifier, options) {
|
|
2602
|
+
if (!await this.promptExists(promptIdentifier)) throw new Error("Prompt does not exist, you must create it first.");
|
|
2603
|
+
const [owner, promptName] = parsePromptIdentifier(promptIdentifier);
|
|
2604
|
+
if (!await this._currentTenantIsOwner(owner)) throw await this._ownerConflictError("update a prompt", owner);
|
|
2605
|
+
const payload = {};
|
|
2606
|
+
if (options?.description !== void 0) payload.description = options.description;
|
|
2607
|
+
if (options?.readme !== void 0) payload.readme = options.readme;
|
|
2608
|
+
if (options?.tags !== void 0) payload.tags = options.tags;
|
|
2609
|
+
if (options?.isPublic !== void 0) payload.is_public = options.isPublic;
|
|
2610
|
+
if (options?.isArchived !== void 0) payload.is_archived = options.isArchived;
|
|
2611
|
+
if (0 === Object.keys(payload).length) throw new Error("No valid update options provided");
|
|
2612
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/repos/${owner}/${promptName}`, {
|
|
2613
|
+
method: "PATCH",
|
|
2614
|
+
body: JSON.stringify(payload),
|
|
2615
|
+
headers: {
|
|
2616
|
+
...this.headers,
|
|
2617
|
+
"Content-Type": "application/json"
|
|
2618
|
+
},
|
|
2619
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2620
|
+
...this.fetchOptions
|
|
2621
|
+
});
|
|
2622
|
+
await raiseForStatus(response, "update prompt");
|
|
2623
|
+
return response.json();
|
|
2624
|
+
}
|
|
2625
|
+
async deletePrompt(promptIdentifier) {
|
|
2626
|
+
if (!await this.promptExists(promptIdentifier)) throw new Error("Prompt does not exist, you must create it first.");
|
|
2627
|
+
const [owner, promptName, _] = parsePromptIdentifier(promptIdentifier);
|
|
2628
|
+
if (!await this._currentTenantIsOwner(owner)) throw await this._ownerConflictError("delete a prompt", owner);
|
|
2629
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/repos/${owner}/${promptName}`, {
|
|
2630
|
+
method: "DELETE",
|
|
2631
|
+
headers: this.headers,
|
|
2632
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2633
|
+
...this.fetchOptions
|
|
2634
|
+
});
|
|
2635
|
+
return await response.json();
|
|
2636
|
+
}
|
|
2637
|
+
async pullPromptCommit(promptIdentifier, options) {
|
|
2638
|
+
const [owner, promptName, commitHash] = parsePromptIdentifier(promptIdentifier);
|
|
2639
|
+
const response = await this.caller.call(_getFetchImplementation(), `${this.apiUrl}/commits/${owner}/${promptName}/${commitHash}${options?.includeModel ? "?include_model=true" : ""}`, {
|
|
2640
|
+
method: "GET",
|
|
2641
|
+
headers: this.headers,
|
|
2642
|
+
signal: AbortSignal.timeout(this.timeout_ms),
|
|
2643
|
+
...this.fetchOptions
|
|
2644
|
+
});
|
|
2645
|
+
await raiseForStatus(response, "pull prompt commit");
|
|
2646
|
+
const result = await response.json();
|
|
2647
|
+
return {
|
|
2648
|
+
owner,
|
|
2649
|
+
repo: promptName,
|
|
2650
|
+
commit_hash: result.commit_hash,
|
|
2651
|
+
manifest: result.manifest,
|
|
2652
|
+
examples: result.examples
|
|
2653
|
+
};
|
|
2654
|
+
}
|
|
2655
|
+
async _pullPrompt(promptIdentifier, options) {
|
|
2656
|
+
const promptObject = await this.pullPromptCommit(promptIdentifier, {
|
|
2657
|
+
includeModel: options?.includeModel
|
|
2658
|
+
});
|
|
2659
|
+
const prompt = JSON.stringify(promptObject.manifest);
|
|
2660
|
+
return prompt;
|
|
2661
|
+
}
|
|
2662
|
+
async pushPrompt(promptIdentifier, options) {
|
|
2663
|
+
if (await this.promptExists(promptIdentifier)) {
|
|
2664
|
+
if (options && Object.keys(options).some((key)=>"object" !== key)) await this.updatePrompt(promptIdentifier, {
|
|
2665
|
+
description: options?.description,
|
|
2666
|
+
readme: options?.readme,
|
|
2667
|
+
tags: options?.tags,
|
|
2668
|
+
isPublic: options?.isPublic
|
|
2669
|
+
});
|
|
2670
|
+
} else await this.createPrompt(promptIdentifier, {
|
|
2671
|
+
description: options?.description,
|
|
2672
|
+
readme: options?.readme,
|
|
2673
|
+
tags: options?.tags,
|
|
2674
|
+
isPublic: options?.isPublic
|
|
2675
|
+
});
|
|
2676
|
+
if (!options?.object) return await this._getPromptUrl(promptIdentifier);
|
|
2677
|
+
const url = await this.createCommit(promptIdentifier, options?.object, {
|
|
2678
|
+
parentCommitHash: options?.parentCommitHash
|
|
2679
|
+
});
|
|
2680
|
+
return url;
|
|
2681
|
+
}
|
|
2682
|
+
async clonePublicDataset(tokenOrUrl, options = {}) {
|
|
2683
|
+
const { sourceApiUrl = this.apiUrl, datasetName } = options;
|
|
2684
|
+
const [parsedApiUrl, tokenUuid] = this.parseTokenOrUrl(tokenOrUrl, sourceApiUrl);
|
|
2685
|
+
const sourceClient = new Client({
|
|
2686
|
+
apiUrl: parsedApiUrl,
|
|
2687
|
+
apiKey: "placeholder"
|
|
2688
|
+
});
|
|
2689
|
+
const ds = await sourceClient.readSharedDataset(tokenUuid);
|
|
2690
|
+
const finalDatasetName = datasetName || ds.name;
|
|
2691
|
+
try {
|
|
2692
|
+
if (await this.hasDataset({
|
|
2693
|
+
datasetId: finalDatasetName
|
|
2694
|
+
})) return void console.log(`Dataset ${finalDatasetName} already exists in your tenant. Skipping.`);
|
|
2695
|
+
} catch (_) {}
|
|
2696
|
+
const examples = await sourceClient.listSharedExamples(tokenUuid);
|
|
2697
|
+
const dataset = await this.createDataset(finalDatasetName, {
|
|
2698
|
+
description: ds.description,
|
|
2699
|
+
dataType: ds.data_type || "kv",
|
|
2700
|
+
inputsSchema: ds.inputs_schema_definition ?? void 0,
|
|
2701
|
+
outputsSchema: ds.outputs_schema_definition ?? void 0
|
|
2702
|
+
});
|
|
2703
|
+
try {
|
|
2704
|
+
await this.createExamples({
|
|
2705
|
+
inputs: examples.map((e)=>e.inputs),
|
|
2706
|
+
outputs: examples.flatMap((e)=>e.outputs ? [
|
|
2707
|
+
e.outputs
|
|
2708
|
+
] : []),
|
|
2709
|
+
datasetId: dataset.id
|
|
2710
|
+
});
|
|
2711
|
+
} catch (e) {
|
|
2712
|
+
console.error(`An error occurred while creating dataset ${finalDatasetName}. You should delete it manually.`);
|
|
2713
|
+
throw e;
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
parseTokenOrUrl(urlOrToken, apiUrl, numParts = 2, kind = "dataset") {
|
|
2717
|
+
try {
|
|
2718
|
+
assertUuid(urlOrToken);
|
|
2719
|
+
return [
|
|
2720
|
+
apiUrl,
|
|
2721
|
+
urlOrToken
|
|
2722
|
+
];
|
|
2723
|
+
} catch (_) {}
|
|
2724
|
+
try {
|
|
2725
|
+
const parsedUrl = new URL(urlOrToken);
|
|
2726
|
+
const pathParts = parsedUrl.pathname.split("/").filter((part)=>"" !== part);
|
|
2727
|
+
if (pathParts.length >= numParts) {
|
|
2728
|
+
const tokenUuid = pathParts[pathParts.length - numParts];
|
|
2729
|
+
return [
|
|
2730
|
+
apiUrl,
|
|
2731
|
+
tokenUuid
|
|
2732
|
+
];
|
|
2733
|
+
}
|
|
2734
|
+
throw new Error(`Invalid public ${kind} URL: ${urlOrToken}`);
|
|
2735
|
+
} catch (error) {
|
|
2736
|
+
throw new Error(`Invalid public ${kind} URL or token: ${urlOrToken}`);
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
awaitPendingTraceBatches() {
|
|
2740
|
+
if (this.manualFlushMode) {
|
|
2741
|
+
console.warn("[WARNING]: When tracing in manual flush mode, you must call `await client.flush()` manually to submit trace batches.");
|
|
2742
|
+
return Promise.resolve();
|
|
2743
|
+
}
|
|
2744
|
+
return Promise.all([
|
|
2745
|
+
...this.autoBatchQueue.items.map(({ itemPromise })=>itemPromise),
|
|
2746
|
+
this.batchIngestCaller.queue.onIdle()
|
|
2747
|
+
]);
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
const __version__ = "0.3.7";
|
|
2751
|
+
let globalEnv;
|
|
2752
|
+
const isBrowser = ()=>"undefined" != typeof window && void 0 !== window.document;
|
|
2753
|
+
const isWebWorker = ()=>"object" == typeof globalThis && globalThis.constructor && "DedicatedWorkerGlobalScope" === globalThis.constructor.name;
|
|
2754
|
+
const isJsDom = ()=>"undefined" != typeof window && "nodejs" === window.name || "undefined" != typeof navigator && (navigator.userAgent.includes("Node.js") || navigator.userAgent.includes("jsdom"));
|
|
2755
|
+
const isDeno = ()=>"undefined" != typeof Deno;
|
|
2756
|
+
const isNode = ()=>"undefined" != typeof process && void 0 !== process.versions && void 0 !== process.versions.node && !isDeno();
|
|
2757
|
+
const getEnv = ()=>{
|
|
2758
|
+
if (globalEnv) return globalEnv;
|
|
2759
|
+
globalEnv = isBrowser() ? "browser" : isNode() ? "node" : isWebWorker() ? "webworker" : isJsDom() ? "jsdom" : isDeno() ? "deno" : "other";
|
|
2760
|
+
return globalEnv;
|
|
2761
|
+
};
|
|
2762
|
+
let runtimeEnvironment;
|
|
2763
|
+
function getRuntimeEnvironment() {
|
|
2764
|
+
if (void 0 === runtimeEnvironment) {
|
|
2765
|
+
const env = getEnv();
|
|
2766
|
+
const releaseEnv = getShas();
|
|
2767
|
+
runtimeEnvironment = {
|
|
2768
|
+
library: "langsmith",
|
|
2769
|
+
runtime: env,
|
|
2770
|
+
sdk: "langsmith-js",
|
|
2771
|
+
sdk_version: __version__,
|
|
2772
|
+
...releaseEnv
|
|
2773
|
+
};
|
|
2774
|
+
}
|
|
2775
|
+
return runtimeEnvironment;
|
|
2776
|
+
}
|
|
2777
|
+
function getLangChainEnvVarsMetadata() {
|
|
2778
|
+
const allEnvVars = getEnvironmentVariables() || {};
|
|
2779
|
+
const envVars = {};
|
|
2780
|
+
const excluded = [
|
|
2781
|
+
"LANGCHAIN_API_KEY",
|
|
2782
|
+
"LANGCHAIN_ENDPOINT",
|
|
2783
|
+
"LANGCHAIN_TRACING_V2",
|
|
2784
|
+
"LANGCHAIN_PROJECT",
|
|
2785
|
+
"LANGCHAIN_SESSION",
|
|
2786
|
+
"LANGSMITH_API_KEY",
|
|
2787
|
+
"LANGSMITH_ENDPOINT",
|
|
2788
|
+
"LANGSMITH_TRACING_V2",
|
|
2789
|
+
"LANGSMITH_PROJECT",
|
|
2790
|
+
"LANGSMITH_SESSION"
|
|
2791
|
+
];
|
|
2792
|
+
for (const [key, value] of Object.entries(allEnvVars))if ((key.startsWith("LANGCHAIN_") || key.startsWith("LANGSMITH_")) && "string" == typeof value && !excluded.includes(key) && !key.toLowerCase().includes("key") && !key.toLowerCase().includes("secret") && !key.toLowerCase().includes("token")) if ("LANGCHAIN_REVISION_ID" === key) envVars["revision_id"] = value;
|
|
2793
|
+
else envVars[key] = value;
|
|
2794
|
+
return envVars;
|
|
2795
|
+
}
|
|
2796
|
+
function getEnvironmentVariables() {
|
|
2797
|
+
try {
|
|
2798
|
+
if ("undefined" != typeof process && process.env) return Object.entries(process.env).reduce((acc, [key, value])=>{
|
|
2799
|
+
acc[key] = String(value);
|
|
2800
|
+
return acc;
|
|
2801
|
+
}, {});
|
|
2802
|
+
return;
|
|
2803
|
+
} catch (e) {
|
|
2804
|
+
return;
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
function getEnvironmentVariable(name) {
|
|
2808
|
+
try {
|
|
2809
|
+
return "undefined" != typeof process ? process.env?.[name] : void 0;
|
|
2810
|
+
} catch (e) {
|
|
2811
|
+
return;
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
function getLangSmithEnvironmentVariable(name) {
|
|
2815
|
+
return getEnvironmentVariable(`LANGSMITH_${name}`) || getEnvironmentVariable(`LANGCHAIN_${name}`);
|
|
2816
|
+
}
|
|
2817
|
+
let cachedCommitSHAs;
|
|
2818
|
+
function getShas() {
|
|
2819
|
+
if (void 0 !== cachedCommitSHAs) return cachedCommitSHAs;
|
|
2820
|
+
const common_release_envs = [
|
|
2821
|
+
"VERCEL_GIT_COMMIT_SHA",
|
|
2822
|
+
"NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA",
|
|
2823
|
+
"COMMIT_REF",
|
|
2824
|
+
"RENDER_GIT_COMMIT",
|
|
2825
|
+
"CI_COMMIT_SHA",
|
|
2826
|
+
"CIRCLE_SHA1",
|
|
2827
|
+
"CF_PAGES_COMMIT_SHA",
|
|
2828
|
+
"REACT_APP_GIT_SHA",
|
|
2829
|
+
"SOURCE_VERSION",
|
|
2830
|
+
"GITHUB_SHA",
|
|
2831
|
+
"TRAVIS_COMMIT",
|
|
2832
|
+
"GIT_COMMIT",
|
|
2833
|
+
"BUILD_VCS_NUMBER",
|
|
2834
|
+
"bamboo_planRepository_revision",
|
|
2835
|
+
"Build.SourceVersion",
|
|
2836
|
+
"BITBUCKET_COMMIT",
|
|
2837
|
+
"DRONE_COMMIT_SHA",
|
|
2838
|
+
"SEMAPHORE_GIT_SHA",
|
|
2839
|
+
"BUILDKITE_COMMIT"
|
|
2840
|
+
];
|
|
2841
|
+
const shas = {};
|
|
2842
|
+
for (const env of common_release_envs){
|
|
2843
|
+
const envVar = getEnvironmentVariable(env);
|
|
2844
|
+
if (void 0 !== envVar) shas[env] = envVar;
|
|
2845
|
+
}
|
|
2846
|
+
cachedCommitSHAs = shas;
|
|
2847
|
+
return shas;
|
|
2848
|
+
}
|
|
2849
|
+
const isTracingEnabled = (tracingEnabled)=>{
|
|
2850
|
+
if (void 0 !== tracingEnabled) return tracingEnabled;
|
|
2851
|
+
const envVars = [
|
|
2852
|
+
"TRACING_V2",
|
|
2853
|
+
"TRACING"
|
|
2854
|
+
];
|
|
2855
|
+
return !!envVars.find((envVar)=>"true" === getLangSmithEnvironmentVariable(envVar));
|
|
2856
|
+
};
|
|
2857
|
+
const _LC_CONTEXT_VARIABLES_KEY = Symbol.for("lc:context_variables");
|
|
2858
|
+
function stripNonAlphanumeric(input) {
|
|
2859
|
+
return input.replace(/[-:.]/g, "");
|
|
2860
|
+
}
|
|
2861
|
+
function convertToDottedOrderFormat(epoch, runId, executionOrder = 1) {
|
|
2862
|
+
const paddedOrder = executionOrder.toFixed(0).slice(0, 3).padStart(3, "0");
|
|
2863
|
+
return stripNonAlphanumeric(`${new Date(epoch).toISOString().slice(0, -1)}${paddedOrder}Z`) + runId;
|
|
2864
|
+
}
|
|
2865
|
+
class Baggage {
|
|
2866
|
+
constructor(metadata, tags){
|
|
2867
|
+
Object.defineProperty(this, "metadata", {
|
|
2868
|
+
enumerable: true,
|
|
2869
|
+
configurable: true,
|
|
2870
|
+
writable: true,
|
|
2871
|
+
value: void 0
|
|
2872
|
+
});
|
|
2873
|
+
Object.defineProperty(this, "tags", {
|
|
2874
|
+
enumerable: true,
|
|
2875
|
+
configurable: true,
|
|
2876
|
+
writable: true,
|
|
2877
|
+
value: void 0
|
|
2878
|
+
});
|
|
2879
|
+
this.metadata = metadata;
|
|
2880
|
+
this.tags = tags;
|
|
2881
|
+
}
|
|
2882
|
+
static fromHeader(value) {
|
|
2883
|
+
const items = value.split(",");
|
|
2884
|
+
let metadata = {};
|
|
2885
|
+
let tags = [];
|
|
2886
|
+
for (const item of items){
|
|
2887
|
+
const [key, uriValue] = item.split("=");
|
|
2888
|
+
const value = decodeURIComponent(uriValue);
|
|
2889
|
+
if ("langsmith-metadata" === key) metadata = JSON.parse(value);
|
|
2890
|
+
else if ("langsmith-tags" === key) tags = value.split(",");
|
|
2891
|
+
}
|
|
2892
|
+
return new Baggage(metadata, tags);
|
|
2893
|
+
}
|
|
2894
|
+
toHeader() {
|
|
2895
|
+
const items = [];
|
|
2896
|
+
if (this.metadata && Object.keys(this.metadata).length > 0) items.push(`langsmith-metadata=${encodeURIComponent(JSON.stringify(this.metadata))}`);
|
|
2897
|
+
if (this.tags && this.tags.length > 0) items.push(`langsmith-tags=${encodeURIComponent(this.tags.join(","))}`);
|
|
2898
|
+
return items.join(",");
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
class RunTree {
|
|
2902
|
+
constructor(originalConfig){
|
|
2903
|
+
Object.defineProperty(this, "id", {
|
|
2904
|
+
enumerable: true,
|
|
2905
|
+
configurable: true,
|
|
2906
|
+
writable: true,
|
|
2907
|
+
value: void 0
|
|
2908
|
+
});
|
|
2909
|
+
Object.defineProperty(this, "name", {
|
|
2910
|
+
enumerable: true,
|
|
2911
|
+
configurable: true,
|
|
2912
|
+
writable: true,
|
|
2913
|
+
value: void 0
|
|
2914
|
+
});
|
|
2915
|
+
Object.defineProperty(this, "run_type", {
|
|
2916
|
+
enumerable: true,
|
|
2917
|
+
configurable: true,
|
|
2918
|
+
writable: true,
|
|
2919
|
+
value: void 0
|
|
2920
|
+
});
|
|
2921
|
+
Object.defineProperty(this, "project_name", {
|
|
2922
|
+
enumerable: true,
|
|
2923
|
+
configurable: true,
|
|
2924
|
+
writable: true,
|
|
2925
|
+
value: void 0
|
|
2926
|
+
});
|
|
2927
|
+
Object.defineProperty(this, "parent_run", {
|
|
2928
|
+
enumerable: true,
|
|
2929
|
+
configurable: true,
|
|
2930
|
+
writable: true,
|
|
2931
|
+
value: void 0
|
|
2932
|
+
});
|
|
2933
|
+
Object.defineProperty(this, "child_runs", {
|
|
2934
|
+
enumerable: true,
|
|
2935
|
+
configurable: true,
|
|
2936
|
+
writable: true,
|
|
2937
|
+
value: void 0
|
|
2938
|
+
});
|
|
2939
|
+
Object.defineProperty(this, "start_time", {
|
|
2940
|
+
enumerable: true,
|
|
2941
|
+
configurable: true,
|
|
2942
|
+
writable: true,
|
|
2943
|
+
value: void 0
|
|
2944
|
+
});
|
|
2945
|
+
Object.defineProperty(this, "end_time", {
|
|
2946
|
+
enumerable: true,
|
|
2947
|
+
configurable: true,
|
|
2948
|
+
writable: true,
|
|
2949
|
+
value: void 0
|
|
2950
|
+
});
|
|
2951
|
+
Object.defineProperty(this, "extra", {
|
|
2952
|
+
enumerable: true,
|
|
2953
|
+
configurable: true,
|
|
2954
|
+
writable: true,
|
|
2955
|
+
value: void 0
|
|
2956
|
+
});
|
|
2957
|
+
Object.defineProperty(this, "tags", {
|
|
2958
|
+
enumerable: true,
|
|
2959
|
+
configurable: true,
|
|
2960
|
+
writable: true,
|
|
2961
|
+
value: void 0
|
|
2962
|
+
});
|
|
2963
|
+
Object.defineProperty(this, "error", {
|
|
2964
|
+
enumerable: true,
|
|
2965
|
+
configurable: true,
|
|
2966
|
+
writable: true,
|
|
2967
|
+
value: void 0
|
|
2968
|
+
});
|
|
2969
|
+
Object.defineProperty(this, "serialized", {
|
|
2970
|
+
enumerable: true,
|
|
2971
|
+
configurable: true,
|
|
2972
|
+
writable: true,
|
|
2973
|
+
value: void 0
|
|
2974
|
+
});
|
|
2975
|
+
Object.defineProperty(this, "inputs", {
|
|
2976
|
+
enumerable: true,
|
|
2977
|
+
configurable: true,
|
|
2978
|
+
writable: true,
|
|
2979
|
+
value: void 0
|
|
2980
|
+
});
|
|
2981
|
+
Object.defineProperty(this, "outputs", {
|
|
2982
|
+
enumerable: true,
|
|
2983
|
+
configurable: true,
|
|
2984
|
+
writable: true,
|
|
2985
|
+
value: void 0
|
|
2986
|
+
});
|
|
2987
|
+
Object.defineProperty(this, "reference_example_id", {
|
|
2988
|
+
enumerable: true,
|
|
2989
|
+
configurable: true,
|
|
2990
|
+
writable: true,
|
|
2991
|
+
value: void 0
|
|
2992
|
+
});
|
|
2993
|
+
Object.defineProperty(this, "client", {
|
|
2994
|
+
enumerable: true,
|
|
2995
|
+
configurable: true,
|
|
2996
|
+
writable: true,
|
|
2997
|
+
value: void 0
|
|
2998
|
+
});
|
|
2999
|
+
Object.defineProperty(this, "events", {
|
|
3000
|
+
enumerable: true,
|
|
3001
|
+
configurable: true,
|
|
3002
|
+
writable: true,
|
|
3003
|
+
value: void 0
|
|
3004
|
+
});
|
|
3005
|
+
Object.defineProperty(this, "trace_id", {
|
|
3006
|
+
enumerable: true,
|
|
3007
|
+
configurable: true,
|
|
3008
|
+
writable: true,
|
|
3009
|
+
value: void 0
|
|
3010
|
+
});
|
|
3011
|
+
Object.defineProperty(this, "dotted_order", {
|
|
3012
|
+
enumerable: true,
|
|
3013
|
+
configurable: true,
|
|
3014
|
+
writable: true,
|
|
3015
|
+
value: void 0
|
|
3016
|
+
});
|
|
3017
|
+
Object.defineProperty(this, "tracingEnabled", {
|
|
3018
|
+
enumerable: true,
|
|
3019
|
+
configurable: true,
|
|
3020
|
+
writable: true,
|
|
3021
|
+
value: void 0
|
|
3022
|
+
});
|
|
3023
|
+
Object.defineProperty(this, "execution_order", {
|
|
3024
|
+
enumerable: true,
|
|
3025
|
+
configurable: true,
|
|
3026
|
+
writable: true,
|
|
3027
|
+
value: void 0
|
|
3028
|
+
});
|
|
3029
|
+
Object.defineProperty(this, "child_execution_order", {
|
|
3030
|
+
enumerable: true,
|
|
3031
|
+
configurable: true,
|
|
3032
|
+
writable: true,
|
|
3033
|
+
value: void 0
|
|
3034
|
+
});
|
|
3035
|
+
Object.defineProperty(this, "attachments", {
|
|
3036
|
+
enumerable: true,
|
|
3037
|
+
configurable: true,
|
|
3038
|
+
writable: true,
|
|
3039
|
+
value: void 0
|
|
3040
|
+
});
|
|
3041
|
+
if (run_trees_isRunTree(originalConfig)) return void Object.assign(this, {
|
|
3042
|
+
...originalConfig
|
|
3043
|
+
});
|
|
3044
|
+
const defaultConfig = RunTree.getDefaultConfig();
|
|
3045
|
+
const { metadata, ...config } = originalConfig;
|
|
3046
|
+
const client = config.client ?? RunTree.getSharedClient();
|
|
3047
|
+
const dedupedMetadata = {
|
|
3048
|
+
...metadata,
|
|
3049
|
+
...config?.extra?.metadata
|
|
3050
|
+
};
|
|
3051
|
+
config.extra = {
|
|
3052
|
+
...config.extra,
|
|
3053
|
+
metadata: dedupedMetadata
|
|
3054
|
+
};
|
|
3055
|
+
Object.assign(this, {
|
|
3056
|
+
...defaultConfig,
|
|
3057
|
+
...config,
|
|
3058
|
+
client
|
|
3059
|
+
});
|
|
3060
|
+
if (!this.trace_id) if (this.parent_run) this.trace_id = this.parent_run.trace_id ?? this.id;
|
|
3061
|
+
else this.trace_id = this.id;
|
|
3062
|
+
this.execution_order ??= 1;
|
|
3063
|
+
this.child_execution_order ??= 1;
|
|
3064
|
+
if (!this.dotted_order) {
|
|
3065
|
+
const currentDottedOrder = convertToDottedOrderFormat(this.start_time, this.id, this.execution_order);
|
|
3066
|
+
if (this.parent_run) this.dotted_order = this.parent_run.dotted_order + "." + currentDottedOrder;
|
|
3067
|
+
else this.dotted_order = currentDottedOrder;
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
static getDefaultConfig() {
|
|
3071
|
+
return {
|
|
3072
|
+
id: v4.Z(),
|
|
3073
|
+
run_type: "chain",
|
|
3074
|
+
project_name: getLangSmithEnvironmentVariable("PROJECT") ?? getEnvironmentVariable("LANGCHAIN_SESSION") ?? "default",
|
|
3075
|
+
child_runs: [],
|
|
3076
|
+
api_url: getEnvironmentVariable("LANGCHAIN_ENDPOINT") ?? "http://localhost:1984",
|
|
3077
|
+
api_key: getEnvironmentVariable("LANGCHAIN_API_KEY"),
|
|
3078
|
+
caller_options: {},
|
|
3079
|
+
start_time: Date.now(),
|
|
3080
|
+
serialized: {},
|
|
3081
|
+
inputs: {},
|
|
3082
|
+
extra: {}
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
3085
|
+
static getSharedClient() {
|
|
3086
|
+
if (!RunTree.sharedClient) RunTree.sharedClient = new Client();
|
|
3087
|
+
return RunTree.sharedClient;
|
|
3088
|
+
}
|
|
3089
|
+
createChild(config) {
|
|
3090
|
+
const child_execution_order = this.child_execution_order + 1;
|
|
3091
|
+
const child = new RunTree({
|
|
3092
|
+
...config,
|
|
3093
|
+
parent_run: this,
|
|
3094
|
+
project_name: this.project_name,
|
|
3095
|
+
client: this.client,
|
|
3096
|
+
tracingEnabled: this.tracingEnabled,
|
|
3097
|
+
execution_order: child_execution_order,
|
|
3098
|
+
child_execution_order: child_execution_order
|
|
3099
|
+
});
|
|
3100
|
+
if (_LC_CONTEXT_VARIABLES_KEY in this) child[_LC_CONTEXT_VARIABLES_KEY] = this[_LC_CONTEXT_VARIABLES_KEY];
|
|
3101
|
+
const LC_CHILD = Symbol.for("lc:child_config");
|
|
3102
|
+
const presentConfig = config.extra?.[LC_CHILD] ?? this.extra[LC_CHILD];
|
|
3103
|
+
if (isRunnableConfigLike(presentConfig)) {
|
|
3104
|
+
const newConfig = {
|
|
3105
|
+
...presentConfig
|
|
3106
|
+
};
|
|
3107
|
+
const callbacks = isCallbackManagerLike(newConfig.callbacks) ? newConfig.callbacks.copy?.() : void 0;
|
|
3108
|
+
if (callbacks) {
|
|
3109
|
+
Object.assign(callbacks, {
|
|
3110
|
+
_parentRunId: child.id
|
|
3111
|
+
});
|
|
3112
|
+
callbacks.handlers?.find(isLangChainTracerLike)?.updateFromRunTree?.(child);
|
|
3113
|
+
newConfig.callbacks = callbacks;
|
|
3114
|
+
}
|
|
3115
|
+
child.extra[LC_CHILD] = newConfig;
|
|
3116
|
+
}
|
|
3117
|
+
const visited = new Set();
|
|
3118
|
+
let current = this;
|
|
3119
|
+
while(null != current && !visited.has(current.id)){
|
|
3120
|
+
visited.add(current.id);
|
|
3121
|
+
current.child_execution_order = Math.max(current.child_execution_order, child_execution_order);
|
|
3122
|
+
current = current.parent_run;
|
|
3123
|
+
}
|
|
3124
|
+
this.child_runs.push(child);
|
|
3125
|
+
return child;
|
|
3126
|
+
}
|
|
3127
|
+
async end(outputs, error, endTime = Date.now(), metadata) {
|
|
3128
|
+
this.outputs = this.outputs ?? outputs;
|
|
3129
|
+
this.error = this.error ?? error;
|
|
3130
|
+
this.end_time = this.end_time ?? endTime;
|
|
3131
|
+
if (metadata && Object.keys(metadata).length > 0) this.extra = this.extra ? {
|
|
3132
|
+
...this.extra,
|
|
3133
|
+
metadata: {
|
|
3134
|
+
...this.extra.metadata,
|
|
3135
|
+
...metadata
|
|
3136
|
+
}
|
|
3137
|
+
} : {
|
|
3138
|
+
metadata
|
|
3139
|
+
};
|
|
3140
|
+
}
|
|
3141
|
+
_convertToCreate(run, runtimeEnv, excludeChildRuns = true) {
|
|
3142
|
+
const runExtra = run.extra ?? {};
|
|
3143
|
+
if (!runExtra.runtime) runExtra.runtime = {};
|
|
3144
|
+
if (runtimeEnv) {
|
|
3145
|
+
for (const [k, v] of Object.entries(runtimeEnv))if (!runExtra.runtime[k]) runExtra.runtime[k] = v;
|
|
3146
|
+
}
|
|
3147
|
+
let child_runs;
|
|
3148
|
+
let parent_run_id;
|
|
3149
|
+
if (excludeChildRuns) {
|
|
3150
|
+
parent_run_id = run.parent_run?.id;
|
|
3151
|
+
child_runs = [];
|
|
3152
|
+
} else {
|
|
3153
|
+
child_runs = run.child_runs.map((child_run)=>this._convertToCreate(child_run, runtimeEnv, excludeChildRuns));
|
|
3154
|
+
parent_run_id = void 0;
|
|
3155
|
+
}
|
|
3156
|
+
const persistedRun = {
|
|
3157
|
+
id: run.id,
|
|
3158
|
+
name: run.name,
|
|
3159
|
+
start_time: run.start_time,
|
|
3160
|
+
end_time: run.end_time,
|
|
3161
|
+
run_type: run.run_type,
|
|
3162
|
+
reference_example_id: run.reference_example_id,
|
|
3163
|
+
extra: runExtra,
|
|
3164
|
+
serialized: run.serialized,
|
|
3165
|
+
error: run.error,
|
|
3166
|
+
inputs: run.inputs,
|
|
3167
|
+
outputs: run.outputs,
|
|
3168
|
+
session_name: run.project_name,
|
|
3169
|
+
child_runs: child_runs,
|
|
3170
|
+
parent_run_id: parent_run_id,
|
|
3171
|
+
trace_id: run.trace_id,
|
|
3172
|
+
dotted_order: run.dotted_order,
|
|
3173
|
+
tags: run.tags,
|
|
3174
|
+
attachments: run.attachments
|
|
3175
|
+
};
|
|
3176
|
+
return persistedRun;
|
|
3177
|
+
}
|
|
3178
|
+
async postRun(excludeChildRuns = true) {
|
|
3179
|
+
try {
|
|
3180
|
+
const runtimeEnv = getRuntimeEnvironment();
|
|
3181
|
+
const runCreate = await this._convertToCreate(this, runtimeEnv, true);
|
|
3182
|
+
await this.client.createRun(runCreate);
|
|
3183
|
+
if (!excludeChildRuns) {
|
|
3184
|
+
warnOnce("Posting with excludeChildRuns=false is deprecated and will be removed in a future version.");
|
|
3185
|
+
for (const childRun of this.child_runs)await childRun.postRun(false);
|
|
3186
|
+
}
|
|
3187
|
+
} catch (error) {
|
|
3188
|
+
console.error(`Error in postRun for run ${this.id}:`, error);
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
async patchRun() {
|
|
3192
|
+
try {
|
|
3193
|
+
const runUpdate = {
|
|
3194
|
+
end_time: this.end_time,
|
|
3195
|
+
error: this.error,
|
|
3196
|
+
inputs: this.inputs,
|
|
3197
|
+
outputs: this.outputs,
|
|
3198
|
+
parent_run_id: this.parent_run?.id,
|
|
3199
|
+
reference_example_id: this.reference_example_id,
|
|
3200
|
+
extra: this.extra,
|
|
3201
|
+
events: this.events,
|
|
3202
|
+
dotted_order: this.dotted_order,
|
|
3203
|
+
trace_id: this.trace_id,
|
|
3204
|
+
tags: this.tags,
|
|
3205
|
+
attachments: this.attachments
|
|
3206
|
+
};
|
|
3207
|
+
await this.client.updateRun(this.id, runUpdate);
|
|
3208
|
+
} catch (error) {
|
|
3209
|
+
console.error(`Error in patchRun for run ${this.id}`, error);
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
toJSON() {
|
|
3213
|
+
return this._convertToCreate(this, void 0, false);
|
|
3214
|
+
}
|
|
3215
|
+
static fromRunnableConfig(parentConfig, props) {
|
|
3216
|
+
const callbackManager = parentConfig?.callbacks;
|
|
3217
|
+
let parentRun;
|
|
3218
|
+
let projectName;
|
|
3219
|
+
let client;
|
|
3220
|
+
let tracingEnabled = isTracingEnabled();
|
|
3221
|
+
if (callbackManager) {
|
|
3222
|
+
const parentRunId = callbackManager?.getParentRunId?.() ?? "";
|
|
3223
|
+
const langChainTracer = callbackManager?.handlers?.find((handler)=>handler?.name == "langchain_tracer");
|
|
3224
|
+
parentRun = langChainTracer?.getRun?.(parentRunId);
|
|
3225
|
+
projectName = langChainTracer?.projectName;
|
|
3226
|
+
client = langChainTracer?.client;
|
|
3227
|
+
tracingEnabled = tracingEnabled || !!langChainTracer;
|
|
3228
|
+
}
|
|
3229
|
+
if (!parentRun) return new RunTree({
|
|
3230
|
+
...props,
|
|
3231
|
+
client,
|
|
3232
|
+
tracingEnabled,
|
|
3233
|
+
project_name: projectName
|
|
3234
|
+
});
|
|
3235
|
+
const parentRunTree = new RunTree({
|
|
3236
|
+
name: parentRun.name,
|
|
3237
|
+
id: parentRun.id,
|
|
3238
|
+
trace_id: parentRun.trace_id,
|
|
3239
|
+
dotted_order: parentRun.dotted_order,
|
|
3240
|
+
client,
|
|
3241
|
+
tracingEnabled,
|
|
3242
|
+
project_name: projectName,
|
|
3243
|
+
tags: [
|
|
3244
|
+
...new Set((parentRun?.tags ?? []).concat(parentConfig?.tags ?? []))
|
|
3245
|
+
],
|
|
3246
|
+
extra: {
|
|
3247
|
+
metadata: {
|
|
3248
|
+
...parentRun?.extra?.metadata,
|
|
3249
|
+
...parentConfig?.metadata
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
});
|
|
3253
|
+
return parentRunTree.createChild(props);
|
|
3254
|
+
}
|
|
3255
|
+
static fromDottedOrder(dottedOrder) {
|
|
3256
|
+
return this.fromHeaders({
|
|
3257
|
+
"langsmith-trace": dottedOrder
|
|
3258
|
+
});
|
|
3259
|
+
}
|
|
3260
|
+
static fromHeaders(headers, inheritArgs) {
|
|
3261
|
+
const rawHeaders = "get" in headers && "function" == typeof headers.get ? {
|
|
3262
|
+
"langsmith-trace": headers.get("langsmith-trace"),
|
|
3263
|
+
baggage: headers.get("baggage")
|
|
3264
|
+
} : headers;
|
|
3265
|
+
const headerTrace = rawHeaders["langsmith-trace"];
|
|
3266
|
+
if (!headerTrace || "string" != typeof headerTrace) return;
|
|
3267
|
+
const parentDottedOrder = headerTrace.trim();
|
|
3268
|
+
const parsedDottedOrder = parentDottedOrder.split(".").map((part)=>{
|
|
3269
|
+
const [strTime, uuid] = part.split("Z");
|
|
3270
|
+
return {
|
|
3271
|
+
strTime,
|
|
3272
|
+
time: Date.parse(strTime + "Z"),
|
|
3273
|
+
uuid
|
|
3274
|
+
};
|
|
3275
|
+
});
|
|
3276
|
+
const traceId = parsedDottedOrder[0].uuid;
|
|
3277
|
+
const config = {
|
|
3278
|
+
...inheritArgs,
|
|
3279
|
+
name: inheritArgs?.["name"] ?? "parent",
|
|
3280
|
+
run_type: inheritArgs?.["run_type"] ?? "chain",
|
|
3281
|
+
start_time: inheritArgs?.["start_time"] ?? Date.now(),
|
|
3282
|
+
id: parsedDottedOrder.at(-1)?.uuid,
|
|
3283
|
+
trace_id: traceId,
|
|
3284
|
+
dotted_order: parentDottedOrder
|
|
3285
|
+
};
|
|
3286
|
+
if (rawHeaders["baggage"] && "string" == typeof rawHeaders["baggage"]) {
|
|
3287
|
+
const baggage = Baggage.fromHeader(rawHeaders["baggage"]);
|
|
3288
|
+
config.metadata = baggage.metadata;
|
|
3289
|
+
config.tags = baggage.tags;
|
|
3290
|
+
}
|
|
3291
|
+
return new RunTree(config);
|
|
3292
|
+
}
|
|
3293
|
+
toHeaders(headers) {
|
|
3294
|
+
const result = {
|
|
3295
|
+
"langsmith-trace": this.dotted_order,
|
|
3296
|
+
baggage: new Baggage(this.extra?.metadata, this.tags).toHeader()
|
|
3297
|
+
};
|
|
3298
|
+
if (headers) for (const [key, value] of Object.entries(result))headers.set(key, value);
|
|
3299
|
+
return result;
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
Object.defineProperty(RunTree, "sharedClient", {
|
|
3303
|
+
enumerable: true,
|
|
3304
|
+
configurable: true,
|
|
3305
|
+
writable: true,
|
|
3306
|
+
value: null
|
|
3307
|
+
});
|
|
3308
|
+
function run_trees_isRunTree(x) {
|
|
3309
|
+
return void 0 !== x && "function" == typeof x.createChild && "function" == typeof x.postRun;
|
|
3310
|
+
}
|
|
3311
|
+
function isLangChainTracerLike(x) {
|
|
3312
|
+
return "object" == typeof x && null != x && "string" == typeof x.name && "langchain_tracer" === x.name;
|
|
3313
|
+
}
|
|
3314
|
+
function containsLangChainTracerLike(x) {
|
|
3315
|
+
return Array.isArray(x) && x.some((callback)=>isLangChainTracerLike(callback));
|
|
3316
|
+
}
|
|
3317
|
+
function isCallbackManagerLike(x) {
|
|
3318
|
+
return "object" == typeof x && null != x && Array.isArray(x.handlers);
|
|
3319
|
+
}
|
|
3320
|
+
function isRunnableConfigLike(x) {
|
|
3321
|
+
return void 0 !== x && "object" == typeof x.callbacks && (containsLangChainTracerLike(x.callbacks?.handlers) || containsLangChainTracerLike(x.callbacks));
|
|
3322
|
+
}
|
|
3323
|
+
class MockAsyncLocalStorage {
|
|
3324
|
+
getStore() {}
|
|
3325
|
+
run(_, callback) {
|
|
3326
|
+
return callback();
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
const TRACING_ALS_KEY = Symbol.for("ls:tracing_async_local_storage");
|
|
3330
|
+
const mockAsyncLocalStorage = new MockAsyncLocalStorage();
|
|
3331
|
+
class AsyncLocalStorageProvider {
|
|
3332
|
+
getInstance() {
|
|
3333
|
+
return globalThis[TRACING_ALS_KEY] ?? mockAsyncLocalStorage;
|
|
3334
|
+
}
|
|
3335
|
+
initializeGlobalInstance(instance) {
|
|
3336
|
+
if (void 0 === globalThis[TRACING_ALS_KEY]) globalThis[TRACING_ALS_KEY] = instance;
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
const AsyncLocalStorageProviderSingleton = new AsyncLocalStorageProvider();
|
|
3340
|
+
const ROOT = Symbol.for("langsmith:traceable:root");
|
|
3341
|
+
function isTraceableFunction(x) {
|
|
3342
|
+
return "function" == typeof x && "langsmith:traceable" in x;
|
|
3343
|
+
}
|
|
3344
|
+
function isPromiseMethod(x) {
|
|
3345
|
+
if ("then" === x || "catch" === x || "finally" === x) return true;
|
|
3346
|
+
return false;
|
|
3347
|
+
}
|
|
3348
|
+
function isKVMap(x) {
|
|
3349
|
+
if ("object" != typeof x || null == x) return false;
|
|
3350
|
+
const prototype = Object.getPrototypeOf(x);
|
|
3351
|
+
return (null === prototype || prototype === Object.prototype || null === Object.getPrototypeOf(prototype)) && !(Symbol.toStringTag in x) && !(Symbol.iterator in x);
|
|
3352
|
+
}
|
|
3353
|
+
const isAsyncIterable = (x)=>null != x && "object" == typeof x && "function" == typeof x[Symbol.asyncIterator];
|
|
3354
|
+
const isIteratorLike = (x)=>null != x && "object" == typeof x && "next" in x && "function" == typeof x.next;
|
|
3355
|
+
const GeneratorFunction = (function*() {}).constructor;
|
|
3356
|
+
const isGenerator = (x)=>null != x && "function" == typeof x && x instanceof GeneratorFunction;
|
|
3357
|
+
const isThenable = (x)=>null != x && "object" == typeof x && "then" in x && "function" == typeof x.then;
|
|
3358
|
+
const isReadableStream = (x)=>null != x && "object" == typeof x && "getReader" in x && "function" == typeof x.getReader;
|
|
3359
|
+
AsyncLocalStorageProviderSingleton.initializeGlobalInstance(new external_node_async_hooks_.AsyncLocalStorage());
|
|
3360
|
+
const runInputsToMap = (rawInputs)=>{
|
|
3361
|
+
const firstInput = rawInputs[0];
|
|
3362
|
+
let inputs;
|
|
3363
|
+
inputs = null == firstInput ? {} : rawInputs.length > 1 ? {
|
|
3364
|
+
args: rawInputs
|
|
3365
|
+
} : isKVMap(firstInput) ? firstInput : {
|
|
3366
|
+
input: firstInput
|
|
3367
|
+
};
|
|
3368
|
+
return inputs;
|
|
3369
|
+
};
|
|
3370
|
+
const handleRunInputs = (inputs, processInputs)=>{
|
|
3371
|
+
try {
|
|
3372
|
+
return processInputs(inputs);
|
|
3373
|
+
} catch (e) {
|
|
3374
|
+
console.error("Error occurred during processInputs. Sending raw inputs:", e);
|
|
3375
|
+
return inputs;
|
|
3376
|
+
}
|
|
3377
|
+
};
|
|
3378
|
+
const handleRunOutputs = (rawOutputs, processOutputs)=>{
|
|
3379
|
+
let outputs;
|
|
3380
|
+
outputs = isKVMap(rawOutputs) ? rawOutputs : {
|
|
3381
|
+
outputs: rawOutputs
|
|
3382
|
+
};
|
|
3383
|
+
try {
|
|
3384
|
+
return processOutputs(outputs);
|
|
3385
|
+
} catch (e) {
|
|
3386
|
+
console.error("Error occurred during processOutputs. Sending raw outputs:", e);
|
|
3387
|
+
return outputs;
|
|
3388
|
+
}
|
|
3389
|
+
};
|
|
3390
|
+
const handleRunAttachments = (rawInputs, extractAttachments)=>{
|
|
3391
|
+
if (!extractAttachments) return [
|
|
3392
|
+
void 0,
|
|
3393
|
+
rawInputs
|
|
3394
|
+
];
|
|
3395
|
+
try {
|
|
3396
|
+
const [attachments, remainingArgs] = extractAttachments(...rawInputs);
|
|
3397
|
+
return [
|
|
3398
|
+
attachments,
|
|
3399
|
+
remainingArgs
|
|
3400
|
+
];
|
|
3401
|
+
} catch (e) {
|
|
3402
|
+
console.error("Error occurred during extractAttachments:", e);
|
|
3403
|
+
return [
|
|
3404
|
+
void 0,
|
|
3405
|
+
rawInputs
|
|
3406
|
+
];
|
|
3407
|
+
}
|
|
3408
|
+
};
|
|
3409
|
+
const getTracingRunTree = (runTree, inputs, getInvocationParams, processInputs, extractAttachments)=>{
|
|
3410
|
+
if (!isTracingEnabled(runTree.tracingEnabled)) return;
|
|
3411
|
+
const [attached, args] = handleRunAttachments(inputs, extractAttachments);
|
|
3412
|
+
runTree.attachments = attached;
|
|
3413
|
+
runTree.inputs = handleRunInputs(args, processInputs);
|
|
3414
|
+
const invocationParams = getInvocationParams?.(...inputs);
|
|
3415
|
+
if (null != invocationParams) {
|
|
3416
|
+
runTree.extra ??= {};
|
|
3417
|
+
runTree.extra.metadata = {
|
|
3418
|
+
...invocationParams,
|
|
3419
|
+
...runTree.extra.metadata
|
|
3420
|
+
};
|
|
3421
|
+
}
|
|
3422
|
+
return runTree;
|
|
3423
|
+
};
|
|
3424
|
+
const getSerializablePromise = (arg)=>{
|
|
3425
|
+
const proxyState = {
|
|
3426
|
+
current: void 0
|
|
3427
|
+
};
|
|
3428
|
+
const promiseProxy = new Proxy(arg, {
|
|
3429
|
+
get (target, prop, receiver) {
|
|
3430
|
+
if ("then" === prop) {
|
|
3431
|
+
const boundThen = arg[prop].bind(arg);
|
|
3432
|
+
return (resolve, reject = (x)=>{
|
|
3433
|
+
throw x;
|
|
3434
|
+
})=>boundThen((value)=>{
|
|
3435
|
+
proxyState.current = [
|
|
3436
|
+
"resolve",
|
|
3437
|
+
value
|
|
3438
|
+
];
|
|
3439
|
+
return resolve(value);
|
|
3440
|
+
}, (error)=>{
|
|
3441
|
+
proxyState.current = [
|
|
3442
|
+
"reject",
|
|
3443
|
+
error
|
|
3444
|
+
];
|
|
3445
|
+
return reject(error);
|
|
3446
|
+
});
|
|
3447
|
+
}
|
|
3448
|
+
if ("catch" === prop) {
|
|
3449
|
+
const boundCatch = arg[prop].bind(arg);
|
|
3450
|
+
return (reject)=>boundCatch((error)=>{
|
|
3451
|
+
proxyState.current = [
|
|
3452
|
+
"reject",
|
|
3453
|
+
error
|
|
3454
|
+
];
|
|
3455
|
+
return reject(error);
|
|
3456
|
+
});
|
|
3457
|
+
}
|
|
3458
|
+
if ("toJSON" === prop) return ()=>{
|
|
3459
|
+
if (!proxyState.current) return;
|
|
3460
|
+
const [type, value] = proxyState.current ?? [];
|
|
3461
|
+
if ("resolve" === type) return value;
|
|
3462
|
+
return {
|
|
3463
|
+
error: value
|
|
3464
|
+
};
|
|
3465
|
+
};
|
|
3466
|
+
return Reflect.get(target, prop, receiver);
|
|
3467
|
+
}
|
|
3468
|
+
});
|
|
3469
|
+
return promiseProxy;
|
|
3470
|
+
};
|
|
3471
|
+
const convertSerializableArg = (arg)=>{
|
|
3472
|
+
if (isReadableStream(arg)) {
|
|
3473
|
+
const proxyState = [];
|
|
3474
|
+
const transform = new TransformStream({
|
|
3475
|
+
start: ()=>void 0,
|
|
3476
|
+
transform: (chunk, controller)=>{
|
|
3477
|
+
proxyState.push(chunk);
|
|
3478
|
+
controller.enqueue(chunk);
|
|
3479
|
+
},
|
|
3480
|
+
flush: ()=>void 0
|
|
3481
|
+
});
|
|
3482
|
+
const pipeThrough = arg.pipeThrough(transform);
|
|
3483
|
+
Object.assign(pipeThrough, {
|
|
3484
|
+
toJSON: ()=>proxyState
|
|
3485
|
+
});
|
|
3486
|
+
return pipeThrough;
|
|
3487
|
+
}
|
|
3488
|
+
if (isAsyncIterable(arg)) {
|
|
3489
|
+
const proxyState = {
|
|
3490
|
+
current: []
|
|
3491
|
+
};
|
|
3492
|
+
return new Proxy(arg, {
|
|
3493
|
+
get (target, prop, receiver) {
|
|
3494
|
+
if (prop === Symbol.asyncIterator) return ()=>{
|
|
3495
|
+
const boundIterator = arg[Symbol.asyncIterator].bind(arg);
|
|
3496
|
+
const iterator = boundIterator();
|
|
3497
|
+
return new Proxy(iterator, {
|
|
3498
|
+
get (target, prop, receiver) {
|
|
3499
|
+
if ("next" === prop || "return" === prop || "throw" === prop) {
|
|
3500
|
+
const bound = iterator.next.bind(iterator);
|
|
3501
|
+
return (...args)=>{
|
|
3502
|
+
const wrapped = getSerializablePromise(bound(...args));
|
|
3503
|
+
proxyState.current.push(wrapped);
|
|
3504
|
+
return wrapped;
|
|
3505
|
+
};
|
|
3506
|
+
}
|
|
3507
|
+
if ("return" === prop || "throw" === prop) return iterator.next.bind(iterator);
|
|
3508
|
+
return Reflect.get(target, prop, receiver);
|
|
3509
|
+
}
|
|
3510
|
+
});
|
|
3511
|
+
};
|
|
3512
|
+
if ("toJSON" === prop) return ()=>{
|
|
3513
|
+
const onlyNexts = proxyState.current;
|
|
3514
|
+
const serialized = onlyNexts.map((next)=>next.toJSON());
|
|
3515
|
+
const chunks = serialized.reduce((memo, next)=>{
|
|
3516
|
+
if (next?.value) memo.push(next.value);
|
|
3517
|
+
return memo;
|
|
3518
|
+
}, []);
|
|
3519
|
+
return chunks;
|
|
3520
|
+
};
|
|
3521
|
+
return Reflect.get(target, prop, receiver);
|
|
3522
|
+
}
|
|
3523
|
+
});
|
|
3524
|
+
}
|
|
3525
|
+
if (!Array.isArray(arg) && isIteratorLike(arg)) {
|
|
3526
|
+
const proxyState = [];
|
|
3527
|
+
return new Proxy(arg, {
|
|
3528
|
+
get (target, prop, receiver) {
|
|
3529
|
+
if ("next" === prop || "return" === prop || "throw" === prop) {
|
|
3530
|
+
const bound = arg[prop]?.bind(arg);
|
|
3531
|
+
return (...args)=>{
|
|
3532
|
+
const next = bound?.(...args);
|
|
3533
|
+
if (null != next) proxyState.push(next);
|
|
3534
|
+
return next;
|
|
3535
|
+
};
|
|
3536
|
+
}
|
|
3537
|
+
if ("toJSON" === prop) return ()=>{
|
|
3538
|
+
const chunks = proxyState.reduce((memo, next)=>{
|
|
3539
|
+
if (next.value) memo.push(next.value);
|
|
3540
|
+
return memo;
|
|
3541
|
+
}, []);
|
|
3542
|
+
return chunks;
|
|
3543
|
+
};
|
|
3544
|
+
return Reflect.get(target, prop, receiver);
|
|
3545
|
+
}
|
|
3546
|
+
});
|
|
3547
|
+
}
|
|
3548
|
+
if (isThenable(arg)) return getSerializablePromise(arg);
|
|
3549
|
+
return arg;
|
|
3550
|
+
};
|
|
3551
|
+
function traceable_traceable(wrappedFunc, config) {
|
|
3552
|
+
const { aggregator, argsConfigPath, __finalTracedIteratorKey, processInputs, processOutputs, extractAttachments, ...runTreeConfig } = config ?? {};
|
|
3553
|
+
const processInputsFn = processInputs ?? ((x)=>x);
|
|
3554
|
+
const processOutputsFn = processOutputs ?? ((x)=>x);
|
|
3555
|
+
const extractAttachmentsFn = extractAttachments ?? ((...x)=>[
|
|
3556
|
+
void 0,
|
|
3557
|
+
runInputsToMap(x)
|
|
3558
|
+
]);
|
|
3559
|
+
const traceableFunc = (...args)=>{
|
|
3560
|
+
let ensuredConfig;
|
|
3561
|
+
try {
|
|
3562
|
+
let runtimeConfig;
|
|
3563
|
+
if (argsConfigPath) {
|
|
3564
|
+
const [index, path] = argsConfigPath;
|
|
3565
|
+
if (index !== args.length - 1 || path) {
|
|
3566
|
+
if (index <= args.length && "object" == typeof args[index] && null !== args[index]) if (path) {
|
|
3567
|
+
const { [path]: extracted, ...rest } = args[index];
|
|
3568
|
+
runtimeConfig = extracted;
|
|
3569
|
+
args[index] = rest;
|
|
3570
|
+
} else {
|
|
3571
|
+
runtimeConfig = args[index];
|
|
3572
|
+
args.splice(index, 1);
|
|
3573
|
+
}
|
|
3574
|
+
} else runtimeConfig = args.pop();
|
|
3575
|
+
}
|
|
3576
|
+
ensuredConfig = {
|
|
3577
|
+
name: wrappedFunc.name || "<lambda>",
|
|
3578
|
+
...runTreeConfig,
|
|
3579
|
+
...runtimeConfig,
|
|
3580
|
+
tags: [
|
|
3581
|
+
...new Set([
|
|
3582
|
+
...runTreeConfig?.tags ?? [],
|
|
3583
|
+
...runtimeConfig?.tags ?? []
|
|
3584
|
+
])
|
|
3585
|
+
],
|
|
3586
|
+
metadata: {
|
|
3587
|
+
...runTreeConfig?.metadata,
|
|
3588
|
+
...runtimeConfig?.metadata
|
|
3589
|
+
}
|
|
3590
|
+
};
|
|
3591
|
+
} catch (err) {
|
|
3592
|
+
console.warn(`Failed to extract runtime config from args for ${runTreeConfig?.name ?? wrappedFunc.name}`, err);
|
|
3593
|
+
ensuredConfig = {
|
|
3594
|
+
name: wrappedFunc.name || "<lambda>",
|
|
3595
|
+
...runTreeConfig
|
|
3596
|
+
};
|
|
3597
|
+
}
|
|
3598
|
+
const asyncLocalStorage = AsyncLocalStorageProviderSingleton.getInstance();
|
|
3599
|
+
const processedArgs = args;
|
|
3600
|
+
for(let i = 0; i < processedArgs.length; i++)processedArgs[i] = convertSerializableArg(processedArgs[i]);
|
|
3601
|
+
const [currentRunTree, rawInputs] = (()=>{
|
|
3602
|
+
const [firstArg, ...restArgs] = processedArgs;
|
|
3603
|
+
if (isRunnableConfigLike(firstArg)) return [
|
|
3604
|
+
getTracingRunTree(RunTree.fromRunnableConfig(firstArg, ensuredConfig), restArgs, config?.getInvocationParams, processInputsFn, extractAttachmentsFn),
|
|
3605
|
+
restArgs
|
|
3606
|
+
];
|
|
3607
|
+
if (run_trees_isRunTree(firstArg) && "callbackManager" in firstArg && null != firstArg.callbackManager) return [
|
|
3608
|
+
firstArg,
|
|
3609
|
+
restArgs
|
|
3610
|
+
];
|
|
3611
|
+
if (firstArg === ROOT || run_trees_isRunTree(firstArg)) {
|
|
3612
|
+
const currentRunTree = getTracingRunTree(firstArg === ROOT ? new RunTree(ensuredConfig) : firstArg.createChild(ensuredConfig), restArgs, config?.getInvocationParams, processInputsFn, extractAttachmentsFn);
|
|
3613
|
+
return [
|
|
3614
|
+
currentRunTree,
|
|
3615
|
+
[
|
|
3616
|
+
currentRunTree,
|
|
3617
|
+
...restArgs
|
|
3618
|
+
]
|
|
3619
|
+
];
|
|
3620
|
+
}
|
|
3621
|
+
const prevRunFromStore = asyncLocalStorage.getStore();
|
|
3622
|
+
if (run_trees_isRunTree(prevRunFromStore)) return [
|
|
3623
|
+
getTracingRunTree(prevRunFromStore.createChild(ensuredConfig), processedArgs, config?.getInvocationParams, processInputsFn, extractAttachmentsFn),
|
|
3624
|
+
processedArgs
|
|
3625
|
+
];
|
|
3626
|
+
const currentRunTree = getTracingRunTree(new RunTree(ensuredConfig), processedArgs, config?.getInvocationParams, processInputsFn, extractAttachmentsFn);
|
|
3627
|
+
if (void 0 !== prevRunFromStore && _LC_CONTEXT_VARIABLES_KEY in prevRunFromStore) currentRunTree[_LC_CONTEXT_VARIABLES_KEY] = prevRunFromStore[_LC_CONTEXT_VARIABLES_KEY];
|
|
3628
|
+
return [
|
|
3629
|
+
currentRunTree,
|
|
3630
|
+
processedArgs
|
|
3631
|
+
];
|
|
3632
|
+
})();
|
|
3633
|
+
return asyncLocalStorage.run(currentRunTree, ()=>{
|
|
3634
|
+
const postRunPromise = currentRunTree?.postRun();
|
|
3635
|
+
async function handleChunks(chunks) {
|
|
3636
|
+
if (void 0 !== aggregator) try {
|
|
3637
|
+
return await aggregator(chunks);
|
|
3638
|
+
} catch (e) {
|
|
3639
|
+
console.error("[ERROR]: LangSmith aggregation failed: ", e);
|
|
3640
|
+
}
|
|
3641
|
+
return chunks;
|
|
3642
|
+
}
|
|
3643
|
+
function tapReadableStreamForTracing(stream, snapshot) {
|
|
3644
|
+
const reader = stream.getReader();
|
|
3645
|
+
let finished = false;
|
|
3646
|
+
const chunks = [];
|
|
3647
|
+
const tappedStream = new ReadableStream({
|
|
3648
|
+
async start (controller) {
|
|
3649
|
+
while(true){
|
|
3650
|
+
const result = await (snapshot ? snapshot(()=>reader.read()) : reader.read());
|
|
3651
|
+
if (result.done) {
|
|
3652
|
+
finished = true;
|
|
3653
|
+
await currentRunTree?.end(handleRunOutputs(await handleChunks(chunks), processOutputsFn));
|
|
3654
|
+
await handleEnd();
|
|
3655
|
+
controller.close();
|
|
3656
|
+
break;
|
|
3657
|
+
}
|
|
3658
|
+
chunks.push(result.value);
|
|
3659
|
+
controller.enqueue(result.value);
|
|
3660
|
+
}
|
|
3661
|
+
},
|
|
3662
|
+
async cancel (reason) {
|
|
3663
|
+
if (!finished) await currentRunTree?.end(void 0, "Cancelled");
|
|
3664
|
+
await currentRunTree?.end(handleRunOutputs(await handleChunks(chunks), processOutputsFn));
|
|
3665
|
+
await handleEnd();
|
|
3666
|
+
return reader.cancel(reason);
|
|
3667
|
+
}
|
|
3668
|
+
});
|
|
3669
|
+
return tappedStream;
|
|
3670
|
+
}
|
|
3671
|
+
async function* wrapAsyncIteratorForTracing(iterator, snapshot) {
|
|
3672
|
+
let finished = false;
|
|
3673
|
+
const chunks = [];
|
|
3674
|
+
try {
|
|
3675
|
+
while(true){
|
|
3676
|
+
const { value, done } = await (snapshot ? snapshot(()=>iterator.next()) : iterator.next());
|
|
3677
|
+
if (done) {
|
|
3678
|
+
finished = true;
|
|
3679
|
+
break;
|
|
3680
|
+
}
|
|
3681
|
+
chunks.push(value);
|
|
3682
|
+
yield value;
|
|
3683
|
+
}
|
|
3684
|
+
} catch (e) {
|
|
3685
|
+
await currentRunTree?.end(void 0, String(e));
|
|
3686
|
+
throw e;
|
|
3687
|
+
} finally{
|
|
3688
|
+
if (!finished) await currentRunTree?.end(void 0, "Cancelled");
|
|
3689
|
+
await currentRunTree?.end(handleRunOutputs(await handleChunks(chunks), processOutputsFn));
|
|
3690
|
+
await handleEnd();
|
|
3691
|
+
}
|
|
3692
|
+
}
|
|
3693
|
+
function wrapAsyncGeneratorForTracing(iterable, snapshot) {
|
|
3694
|
+
if (isReadableStream(iterable)) return tapReadableStreamForTracing(iterable, snapshot);
|
|
3695
|
+
const iterator = iterable[Symbol.asyncIterator]();
|
|
3696
|
+
const wrappedIterator = wrapAsyncIteratorForTracing(iterator, snapshot);
|
|
3697
|
+
iterable[Symbol.asyncIterator] = ()=>wrappedIterator;
|
|
3698
|
+
return iterable;
|
|
3699
|
+
}
|
|
3700
|
+
async function handleEnd() {
|
|
3701
|
+
const onEnd = config?.on_end;
|
|
3702
|
+
if (onEnd) if (currentRunTree) onEnd(currentRunTree);
|
|
3703
|
+
else console.warn("Can not call 'on_end' if currentRunTree is undefined");
|
|
3704
|
+
await postRunPromise;
|
|
3705
|
+
await currentRunTree?.patchRun();
|
|
3706
|
+
}
|
|
3707
|
+
function gatherAll(iterator) {
|
|
3708
|
+
const chunks = [];
|
|
3709
|
+
while(true){
|
|
3710
|
+
const next = iterator.next();
|
|
3711
|
+
chunks.push(next);
|
|
3712
|
+
if (next.done) break;
|
|
3713
|
+
}
|
|
3714
|
+
return chunks;
|
|
3715
|
+
}
|
|
3716
|
+
let returnValue;
|
|
3717
|
+
try {
|
|
3718
|
+
returnValue = wrappedFunc(...rawInputs);
|
|
3719
|
+
} catch (err) {
|
|
3720
|
+
returnValue = Promise.reject(err);
|
|
3721
|
+
}
|
|
3722
|
+
if (isAsyncIterable(returnValue)) {
|
|
3723
|
+
const snapshot = external_node_async_hooks_.AsyncLocalStorage.snapshot();
|
|
3724
|
+
return wrapAsyncGeneratorForTracing(returnValue, snapshot);
|
|
3725
|
+
}
|
|
3726
|
+
if (!Array.isArray(returnValue) && "object" == typeof returnValue && null != returnValue && void 0 !== __finalTracedIteratorKey && isAsyncIterable(returnValue[__finalTracedIteratorKey])) {
|
|
3727
|
+
const snapshot = external_node_async_hooks_.AsyncLocalStorage.snapshot();
|
|
3728
|
+
return {
|
|
3729
|
+
...returnValue,
|
|
3730
|
+
[__finalTracedIteratorKey]: wrapAsyncGeneratorForTracing(returnValue[__finalTracedIteratorKey], snapshot)
|
|
3731
|
+
};
|
|
3732
|
+
}
|
|
3733
|
+
const tracedPromise = new Promise((resolve, reject)=>{
|
|
3734
|
+
Promise.resolve(returnValue).then(async (rawOutput)=>{
|
|
3735
|
+
if (isAsyncIterable(rawOutput)) {
|
|
3736
|
+
const snapshot = external_node_async_hooks_.AsyncLocalStorage.snapshot();
|
|
3737
|
+
return resolve(wrapAsyncGeneratorForTracing(rawOutput, snapshot));
|
|
3738
|
+
}
|
|
3739
|
+
if (!Array.isArray(rawOutput) && "object" == typeof rawOutput && null != rawOutput && void 0 !== __finalTracedIteratorKey && isAsyncIterable(rawOutput[__finalTracedIteratorKey])) {
|
|
3740
|
+
const snapshot = external_node_async_hooks_.AsyncLocalStorage.snapshot();
|
|
3741
|
+
return {
|
|
3742
|
+
...rawOutput,
|
|
3743
|
+
[__finalTracedIteratorKey]: wrapAsyncGeneratorForTracing(rawOutput[__finalTracedIteratorKey], snapshot)
|
|
3744
|
+
};
|
|
3745
|
+
}
|
|
3746
|
+
if (isGenerator(wrappedFunc) && isIteratorLike(rawOutput)) {
|
|
3747
|
+
const chunks = gatherAll(rawOutput);
|
|
3748
|
+
try {
|
|
3749
|
+
await currentRunTree?.end(handleRunOutputs(await handleChunks(chunks.reduce((memo, { value, done })=>{
|
|
3750
|
+
if (!done || void 0 !== value) memo.push(value);
|
|
3751
|
+
return memo;
|
|
3752
|
+
}, [])), processOutputsFn));
|
|
3753
|
+
await handleEnd();
|
|
3754
|
+
} catch (e) {
|
|
3755
|
+
console.error("Error occurred during handleEnd:", e);
|
|
3756
|
+
}
|
|
3757
|
+
return function*() {
|
|
3758
|
+
for (const ret of chunks){
|
|
3759
|
+
if (ret.done) return ret.value;
|
|
3760
|
+
yield ret.value;
|
|
3761
|
+
}
|
|
3762
|
+
}();
|
|
3763
|
+
}
|
|
3764
|
+
try {
|
|
3765
|
+
await currentRunTree?.end(handleRunOutputs(rawOutput, processOutputsFn));
|
|
3766
|
+
await handleEnd();
|
|
3767
|
+
} finally{
|
|
3768
|
+
return rawOutput;
|
|
3769
|
+
}
|
|
3770
|
+
}, async (error)=>{
|
|
3771
|
+
await currentRunTree?.end(void 0, String(error));
|
|
3772
|
+
await handleEnd();
|
|
3773
|
+
throw error;
|
|
3774
|
+
}).then(resolve, reject);
|
|
3775
|
+
});
|
|
3776
|
+
if ("object" != typeof returnValue || null === returnValue) return tracedPromise;
|
|
3777
|
+
return new Proxy(returnValue, {
|
|
3778
|
+
get (target, prop, receiver) {
|
|
3779
|
+
if (isPromiseMethod(prop)) return tracedPromise[prop].bind(tracedPromise);
|
|
3780
|
+
return Reflect.get(target, prop, receiver);
|
|
3781
|
+
}
|
|
3782
|
+
});
|
|
3783
|
+
});
|
|
3784
|
+
};
|
|
3785
|
+
Object.defineProperty(traceableFunc, "langsmith:traceable", {
|
|
3786
|
+
value: runTreeConfig
|
|
3787
|
+
});
|
|
3788
|
+
return traceableFunc;
|
|
3789
|
+
}
|
|
3790
|
+
function _combineChatCompletionChoices(choices) {
|
|
3791
|
+
const reversedChoices = choices.slice().reverse();
|
|
3792
|
+
const message = {
|
|
3793
|
+
role: "assistant",
|
|
3794
|
+
content: ""
|
|
3795
|
+
};
|
|
3796
|
+
for (const c of reversedChoices)if (c.delta.role) {
|
|
3797
|
+
message["role"] = c.delta.role;
|
|
3798
|
+
break;
|
|
3799
|
+
}
|
|
3800
|
+
const toolCalls = {};
|
|
3801
|
+
for (const c of choices){
|
|
3802
|
+
if (c.delta.content) message.content = message.content.concat(c.delta.content);
|
|
3803
|
+
if (c.delta.function_call) {
|
|
3804
|
+
if (!message.function_call) message.function_call = {
|
|
3805
|
+
name: "",
|
|
3806
|
+
arguments: ""
|
|
3807
|
+
};
|
|
3808
|
+
if (c.delta.function_call.name) message.function_call.name += c.delta.function_call.name;
|
|
3809
|
+
if (c.delta.function_call.arguments) message.function_call.arguments += c.delta.function_call.arguments;
|
|
3810
|
+
}
|
|
3811
|
+
if (c.delta.tool_calls) for (const tool_call of c.delta.tool_calls){
|
|
3812
|
+
if (!toolCalls[c.index]) toolCalls[c.index] = [];
|
|
3813
|
+
toolCalls[c.index].push(tool_call);
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
if (Object.keys(toolCalls).length > 0) {
|
|
3817
|
+
message.tool_calls = [
|
|
3818
|
+
...Array(Object.keys(toolCalls).length)
|
|
3819
|
+
];
|
|
3820
|
+
for (const [index, toolCallChunks] of Object.entries(toolCalls)){
|
|
3821
|
+
const idx = parseInt(index);
|
|
3822
|
+
message.tool_calls[idx] = {
|
|
3823
|
+
index: idx,
|
|
3824
|
+
id: toolCallChunks.find((c)=>c.id)?.id || null,
|
|
3825
|
+
type: toolCallChunks.find((c)=>c.type)?.type || null
|
|
3826
|
+
};
|
|
3827
|
+
for (const chunk of toolCallChunks)if (chunk.function) {
|
|
3828
|
+
if (!message.tool_calls[idx].function) message.tool_calls[idx].function = {
|
|
3829
|
+
name: "",
|
|
3830
|
+
arguments: ""
|
|
3831
|
+
};
|
|
3832
|
+
if (chunk.function.name) message.tool_calls[idx].function.name += chunk.function.name;
|
|
3833
|
+
if (chunk.function.arguments) message.tool_calls[idx].function.arguments += chunk.function.arguments;
|
|
3834
|
+
}
|
|
3835
|
+
}
|
|
3836
|
+
}
|
|
3837
|
+
return {
|
|
3838
|
+
index: choices[0].index,
|
|
3839
|
+
finish_reason: reversedChoices.find((c)=>c.finish_reason) || null,
|
|
3840
|
+
message: message
|
|
3841
|
+
};
|
|
3842
|
+
}
|
|
3843
|
+
const chatAggregator = (chunks)=>{
|
|
3844
|
+
if (!chunks || 0 === chunks.length) return {
|
|
3845
|
+
choices: [
|
|
3846
|
+
{
|
|
3847
|
+
message: {
|
|
3848
|
+
role: "assistant",
|
|
3849
|
+
content: ""
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
]
|
|
3853
|
+
};
|
|
3854
|
+
const choicesByIndex = {};
|
|
3855
|
+
for (const chunk of chunks)for (const choice of chunk.choices){
|
|
3856
|
+
if (void 0 === choicesByIndex[choice.index]) choicesByIndex[choice.index] = [];
|
|
3857
|
+
choicesByIndex[choice.index].push(choice);
|
|
3858
|
+
}
|
|
3859
|
+
const aggregatedOutput = chunks[chunks.length - 1];
|
|
3860
|
+
aggregatedOutput.choices = Object.values(choicesByIndex).map((choices)=>_combineChatCompletionChoices(choices));
|
|
3861
|
+
return aggregatedOutput;
|
|
3862
|
+
};
|
|
3863
|
+
const textAggregator = (allChunks)=>{
|
|
3864
|
+
if (0 === allChunks.length) return {
|
|
3865
|
+
choices: [
|
|
3866
|
+
{
|
|
3867
|
+
text: ""
|
|
3868
|
+
}
|
|
3869
|
+
]
|
|
3870
|
+
};
|
|
3871
|
+
const allContent = [];
|
|
3872
|
+
for (const chunk of allChunks){
|
|
3873
|
+
const content = chunk.choices[0].text;
|
|
3874
|
+
if (null != content) allContent.push(content);
|
|
3875
|
+
}
|
|
3876
|
+
const content = allContent.join("");
|
|
3877
|
+
const aggregatedOutput = allChunks[allChunks.length - 1];
|
|
3878
|
+
aggregatedOutput.choices = [
|
|
3879
|
+
{
|
|
3880
|
+
...aggregatedOutput.choices[0],
|
|
3881
|
+
text: content
|
|
3882
|
+
}
|
|
3883
|
+
];
|
|
3884
|
+
return aggregatedOutput;
|
|
3885
|
+
};
|
|
3886
|
+
function processChatCompletion(outputs) {
|
|
3887
|
+
const chatCompletion = outputs;
|
|
3888
|
+
const result = {
|
|
3889
|
+
...chatCompletion
|
|
3890
|
+
};
|
|
3891
|
+
const usage = chatCompletion.usage;
|
|
3892
|
+
if (usage) {
|
|
3893
|
+
const inputTokenDetails = {
|
|
3894
|
+
...usage.prompt_tokens_details?.audio_tokens !== null && {
|
|
3895
|
+
audio: usage.prompt_tokens_details?.audio_tokens
|
|
3896
|
+
},
|
|
3897
|
+
...usage.prompt_tokens_details?.cached_tokens !== null && {
|
|
3898
|
+
cache_read: usage.prompt_tokens_details?.cached_tokens
|
|
3899
|
+
}
|
|
3900
|
+
};
|
|
3901
|
+
const outputTokenDetails = {
|
|
3902
|
+
...usage.completion_tokens_details?.audio_tokens !== null && {
|
|
3903
|
+
audio: usage.completion_tokens_details?.audio_tokens
|
|
3904
|
+
},
|
|
3905
|
+
...usage.completion_tokens_details?.reasoning_tokens !== null && {
|
|
3906
|
+
reasoning: usage.completion_tokens_details?.reasoning_tokens
|
|
3907
|
+
}
|
|
3908
|
+
};
|
|
3909
|
+
result.usage_metadata = {
|
|
3910
|
+
input_tokens: usage.prompt_tokens ?? 0,
|
|
3911
|
+
output_tokens: usage.completion_tokens ?? 0,
|
|
3912
|
+
total_tokens: usage.total_tokens ?? 0,
|
|
3913
|
+
...Object.keys(inputTokenDetails).length > 0 && {
|
|
3914
|
+
input_token_details: inputTokenDetails
|
|
3915
|
+
},
|
|
3916
|
+
...Object.keys(outputTokenDetails).length > 0 && {
|
|
3917
|
+
output_token_details: outputTokenDetails
|
|
3918
|
+
}
|
|
3919
|
+
};
|
|
3920
|
+
}
|
|
3921
|
+
delete result.usage;
|
|
3922
|
+
return result;
|
|
3923
|
+
}
|
|
3924
|
+
const wrapOpenAI = (openai, options)=>{
|
|
3925
|
+
if (isTraceableFunction(openai.chat.completions.create) || isTraceableFunction(openai.completions.create)) throw new Error("This instance of OpenAI client has been already wrapped once.");
|
|
3926
|
+
const tracedOpenAIClient = {
|
|
3927
|
+
...openai
|
|
3928
|
+
};
|
|
3929
|
+
if (openai.beta && openai.beta.chat && openai.beta.chat.completions && "function" == typeof openai.beta.chat.completions.parse) tracedOpenAIClient.beta = {
|
|
3930
|
+
...openai.beta,
|
|
3931
|
+
chat: {
|
|
3932
|
+
...openai.beta.chat,
|
|
3933
|
+
completions: {
|
|
3934
|
+
...openai.beta.chat.completions,
|
|
3935
|
+
parse: traceable_traceable(openai.beta.chat.completions.parse.bind(openai.beta.chat.completions), {
|
|
3936
|
+
name: "ChatOpenAI",
|
|
3937
|
+
run_type: "llm",
|
|
3938
|
+
aggregator: chatAggregator,
|
|
3939
|
+
argsConfigPath: [
|
|
3940
|
+
1,
|
|
3941
|
+
"langsmithExtra"
|
|
3942
|
+
],
|
|
3943
|
+
getInvocationParams: (payload)=>{
|
|
3944
|
+
if ("object" != typeof payload || null == payload) return;
|
|
3945
|
+
const params = payload;
|
|
3946
|
+
const ls_stop = ("string" == typeof params.stop ? [
|
|
3947
|
+
params.stop
|
|
3948
|
+
] : params.stop) ?? void 0;
|
|
3949
|
+
return {
|
|
3950
|
+
ls_provider: "openai",
|
|
3951
|
+
ls_model_type: "chat",
|
|
3952
|
+
ls_model_name: params.model,
|
|
3953
|
+
ls_max_tokens: params.max_tokens ?? void 0,
|
|
3954
|
+
ls_temperature: params.temperature ?? void 0,
|
|
3955
|
+
ls_stop
|
|
3956
|
+
};
|
|
3957
|
+
},
|
|
3958
|
+
...options
|
|
3959
|
+
})
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3962
|
+
};
|
|
3963
|
+
tracedOpenAIClient.chat = {
|
|
3964
|
+
...openai.chat,
|
|
3965
|
+
completions: {
|
|
3966
|
+
...openai.chat.completions,
|
|
3967
|
+
create: traceable_traceable(openai.chat.completions.create.bind(openai.chat.completions), {
|
|
3968
|
+
name: "ChatOpenAI",
|
|
3969
|
+
run_type: "llm",
|
|
3970
|
+
aggregator: chatAggregator,
|
|
3971
|
+
argsConfigPath: [
|
|
3972
|
+
1,
|
|
3973
|
+
"langsmithExtra"
|
|
3974
|
+
],
|
|
3975
|
+
getInvocationParams: (payload)=>{
|
|
3976
|
+
if ("object" != typeof payload || null == payload) return;
|
|
3977
|
+
const params = payload;
|
|
3978
|
+
const ls_stop = ("string" == typeof params.stop ? [
|
|
3979
|
+
params.stop
|
|
3980
|
+
] : params.stop) ?? void 0;
|
|
3981
|
+
return {
|
|
3982
|
+
ls_provider: "openai",
|
|
3983
|
+
ls_model_type: "chat",
|
|
3984
|
+
ls_model_name: params.model,
|
|
3985
|
+
ls_max_tokens: params.max_tokens ?? void 0,
|
|
3986
|
+
ls_temperature: params.temperature ?? void 0,
|
|
3987
|
+
ls_stop
|
|
3988
|
+
};
|
|
3989
|
+
},
|
|
3990
|
+
processOutputs: processChatCompletion,
|
|
3991
|
+
...options
|
|
3992
|
+
})
|
|
3993
|
+
}
|
|
3994
|
+
};
|
|
3995
|
+
tracedOpenAIClient.completions = {
|
|
3996
|
+
...openai.completions,
|
|
3997
|
+
create: traceable_traceable(openai.completions.create.bind(openai.completions), {
|
|
3998
|
+
name: "OpenAI",
|
|
3999
|
+
run_type: "llm",
|
|
4000
|
+
aggregator: textAggregator,
|
|
4001
|
+
argsConfigPath: [
|
|
4002
|
+
1,
|
|
4003
|
+
"langsmithExtra"
|
|
4004
|
+
],
|
|
4005
|
+
getInvocationParams: (payload)=>{
|
|
4006
|
+
if ("object" != typeof payload || null == payload) return;
|
|
4007
|
+
const params = payload;
|
|
4008
|
+
const ls_stop = ("string" == typeof params.stop ? [
|
|
4009
|
+
params.stop
|
|
4010
|
+
] : params.stop) ?? void 0;
|
|
4011
|
+
return {
|
|
4012
|
+
ls_provider: "openai",
|
|
4013
|
+
ls_model_type: "llm",
|
|
4014
|
+
ls_model_name: params.model,
|
|
4015
|
+
ls_max_tokens: params.max_tokens ?? void 0,
|
|
4016
|
+
ls_temperature: params.temperature ?? void 0,
|
|
4017
|
+
ls_stop
|
|
4018
|
+
};
|
|
4019
|
+
},
|
|
4020
|
+
...options
|
|
4021
|
+
})
|
|
4022
|
+
};
|
|
4023
|
+
return tracedOpenAIClient;
|
|
4024
|
+
};
|
|
4025
|
+
}
|
|
4026
|
+
};
|