langsmith 0.1.3 → 0.1.6
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 +3 -3
- package/dist/cli/docker-compose.yaml +30 -2
- package/dist/client.cjs +28 -11
- package/dist/client.d.ts +1 -1
- package/dist/client.js +28 -11
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/run_trees.cjs +60 -4
- package/dist/run_trees.d.ts +27 -1
- package/dist/run_trees.js +58 -3
- package/dist/schemas.d.ts +1 -0
- package/dist/traceable.cjs +4 -0
- package/dist/traceable.d.ts +2 -1
- package/dist/traceable.js +5 -1
- package/dist/utils/async_caller.cjs +14 -2
- package/dist/utils/async_caller.d.ts +4 -0
- package/dist/utils/async_caller.js +14 -2
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -91,8 +91,8 @@ Langsmith's `traceable` wrapper function makes it easy to trace any function or
|
|
|
91
91
|
|
|
92
92
|
<!-- markdown-link-check-disable -->
|
|
93
93
|
|
|
94
|
-
The easiest
|
|
95
|
-
is using the `
|
|
94
|
+
The easiest way to trace calls from the [OpenAI SDK](https://platform.openai.com/docs/api-reference) with LangSmith
|
|
95
|
+
is using the `wrapOpenAI` wrapper function available in LangSmith 0.1.3 and up.
|
|
96
96
|
|
|
97
97
|
In order to use, you first need to set your LangSmith API key:
|
|
98
98
|
|
|
@@ -106,7 +106,7 @@ Next, you will need to install the LangSmith SDK and the OpenAI SDK:
|
|
|
106
106
|
npm install langsmith openai
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
-
After that, initialize your OpenAI client and wrap the client with `wrapOpenAI` method to enable tracing for
|
|
109
|
+
After that, initialize your OpenAI client and wrap the client with `wrapOpenAI` method to enable tracing for the completions and chat completions methods:
|
|
110
110
|
|
|
111
111
|
```ts
|
|
112
112
|
import { OpenAI } from "openai";
|
|
@@ -29,6 +29,8 @@ services:
|
|
|
29
29
|
condition: service_healthy
|
|
30
30
|
clickhouse-setup:
|
|
31
31
|
condition: service_completed_successfully
|
|
32
|
+
postgres-setup:
|
|
33
|
+
condition: service_completed_successfully
|
|
32
34
|
restart: always
|
|
33
35
|
langchain-queue:
|
|
34
36
|
image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:${_LANGSMITH_IMAGE_VERSION:-latest}
|
|
@@ -44,6 +46,8 @@ services:
|
|
|
44
46
|
condition: service_healthy
|
|
45
47
|
clickhouse-setup:
|
|
46
48
|
condition: service_completed_successfully
|
|
49
|
+
postgres-setup:
|
|
50
|
+
condition: service_completed_successfully
|
|
47
51
|
restart: always
|
|
48
52
|
langchain-hub:
|
|
49
53
|
image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainhub-backend:${_LANGSMITH_IMAGE_VERSION:-latest}
|
|
@@ -55,7 +59,15 @@ services:
|
|
|
55
59
|
ports:
|
|
56
60
|
- 1985:1985
|
|
57
61
|
depends_on:
|
|
58
|
-
|
|
62
|
+
langchain-db:
|
|
63
|
+
condition: service_healthy
|
|
64
|
+
langchain-redis:
|
|
65
|
+
condition: service_healthy
|
|
66
|
+
clickhouse-setup:
|
|
67
|
+
condition: service_completed_successfully
|
|
68
|
+
postgres-setup:
|
|
69
|
+
condition: service_completed_successfully
|
|
70
|
+
restart: always
|
|
59
71
|
langchain-db:
|
|
60
72
|
image: postgres:14.7
|
|
61
73
|
command:
|
|
@@ -114,13 +126,29 @@ services:
|
|
|
114
126
|
depends_on:
|
|
115
127
|
langchain-clickhouse:
|
|
116
128
|
condition: service_healthy
|
|
117
|
-
restart: "
|
|
129
|
+
restart: "on-failure:10"
|
|
118
130
|
entrypoint:
|
|
119
131
|
[
|
|
120
132
|
"bash",
|
|
121
133
|
"-c",
|
|
122
134
|
"migrate -source file://clickhouse/migrations -database 'clickhouse://langchain-clickhouse:9000?username=default&password=password&database=default&x-multi-statement=true&x-migrations-table-engine=MergeTree' up",
|
|
123
135
|
]
|
|
136
|
+
postgres-setup:
|
|
137
|
+
image: langchain/${_LANGSMITH_IMAGE_PREFIX-}langchainplus-backend:${_LANGSMITH_IMAGE_VERSION:-latest}
|
|
138
|
+
depends_on:
|
|
139
|
+
langchain-db:
|
|
140
|
+
condition: service_healthy
|
|
141
|
+
environment:
|
|
142
|
+
- LANGCHAIN_ENV=local_docker
|
|
143
|
+
- LOG_LEVEL=warning
|
|
144
|
+
- LANGSMITH_LICENSE_KEY=${LANGSMITH_LICENSE_KEY}
|
|
145
|
+
restart: "on-failure:10"
|
|
146
|
+
entrypoint:
|
|
147
|
+
[
|
|
148
|
+
"bash",
|
|
149
|
+
"-c",
|
|
150
|
+
"alembic upgrade head",
|
|
151
|
+
]
|
|
124
152
|
volumes:
|
|
125
153
|
langchain-db-data:
|
|
126
154
|
langchain-redis-data:
|
package/dist/client.cjs
CHANGED
|
@@ -98,6 +98,18 @@ function assertUuid(str) {
|
|
|
98
98
|
throw new Error(`Invalid UUID: ${str}`);
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
+
const handle429 = async (response) => {
|
|
102
|
+
if (response?.status === 429) {
|
|
103
|
+
const retryAfter = parseInt(response.headers.get("retry-after") ?? "30", 10) * 1000;
|
|
104
|
+
if (retryAfter > 0) {
|
|
105
|
+
await new Promise((resolve) => setTimeout(resolve, retryAfter));
|
|
106
|
+
// Return directly after calling this check
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Fall back to existing status checks
|
|
111
|
+
return false;
|
|
112
|
+
};
|
|
101
113
|
class Queue {
|
|
102
114
|
constructor() {
|
|
103
115
|
Object.defineProperty(this, "items", {
|
|
@@ -161,6 +173,12 @@ class Client {
|
|
|
161
173
|
writable: true,
|
|
162
174
|
value: void 0
|
|
163
175
|
});
|
|
176
|
+
Object.defineProperty(this, "batchIngestCaller", {
|
|
177
|
+
enumerable: true,
|
|
178
|
+
configurable: true,
|
|
179
|
+
writable: true,
|
|
180
|
+
value: void 0
|
|
181
|
+
});
|
|
164
182
|
Object.defineProperty(this, "timeout_ms", {
|
|
165
183
|
enumerable: true,
|
|
166
184
|
configurable: true,
|
|
@@ -244,9 +262,12 @@ class Client {
|
|
|
244
262
|
this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
|
|
245
263
|
this.apiKey = trimQuotes(config.apiKey ?? defaultConfig.apiKey);
|
|
246
264
|
this.webUrl = trimQuotes(config.webUrl ?? defaultConfig.webUrl);
|
|
247
|
-
this.validateApiKeyIfHosted();
|
|
248
265
|
this.timeout_ms = config.timeout_ms ?? 12000;
|
|
249
266
|
this.caller = new async_caller_js_1.AsyncCaller(config.callerOptions ?? {});
|
|
267
|
+
this.batchIngestCaller = new async_caller_js_1.AsyncCaller({
|
|
268
|
+
...(config.callerOptions ?? {}),
|
|
269
|
+
onFailedResponseHook: handle429,
|
|
270
|
+
});
|
|
250
271
|
this.hideInputs = config.hideInputs ?? defaultConfig.hideInputs;
|
|
251
272
|
this.hideOutputs = config.hideOutputs ?? defaultConfig.hideOutputs;
|
|
252
273
|
this.autoBatchTracing = config.autoBatchTracing ?? this.autoBatchTracing;
|
|
@@ -267,12 +288,6 @@ class Client {
|
|
|
267
288
|
hideOutputs: hideOutputs,
|
|
268
289
|
};
|
|
269
290
|
}
|
|
270
|
-
validateApiKeyIfHosted() {
|
|
271
|
-
const isLocal = isLocalhost(this.apiUrl);
|
|
272
|
-
if (!isLocal && !this.apiKey) {
|
|
273
|
-
throw new Error("API key must be provided when using hosted LangSmith API");
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
291
|
getHostUrl() {
|
|
277
292
|
if (this.webUrl) {
|
|
278
293
|
return this.webUrl;
|
|
@@ -455,7 +470,9 @@ class Client {
|
|
|
455
470
|
if (this.autoBatchQueue.size > 0) {
|
|
456
471
|
this.autoBatchTimeout = setTimeout(() => {
|
|
457
472
|
this.autoBatchTimeout = undefined;
|
|
458
|
-
|
|
473
|
+
// This error would happen in the background and is uncatchable
|
|
474
|
+
// from the outside. So just log instead.
|
|
475
|
+
void this.drainAutoBatchQueue().catch(console.error);
|
|
459
476
|
}, oldTimeout
|
|
460
477
|
? this.autoBatchAggregationDelayMs
|
|
461
478
|
: this.autoBatchInitialDelayMs);
|
|
@@ -494,7 +511,7 @@ class Client {
|
|
|
494
511
|
void this.processRunOperation({
|
|
495
512
|
action: "create",
|
|
496
513
|
item: runCreate,
|
|
497
|
-
});
|
|
514
|
+
}).catch(console.error);
|
|
498
515
|
return;
|
|
499
516
|
}
|
|
500
517
|
const mergedRunCreateParams = await mergeRuntimeEnvIntoRunCreates([
|
|
@@ -569,7 +586,7 @@ class Client {
|
|
|
569
586
|
"Content-Type": "application/json",
|
|
570
587
|
Accept: "application/json",
|
|
571
588
|
};
|
|
572
|
-
const response = await this.
|
|
589
|
+
const response = await this.batchIngestCaller.call(fetch, `${this.apiUrl}/runs/batch`, {
|
|
573
590
|
method: "POST",
|
|
574
591
|
headers,
|
|
575
592
|
body: JSON.stringify(body),
|
|
@@ -600,7 +617,7 @@ class Client {
|
|
|
600
617
|
return;
|
|
601
618
|
}
|
|
602
619
|
else {
|
|
603
|
-
void this.processRunOperation({ action: "update", item: data });
|
|
620
|
+
void this.processRunOperation({ action: "update", item: data }).catch(console.error);
|
|
604
621
|
}
|
|
605
622
|
return;
|
|
606
623
|
}
|
package/dist/client.d.ts
CHANGED
|
@@ -77,6 +77,7 @@ export declare class Client {
|
|
|
77
77
|
private apiUrl;
|
|
78
78
|
private webUrl?;
|
|
79
79
|
private caller;
|
|
80
|
+
private batchIngestCaller;
|
|
80
81
|
private timeout_ms;
|
|
81
82
|
private _tenantId;
|
|
82
83
|
private hideInputs?;
|
|
@@ -98,7 +99,6 @@ export declare class Client {
|
|
|
98
99
|
hideInputs?: boolean;
|
|
99
100
|
hideOutputs?: boolean;
|
|
100
101
|
};
|
|
101
|
-
private validateApiKeyIfHosted;
|
|
102
102
|
private getHostUrl;
|
|
103
103
|
private get headers();
|
|
104
104
|
private processInputs;
|
package/dist/client.js
CHANGED
|
@@ -72,6 +72,18 @@ function assertUuid(str) {
|
|
|
72
72
|
throw new Error(`Invalid UUID: ${str}`);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
+
const handle429 = async (response) => {
|
|
76
|
+
if (response?.status === 429) {
|
|
77
|
+
const retryAfter = parseInt(response.headers.get("retry-after") ?? "30", 10) * 1000;
|
|
78
|
+
if (retryAfter > 0) {
|
|
79
|
+
await new Promise((resolve) => setTimeout(resolve, retryAfter));
|
|
80
|
+
// Return directly after calling this check
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Fall back to existing status checks
|
|
85
|
+
return false;
|
|
86
|
+
};
|
|
75
87
|
export class Queue {
|
|
76
88
|
constructor() {
|
|
77
89
|
Object.defineProperty(this, "items", {
|
|
@@ -134,6 +146,12 @@ export class Client {
|
|
|
134
146
|
writable: true,
|
|
135
147
|
value: void 0
|
|
136
148
|
});
|
|
149
|
+
Object.defineProperty(this, "batchIngestCaller", {
|
|
150
|
+
enumerable: true,
|
|
151
|
+
configurable: true,
|
|
152
|
+
writable: true,
|
|
153
|
+
value: void 0
|
|
154
|
+
});
|
|
137
155
|
Object.defineProperty(this, "timeout_ms", {
|
|
138
156
|
enumerable: true,
|
|
139
157
|
configurable: true,
|
|
@@ -217,9 +235,12 @@ export class Client {
|
|
|
217
235
|
this.apiUrl = trimQuotes(config.apiUrl ?? defaultConfig.apiUrl) ?? "";
|
|
218
236
|
this.apiKey = trimQuotes(config.apiKey ?? defaultConfig.apiKey);
|
|
219
237
|
this.webUrl = trimQuotes(config.webUrl ?? defaultConfig.webUrl);
|
|
220
|
-
this.validateApiKeyIfHosted();
|
|
221
238
|
this.timeout_ms = config.timeout_ms ?? 12000;
|
|
222
239
|
this.caller = new AsyncCaller(config.callerOptions ?? {});
|
|
240
|
+
this.batchIngestCaller = new AsyncCaller({
|
|
241
|
+
...(config.callerOptions ?? {}),
|
|
242
|
+
onFailedResponseHook: handle429,
|
|
243
|
+
});
|
|
223
244
|
this.hideInputs = config.hideInputs ?? defaultConfig.hideInputs;
|
|
224
245
|
this.hideOutputs = config.hideOutputs ?? defaultConfig.hideOutputs;
|
|
225
246
|
this.autoBatchTracing = config.autoBatchTracing ?? this.autoBatchTracing;
|
|
@@ -240,12 +261,6 @@ export class Client {
|
|
|
240
261
|
hideOutputs: hideOutputs,
|
|
241
262
|
};
|
|
242
263
|
}
|
|
243
|
-
validateApiKeyIfHosted() {
|
|
244
|
-
const isLocal = isLocalhost(this.apiUrl);
|
|
245
|
-
if (!isLocal && !this.apiKey) {
|
|
246
|
-
throw new Error("API key must be provided when using hosted LangSmith API");
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
264
|
getHostUrl() {
|
|
250
265
|
if (this.webUrl) {
|
|
251
266
|
return this.webUrl;
|
|
@@ -428,7 +443,9 @@ export class Client {
|
|
|
428
443
|
if (this.autoBatchQueue.size > 0) {
|
|
429
444
|
this.autoBatchTimeout = setTimeout(() => {
|
|
430
445
|
this.autoBatchTimeout = undefined;
|
|
431
|
-
|
|
446
|
+
// This error would happen in the background and is uncatchable
|
|
447
|
+
// from the outside. So just log instead.
|
|
448
|
+
void this.drainAutoBatchQueue().catch(console.error);
|
|
432
449
|
}, oldTimeout
|
|
433
450
|
? this.autoBatchAggregationDelayMs
|
|
434
451
|
: this.autoBatchInitialDelayMs);
|
|
@@ -467,7 +484,7 @@ export class Client {
|
|
|
467
484
|
void this.processRunOperation({
|
|
468
485
|
action: "create",
|
|
469
486
|
item: runCreate,
|
|
470
|
-
});
|
|
487
|
+
}).catch(console.error);
|
|
471
488
|
return;
|
|
472
489
|
}
|
|
473
490
|
const mergedRunCreateParams = await mergeRuntimeEnvIntoRunCreates([
|
|
@@ -542,7 +559,7 @@ export class Client {
|
|
|
542
559
|
"Content-Type": "application/json",
|
|
543
560
|
Accept: "application/json",
|
|
544
561
|
};
|
|
545
|
-
const response = await this.
|
|
562
|
+
const response = await this.batchIngestCaller.call(fetch, `${this.apiUrl}/runs/batch`, {
|
|
546
563
|
method: "POST",
|
|
547
564
|
headers,
|
|
548
565
|
body: JSON.stringify(body),
|
|
@@ -573,7 +590,7 @@ export class Client {
|
|
|
573
590
|
return;
|
|
574
591
|
}
|
|
575
592
|
else {
|
|
576
|
-
void this.processRunOperation({ action: "update", item: data });
|
|
593
|
+
void this.processRunOperation({ action: "update", item: data }).catch(console.error);
|
|
577
594
|
}
|
|
578
595
|
return;
|
|
579
596
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -6,4 +6,4 @@ Object.defineProperty(exports, "Client", { enumerable: true, get: function () {
|
|
|
6
6
|
var run_trees_js_1 = require("./run_trees.cjs");
|
|
7
7
|
Object.defineProperty(exports, "RunTree", { enumerable: true, get: function () { return run_trees_js_1.RunTree; } });
|
|
8
8
|
// Update using yarn bump-version
|
|
9
|
-
exports.__version__ = "0.1.
|
|
9
|
+
exports.__version__ = "0.1.6";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { Client } from "./client.js";
|
|
2
2
|
export type { Dataset, Example, TracerSession, Run, Feedback, } from "./schemas.js";
|
|
3
3
|
export { RunTree, type RunTreeConfig } from "./run_trees.js";
|
|
4
|
-
export declare const __version__ = "0.1.
|
|
4
|
+
export declare const __version__ = "0.1.6";
|
package/dist/index.js
CHANGED
package/dist/run_trees.cjs
CHANGED
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.isRunTree = exports.RunTree = exports.convertToDottedOrderFormat = void 0;
|
|
26
|
+
exports.isRunnableConfigLike = exports.isRunTree = exports.RunTree = exports.convertToDottedOrderFormat = void 0;
|
|
27
27
|
const uuid = __importStar(require("uuid"));
|
|
28
28
|
const env_js_1 = require("./utils/env.cjs");
|
|
29
29
|
const client_js_1 = require("./client.cjs");
|
|
@@ -98,6 +98,12 @@ class RunTree {
|
|
|
98
98
|
writable: true,
|
|
99
99
|
value: void 0
|
|
100
100
|
});
|
|
101
|
+
Object.defineProperty(this, "tags", {
|
|
102
|
+
enumerable: true,
|
|
103
|
+
configurable: true,
|
|
104
|
+
writable: true,
|
|
105
|
+
value: void 0
|
|
106
|
+
});
|
|
101
107
|
Object.defineProperty(this, "error", {
|
|
102
108
|
enumerable: true,
|
|
103
109
|
configurable: true,
|
|
@@ -153,10 +159,11 @@ class RunTree {
|
|
|
153
159
|
value: void 0
|
|
154
160
|
});
|
|
155
161
|
const defaultConfig = RunTree.getDefaultConfig();
|
|
156
|
-
|
|
162
|
+
const client = config.client ?? new client_js_1.Client();
|
|
163
|
+
Object.assign(this, { ...defaultConfig, ...config, client });
|
|
157
164
|
if (!this.trace_id) {
|
|
158
165
|
if (this.parent_run) {
|
|
159
|
-
this.trace_id = this.parent_run.trace_id;
|
|
166
|
+
this.trace_id = this.parent_run.trace_id ?? this.id;
|
|
160
167
|
}
|
|
161
168
|
else {
|
|
162
169
|
this.trace_id = this.id;
|
|
@@ -173,6 +180,35 @@ class RunTree {
|
|
|
173
180
|
}
|
|
174
181
|
}
|
|
175
182
|
}
|
|
183
|
+
static fromRunnableConfig(config, props) {
|
|
184
|
+
// We only handle the callback manager case for now
|
|
185
|
+
const callbackManager = config?.callbacks;
|
|
186
|
+
let parentRun;
|
|
187
|
+
let projectName;
|
|
188
|
+
if (callbackManager) {
|
|
189
|
+
const parentRunId = callbackManager?.getParentRunId?.() ?? "";
|
|
190
|
+
const langChainTracer = callbackManager?.handlers?.find((handler) => handler?.name == "langchain_tracer");
|
|
191
|
+
parentRun = langChainTracer?.getRun?.(parentRunId);
|
|
192
|
+
projectName = langChainTracer?.projectName;
|
|
193
|
+
}
|
|
194
|
+
const deduppedTags = [
|
|
195
|
+
...new Set((parentRun?.tags ?? []).concat(config?.tags ?? [])),
|
|
196
|
+
];
|
|
197
|
+
const dedupedMetadata = {
|
|
198
|
+
...parentRun?.extra?.metadata,
|
|
199
|
+
...config?.metadata,
|
|
200
|
+
};
|
|
201
|
+
const rt = new RunTree({
|
|
202
|
+
name: props?.name ?? "<lambda>",
|
|
203
|
+
parent_run: parentRun,
|
|
204
|
+
tags: deduppedTags,
|
|
205
|
+
extra: {
|
|
206
|
+
metadata: dedupedMetadata,
|
|
207
|
+
},
|
|
208
|
+
project_name: projectName,
|
|
209
|
+
});
|
|
210
|
+
return rt;
|
|
211
|
+
}
|
|
176
212
|
static getDefaultConfig() {
|
|
177
213
|
return {
|
|
178
214
|
id: uuid.v4(),
|
|
@@ -188,7 +224,6 @@ class RunTree {
|
|
|
188
224
|
serialized: {},
|
|
189
225
|
inputs: {},
|
|
190
226
|
extra: {},
|
|
191
|
-
client: new client_js_1.Client({}),
|
|
192
227
|
};
|
|
193
228
|
}
|
|
194
229
|
async createChild(config) {
|
|
@@ -244,6 +279,7 @@ class RunTree {
|
|
|
244
279
|
parent_run_id: parent_run_id,
|
|
245
280
|
trace_id: run.trace_id,
|
|
246
281
|
dotted_order: run.dotted_order,
|
|
282
|
+
tags: run.tags,
|
|
247
283
|
};
|
|
248
284
|
return persistedRun;
|
|
249
285
|
}
|
|
@@ -268,6 +304,7 @@ class RunTree {
|
|
|
268
304
|
events: this.events,
|
|
269
305
|
dotted_order: this.dotted_order,
|
|
270
306
|
trace_id: this.trace_id,
|
|
307
|
+
tags: this.tags,
|
|
271
308
|
};
|
|
272
309
|
await this.client.updateRun(this.id, runUpdate);
|
|
273
310
|
}
|
|
@@ -279,3 +316,22 @@ function isRunTree(x) {
|
|
|
279
316
|
typeof x.postRun === "function");
|
|
280
317
|
}
|
|
281
318
|
exports.isRunTree = isRunTree;
|
|
319
|
+
function containsLangChainTracerLike(x) {
|
|
320
|
+
return (Array.isArray(x) &&
|
|
321
|
+
x.some((callback) => {
|
|
322
|
+
return (typeof callback.name === "string" &&
|
|
323
|
+
callback.name === "langchain_tracer");
|
|
324
|
+
}));
|
|
325
|
+
}
|
|
326
|
+
function isRunnableConfigLike(x) {
|
|
327
|
+
// Check that it's an object with a callbacks arg
|
|
328
|
+
// that has either a CallbackManagerLike object with a langchain tracer within it
|
|
329
|
+
// or an array with a LangChainTracerLike object within it
|
|
330
|
+
return (x !== undefined &&
|
|
331
|
+
typeof x.callbacks === "object" &&
|
|
332
|
+
// Callback manager with a langchain tracer
|
|
333
|
+
(containsLangChainTracerLike(x.callbacks?.handlers) ||
|
|
334
|
+
// Or it's an array with a LangChainTracerLike object within it
|
|
335
|
+
containsLangChainTracerLike(x.callbacks)));
|
|
336
|
+
}
|
|
337
|
+
exports.isRunnableConfigLike = isRunnableConfigLike;
|
package/dist/run_trees.d.ts
CHANGED
|
@@ -7,10 +7,12 @@ export interface RunTreeConfig {
|
|
|
7
7
|
id?: string;
|
|
8
8
|
project_name?: string;
|
|
9
9
|
parent_run?: RunTree;
|
|
10
|
+
parent_run_id?: string;
|
|
10
11
|
child_runs?: RunTree[];
|
|
11
12
|
start_time?: number;
|
|
12
13
|
end_time?: number;
|
|
13
14
|
extra?: KVMap;
|
|
15
|
+
tags?: string[];
|
|
14
16
|
error?: string;
|
|
15
17
|
serialized?: object;
|
|
16
18
|
inputs?: KVMap;
|
|
@@ -18,16 +20,34 @@ export interface RunTreeConfig {
|
|
|
18
20
|
reference_example_id?: string;
|
|
19
21
|
client?: Client;
|
|
20
22
|
}
|
|
23
|
+
export interface RunnableConfigLike {
|
|
24
|
+
/**
|
|
25
|
+
* Tags for this call and any sub-calls (eg. a Chain calling an LLM).
|
|
26
|
+
* You can use these to filter calls.
|
|
27
|
+
*/
|
|
28
|
+
tags?: string[];
|
|
29
|
+
/**
|
|
30
|
+
* Metadata for this call and any sub-calls (eg. a Chain calling an LLM).
|
|
31
|
+
* Keys should be strings, values should be JSON-serializable.
|
|
32
|
+
*/
|
|
33
|
+
metadata?: Record<string, unknown>;
|
|
34
|
+
/**
|
|
35
|
+
* Callbacks for this call and any sub-calls (eg. a Chain calling an LLM).
|
|
36
|
+
* Tags are passed to all callbacks, metadata is passed to handle*Start callbacks.
|
|
37
|
+
*/
|
|
38
|
+
callbacks?: any;
|
|
39
|
+
}
|
|
21
40
|
export declare class RunTree implements BaseRun {
|
|
22
41
|
id: string;
|
|
23
42
|
name: RunTreeConfig["name"];
|
|
24
43
|
run_type: string;
|
|
25
44
|
project_name: string;
|
|
26
|
-
parent_run?:
|
|
45
|
+
parent_run?: BaseRun;
|
|
27
46
|
child_runs: RunTree[];
|
|
28
47
|
start_time: number;
|
|
29
48
|
end_time?: number;
|
|
30
49
|
extra: KVMap;
|
|
50
|
+
tags?: string[];
|
|
31
51
|
error?: string;
|
|
32
52
|
serialized: object;
|
|
33
53
|
inputs: KVMap;
|
|
@@ -38,6 +58,11 @@ export declare class RunTree implements BaseRun {
|
|
|
38
58
|
trace_id: string;
|
|
39
59
|
dotted_order: string;
|
|
40
60
|
constructor(config: RunTreeConfig);
|
|
61
|
+
static fromRunnableConfig(config: RunnableConfigLike, props: {
|
|
62
|
+
name: string;
|
|
63
|
+
tags?: string[];
|
|
64
|
+
metadata?: KVMap;
|
|
65
|
+
}): RunTree;
|
|
41
66
|
private static getDefaultConfig;
|
|
42
67
|
createChild(config: RunTreeConfig): Promise<RunTree>;
|
|
43
68
|
end(outputs?: KVMap, error?: string, endTime?: number): Promise<void>;
|
|
@@ -46,3 +71,4 @@ export declare class RunTree implements BaseRun {
|
|
|
46
71
|
patchRun(): Promise<void>;
|
|
47
72
|
}
|
|
48
73
|
export declare function isRunTree(x?: unknown): x is RunTree;
|
|
74
|
+
export declare function isRunnableConfigLike(x?: unknown): x is RunnableConfigLike;
|
package/dist/run_trees.js
CHANGED
|
@@ -71,6 +71,12 @@ export class RunTree {
|
|
|
71
71
|
writable: true,
|
|
72
72
|
value: void 0
|
|
73
73
|
});
|
|
74
|
+
Object.defineProperty(this, "tags", {
|
|
75
|
+
enumerable: true,
|
|
76
|
+
configurable: true,
|
|
77
|
+
writable: true,
|
|
78
|
+
value: void 0
|
|
79
|
+
});
|
|
74
80
|
Object.defineProperty(this, "error", {
|
|
75
81
|
enumerable: true,
|
|
76
82
|
configurable: true,
|
|
@@ -126,10 +132,11 @@ export class RunTree {
|
|
|
126
132
|
value: void 0
|
|
127
133
|
});
|
|
128
134
|
const defaultConfig = RunTree.getDefaultConfig();
|
|
129
|
-
|
|
135
|
+
const client = config.client ?? new Client();
|
|
136
|
+
Object.assign(this, { ...defaultConfig, ...config, client });
|
|
130
137
|
if (!this.trace_id) {
|
|
131
138
|
if (this.parent_run) {
|
|
132
|
-
this.trace_id = this.parent_run.trace_id;
|
|
139
|
+
this.trace_id = this.parent_run.trace_id ?? this.id;
|
|
133
140
|
}
|
|
134
141
|
else {
|
|
135
142
|
this.trace_id = this.id;
|
|
@@ -146,6 +153,35 @@ export class RunTree {
|
|
|
146
153
|
}
|
|
147
154
|
}
|
|
148
155
|
}
|
|
156
|
+
static fromRunnableConfig(config, props) {
|
|
157
|
+
// We only handle the callback manager case for now
|
|
158
|
+
const callbackManager = config?.callbacks;
|
|
159
|
+
let parentRun;
|
|
160
|
+
let projectName;
|
|
161
|
+
if (callbackManager) {
|
|
162
|
+
const parentRunId = callbackManager?.getParentRunId?.() ?? "";
|
|
163
|
+
const langChainTracer = callbackManager?.handlers?.find((handler) => handler?.name == "langchain_tracer");
|
|
164
|
+
parentRun = langChainTracer?.getRun?.(parentRunId);
|
|
165
|
+
projectName = langChainTracer?.projectName;
|
|
166
|
+
}
|
|
167
|
+
const deduppedTags = [
|
|
168
|
+
...new Set((parentRun?.tags ?? []).concat(config?.tags ?? [])),
|
|
169
|
+
];
|
|
170
|
+
const dedupedMetadata = {
|
|
171
|
+
...parentRun?.extra?.metadata,
|
|
172
|
+
...config?.metadata,
|
|
173
|
+
};
|
|
174
|
+
const rt = new RunTree({
|
|
175
|
+
name: props?.name ?? "<lambda>",
|
|
176
|
+
parent_run: parentRun,
|
|
177
|
+
tags: deduppedTags,
|
|
178
|
+
extra: {
|
|
179
|
+
metadata: dedupedMetadata,
|
|
180
|
+
},
|
|
181
|
+
project_name: projectName,
|
|
182
|
+
});
|
|
183
|
+
return rt;
|
|
184
|
+
}
|
|
149
185
|
static getDefaultConfig() {
|
|
150
186
|
return {
|
|
151
187
|
id: uuid.v4(),
|
|
@@ -161,7 +197,6 @@ export class RunTree {
|
|
|
161
197
|
serialized: {},
|
|
162
198
|
inputs: {},
|
|
163
199
|
extra: {},
|
|
164
|
-
client: new Client({}),
|
|
165
200
|
};
|
|
166
201
|
}
|
|
167
202
|
async createChild(config) {
|
|
@@ -217,6 +252,7 @@ export class RunTree {
|
|
|
217
252
|
parent_run_id: parent_run_id,
|
|
218
253
|
trace_id: run.trace_id,
|
|
219
254
|
dotted_order: run.dotted_order,
|
|
255
|
+
tags: run.tags,
|
|
220
256
|
};
|
|
221
257
|
return persistedRun;
|
|
222
258
|
}
|
|
@@ -241,6 +277,7 @@ export class RunTree {
|
|
|
241
277
|
events: this.events,
|
|
242
278
|
dotted_order: this.dotted_order,
|
|
243
279
|
trace_id: this.trace_id,
|
|
280
|
+
tags: this.tags,
|
|
244
281
|
};
|
|
245
282
|
await this.client.updateRun(this.id, runUpdate);
|
|
246
283
|
}
|
|
@@ -250,3 +287,21 @@ export function isRunTree(x) {
|
|
|
250
287
|
typeof x.createChild === "function" &&
|
|
251
288
|
typeof x.postRun === "function");
|
|
252
289
|
}
|
|
290
|
+
function containsLangChainTracerLike(x) {
|
|
291
|
+
return (Array.isArray(x) &&
|
|
292
|
+
x.some((callback) => {
|
|
293
|
+
return (typeof callback.name === "string" &&
|
|
294
|
+
callback.name === "langchain_tracer");
|
|
295
|
+
}));
|
|
296
|
+
}
|
|
297
|
+
export function isRunnableConfigLike(x) {
|
|
298
|
+
// Check that it's an object with a callbacks arg
|
|
299
|
+
// that has either a CallbackManagerLike object with a langchain tracer within it
|
|
300
|
+
// or an array with a LangChainTracerLike object within it
|
|
301
|
+
return (x !== undefined &&
|
|
302
|
+
typeof x.callbacks === "object" &&
|
|
303
|
+
// Callback manager with a langchain tracer
|
|
304
|
+
(containsLangChainTracerLike(x.callbacks?.handlers) ||
|
|
305
|
+
// Or it's an array with a LangChainTracerLike object within it
|
|
306
|
+
containsLangChainTracerLike(x.callbacks)));
|
|
307
|
+
}
|
package/dist/schemas.d.ts
CHANGED
package/dist/traceable.cjs
CHANGED
|
@@ -36,6 +36,10 @@ function traceable(wrappedFunc, config) {
|
|
|
36
36
|
currentRunTree = args[0];
|
|
37
37
|
rawInputs = args.slice(1);
|
|
38
38
|
}
|
|
39
|
+
else if ((0, run_trees_js_1.isRunnableConfigLike)(args[0])) {
|
|
40
|
+
currentRunTree = run_trees_js_1.RunTree.fromRunnableConfig(args[0], ensuredConfig);
|
|
41
|
+
rawInputs = args.slice(1);
|
|
42
|
+
}
|
|
39
43
|
else if (previousRunTree !== undefined) {
|
|
40
44
|
currentRunTree = await previousRunTree.createChild(ensuredConfig);
|
|
41
45
|
rawInputs = args;
|
package/dist/traceable.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RunTree, RunTreeConfig } from "./run_trees.js";
|
|
1
|
+
import { RunTree, RunTreeConfig, RunnableConfigLike } from "./run_trees.js";
|
|
2
2
|
export type RunTreeLike = RunTree;
|
|
3
3
|
type WrapArgReturnPair<Pair> = Pair extends [
|
|
4
4
|
infer Args extends any[],
|
|
@@ -6,6 +6,7 @@ type WrapArgReturnPair<Pair> = Pair extends [
|
|
|
6
6
|
] ? {
|
|
7
7
|
(...args: Args): Promise<Return>;
|
|
8
8
|
(...args: [runTree: RunTreeLike, ...rest: Args]): Promise<Return>;
|
|
9
|
+
(...args: [config: RunnableConfigLike, ...rest: Args]): Promise<Return>;
|
|
9
10
|
} : never;
|
|
10
11
|
type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
|
|
11
12
|
export type TraceableFunction<Func extends (...args: any[]) => any> = Func extends {
|
package/dist/traceable.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "async_hooks";
|
|
2
|
-
import { RunTree, isRunTree } from "./run_trees.js";
|
|
2
|
+
import { RunTree, isRunTree, isRunnableConfigLike, } from "./run_trees.js";
|
|
3
3
|
const asyncLocalStorage = new AsyncLocalStorage();
|
|
4
4
|
const isAsyncIterable = (x) => x != null &&
|
|
5
5
|
typeof x === "object" &&
|
|
@@ -33,6 +33,10 @@ export function traceable(wrappedFunc, config) {
|
|
|
33
33
|
currentRunTree = args[0];
|
|
34
34
|
rawInputs = args.slice(1);
|
|
35
35
|
}
|
|
36
|
+
else if (isRunnableConfigLike(args[0])) {
|
|
37
|
+
currentRunTree = RunTree.fromRunnableConfig(args[0], ensuredConfig);
|
|
38
|
+
rawInputs = args.slice(1);
|
|
39
|
+
}
|
|
36
40
|
else if (previousRunTree !== undefined) {
|
|
37
41
|
currentRunTree = await previousRunTree.createChild(ensuredConfig);
|
|
38
42
|
rawInputs = args;
|
|
@@ -52,13 +52,21 @@ class AsyncCaller {
|
|
|
52
52
|
writable: true,
|
|
53
53
|
value: void 0
|
|
54
54
|
});
|
|
55
|
+
Object.defineProperty(this, "onFailedResponseHook", {
|
|
56
|
+
enumerable: true,
|
|
57
|
+
configurable: true,
|
|
58
|
+
writable: true,
|
|
59
|
+
value: void 0
|
|
60
|
+
});
|
|
55
61
|
this.maxConcurrency = params.maxConcurrency ?? Infinity;
|
|
56
62
|
this.maxRetries = params.maxRetries ?? 6;
|
|
57
63
|
const PQueue = "default" in p_queue_1.default ? p_queue_1.default.default : p_queue_1.default;
|
|
58
64
|
this.queue = new PQueue({ concurrency: this.maxConcurrency });
|
|
65
|
+
this.onFailedResponseHook = params?.onFailedResponseHook;
|
|
59
66
|
}
|
|
60
67
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
61
68
|
call(callable, ...args) {
|
|
69
|
+
const onFailedResponseHook = this.onFailedResponseHook;
|
|
62
70
|
return this.queue.add(() => (0, p_retry_1.default)(() => callable(...args).catch((error) => {
|
|
63
71
|
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
64
72
|
if (error instanceof Error) {
|
|
@@ -68,7 +76,7 @@ class AsyncCaller {
|
|
|
68
76
|
throw new Error(error);
|
|
69
77
|
}
|
|
70
78
|
}), {
|
|
71
|
-
onFailedAttempt(error) {
|
|
79
|
+
async onFailedAttempt(error) {
|
|
72
80
|
if (error.message.startsWith("Cancel") ||
|
|
73
81
|
error.message.startsWith("TimeoutError") ||
|
|
74
82
|
error.message.startsWith("AbortError")) {
|
|
@@ -79,7 +87,8 @@ class AsyncCaller {
|
|
|
79
87
|
throw error;
|
|
80
88
|
}
|
|
81
89
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
82
|
-
const
|
|
90
|
+
const response = error?.response;
|
|
91
|
+
const status = response?.status;
|
|
83
92
|
if (status) {
|
|
84
93
|
if (STATUS_NO_RETRY.includes(+status)) {
|
|
85
94
|
throw error;
|
|
@@ -87,6 +96,9 @@ class AsyncCaller {
|
|
|
87
96
|
else if (STATUS_IGNORE.includes(+status)) {
|
|
88
97
|
return;
|
|
89
98
|
}
|
|
99
|
+
if (onFailedResponseHook) {
|
|
100
|
+
await onFailedResponseHook(response);
|
|
101
|
+
}
|
|
90
102
|
}
|
|
91
103
|
},
|
|
92
104
|
// If needed we can change some of the defaults here,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
type ResponseCallback = (response?: Response) => Promise<boolean>;
|
|
1
2
|
export interface AsyncCallerParams {
|
|
2
3
|
/**
|
|
3
4
|
* The maximum number of concurrent calls that can be made.
|
|
@@ -9,6 +10,7 @@ export interface AsyncCallerParams {
|
|
|
9
10
|
* with an exponential backoff between each attempt. Defaults to 6.
|
|
10
11
|
*/
|
|
11
12
|
maxRetries?: number;
|
|
13
|
+
onFailedResponseHook?: ResponseCallback;
|
|
12
14
|
}
|
|
13
15
|
export interface AsyncCallerCallOptions {
|
|
14
16
|
signal?: AbortSignal;
|
|
@@ -30,8 +32,10 @@ export declare class AsyncCaller {
|
|
|
30
32
|
protected maxConcurrency: AsyncCallerParams["maxConcurrency"];
|
|
31
33
|
protected maxRetries: AsyncCallerParams["maxRetries"];
|
|
32
34
|
private queue;
|
|
35
|
+
private onFailedResponseHook?;
|
|
33
36
|
constructor(params: AsyncCallerParams);
|
|
34
37
|
call<A extends any[], T extends (...args: A) => Promise<any>>(callable: T, ...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;
|
|
35
38
|
callWithOptions<A extends any[], T extends (...args: A) => Promise<any>>(options: AsyncCallerCallOptions, callable: T, ...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;
|
|
36
39
|
fetch(...args: Parameters<typeof fetch>): ReturnType<typeof fetch>;
|
|
37
40
|
}
|
|
41
|
+
export {};
|
|
@@ -46,13 +46,21 @@ export class AsyncCaller {
|
|
|
46
46
|
writable: true,
|
|
47
47
|
value: void 0
|
|
48
48
|
});
|
|
49
|
+
Object.defineProperty(this, "onFailedResponseHook", {
|
|
50
|
+
enumerable: true,
|
|
51
|
+
configurable: true,
|
|
52
|
+
writable: true,
|
|
53
|
+
value: void 0
|
|
54
|
+
});
|
|
49
55
|
this.maxConcurrency = params.maxConcurrency ?? Infinity;
|
|
50
56
|
this.maxRetries = params.maxRetries ?? 6;
|
|
51
57
|
const PQueue = "default" in PQueueMod ? PQueueMod.default : PQueueMod;
|
|
52
58
|
this.queue = new PQueue({ concurrency: this.maxConcurrency });
|
|
59
|
+
this.onFailedResponseHook = params?.onFailedResponseHook;
|
|
53
60
|
}
|
|
54
61
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
62
|
call(callable, ...args) {
|
|
63
|
+
const onFailedResponseHook = this.onFailedResponseHook;
|
|
56
64
|
return this.queue.add(() => pRetry(() => callable(...args).catch((error) => {
|
|
57
65
|
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
58
66
|
if (error instanceof Error) {
|
|
@@ -62,7 +70,7 @@ export class AsyncCaller {
|
|
|
62
70
|
throw new Error(error);
|
|
63
71
|
}
|
|
64
72
|
}), {
|
|
65
|
-
onFailedAttempt(error) {
|
|
73
|
+
async onFailedAttempt(error) {
|
|
66
74
|
if (error.message.startsWith("Cancel") ||
|
|
67
75
|
error.message.startsWith("TimeoutError") ||
|
|
68
76
|
error.message.startsWith("AbortError")) {
|
|
@@ -73,7 +81,8 @@ export class AsyncCaller {
|
|
|
73
81
|
throw error;
|
|
74
82
|
}
|
|
75
83
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
76
|
-
const
|
|
84
|
+
const response = error?.response;
|
|
85
|
+
const status = response?.status;
|
|
77
86
|
if (status) {
|
|
78
87
|
if (STATUS_NO_RETRY.includes(+status)) {
|
|
79
88
|
throw error;
|
|
@@ -81,6 +90,9 @@ export class AsyncCaller {
|
|
|
81
90
|
else if (STATUS_IGNORE.includes(+status)) {
|
|
82
91
|
return;
|
|
83
92
|
}
|
|
93
|
+
if (onFailedResponseHook) {
|
|
94
|
+
await onFailedResponseHook(response);
|
|
95
|
+
}
|
|
84
96
|
}
|
|
85
97
|
},
|
|
86
98
|
// If needed we can change some of the defaults here,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "langsmith",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.",
|
|
5
5
|
"packageManager": "yarn@1.22.19",
|
|
6
6
|
"files": [
|
|
@@ -69,7 +69,8 @@
|
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@babel/preset-env": "^7.22.4",
|
|
71
71
|
"@jest/globals": "^29.5.0",
|
|
72
|
-
"@langchain/core": "^0.1.
|
|
72
|
+
"@langchain/core": "^0.1.32",
|
|
73
|
+
"@langchain/langgraph": "^0.0.8",
|
|
73
74
|
"@tsconfig/recommended": "^1.0.2",
|
|
74
75
|
"@types/jest": "^29.5.1",
|
|
75
76
|
"@typescript-eslint/eslint-plugin": "^5.59.8",
|