langsmith 0.8.7 → 0.8.9
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/_openapi_client/client.cjs +8 -0
- package/dist/_openapi_client/client.d.ts +3 -0
- package/dist/_openapi_client/client.js +8 -0
- package/dist/_openapi_client/resources/annotation-queues/annotation-queues.cjs +157 -0
- package/dist/_openapi_client/resources/annotation-queues/annotation-queues.d.ts +382 -0
- package/dist/_openapi_client/resources/annotation-queues/annotation-queues.js +120 -0
- package/dist/_openapi_client/resources/annotation-queues/items.cjs +84 -0
- package/dist/_openapi_client/resources/annotation-queues/items.d.ts +207 -0
- package/dist/_openapi_client/resources/annotation-queues/items.js +80 -0
- package/dist/_openapi_client/resources/annotation-queues/runs.cjs +73 -0
- package/dist/_openapi_client/resources/annotation-queues/runs.d.ts +197 -0
- package/dist/_openapi_client/resources/annotation-queues/runs.js +69 -0
- package/dist/_openapi_client/resources/datasets/experiment-runs.cjs +3 -1
- package/dist/_openapi_client/resources/datasets/experiment-runs.d.ts +2 -0
- package/dist/_openapi_client/resources/datasets/experiment-runs.js +3 -1
- package/dist/_openapi_client/resources/index.cjs +3 -1
- package/dist/_openapi_client/resources/index.d.ts +1 -0
- package/dist/_openapi_client/resources/index.js +1 -0
- package/dist/_openapi_client/resources/info.cjs +3 -1
- package/dist/_openapi_client/resources/info.d.ts +16 -22
- package/dist/_openapi_client/resources/info.js +3 -1
- package/dist/_openapi_client/resources/issues.cjs +2 -2
- package/dist/_openapi_client/resources/issues.d.ts +1 -1
- package/dist/_openapi_client/resources/issues.js +2 -2
- package/dist/_openapi_client/resources/online-evaluators.cjs +7 -7
- package/dist/_openapi_client/resources/online-evaluators.d.ts +8 -0
- package/dist/_openapi_client/resources/online-evaluators.js +7 -7
- package/dist/_openapi_client/resources/public/runs.cjs +10 -8
- package/dist/_openapi_client/resources/public/runs.d.ts +9 -7
- package/dist/_openapi_client/resources/public/runs.js +10 -8
- package/dist/_openapi_client/resources/runs/runs.cjs +14 -9
- package/dist/_openapi_client/resources/runs/runs.d.ts +20 -10
- package/dist/_openapi_client/resources/runs/runs.js +14 -9
- package/dist/_openapi_client/resources/runs/share.cjs +6 -2
- package/dist/_openapi_client/resources/runs/share.d.ts +4 -0
- package/dist/_openapi_client/resources/runs/share.js +6 -2
- package/dist/_openapi_client/resources/sandboxes/boxes.cjs +10 -10
- package/dist/_openapi_client/resources/sandboxes/boxes.d.ts +40 -0
- package/dist/_openapi_client/resources/sandboxes/boxes.js +10 -10
- package/dist/_openapi_client/resources/sandboxes/registries.cjs +5 -5
- package/dist/_openapi_client/resources/sandboxes/registries.js +5 -5
- package/dist/_openapi_client/resources/sandboxes/sandboxes.d.ts +17 -0
- package/dist/_openapi_client/resources/sandboxes/snapshots.cjs +4 -4
- package/dist/_openapi_client/resources/sandboxes/snapshots.d.ts +12 -0
- package/dist/_openapi_client/resources/sandboxes/snapshots.js +4 -4
- package/dist/_openapi_client/resources/threads.cjs +14 -11
- package/dist/_openapi_client/resources/threads.d.ts +13 -9
- package/dist/_openapi_client/resources/threads.js +14 -11
- package/dist/_openapi_client/resources/traces.cjs +8 -5
- package/dist/_openapi_client/resources/traces.d.ts +7 -4
- package/dist/_openapi_client/resources/traces.js +8 -5
- package/dist/client.cjs +318 -40
- package/dist/client.d.ts +111 -25
- package/dist/client.js +318 -40
- package/dist/evaluation/evaluate_comparative.cjs +7 -4
- package/dist/evaluation/evaluate_comparative.js +7 -4
- 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 +38 -11
- package/dist/sandbox/command_handle.d.ts +1 -0
- package/dist/sandbox/command_handle.js +39 -12
- 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/index.cjs +2 -1
- package/dist/sandbox/index.d.ts +1 -1
- package/dist/sandbox/index.js +1 -1
- package/dist/sandbox/sandbox.cjs +22 -4
- package/dist/sandbox/sandbox.js +24 -6
- package/dist/sandbox/ws_execute.cjs +82 -11
- package/dist/sandbox/ws_execute.d.ts +12 -2
- package/dist/sandbox/ws_execute.js +79 -11
- package/dist/utils/v2_migration.cjs +18 -0
- package/dist/utils/v2_migration.d.ts +8 -0
- package/dist/utils/v2_migration.js +16 -0
- package/dist/utils/warn.cjs +30 -4
- package/dist/utils/warn.d.ts +4 -1
- package/dist/utils/warn.js +29 -4
- package/package.json +1 -1
- package/dist/utils/constants.cjs +0 -4
- package/dist/utils/constants.d.ts +0 -1
- package/dist/utils/constants.js +0 -1
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.9";
|
|
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.9";
|
|
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.9";
|
|
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";
|
|
@@ -8,6 +8,22 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.CommandHandle = void 0;
|
|
10
10
|
const errors_js_1 = require("./errors.cjs");
|
|
11
|
+
/**
|
|
12
|
+
* Whether a 'started' frame proves *this* command was reattached to.
|
|
13
|
+
*
|
|
14
|
+
* A command and its WebSocket are separate things: the command keeps running on
|
|
15
|
+
* the server and the socket is only this client's attachment to it. The server
|
|
16
|
+
* acknowledges every successful reattachment with 'started', which for a command
|
|
17
|
+
* that produces no output is the only evidence it landed. One naming a different
|
|
18
|
+
* command is not evidence, and must not clear the reconnect budget.
|
|
19
|
+
*/
|
|
20
|
+
function acknowledgesReconnect(msg, commandId) {
|
|
21
|
+
const acked = msg.command_id;
|
|
22
|
+
if (acked === commandId)
|
|
23
|
+
return true;
|
|
24
|
+
console.warn(`Ignoring reconnect acknowledgement for command ${String(acked)} while attached to ${String(commandId)}`);
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
11
27
|
/**
|
|
12
28
|
* Async handle to a running command with streaming output and auto-reconnect.
|
|
13
29
|
*
|
|
@@ -107,6 +123,12 @@ class CommandHandle {
|
|
|
107
123
|
writable: true,
|
|
108
124
|
value: void 0
|
|
109
125
|
});
|
|
126
|
+
Object.defineProperty(this, "_reconnectAttempts", {
|
|
127
|
+
enumerable: true,
|
|
128
|
+
configurable: true,
|
|
129
|
+
writable: true,
|
|
130
|
+
value: 0
|
|
131
|
+
});
|
|
110
132
|
Object.defineProperty(this, "_onStdout", {
|
|
111
133
|
enumerable: true,
|
|
112
134
|
configurable: true,
|
|
@@ -192,7 +214,12 @@ class CommandHandle {
|
|
|
192
214
|
return;
|
|
193
215
|
for await (const msg of this._stream) {
|
|
194
216
|
const msgType = msg.type;
|
|
195
|
-
if (msgType === "
|
|
217
|
+
if (msgType === "started") {
|
|
218
|
+
if (acknowledgesReconnect(msg, this._commandId)) {
|
|
219
|
+
this._reconnectAttempts = 0;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else if (msgType === "stdout" || msgType === "stderr") {
|
|
196
223
|
const chunk = {
|
|
197
224
|
stream: msgType,
|
|
198
225
|
data: msg.data,
|
|
@@ -227,11 +254,11 @@ class CommandHandle {
|
|
|
227
254
|
* - After kill(): no reconnect, error propagates
|
|
228
255
|
*/
|
|
229
256
|
async *[Symbol.asyncIterator]() {
|
|
230
|
-
|
|
257
|
+
this._reconnectAttempts = 0;
|
|
231
258
|
while (true) {
|
|
232
259
|
try {
|
|
233
260
|
for await (const chunk of this._iterStream()) {
|
|
234
|
-
|
|
261
|
+
this._reconnectAttempts = 0; // Reset on successful data
|
|
235
262
|
if (chunk.stream === "stdout") {
|
|
236
263
|
this._lastStdoutOffset =
|
|
237
264
|
chunk.offset + new TextEncoder().encode(chunk.data).length;
|
|
@@ -247,21 +274,21 @@ class CommandHandle {
|
|
|
247
274
|
return; // Stream ended normally (exit message received)
|
|
248
275
|
}
|
|
249
276
|
catch (e) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
277
|
+
// instanceof, not a name check: subclasses (connect timeout, server
|
|
278
|
+
// reload) must stay retryable here.
|
|
279
|
+
if (!(e instanceof errors_js_1.LangSmithSandboxConnectionError)) {
|
|
253
280
|
throw e;
|
|
254
281
|
}
|
|
255
282
|
if (this._control && this._control.killed) {
|
|
256
283
|
throw e;
|
|
257
284
|
}
|
|
258
|
-
|
|
259
|
-
if (
|
|
260
|
-
throw new errors_js_1.LangSmithSandboxConnectionError(`
|
|
285
|
+
this._reconnectAttempts++;
|
|
286
|
+
if (this._reconnectAttempts > CommandHandle.MAX_AUTO_RECONNECTS) {
|
|
287
|
+
throw new errors_js_1.LangSmithSandboxConnectionError(`Failed to reattach to the command ${this._reconnectAttempts} times in succession, giving up`);
|
|
261
288
|
}
|
|
262
|
-
const isHotReload =
|
|
289
|
+
const isHotReload = e instanceof errors_js_1.LangSmithSandboxServerReloadError;
|
|
263
290
|
if (!isHotReload) {
|
|
264
|
-
const delay = Math.min(CommandHandle.BACKOFF_BASE * 2 ** (
|
|
291
|
+
const delay = Math.min(CommandHandle.BACKOFF_BASE * 2 ** (this._reconnectAttempts - 1), CommandHandle.BACKOFF_MAX);
|
|
265
292
|
await new Promise((r) => setTimeout(r, delay * 1000));
|
|
266
293
|
}
|
|
267
294
|
if (this._commandId === null) {
|
|
@@ -4,7 +4,23 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Port of Python's AsyncCommandHandle to TypeScript.
|
|
6
6
|
*/
|
|
7
|
-
import { LangSmithSandboxConnectionError, LangSmithSandboxOperationError, LangSmithStreamEndedBeforeStartedError, } from "./errors.js";
|
|
7
|
+
import { LangSmithSandboxConnectionError, LangSmithSandboxServerReloadError, LangSmithSandboxOperationError, LangSmithStreamEndedBeforeStartedError, } from "./errors.js";
|
|
8
|
+
/**
|
|
9
|
+
* Whether a 'started' frame proves *this* command was reattached to.
|
|
10
|
+
*
|
|
11
|
+
* A command and its WebSocket are separate things: the command keeps running on
|
|
12
|
+
* the server and the socket is only this client's attachment to it. The server
|
|
13
|
+
* acknowledges every successful reattachment with 'started', which for a command
|
|
14
|
+
* that produces no output is the only evidence it landed. One naming a different
|
|
15
|
+
* command is not evidence, and must not clear the reconnect budget.
|
|
16
|
+
*/
|
|
17
|
+
function acknowledgesReconnect(msg, commandId) {
|
|
18
|
+
const acked = msg.command_id;
|
|
19
|
+
if (acked === commandId)
|
|
20
|
+
return true;
|
|
21
|
+
console.warn(`Ignoring reconnect acknowledgement for command ${String(acked)} while attached to ${String(commandId)}`);
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
8
24
|
/**
|
|
9
25
|
* Async handle to a running command with streaming output and auto-reconnect.
|
|
10
26
|
*
|
|
@@ -104,6 +120,12 @@ export class CommandHandle {
|
|
|
104
120
|
writable: true,
|
|
105
121
|
value: void 0
|
|
106
122
|
});
|
|
123
|
+
Object.defineProperty(this, "_reconnectAttempts", {
|
|
124
|
+
enumerable: true,
|
|
125
|
+
configurable: true,
|
|
126
|
+
writable: true,
|
|
127
|
+
value: 0
|
|
128
|
+
});
|
|
107
129
|
Object.defineProperty(this, "_onStdout", {
|
|
108
130
|
enumerable: true,
|
|
109
131
|
configurable: true,
|
|
@@ -189,7 +211,12 @@ export class CommandHandle {
|
|
|
189
211
|
return;
|
|
190
212
|
for await (const msg of this._stream) {
|
|
191
213
|
const msgType = msg.type;
|
|
192
|
-
if (msgType === "
|
|
214
|
+
if (msgType === "started") {
|
|
215
|
+
if (acknowledgesReconnect(msg, this._commandId)) {
|
|
216
|
+
this._reconnectAttempts = 0;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else if (msgType === "stdout" || msgType === "stderr") {
|
|
193
220
|
const chunk = {
|
|
194
221
|
stream: msgType,
|
|
195
222
|
data: msg.data,
|
|
@@ -224,11 +251,11 @@ export class CommandHandle {
|
|
|
224
251
|
* - After kill(): no reconnect, error propagates
|
|
225
252
|
*/
|
|
226
253
|
async *[Symbol.asyncIterator]() {
|
|
227
|
-
|
|
254
|
+
this._reconnectAttempts = 0;
|
|
228
255
|
while (true) {
|
|
229
256
|
try {
|
|
230
257
|
for await (const chunk of this._iterStream()) {
|
|
231
|
-
|
|
258
|
+
this._reconnectAttempts = 0; // Reset on successful data
|
|
232
259
|
if (chunk.stream === "stdout") {
|
|
233
260
|
this._lastStdoutOffset =
|
|
234
261
|
chunk.offset + new TextEncoder().encode(chunk.data).length;
|
|
@@ -244,21 +271,21 @@ export class CommandHandle {
|
|
|
244
271
|
return; // Stream ended normally (exit message received)
|
|
245
272
|
}
|
|
246
273
|
catch (e) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
274
|
+
// instanceof, not a name check: subclasses (connect timeout, server
|
|
275
|
+
// reload) must stay retryable here.
|
|
276
|
+
if (!(e instanceof LangSmithSandboxConnectionError)) {
|
|
250
277
|
throw e;
|
|
251
278
|
}
|
|
252
279
|
if (this._control && this._control.killed) {
|
|
253
280
|
throw e;
|
|
254
281
|
}
|
|
255
|
-
|
|
256
|
-
if (
|
|
257
|
-
throw new LangSmithSandboxConnectionError(`
|
|
282
|
+
this._reconnectAttempts++;
|
|
283
|
+
if (this._reconnectAttempts > CommandHandle.MAX_AUTO_RECONNECTS) {
|
|
284
|
+
throw new LangSmithSandboxConnectionError(`Failed to reattach to the command ${this._reconnectAttempts} times in succession, giving up`);
|
|
258
285
|
}
|
|
259
|
-
const isHotReload =
|
|
286
|
+
const isHotReload = e instanceof LangSmithSandboxServerReloadError;
|
|
260
287
|
if (!isHotReload) {
|
|
261
|
-
const delay = Math.min(CommandHandle.BACKOFF_BASE * 2 ** (
|
|
288
|
+
const delay = Math.min(CommandHandle.BACKOFF_BASE * 2 ** (this._reconnectAttempts - 1), CommandHandle.BACKOFF_MAX);
|
|
262
289
|
await new Promise((r) => setTimeout(r, delay * 1000));
|
|
263
290
|
}
|
|
264
291
|
if (this._commandId === null) {
|
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.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;
|
|
10
|
+
exports.LangSmithSandboxServerReloadError = exports.LangSmithSandboxConnectTimeoutError = 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
|
*/
|
|
@@ -372,6 +372,21 @@ class LangSmithStreamEndedBeforeStartedError extends LangSmithSandboxOperationEr
|
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
374
|
exports.LangSmithStreamEndedBeforeStartedError = LangSmithStreamEndedBeforeStartedError;
|
|
375
|
+
/**
|
|
376
|
+
* Thrown when the socket fails or times out before the WebSocket handshake.
|
|
377
|
+
*
|
|
378
|
+
* Distinct from its parent because it is safely retryable: the execute frame
|
|
379
|
+
* was never sent, so re-issuing the same command_id cannot double-run a
|
|
380
|
+
* command. run() retries this with backoff; a plain connection error (a
|
|
381
|
+
* rejected handshake) is permanent and propagates immediately.
|
|
382
|
+
*/
|
|
383
|
+
class LangSmithSandboxConnectTimeoutError extends LangSmithSandboxConnectionError {
|
|
384
|
+
constructor(message) {
|
|
385
|
+
super(message);
|
|
386
|
+
this.name = "LangSmithSandboxConnectTimeoutError";
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
exports.LangSmithSandboxConnectTimeoutError = LangSmithSandboxConnectTimeoutError;
|
|
375
390
|
/**
|
|
376
391
|
* Raised when the sandbox server is reloading (close code 1001).
|
|
377
392
|
*
|
package/dist/sandbox/errors.d.ts
CHANGED
|
@@ -165,6 +165,17 @@ export declare class LangSmithCommandTimeoutError extends LangSmithSandboxOperat
|
|
|
165
165
|
export declare class LangSmithStreamEndedBeforeStartedError extends LangSmithSandboxOperationError {
|
|
166
166
|
constructor(message: string);
|
|
167
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Thrown when the socket fails or times out before the WebSocket handshake.
|
|
170
|
+
*
|
|
171
|
+
* Distinct from its parent because it is safely retryable: the execute frame
|
|
172
|
+
* was never sent, so re-issuing the same command_id cannot double-run a
|
|
173
|
+
* command. run() retries this with backoff; a plain connection error (a
|
|
174
|
+
* rejected handshake) is permanent and propagates immediately.
|
|
175
|
+
*/
|
|
176
|
+
export declare class LangSmithSandboxConnectTimeoutError extends LangSmithSandboxConnectionError {
|
|
177
|
+
constructor(message: string);
|
|
178
|
+
}
|
|
168
179
|
/**
|
|
169
180
|
* Raised when the sandbox server is reloading (close code 1001).
|
|
170
181
|
*
|
package/dist/sandbox/errors.js
CHANGED
|
@@ -351,6 +351,20 @@ export class LangSmithStreamEndedBeforeStartedError extends LangSmithSandboxOper
|
|
|
351
351
|
this.name = "LangSmithStreamEndedBeforeStartedError";
|
|
352
352
|
}
|
|
353
353
|
}
|
|
354
|
+
/**
|
|
355
|
+
* Thrown when the socket fails or times out before the WebSocket handshake.
|
|
356
|
+
*
|
|
357
|
+
* Distinct from its parent because it is safely retryable: the execute frame
|
|
358
|
+
* was never sent, so re-issuing the same command_id cannot double-run a
|
|
359
|
+
* command. run() retries this with backoff; a plain connection error (a
|
|
360
|
+
* rejected handshake) is permanent and propagates immediately.
|
|
361
|
+
*/
|
|
362
|
+
export class LangSmithSandboxConnectTimeoutError extends LangSmithSandboxConnectionError {
|
|
363
|
+
constructor(message) {
|
|
364
|
+
super(message);
|
|
365
|
+
this.name = "LangSmithSandboxConnectTimeoutError";
|
|
366
|
+
}
|
|
367
|
+
}
|
|
354
368
|
/**
|
|
355
369
|
* Raised when the sandbox server is reloading (close code 1001).
|
|
356
370
|
*
|
package/dist/sandbox/index.cjs
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* @packageDocumentation
|
|
30
30
|
*/
|
|
31
31
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
-
exports.LangSmithDataplaneNotConfiguredError = exports.LangSmithCommandTimeoutError = exports.LangSmithSandboxOperationError = exports.LangSmithSandboxNotReadyError = exports.LangSmithSandboxCreationError = exports.LangSmithResourceCreationError = exports.LangSmithQuotaExceededError = exports.LangSmithValidationError = exports.LangSmithResourceNameConflictError = exports.LangSmithResourceAlreadyExistsError = exports.LangSmithResourceInUseError = exports.LangSmithResourceTimeoutError = exports.LangSmithResourceNotFoundError = exports.LangSmithSandboxServerReloadError = exports.LangSmithSandboxConnectionError = exports.LangSmithSandboxAuthenticationError = exports.LangSmithSandboxAPIError = exports.LangSmithSandboxError = exports.s3Mount = exports.mountConfig = exports.gitMount = exports.gcsMount = exports.workspaceSecret = exports.proxyConfig = exports.opaqueSecret = exports.gcpAuth = exports.awsAuth = exports.CommandHandle = exports.Sandbox = exports.SandboxClient = void 0;
|
|
32
|
+
exports.LangSmithDataplaneNotConfiguredError = exports.LangSmithCommandTimeoutError = exports.LangSmithSandboxOperationError = exports.LangSmithSandboxNotReadyError = exports.LangSmithSandboxCreationError = exports.LangSmithResourceCreationError = exports.LangSmithQuotaExceededError = exports.LangSmithValidationError = exports.LangSmithResourceNameConflictError = exports.LangSmithResourceAlreadyExistsError = exports.LangSmithResourceInUseError = exports.LangSmithResourceTimeoutError = exports.LangSmithResourceNotFoundError = exports.LangSmithSandboxServerReloadError = exports.LangSmithSandboxConnectTimeoutError = exports.LangSmithSandboxConnectionError = exports.LangSmithSandboxAuthenticationError = exports.LangSmithSandboxAPIError = exports.LangSmithSandboxError = exports.s3Mount = exports.mountConfig = exports.gitMount = exports.gcsMount = exports.workspaceSecret = exports.proxyConfig = exports.opaqueSecret = exports.gcpAuth = exports.awsAuth = exports.CommandHandle = exports.Sandbox = exports.SandboxClient = void 0;
|
|
33
33
|
// Main classes
|
|
34
34
|
var client_js_1 = require("./client.cjs");
|
|
35
35
|
Object.defineProperty(exports, "SandboxClient", { enumerable: true, get: function () { return client_js_1.SandboxClient; } });
|
|
@@ -55,6 +55,7 @@ Object.defineProperty(exports, "LangSmithSandboxError", { enumerable: true, get:
|
|
|
55
55
|
Object.defineProperty(exports, "LangSmithSandboxAPIError", { enumerable: true, get: function () { return errors_js_1.LangSmithSandboxAPIError; } });
|
|
56
56
|
Object.defineProperty(exports, "LangSmithSandboxAuthenticationError", { enumerable: true, get: function () { return errors_js_1.LangSmithSandboxAuthenticationError; } });
|
|
57
57
|
Object.defineProperty(exports, "LangSmithSandboxConnectionError", { enumerable: true, get: function () { return errors_js_1.LangSmithSandboxConnectionError; } });
|
|
58
|
+
Object.defineProperty(exports, "LangSmithSandboxConnectTimeoutError", { enumerable: true, get: function () { return errors_js_1.LangSmithSandboxConnectTimeoutError; } });
|
|
58
59
|
Object.defineProperty(exports, "LangSmithSandboxServerReloadError", { enumerable: true, get: function () { return errors_js_1.LangSmithSandboxServerReloadError; } });
|
|
59
60
|
// Resource errors (type-based with resourceType attribute)
|
|
60
61
|
Object.defineProperty(exports, "LangSmithResourceNotFoundError", { enumerable: true, get: function () { return errors_js_1.LangSmithResourceNotFoundError; } });
|
package/dist/sandbox/index.d.ts
CHANGED
|
@@ -33,4 +33,4 @@ export { CommandHandle } from "./command_handle.js";
|
|
|
33
33
|
export { awsAuth, gcpAuth, opaqueSecret, proxyConfig, workspaceSecret, } from "./proxy_config.js";
|
|
34
34
|
export { gcsMount, gitMount, mountConfig, s3Mount } from "./mounts.js";
|
|
35
35
|
export type { ExecutionResult, OutputChunk, WsMessage, WsRunOptions, ResourceStatus, Snapshot, SandboxData, SandboxClientConfig, RunOptions, CreateSandboxOptions, SandboxAccessControl, SandboxAwsAuthRule, SandboxAwsMountAuthConfig, SandboxGcpAuthRule, SandboxGcpMountAuthConfig, SandboxMountAuth, SandboxMountAuthConfig, SandboxMountConfig, SandboxProxyConfig, SandboxProxyRule, SandboxProxySecret, SandboxMount, MountCacheConfig, GCSMountConfig, GCSMountSpec, GitMountConfig, GitMountRefSpec, GitMountSpec, S3MountConfig, S3MountSpec, CreateSnapshotOptions, CreateDockerfileSnapshotOptions, CaptureSnapshotOptions, ListSnapshotsOptions, WaitForSnapshotOptions, StartSandboxOptions, UpdateSandboxOptions, WaitForSandboxOptions, } from "./types.js";
|
|
36
|
-
export { LangSmithSandboxError, LangSmithSandboxAPIError, LangSmithSandboxAuthenticationError, LangSmithSandboxConnectionError, LangSmithSandboxServerReloadError, LangSmithResourceNotFoundError, LangSmithResourceTimeoutError, LangSmithResourceInUseError, LangSmithResourceAlreadyExistsError, LangSmithResourceNameConflictError, LangSmithValidationError, LangSmithQuotaExceededError, LangSmithResourceCreationError, LangSmithSandboxCreationError, LangSmithSandboxNotReadyError, LangSmithSandboxOperationError, LangSmithCommandTimeoutError, LangSmithDataplaneNotConfiguredError, } from "./errors.js";
|
|
36
|
+
export { LangSmithSandboxError, LangSmithSandboxAPIError, LangSmithSandboxAuthenticationError, LangSmithSandboxConnectionError, LangSmithSandboxConnectTimeoutError, LangSmithSandboxServerReloadError, LangSmithResourceNotFoundError, LangSmithResourceTimeoutError, LangSmithResourceInUseError, LangSmithResourceAlreadyExistsError, LangSmithResourceNameConflictError, LangSmithValidationError, LangSmithQuotaExceededError, LangSmithResourceCreationError, LangSmithSandboxCreationError, LangSmithSandboxNotReadyError, LangSmithSandboxOperationError, LangSmithCommandTimeoutError, LangSmithDataplaneNotConfiguredError, } from "./errors.js";
|
package/dist/sandbox/index.js
CHANGED
|
@@ -36,7 +36,7 @@ export { gcsMount, gitMount, mountConfig, s3Mount } from "./mounts.js";
|
|
|
36
36
|
// Errors
|
|
37
37
|
export {
|
|
38
38
|
// Base and connection errors
|
|
39
|
-
LangSmithSandboxError, LangSmithSandboxAPIError, LangSmithSandboxAuthenticationError, LangSmithSandboxConnectionError, LangSmithSandboxServerReloadError,
|
|
39
|
+
LangSmithSandboxError, LangSmithSandboxAPIError, LangSmithSandboxAuthenticationError, LangSmithSandboxConnectionError, LangSmithSandboxConnectTimeoutError, LangSmithSandboxServerReloadError,
|
|
40
40
|
// Resource errors (type-based with resourceType attribute)
|
|
41
41
|
LangSmithResourceNotFoundError, LangSmithResourceTimeoutError, LangSmithResourceInUseError, LangSmithResourceAlreadyExistsError, LangSmithResourceNameConflictError,
|
|
42
42
|
// Validation and quota errors
|
package/dist/sandbox/sandbox.cjs
CHANGED
|
@@ -234,6 +234,7 @@ class Sandbox {
|
|
|
234
234
|
// spawning a second one.
|
|
235
235
|
const execCommandId = commandId ?? (0, uuid_js_1.uuid7)();
|
|
236
236
|
let attempt = 0;
|
|
237
|
+
const deadline = (0, ws_execute_js_1.connectDeadline)();
|
|
237
238
|
// eslint-disable-next-line no-constant-condition
|
|
238
239
|
while (true) {
|
|
239
240
|
const [stream, control] = await (0, ws_execute_js_1.runWsStream)(dataplaneUrl, this._client.getApiKey(), command, {
|
|
@@ -246,6 +247,7 @@ class Sandbox {
|
|
|
246
247
|
killOnDisconnect,
|
|
247
248
|
ttlSeconds,
|
|
248
249
|
pty,
|
|
250
|
+
openTimeout: (0, ws_execute_js_1.openTimeoutFor)(deadline),
|
|
249
251
|
...(Object.keys(clientHeaders).length > 0
|
|
250
252
|
? { headers: clientHeaders }
|
|
251
253
|
: {}),
|
|
@@ -259,16 +261,31 @@ class Sandbox {
|
|
|
259
261
|
return handle;
|
|
260
262
|
}
|
|
261
263
|
catch (e) {
|
|
262
|
-
// Idempotent re-issue (same command_id)
|
|
263
|
-
|
|
264
|
+
// Idempotent re-issue (same command_id): neither an early close nor a
|
|
265
|
+
// failed connect can have started a second command.
|
|
266
|
+
if (!(e instanceof errors_js_1.LangSmithStreamEndedBeforeStartedError) &&
|
|
267
|
+
!(e instanceof errors_js_1.LangSmithSandboxConnectTimeoutError)) {
|
|
264
268
|
throw e;
|
|
265
269
|
}
|
|
266
270
|
attempt++;
|
|
267
271
|
if (attempt > command_handle_js_1.CommandHandle.MAX_AUTO_RECONNECTS) {
|
|
268
272
|
throw e;
|
|
269
273
|
}
|
|
270
|
-
|
|
274
|
+
let delay = Math.min(command_handle_js_1.CommandHandle.BACKOFF_BASE * 2 ** (attempt - 1), command_handle_js_1.CommandHandle.BACKOFF_MAX);
|
|
275
|
+
const remaining = (0, ws_execute_js_1.remainingBudget)(deadline);
|
|
276
|
+
if (remaining !== undefined) {
|
|
277
|
+
if (remaining <= 0) {
|
|
278
|
+
throw e;
|
|
279
|
+
}
|
|
280
|
+
delay = Math.min(delay, remaining);
|
|
281
|
+
}
|
|
271
282
|
await new Promise((r) => setTimeout(r, delay * 1000));
|
|
283
|
+
// Never start an attempt with no budget left: openTimeoutFor would
|
|
284
|
+
// return 0, which ws forwards to Node as "no timeout at all".
|
|
285
|
+
const left = (0, ws_execute_js_1.remainingBudget)(deadline);
|
|
286
|
+
if (left !== undefined && left <= 0) {
|
|
287
|
+
throw e;
|
|
288
|
+
}
|
|
272
289
|
}
|
|
273
290
|
}
|
|
274
291
|
}
|
|
@@ -426,8 +443,9 @@ class Sandbox {
|
|
|
426
443
|
*/
|
|
427
444
|
async stop() {
|
|
428
445
|
await this._client.stopSandbox(this.name);
|
|
446
|
+
// dataplane_url stays set: it is stable across stop/start and a request on
|
|
447
|
+
// it resumes the sandbox.
|
|
429
448
|
this.status = "stopped";
|
|
430
|
-
this.dataplane_url = undefined;
|
|
431
449
|
}
|
|
432
450
|
/**
|
|
433
451
|
* Capture a snapshot from this sandbox.
|
package/dist/sandbox/sandbox.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Sandbox class for interacting with a specific sandbox instance.
|
|
3
3
|
*/
|
|
4
4
|
import { uuid7 } from "../uuid.js";
|
|
5
|
-
import { LangSmithDataplaneNotConfiguredError, LangSmithStreamEndedBeforeStartedError, } from "./errors.js";
|
|
5
|
+
import { LangSmithDataplaneNotConfiguredError, LangSmithSandboxConnectTimeoutError, LangSmithStreamEndedBeforeStartedError, } from "./errors.js";
|
|
6
6
|
import { handleSandboxHttpError } from "./helpers.js";
|
|
7
7
|
import { CommandHandle } from "./command_handle.js";
|
|
8
|
-
import { isWsAvailable, reconnectWsStream, runWsStream } from "./ws_execute.js";
|
|
8
|
+
import { connectDeadline, isWsAvailable, openTimeoutFor, reconnectWsStream, remainingBudget, runWsStream, } from "./ws_execute.js";
|
|
9
9
|
/**
|
|
10
10
|
* Represents an active sandbox for running commands and file operations.
|
|
11
11
|
*
|
|
@@ -231,6 +231,7 @@ export class Sandbox {
|
|
|
231
231
|
// spawning a second one.
|
|
232
232
|
const execCommandId = commandId ?? uuid7();
|
|
233
233
|
let attempt = 0;
|
|
234
|
+
const deadline = connectDeadline();
|
|
234
235
|
// eslint-disable-next-line no-constant-condition
|
|
235
236
|
while (true) {
|
|
236
237
|
const [stream, control] = await runWsStream(dataplaneUrl, this._client.getApiKey(), command, {
|
|
@@ -243,6 +244,7 @@ export class Sandbox {
|
|
|
243
244
|
killOnDisconnect,
|
|
244
245
|
ttlSeconds,
|
|
245
246
|
pty,
|
|
247
|
+
openTimeout: openTimeoutFor(deadline),
|
|
246
248
|
...(Object.keys(clientHeaders).length > 0
|
|
247
249
|
? { headers: clientHeaders }
|
|
248
250
|
: {}),
|
|
@@ -256,16 +258,31 @@ export class Sandbox {
|
|
|
256
258
|
return handle;
|
|
257
259
|
}
|
|
258
260
|
catch (e) {
|
|
259
|
-
// Idempotent re-issue (same command_id)
|
|
260
|
-
|
|
261
|
+
// Idempotent re-issue (same command_id): neither an early close nor a
|
|
262
|
+
// failed connect can have started a second command.
|
|
263
|
+
if (!(e instanceof LangSmithStreamEndedBeforeStartedError) &&
|
|
264
|
+
!(e instanceof LangSmithSandboxConnectTimeoutError)) {
|
|
261
265
|
throw e;
|
|
262
266
|
}
|
|
263
267
|
attempt++;
|
|
264
268
|
if (attempt > CommandHandle.MAX_AUTO_RECONNECTS) {
|
|
265
269
|
throw e;
|
|
266
270
|
}
|
|
267
|
-
|
|
271
|
+
let delay = Math.min(CommandHandle.BACKOFF_BASE * 2 ** (attempt - 1), CommandHandle.BACKOFF_MAX);
|
|
272
|
+
const remaining = remainingBudget(deadline);
|
|
273
|
+
if (remaining !== undefined) {
|
|
274
|
+
if (remaining <= 0) {
|
|
275
|
+
throw e;
|
|
276
|
+
}
|
|
277
|
+
delay = Math.min(delay, remaining);
|
|
278
|
+
}
|
|
268
279
|
await new Promise((r) => setTimeout(r, delay * 1000));
|
|
280
|
+
// Never start an attempt with no budget left: openTimeoutFor would
|
|
281
|
+
// return 0, which ws forwards to Node as "no timeout at all".
|
|
282
|
+
const left = remainingBudget(deadline);
|
|
283
|
+
if (left !== undefined && left <= 0) {
|
|
284
|
+
throw e;
|
|
285
|
+
}
|
|
269
286
|
}
|
|
270
287
|
}
|
|
271
288
|
}
|
|
@@ -423,8 +440,9 @@ export class Sandbox {
|
|
|
423
440
|
*/
|
|
424
441
|
async stop() {
|
|
425
442
|
await this._client.stopSandbox(this.name);
|
|
443
|
+
// dataplane_url stays set: it is stable across stop/start and a request on
|
|
444
|
+
// it resumes the sandbox.
|
|
426
445
|
this.status = "stopped";
|
|
427
|
-
this.dataplane_url = undefined;
|
|
428
446
|
}
|
|
429
447
|
/**
|
|
430
448
|
* Capture a snapshot from this sandbox.
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
* Install with: npm install ws
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.WSStreamControl = void 0;
|
|
9
|
+
exports.WSStreamControl = exports.WS_CONNECT_BUDGET = exports.WS_OPEN_TIMEOUT = void 0;
|
|
10
|
+
exports.connectDeadline = connectDeadline;
|
|
11
|
+
exports.remainingBudget = remainingBudget;
|
|
12
|
+
exports.openTimeoutFor = openTimeoutFor;
|
|
10
13
|
exports.isWsAvailable = isWsAvailable;
|
|
11
14
|
exports.buildWsUrl = buildWsUrl;
|
|
12
15
|
exports.buildAuthHeaders = buildAuthHeaders;
|
|
@@ -14,6 +17,46 @@ exports.raiseForWsError = raiseForWsError;
|
|
|
14
17
|
exports.runWsStream = runWsStream;
|
|
15
18
|
exports.reconnectWsStream = reconnectWsStream;
|
|
16
19
|
const errors_js_1 = require("./errors.cjs");
|
|
20
|
+
const env_js_1 = require("../utils/env.cjs");
|
|
21
|
+
/** Read a WebSocket timeout override, in seconds. `<= 0` disables it. */
|
|
22
|
+
function envTimeout(name, defaultSeconds) {
|
|
23
|
+
const raw = (0, env_js_1.getLangSmithEnvironmentVariable)(name);
|
|
24
|
+
if (raw === undefined || raw.trim() === "")
|
|
25
|
+
return defaultSeconds;
|
|
26
|
+
const value = Number(raw);
|
|
27
|
+
if (!Number.isFinite(value)) {
|
|
28
|
+
console.warn(`Ignoring invalid LANGSMITH_${name}=${raw}, using ${defaultSeconds}`);
|
|
29
|
+
return defaultSeconds;
|
|
30
|
+
}
|
|
31
|
+
return value > 0 ? value : undefined;
|
|
32
|
+
}
|
|
33
|
+
// A slow cold start is recovered by the retry loop in run(), not by waiting here.
|
|
34
|
+
exports.WS_OPEN_TIMEOUT = envTimeout("SANDBOX_WS_TIMEOUT_OPEN", 30);
|
|
35
|
+
// Ceiling on the whole connect phase. Without it, retrying a blackholed
|
|
36
|
+
// handshake costs MAX_AUTO_RECONNECTS + 1 full open timeouts plus backoff.
|
|
37
|
+
exports.WS_CONNECT_BUDGET = envTimeout("SANDBOX_WS_TIMEOUT_CONNECT_BUDGET", 120);
|
|
38
|
+
function nowSeconds() {
|
|
39
|
+
return performance.now() / 1000;
|
|
40
|
+
}
|
|
41
|
+
/** Instant after which connect attempts must stop, if bounded. */
|
|
42
|
+
function connectDeadline() {
|
|
43
|
+
return exports.WS_CONNECT_BUDGET === undefined
|
|
44
|
+
? undefined
|
|
45
|
+
: nowSeconds() + exports.WS_CONNECT_BUDGET;
|
|
46
|
+
}
|
|
47
|
+
/** Seconds left in the connect budget, or undefined when unbounded. */
|
|
48
|
+
function remainingBudget(deadline) {
|
|
49
|
+
return deadline === undefined ? undefined : deadline - nowSeconds();
|
|
50
|
+
}
|
|
51
|
+
/** Per-attempt open timeout, clamped so it cannot outlive `deadline`. */
|
|
52
|
+
function openTimeoutFor(deadline) {
|
|
53
|
+
if (deadline === undefined)
|
|
54
|
+
return exports.WS_OPEN_TIMEOUT;
|
|
55
|
+
const remaining = Math.max(deadline - nowSeconds(), 0);
|
|
56
|
+
return exports.WS_OPEN_TIMEOUT === undefined
|
|
57
|
+
? remaining
|
|
58
|
+
: Math.min(exports.WS_OPEN_TIMEOUT, remaining);
|
|
59
|
+
}
|
|
17
60
|
// Load the optional 'ws' package once, at module load, instead of importing on
|
|
18
61
|
// every call. Resolves to the WebSocket constructor, or null if 'ws' isn't
|
|
19
62
|
// installed. run() reads isWsAvailable() to choose WS vs the HTTP fallback.
|
|
@@ -140,18 +183,42 @@ function raiseForWsError(msg, commandId = "") {
|
|
|
140
183
|
/**
|
|
141
184
|
* Create a ws WebSocket connection and return a promise that resolves when open
|
|
142
185
|
* or rejects on error.
|
|
186
|
+
*
|
|
187
|
+
* A socket-level failure rejects with the retryable connect-timeout error; a
|
|
188
|
+
* non-101 response rejects with the permanent connection error.
|
|
143
189
|
*/
|
|
144
|
-
async function connectWs(url, headers) {
|
|
190
|
+
async function connectWs(url, headers, openTimeout = exports.WS_OPEN_TIMEOUT) {
|
|
145
191
|
const { WebSocket: WS } = await ensureWs();
|
|
146
192
|
return new Promise((resolve, reject) => {
|
|
147
|
-
const ws = new WS(url, {
|
|
193
|
+
const ws = new WS(url, {
|
|
194
|
+
headers,
|
|
195
|
+
handshakeTimeout: openTimeout === undefined ? undefined : openTimeout * 1000,
|
|
196
|
+
});
|
|
197
|
+
let settled = false;
|
|
148
198
|
ws.on("open", () => {
|
|
149
|
-
|
|
199
|
+
if (settled)
|
|
200
|
+
return;
|
|
201
|
+
settled = true;
|
|
150
202
|
resolve(ws);
|
|
151
203
|
});
|
|
204
|
+
// Attaching this suppresses ws's own "error" for a non-101 response, so the
|
|
205
|
+
// rejected upgrade cannot be misreported as a retryable socket failure. ws
|
|
206
|
+
// leaves cleanup to the handler once a listener is present.
|
|
207
|
+
ws.on("unexpected-response", (req, res) => {
|
|
208
|
+
res.resume?.();
|
|
209
|
+
req.destroy?.();
|
|
210
|
+
if (settled)
|
|
211
|
+
return;
|
|
212
|
+
settled = true;
|
|
213
|
+
reject(new errors_js_1.LangSmithSandboxConnectionError(`WebSocket upgrade to ${url} rejected by server (HTTP ${res.statusCode})`));
|
|
214
|
+
});
|
|
215
|
+
// Stays attached after settling so a late error has a listener and cannot
|
|
216
|
+
// become an unhandled 'error' event.
|
|
152
217
|
ws.on("error", (err) => {
|
|
153
|
-
|
|
154
|
-
|
|
218
|
+
if (settled)
|
|
219
|
+
return;
|
|
220
|
+
settled = true;
|
|
221
|
+
reject(new errors_js_1.LangSmithSandboxConnectTimeoutError(`Failed to connect to sandbox WebSocket: ${err.message}`));
|
|
155
222
|
});
|
|
156
223
|
});
|
|
157
224
|
}
|
|
@@ -249,14 +316,14 @@ async function* readWsMessages(ws) {
|
|
|
249
316
|
* data arrives in addition to yielding the messages.
|
|
250
317
|
*/
|
|
251
318
|
async function runWsStream(dataplaneUrl, apiKey, command, options = {}) {
|
|
252
|
-
const { timeout = 60, env, cwd, shell = "/bin/bash", onStdout, onStderr, commandId, idleTimeout = 300, killOnDisconnect = false, ttlSeconds = 600, pty, headers: extraHeaders, } = options;
|
|
319
|
+
const { timeout = 60, env, cwd, shell = "/bin/bash", onStdout, onStderr, commandId, idleTimeout = 300, killOnDisconnect = false, ttlSeconds = 600, pty, headers: extraHeaders, openTimeout = exports.WS_OPEN_TIMEOUT, } = options;
|
|
253
320
|
const wsUrl = buildWsUrl(dataplaneUrl);
|
|
254
321
|
const headers = buildAuthHeaders(apiKey, extraHeaders);
|
|
255
322
|
const control = new WSStreamControl();
|
|
256
323
|
async function* stream() {
|
|
257
324
|
let ws;
|
|
258
325
|
try {
|
|
259
|
-
ws = await connectWs(wsUrl, headers);
|
|
326
|
+
ws = await connectWs(wsUrl, headers, openTimeout);
|
|
260
327
|
control._bind(ws);
|
|
261
328
|
// Send execute request
|
|
262
329
|
const payload = {
|
|
@@ -315,8 +382,10 @@ async function runWsStream(dataplaneUrl, apiKey, command, options = {}) {
|
|
|
315
382
|
* Reconnect to an existing command over WebSocket.
|
|
316
383
|
*
|
|
317
384
|
* Returns a tuple of [async_message_iterator, control], same as runWsStream.
|
|
318
|
-
* The iterator yields
|
|
319
|
-
*
|
|
385
|
+
* The iterator yields the server's 'started' acknowledgement, then stdout,
|
|
386
|
+
* stderr, exit, and error messages. That acknowledgement is the only evidence a
|
|
387
|
+
* reattachment landed for a command producing no output, so it is forwarded
|
|
388
|
+
* rather than dropped.
|
|
320
389
|
*/
|
|
321
390
|
async function reconnectWsStream(dataplaneUrl, apiKey, commandId, options = {}) {
|
|
322
391
|
const { stdoutOffset = 0, stderrOffset = 0, headers: extraHeaders } = options;
|
|
@@ -338,7 +407,9 @@ async function reconnectWsStream(dataplaneUrl, apiKey, commandId, options = {})
|
|
|
338
407
|
// Read messages until exit or error
|
|
339
408
|
for await (const msg of readWsMessages(ws)) {
|
|
340
409
|
const msgType = msg.type;
|
|
341
|
-
if (msgType === "
|
|
410
|
+
if (msgType === "started" ||
|
|
411
|
+
msgType === "stdout" ||
|
|
412
|
+
msgType === "stderr") {
|
|
342
413
|
yield msg;
|
|
343
414
|
}
|
|
344
415
|
else if (msgType === "exit") {
|