langsmith 0.8.5 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/experimental/vercel/telemetry.cjs +158 -29
- package/dist/experimental/vercel/telemetry.js +158 -29
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/sandbox/command_handle.cjs +1 -1
- package/dist/sandbox/command_handle.js +2 -2
- package/dist/sandbox/errors.cjs +16 -1
- package/dist/sandbox/errors.d.ts +11 -0
- package/dist/sandbox/errors.js +14 -0
- package/dist/sandbox/sandbox.cjs +55 -33
- package/dist/sandbox/sandbox.d.ts +2 -1
- package/dist/sandbox/sandbox.js +57 -35
- package/dist/sandbox/ws_execute.cjs +12 -5
- package/dist/sandbox/ws_execute.d.ts +2 -0
- package/dist/sandbox/ws_execute.js +11 -5
- package/dist/utils/jestlike/globals.cjs +2 -3
- package/dist/utils/jestlike/globals.d.ts +1 -1
- package/dist/utils/jestlike/globals.js +1 -2
- package/dist/utils/jestlike/index.cjs +11 -5
- package/dist/utils/jestlike/index.js +12 -6
- package/package.json +9 -3
package/dist/index.cjs
CHANGED
|
@@ -35,6 +35,6 @@ Object.defineProperty(exports, "UnprocessableEntityError", { enumerable: true, g
|
|
|
35
35
|
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return error_js_1.RateLimitError; } });
|
|
36
36
|
Object.defineProperty(exports, "InternalServerError", { enumerable: true, get: function () { return error_js_1.InternalServerError; } });
|
|
37
37
|
// Update using pnpm bump-version
|
|
38
|
-
exports.__version__ = "0.8.
|
|
38
|
+
exports.__version__ = "0.8.7";
|
|
39
39
|
// Metadata key to hide a traced run from LangSmith's Messages View.
|
|
40
40
|
exports.LS_MESSAGE_VIEW_EXCLUDE = "ls_message_view_exclude";
|
package/dist/index.d.ts
CHANGED
|
@@ -7,5 +7,5 @@ export { computeRunIdForSecondaryReplica, uuid7, uuid7FromTime, } from "./uuid.j
|
|
|
7
7
|
export { isTracingEnabled } from "./utils/guard.js";
|
|
8
8
|
export { Cache, PromptCache, type CacheConfig, type CacheMetrics, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
|
|
9
9
|
export { LangsmithError, APIError, APIUserAbortError, APIConnectionError, APIConnectionTimeoutError, BadRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, } from "./_openapi_client/core/error.js";
|
|
10
|
-
export declare const __version__ = "0.8.
|
|
10
|
+
export declare const __version__ = "0.8.7";
|
|
11
11
|
export declare const LS_MESSAGE_VIEW_EXCLUDE: "ls_message_view_exclude";
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,6 @@ export { isTracingEnabled } from "./utils/guard.js";
|
|
|
7
7
|
export { Cache, PromptCache, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
|
|
8
8
|
export { LangsmithError, APIError, APIUserAbortError, APIConnectionError, APIConnectionTimeoutError, BadRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, } from "./_openapi_client/core/error.js";
|
|
9
9
|
// Update using pnpm bump-version
|
|
10
|
-
export const __version__ = "0.8.
|
|
10
|
+
export const __version__ = "0.8.7";
|
|
11
11
|
// Metadata key to hide a traced run from LangSmith's Messages View.
|
|
12
12
|
export const LS_MESSAGE_VIEW_EXCLUDE = "ls_message_view_exclude";
|
|
@@ -147,7 +147,7 @@ class CommandHandle {
|
|
|
147
147
|
return;
|
|
148
148
|
const firstResult = await this._stream.next();
|
|
149
149
|
if (firstResult.done) {
|
|
150
|
-
throw new errors_js_1.
|
|
150
|
+
throw new errors_js_1.LangSmithStreamEndedBeforeStartedError("Command stream ended before 'started' message");
|
|
151
151
|
}
|
|
152
152
|
const firstMsg = firstResult.value;
|
|
153
153
|
if (firstMsg.type !== "started") {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Port of Python's AsyncCommandHandle to TypeScript.
|
|
6
6
|
*/
|
|
7
|
-
import { LangSmithSandboxConnectionError, LangSmithSandboxOperationError, } from "./errors.js";
|
|
7
|
+
import { LangSmithSandboxConnectionError, LangSmithSandboxOperationError, LangSmithStreamEndedBeforeStartedError, } from "./errors.js";
|
|
8
8
|
/**
|
|
9
9
|
* Async handle to a running command with streaming output and auto-reconnect.
|
|
10
10
|
*
|
|
@@ -144,7 +144,7 @@ export class CommandHandle {
|
|
|
144
144
|
return;
|
|
145
145
|
const firstResult = await this._stream.next();
|
|
146
146
|
if (firstResult.done) {
|
|
147
|
-
throw new
|
|
147
|
+
throw new LangSmithStreamEndedBeforeStartedError("Command stream ended before 'started' message");
|
|
148
148
|
}
|
|
149
149
|
const firstMsg = firstResult.value;
|
|
150
150
|
if (firstMsg.type !== "started") {
|
package/dist/sandbox/errors.cjs
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* properties for specific handling when needed.
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.LangSmithSandboxServerReloadError = exports.LangSmithCommandTimeoutError = exports.LangSmithSandboxOperationError = exports.LangSmithSandboxNotReadyError = exports.LangSmithDataplaneNotConfiguredError = exports.LangSmithSandboxCreationError = exports.LangSmithResourceCreationError = exports.LangSmithQuotaExceededError = exports.LangSmithValidationError = exports.LangSmithResourceNameConflictError = exports.LangSmithResourceAlreadyExistsError = exports.LangSmithResourceInUseError = exports.LangSmithResourceTimeoutError = exports.LangSmithResourceNotFoundError = exports.LangSmithSandboxConnectionError = exports.LangSmithSandboxAuthenticationError = exports.LangSmithSandboxAPIError = exports.LangSmithSandboxError = void 0;
|
|
10
|
+
exports.LangSmithSandboxServerReloadError = exports.LangSmithStreamEndedBeforeStartedError = exports.LangSmithCommandTimeoutError = exports.LangSmithSandboxOperationError = exports.LangSmithSandboxNotReadyError = exports.LangSmithDataplaneNotConfiguredError = exports.LangSmithSandboxCreationError = exports.LangSmithResourceCreationError = exports.LangSmithQuotaExceededError = exports.LangSmithValidationError = exports.LangSmithResourceNameConflictError = exports.LangSmithResourceAlreadyExistsError = exports.LangSmithResourceInUseError = exports.LangSmithResourceTimeoutError = exports.LangSmithResourceNotFoundError = exports.LangSmithSandboxConnectionError = exports.LangSmithSandboxAuthenticationError = exports.LangSmithSandboxAPIError = exports.LangSmithSandboxError = void 0;
|
|
11
11
|
/**
|
|
12
12
|
* Base exception for sandbox client errors.
|
|
13
13
|
*/
|
|
@@ -357,6 +357,21 @@ class LangSmithCommandTimeoutError extends LangSmithSandboxOperationError {
|
|
|
357
357
|
}
|
|
358
358
|
}
|
|
359
359
|
exports.LangSmithCommandTimeoutError = LangSmithCommandTimeoutError;
|
|
360
|
+
/**
|
|
361
|
+
* Internal: a command WebSocket closed before the guest sent its 'started'
|
|
362
|
+
* frame (the proxied tunnel was torn down gracefully mid-handshake).
|
|
363
|
+
*
|
|
364
|
+
* Marks the idempotently-retryable early close, as distinct from a
|
|
365
|
+
* command-level failure. Subclasses the operation error so callers that catch
|
|
366
|
+
* the public type are unaffected.
|
|
367
|
+
*/
|
|
368
|
+
class LangSmithStreamEndedBeforeStartedError extends LangSmithSandboxOperationError {
|
|
369
|
+
constructor(message) {
|
|
370
|
+
super(message, "command");
|
|
371
|
+
this.name = "LangSmithStreamEndedBeforeStartedError";
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
exports.LangSmithStreamEndedBeforeStartedError = LangSmithStreamEndedBeforeStartedError;
|
|
360
375
|
/**
|
|
361
376
|
* Raised when the sandbox server is reloading (close code 1001).
|
|
362
377
|
*
|
package/dist/sandbox/errors.d.ts
CHANGED
|
@@ -154,6 +154,17 @@ export declare class LangSmithCommandTimeoutError extends LangSmithSandboxOperat
|
|
|
154
154
|
timeout?: number;
|
|
155
155
|
constructor(message: string, timeout?: number);
|
|
156
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* Internal: a command WebSocket closed before the guest sent its 'started'
|
|
159
|
+
* frame (the proxied tunnel was torn down gracefully mid-handshake).
|
|
160
|
+
*
|
|
161
|
+
* Marks the idempotently-retryable early close, as distinct from a
|
|
162
|
+
* command-level failure. Subclasses the operation error so callers that catch
|
|
163
|
+
* the public type are unaffected.
|
|
164
|
+
*/
|
|
165
|
+
export declare class LangSmithStreamEndedBeforeStartedError extends LangSmithSandboxOperationError {
|
|
166
|
+
constructor(message: string);
|
|
167
|
+
}
|
|
157
168
|
/**
|
|
158
169
|
* Raised when the sandbox server is reloading (close code 1001).
|
|
159
170
|
*
|
package/dist/sandbox/errors.js
CHANGED
|
@@ -337,6 +337,20 @@ export class LangSmithCommandTimeoutError extends LangSmithSandboxOperationError
|
|
|
337
337
|
this.timeout = timeout;
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
|
+
/**
|
|
341
|
+
* Internal: a command WebSocket closed before the guest sent its 'started'
|
|
342
|
+
* frame (the proxied tunnel was torn down gracefully mid-handshake).
|
|
343
|
+
*
|
|
344
|
+
* Marks the idempotently-retryable early close, as distinct from a
|
|
345
|
+
* command-level failure. Subclasses the operation error so callers that catch
|
|
346
|
+
* the public type are unaffected.
|
|
347
|
+
*/
|
|
348
|
+
export class LangSmithStreamEndedBeforeStartedError extends LangSmithSandboxOperationError {
|
|
349
|
+
constructor(message) {
|
|
350
|
+
super(message, "command");
|
|
351
|
+
this.name = "LangSmithStreamEndedBeforeStartedError";
|
|
352
|
+
}
|
|
353
|
+
}
|
|
340
354
|
/**
|
|
341
355
|
* Raised when the sandbox server is reloading (close code 1001).
|
|
342
356
|
*
|
package/dist/sandbox/sandbox.cjs
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Sandbox = void 0;
|
|
7
|
+
const uuid_js_1 = require("../uuid.cjs");
|
|
7
8
|
const errors_js_1 = require("./errors.cjs");
|
|
8
9
|
const helpers_js_1 = require("./helpers.cjs");
|
|
9
10
|
const command_handle_js_1 = require("./command_handle.cjs");
|
|
@@ -198,8 +199,9 @@ class Sandbox {
|
|
|
198
199
|
// wait=true with callbacks: drain stream and return result
|
|
199
200
|
return handle.result;
|
|
200
201
|
}
|
|
201
|
-
// wait=true, no callbacks:
|
|
202
|
-
|
|
202
|
+
// wait=true, no callbacks: use WebSocket when the 'ws' package is
|
|
203
|
+
// available, otherwise the blocking HTTP endpoint. WS errors propagate.
|
|
204
|
+
if (await this._wsAvailable()) {
|
|
203
205
|
const handle = await this._runWs(command, {
|
|
204
206
|
...restOptions,
|
|
205
207
|
idleTimeout,
|
|
@@ -209,17 +211,14 @@ class Sandbox {
|
|
|
209
211
|
});
|
|
210
212
|
return await handle.result;
|
|
211
213
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
throw e;
|
|
222
|
-
}
|
|
214
|
+
return this._runHttp(command, restOptions);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Whether the optional `ws` package is importable (resolved once).
|
|
218
|
+
* @internal
|
|
219
|
+
*/
|
|
220
|
+
_wsAvailable() {
|
|
221
|
+
return (0, ws_execute_js_1.isWsAvailable)();
|
|
223
222
|
}
|
|
224
223
|
/**
|
|
225
224
|
* Execute a command via WebSocket streaming.
|
|
@@ -229,26 +228,49 @@ class Sandbox {
|
|
|
229
228
|
const { timeout = 60, env, cwd, shell = "/bin/bash", onStdout, onStderr, commandId, idleTimeout, killOnDisconnect, ttlSeconds, pty, } = options;
|
|
230
229
|
const dataplaneUrl = this.requireDataplaneUrl();
|
|
231
230
|
const clientHeaders = this._client.getDefaultHeaders();
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
231
|
+
// A client-supplied command_id makes execute idempotent: the daemon does
|
|
232
|
+
// get-or-create keyed on it, so if the tunnel closes before "started" we
|
|
233
|
+
// can re-issue the same id and reattach to the existing command instead of
|
|
234
|
+
// spawning a second one.
|
|
235
|
+
const execCommandId = commandId ?? (0, uuid_js_1.uuid7)();
|
|
236
|
+
let attempt = 0;
|
|
237
|
+
// eslint-disable-next-line no-constant-condition
|
|
238
|
+
while (true) {
|
|
239
|
+
const [stream, control] = await (0, ws_execute_js_1.runWsStream)(dataplaneUrl, this._client.getApiKey(), command, {
|
|
240
|
+
timeout,
|
|
241
|
+
env,
|
|
242
|
+
cwd,
|
|
243
|
+
shell,
|
|
244
|
+
commandId: execCommandId,
|
|
245
|
+
idleTimeout,
|
|
246
|
+
killOnDisconnect,
|
|
247
|
+
ttlSeconds,
|
|
248
|
+
pty,
|
|
249
|
+
...(Object.keys(clientHeaders).length > 0
|
|
250
|
+
? { headers: clientHeaders }
|
|
251
|
+
: {}),
|
|
252
|
+
});
|
|
253
|
+
const handle = new command_handle_js_1.CommandHandle(stream, control, this, {
|
|
254
|
+
onStdout,
|
|
255
|
+
onStderr,
|
|
256
|
+
});
|
|
257
|
+
try {
|
|
258
|
+
await handle._ensureStarted();
|
|
259
|
+
return handle;
|
|
260
|
+
}
|
|
261
|
+
catch (e) {
|
|
262
|
+
// Idempotent re-issue (same command_id) after an early close.
|
|
263
|
+
if (!(e instanceof errors_js_1.LangSmithStreamEndedBeforeStartedError)) {
|
|
264
|
+
throw e;
|
|
265
|
+
}
|
|
266
|
+
attempt++;
|
|
267
|
+
if (attempt > command_handle_js_1.CommandHandle.MAX_AUTO_RECONNECTS) {
|
|
268
|
+
throw e;
|
|
269
|
+
}
|
|
270
|
+
const delay = Math.min(command_handle_js_1.CommandHandle.BACKOFF_BASE * 2 ** (attempt - 1), command_handle_js_1.CommandHandle.BACKOFF_MAX);
|
|
271
|
+
await new Promise((r) => setTimeout(r, delay * 1000));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
252
274
|
}
|
|
253
275
|
/**
|
|
254
276
|
* Execute a command via HTTP POST (blocking).
|
|
@@ -78,7 +78,8 @@ export declare class Sandbox {
|
|
|
78
78
|
* Execute a command in the sandbox.
|
|
79
79
|
*
|
|
80
80
|
* When `wait` is true (default) and no streaming callbacks are provided,
|
|
81
|
-
*
|
|
81
|
+
* uses WebSocket, falling back to HTTP POST only when the optional `ws`
|
|
82
|
+
* package isn't installed.
|
|
82
83
|
*
|
|
83
84
|
* When `wait` is false or streaming callbacks are provided, uses WebSocket
|
|
84
85
|
* (required). Returns a CommandHandle for streaming output.
|
package/dist/sandbox/sandbox.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Sandbox class for interacting with a specific sandbox instance.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { uuid7 } from "../uuid.js";
|
|
5
|
+
import { LangSmithDataplaneNotConfiguredError, LangSmithStreamEndedBeforeStartedError, } from "./errors.js";
|
|
5
6
|
import { handleSandboxHttpError } from "./helpers.js";
|
|
6
7
|
import { CommandHandle } from "./command_handle.js";
|
|
7
|
-
import { reconnectWsStream, runWsStream } from "./ws_execute.js";
|
|
8
|
+
import { isWsAvailable, reconnectWsStream, runWsStream } from "./ws_execute.js";
|
|
8
9
|
/**
|
|
9
10
|
* Represents an active sandbox for running commands and file operations.
|
|
10
11
|
*
|
|
@@ -195,8 +196,9 @@ export class Sandbox {
|
|
|
195
196
|
// wait=true with callbacks: drain stream and return result
|
|
196
197
|
return handle.result;
|
|
197
198
|
}
|
|
198
|
-
// wait=true, no callbacks:
|
|
199
|
-
|
|
199
|
+
// wait=true, no callbacks: use WebSocket when the 'ws' package is
|
|
200
|
+
// available, otherwise the blocking HTTP endpoint. WS errors propagate.
|
|
201
|
+
if (await this._wsAvailable()) {
|
|
200
202
|
const handle = await this._runWs(command, {
|
|
201
203
|
...restOptions,
|
|
202
204
|
idleTimeout,
|
|
@@ -206,17 +208,14 @@ export class Sandbox {
|
|
|
206
208
|
});
|
|
207
209
|
return await handle.result;
|
|
208
210
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
throw e;
|
|
219
|
-
}
|
|
211
|
+
return this._runHttp(command, restOptions);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Whether the optional `ws` package is importable (resolved once).
|
|
215
|
+
* @internal
|
|
216
|
+
*/
|
|
217
|
+
_wsAvailable() {
|
|
218
|
+
return isWsAvailable();
|
|
220
219
|
}
|
|
221
220
|
/**
|
|
222
221
|
* Execute a command via WebSocket streaming.
|
|
@@ -226,26 +225,49 @@ export class Sandbox {
|
|
|
226
225
|
const { timeout = 60, env, cwd, shell = "/bin/bash", onStdout, onStderr, commandId, idleTimeout, killOnDisconnect, ttlSeconds, pty, } = options;
|
|
227
226
|
const dataplaneUrl = this.requireDataplaneUrl();
|
|
228
227
|
const clientHeaders = this._client.getDefaultHeaders();
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
228
|
+
// A client-supplied command_id makes execute idempotent: the daemon does
|
|
229
|
+
// get-or-create keyed on it, so if the tunnel closes before "started" we
|
|
230
|
+
// can re-issue the same id and reattach to the existing command instead of
|
|
231
|
+
// spawning a second one.
|
|
232
|
+
const execCommandId = commandId ?? uuid7();
|
|
233
|
+
let attempt = 0;
|
|
234
|
+
// eslint-disable-next-line no-constant-condition
|
|
235
|
+
while (true) {
|
|
236
|
+
const [stream, control] = await runWsStream(dataplaneUrl, this._client.getApiKey(), command, {
|
|
237
|
+
timeout,
|
|
238
|
+
env,
|
|
239
|
+
cwd,
|
|
240
|
+
shell,
|
|
241
|
+
commandId: execCommandId,
|
|
242
|
+
idleTimeout,
|
|
243
|
+
killOnDisconnect,
|
|
244
|
+
ttlSeconds,
|
|
245
|
+
pty,
|
|
246
|
+
...(Object.keys(clientHeaders).length > 0
|
|
247
|
+
? { headers: clientHeaders }
|
|
248
|
+
: {}),
|
|
249
|
+
});
|
|
250
|
+
const handle = new CommandHandle(stream, control, this, {
|
|
251
|
+
onStdout,
|
|
252
|
+
onStderr,
|
|
253
|
+
});
|
|
254
|
+
try {
|
|
255
|
+
await handle._ensureStarted();
|
|
256
|
+
return handle;
|
|
257
|
+
}
|
|
258
|
+
catch (e) {
|
|
259
|
+
// Idempotent re-issue (same command_id) after an early close.
|
|
260
|
+
if (!(e instanceof LangSmithStreamEndedBeforeStartedError)) {
|
|
261
|
+
throw e;
|
|
262
|
+
}
|
|
263
|
+
attempt++;
|
|
264
|
+
if (attempt > CommandHandle.MAX_AUTO_RECONNECTS) {
|
|
265
|
+
throw e;
|
|
266
|
+
}
|
|
267
|
+
const delay = Math.min(CommandHandle.BACKOFF_BASE * 2 ** (attempt - 1), CommandHandle.BACKOFF_MAX);
|
|
268
|
+
await new Promise((r) => setTimeout(r, delay * 1000));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
249
271
|
}
|
|
250
272
|
/**
|
|
251
273
|
* Execute a command via HTTP POST (blocking).
|
|
@@ -7,21 +7,28 @@
|
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.WSStreamControl = void 0;
|
|
10
|
+
exports.isWsAvailable = isWsAvailable;
|
|
10
11
|
exports.buildWsUrl = buildWsUrl;
|
|
11
12
|
exports.buildAuthHeaders = buildAuthHeaders;
|
|
12
13
|
exports.raiseForWsError = raiseForWsError;
|
|
13
14
|
exports.runWsStream = runWsStream;
|
|
14
15
|
exports.reconnectWsStream = reconnectWsStream;
|
|
15
16
|
const errors_js_1 = require("./errors.cjs");
|
|
17
|
+
// Load the optional 'ws' package once, at module load, instead of importing on
|
|
18
|
+
// every call. Resolves to the WebSocket constructor, or null if 'ws' isn't
|
|
19
|
+
// installed. run() reads isWsAvailable() to choose WS vs the HTTP fallback.
|
|
20
|
+
const wsWebSocketPromise = import("ws").then((ws) => ws.default || ws.WebSocket || ws, () => null);
|
|
21
|
+
/** Whether the optional `ws` package could be loaded (resolved once). */
|
|
22
|
+
async function isWsAvailable() {
|
|
23
|
+
return (await wsWebSocketPromise) !== null;
|
|
24
|
+
}
|
|
16
25
|
async function ensureWs() {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return { WebSocket: ws.default || ws.WebSocket || ws };
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
26
|
+
const WebSocket = await wsWebSocketPromise;
|
|
27
|
+
if (!WebSocket) {
|
|
22
28
|
throw new Error("WebSocket-based execution requires the 'ws' package. " +
|
|
23
29
|
"Install it with: npm install ws");
|
|
24
30
|
}
|
|
31
|
+
return { WebSocket };
|
|
25
32
|
}
|
|
26
33
|
// =============================================================================
|
|
27
34
|
// URL and Auth Helpers
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { WsMessage, WsRunOptions } from "./types.js";
|
|
8
8
|
type WsWebSocket = any;
|
|
9
|
+
/** Whether the optional `ws` package could be loaded (resolved once). */
|
|
10
|
+
export declare function isWsAvailable(): Promise<boolean>;
|
|
9
11
|
/**
|
|
10
12
|
* Convert a dataplane HTTP URL to a WebSocket URL for /execute/ws.
|
|
11
13
|
*/
|
|
@@ -5,15 +5,21 @@
|
|
|
5
5
|
* Install with: npm install ws
|
|
6
6
|
*/
|
|
7
7
|
import { LangSmithCommandTimeoutError, LangSmithSandboxConnectionError, LangSmithSandboxOperationError, LangSmithSandboxServerReloadError, } from "./errors.js";
|
|
8
|
+
// Load the optional 'ws' package once, at module load, instead of importing on
|
|
9
|
+
// every call. Resolves to the WebSocket constructor, or null if 'ws' isn't
|
|
10
|
+
// installed. run() reads isWsAvailable() to choose WS vs the HTTP fallback.
|
|
11
|
+
const wsWebSocketPromise = import("ws").then((ws) => ws.default || ws.WebSocket || ws, () => null);
|
|
12
|
+
/** Whether the optional `ws` package could be loaded (resolved once). */
|
|
13
|
+
export async function isWsAvailable() {
|
|
14
|
+
return (await wsWebSocketPromise) !== null;
|
|
15
|
+
}
|
|
8
16
|
async function ensureWs() {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return { WebSocket: ws.default || ws.WebSocket || ws };
|
|
12
|
-
}
|
|
13
|
-
catch {
|
|
17
|
+
const WebSocket = await wsWebSocketPromise;
|
|
18
|
+
if (!WebSocket) {
|
|
14
19
|
throw new Error("WebSocket-based execution requires the 'ws' package. " +
|
|
15
20
|
"Install it with: npm install ws");
|
|
16
21
|
}
|
|
22
|
+
return { WebSocket };
|
|
17
23
|
}
|
|
18
24
|
// =============================================================================
|
|
19
25
|
// URL and Auth Helpers
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.evaluatorLogFeedbackPromises = exports.testWrapperAsyncLocalStorageInstance = exports.DEFAULT_TEST_CLIENT = void 0;
|
|
4
4
|
exports.trackingEnabled = trackingEnabled;
|
|
5
5
|
exports._logTestFeedback = _logTestFeedback;
|
|
6
6
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
@@ -19,7 +19,6 @@ function trackingEnabled(context) {
|
|
|
19
19
|
return (0, env_js_2.isEnvTracingEnabled)();
|
|
20
20
|
}
|
|
21
21
|
exports.evaluatorLogFeedbackPromises = new Set();
|
|
22
|
-
exports.syncExamplePromises = new Map();
|
|
23
22
|
function _logTestFeedback(params) {
|
|
24
23
|
const { exampleId, feedback, context, runTree, client, sourceRunId } = params;
|
|
25
24
|
if (trackingEnabled(context)) {
|
|
@@ -33,7 +32,7 @@ function _logTestFeedback(params) {
|
|
|
33
32
|
if (context.project == null) {
|
|
34
33
|
throw new Error("Could not log feedback to LangSmith: missing project information. Please contact us for help.");
|
|
35
34
|
}
|
|
36
|
-
await
|
|
35
|
+
await context.syncExamplePromises?.get(exampleId);
|
|
37
36
|
await client?.logEvaluationFeedback({
|
|
38
37
|
evaluatorResponse: feedback,
|
|
39
38
|
run: runTree,
|
|
@@ -20,11 +20,11 @@ export type TestWrapperAsyncLocalStorageData = {
|
|
|
20
20
|
suiteName: string;
|
|
21
21
|
testRootRunTree?: RunTree;
|
|
22
22
|
setupPromise?: Promise<void>;
|
|
23
|
+
syncExamplePromises?: Map<string, Promise<Example>>;
|
|
23
24
|
};
|
|
24
25
|
export declare const testWrapperAsyncLocalStorageInstance: AsyncLocalStorage<TestWrapperAsyncLocalStorageData>;
|
|
25
26
|
export declare function trackingEnabled(context: TestWrapperAsyncLocalStorageData): boolean;
|
|
26
27
|
export declare const evaluatorLogFeedbackPromises: Set<unknown>;
|
|
27
|
-
export declare const syncExamplePromises: Map<any, any>;
|
|
28
28
|
export declare function _logTestFeedback(params: {
|
|
29
29
|
exampleId?: string;
|
|
30
30
|
feedback: SimpleEvaluationResult;
|
|
@@ -14,7 +14,6 @@ export function trackingEnabled(context) {
|
|
|
14
14
|
return isEnvTracingEnabled();
|
|
15
15
|
}
|
|
16
16
|
export const evaluatorLogFeedbackPromises = new Set();
|
|
17
|
-
export const syncExamplePromises = new Map();
|
|
18
17
|
export function _logTestFeedback(params) {
|
|
19
18
|
const { exampleId, feedback, context, runTree, client, sourceRunId } = params;
|
|
20
19
|
if (trackingEnabled(context)) {
|
|
@@ -28,7 +27,7 @@ export function _logTestFeedback(params) {
|
|
|
28
27
|
if (context.project == null) {
|
|
29
28
|
throw new Error("Could not log feedback to LangSmith: missing project information. Please contact us for help.");
|
|
30
29
|
}
|
|
31
|
-
await syncExamplePromises
|
|
30
|
+
await context.syncExamplePromises?.get(exampleId);
|
|
32
31
|
await client?.logEvaluationFeedback({
|
|
33
32
|
evaluatorResponse: feedback,
|
|
34
33
|
run: runTree,
|
|
@@ -300,6 +300,7 @@ function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
|
|
|
300
300
|
},
|
|
301
301
|
enableTestTracking: experimentConfig?.enableTestTracking,
|
|
302
302
|
setupPromise,
|
|
303
|
+
syncExamplePromises: new Map(),
|
|
303
304
|
};
|
|
304
305
|
beforeAll(async () => {
|
|
305
306
|
const storageValue = await runDatasetSetup(context);
|
|
@@ -307,15 +308,14 @@ function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
|
|
|
307
308
|
setupPromiseResolver();
|
|
308
309
|
});
|
|
309
310
|
afterAll(async () => {
|
|
311
|
+
const examples = await Promise.all(context.syncExamplePromises.values());
|
|
310
312
|
await Promise.all([
|
|
311
313
|
client.awaitPendingTraceBatches(),
|
|
312
|
-
...globals_js_1.syncExamplePromises.values(),
|
|
313
314
|
...globals_js_1.evaluatorLogFeedbackPromises.values(),
|
|
314
315
|
]);
|
|
315
316
|
if (!(0, globals_js_1.trackingEnabled)(context)) {
|
|
316
317
|
return;
|
|
317
318
|
}
|
|
318
|
-
const examples = [...globals_js_1.syncExamplePromises.values()];
|
|
319
319
|
if (examples.length === 0) {
|
|
320
320
|
return;
|
|
321
321
|
}
|
|
@@ -364,6 +364,7 @@ function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
|
|
|
364
364
|
await client.updateProject(datasetInfo.project.id, {
|
|
365
365
|
metadata: {
|
|
366
366
|
...suiteMetadata,
|
|
367
|
+
dataset_version: finalModifiedAt,
|
|
367
368
|
commit,
|
|
368
369
|
branch,
|
|
369
370
|
dirty,
|
|
@@ -546,8 +547,11 @@ function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
|
|
|
546
547
|
// Currently run end time has to be after example modified time
|
|
547
548
|
// for examples to render properly, so we must modify the example
|
|
548
549
|
// first before running the test.
|
|
549
|
-
if (
|
|
550
|
-
|
|
550
|
+
if (context.syncExamplePromises === undefined) {
|
|
551
|
+
throw new Error("Internal error: syncExamplePromises not initialized. This is a bug in the LangSmith SDK — please open an issue at https://github.com/langchain-ai/langsmith-sdk/issues.");
|
|
552
|
+
}
|
|
553
|
+
if (!context.syncExamplePromises.has(exampleId)) {
|
|
554
|
+
const syncPromise = syncExample({
|
|
551
555
|
client,
|
|
552
556
|
exampleId,
|
|
553
557
|
datasetId: dataset.id,
|
|
@@ -556,8 +560,10 @@ function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
|
|
|
556
560
|
metadata,
|
|
557
561
|
split,
|
|
558
562
|
createdAt,
|
|
559
|
-
})
|
|
563
|
+
});
|
|
564
|
+
context.syncExamplePromises.set(exampleId, syncPromise);
|
|
560
565
|
}
|
|
566
|
+
await context.syncExamplePromises.get(exampleId);
|
|
561
567
|
const traceableOptions = {
|
|
562
568
|
reference_example_id: exampleId,
|
|
563
569
|
project_name: project.name,
|
|
@@ -9,7 +9,7 @@ import { execSync } from "child_process";
|
|
|
9
9
|
import { getCurrentRunTree, traceable } from "../../traceable.js";
|
|
10
10
|
import { randomName } from "../../evaluation/_random_name.js";
|
|
11
11
|
import { toBeRelativeCloseTo, toBeAbsoluteCloseTo, toBeSemanticCloseTo, } from "./matchers.js";
|
|
12
|
-
import { evaluatorLogFeedbackPromises, testWrapperAsyncLocalStorageInstance, _logTestFeedback,
|
|
12
|
+
import { evaluatorLogFeedbackPromises, testWrapperAsyncLocalStorageInstance, _logTestFeedback, trackingEnabled, DEFAULT_TEST_CLIENT, } from "./globals.js";
|
|
13
13
|
import { wrapExpect } from "./vendor/chain.js";
|
|
14
14
|
import { getEnvironmentVariable, isJsDom } from "../env.js";
|
|
15
15
|
import { STRIP_ANSI_REGEX, TEST_ID_DELIMITER, UUID5_NAMESPACE, } from "./constants.js";
|
|
@@ -253,6 +253,7 @@ export function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
|
|
|
253
253
|
},
|
|
254
254
|
enableTestTracking: experimentConfig?.enableTestTracking,
|
|
255
255
|
setupPromise,
|
|
256
|
+
syncExamplePromises: new Map(),
|
|
256
257
|
};
|
|
257
258
|
beforeAll(async () => {
|
|
258
259
|
const storageValue = await runDatasetSetup(context);
|
|
@@ -260,15 +261,14 @@ export function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
|
|
|
260
261
|
setupPromiseResolver();
|
|
261
262
|
});
|
|
262
263
|
afterAll(async () => {
|
|
264
|
+
const examples = await Promise.all(context.syncExamplePromises.values());
|
|
263
265
|
await Promise.all([
|
|
264
266
|
client.awaitPendingTraceBatches(),
|
|
265
|
-
...syncExamplePromises.values(),
|
|
266
267
|
...evaluatorLogFeedbackPromises.values(),
|
|
267
268
|
]);
|
|
268
269
|
if (!trackingEnabled(context)) {
|
|
269
270
|
return;
|
|
270
271
|
}
|
|
271
|
-
const examples = [...syncExamplePromises.values()];
|
|
272
272
|
if (examples.length === 0) {
|
|
273
273
|
return;
|
|
274
274
|
}
|
|
@@ -317,6 +317,7 @@ export function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
|
|
|
317
317
|
await client.updateProject(datasetInfo.project.id, {
|
|
318
318
|
metadata: {
|
|
319
319
|
...suiteMetadata,
|
|
320
|
+
dataset_version: finalModifiedAt,
|
|
320
321
|
commit,
|
|
321
322
|
branch,
|
|
322
323
|
dirty,
|
|
@@ -499,8 +500,11 @@ export function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
|
|
|
499
500
|
// Currently run end time has to be after example modified time
|
|
500
501
|
// for examples to render properly, so we must modify the example
|
|
501
502
|
// first before running the test.
|
|
502
|
-
if (syncExamplePromises
|
|
503
|
-
syncExamplePromises.
|
|
503
|
+
if (context.syncExamplePromises === undefined) {
|
|
504
|
+
throw new Error("Internal error: syncExamplePromises not initialized. This is a bug in the LangSmith SDK — please open an issue at https://github.com/langchain-ai/langsmith-sdk/issues.");
|
|
505
|
+
}
|
|
506
|
+
if (!context.syncExamplePromises.has(exampleId)) {
|
|
507
|
+
const syncPromise = syncExample({
|
|
504
508
|
client,
|
|
505
509
|
exampleId,
|
|
506
510
|
datasetId: dataset.id,
|
|
@@ -509,8 +513,10 @@ export function generateWrapperFromJestlikeMethods(methods, testRunnerName) {
|
|
|
509
513
|
metadata,
|
|
510
514
|
split,
|
|
511
515
|
createdAt,
|
|
512
|
-
})
|
|
516
|
+
});
|
|
517
|
+
context.syncExamplePromises.set(exampleId, syncPromise);
|
|
513
518
|
}
|
|
519
|
+
await context.syncExamplePromises.get(exampleId);
|
|
514
520
|
const traceableOptions = {
|
|
515
521
|
reference_example_id: exampleId,
|
|
516
522
|
project_name: project.name,
|