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.
Files changed (83) hide show
  1. package/dist/_openapi_client/client.cjs +8 -0
  2. package/dist/_openapi_client/client.d.ts +3 -0
  3. package/dist/_openapi_client/client.js +8 -0
  4. package/dist/_openapi_client/resources/annotation-queues/annotation-queues.cjs +157 -0
  5. package/dist/_openapi_client/resources/annotation-queues/annotation-queues.d.ts +382 -0
  6. package/dist/_openapi_client/resources/annotation-queues/annotation-queues.js +120 -0
  7. package/dist/_openapi_client/resources/annotation-queues/items.cjs +84 -0
  8. package/dist/_openapi_client/resources/annotation-queues/items.d.ts +207 -0
  9. package/dist/_openapi_client/resources/annotation-queues/items.js +80 -0
  10. package/dist/_openapi_client/resources/annotation-queues/runs.cjs +73 -0
  11. package/dist/_openapi_client/resources/annotation-queues/runs.d.ts +197 -0
  12. package/dist/_openapi_client/resources/annotation-queues/runs.js +69 -0
  13. package/dist/_openapi_client/resources/datasets/experiment-runs.cjs +3 -1
  14. package/dist/_openapi_client/resources/datasets/experiment-runs.d.ts +2 -0
  15. package/dist/_openapi_client/resources/datasets/experiment-runs.js +3 -1
  16. package/dist/_openapi_client/resources/index.cjs +3 -1
  17. package/dist/_openapi_client/resources/index.d.ts +1 -0
  18. package/dist/_openapi_client/resources/index.js +1 -0
  19. package/dist/_openapi_client/resources/info.cjs +3 -1
  20. package/dist/_openapi_client/resources/info.d.ts +16 -22
  21. package/dist/_openapi_client/resources/info.js +3 -1
  22. package/dist/_openapi_client/resources/issues.cjs +2 -2
  23. package/dist/_openapi_client/resources/issues.d.ts +1 -1
  24. package/dist/_openapi_client/resources/issues.js +2 -2
  25. package/dist/_openapi_client/resources/online-evaluators.cjs +7 -7
  26. package/dist/_openapi_client/resources/online-evaluators.d.ts +8 -0
  27. package/dist/_openapi_client/resources/online-evaluators.js +7 -7
  28. package/dist/_openapi_client/resources/public/runs.cjs +10 -8
  29. package/dist/_openapi_client/resources/public/runs.d.ts +9 -7
  30. package/dist/_openapi_client/resources/public/runs.js +10 -8
  31. package/dist/_openapi_client/resources/runs/runs.cjs +14 -9
  32. package/dist/_openapi_client/resources/runs/runs.d.ts +20 -10
  33. package/dist/_openapi_client/resources/runs/runs.js +14 -9
  34. package/dist/_openapi_client/resources/runs/share.cjs +6 -2
  35. package/dist/_openapi_client/resources/runs/share.d.ts +4 -0
  36. package/dist/_openapi_client/resources/runs/share.js +6 -2
  37. package/dist/_openapi_client/resources/sandboxes/boxes.cjs +10 -10
  38. package/dist/_openapi_client/resources/sandboxes/boxes.d.ts +40 -0
  39. package/dist/_openapi_client/resources/sandboxes/boxes.js +10 -10
  40. package/dist/_openapi_client/resources/sandboxes/registries.cjs +5 -5
  41. package/dist/_openapi_client/resources/sandboxes/registries.js +5 -5
  42. package/dist/_openapi_client/resources/sandboxes/sandboxes.d.ts +17 -0
  43. package/dist/_openapi_client/resources/sandboxes/snapshots.cjs +4 -4
  44. package/dist/_openapi_client/resources/sandboxes/snapshots.d.ts +12 -0
  45. package/dist/_openapi_client/resources/sandboxes/snapshots.js +4 -4
  46. package/dist/_openapi_client/resources/threads.cjs +14 -11
  47. package/dist/_openapi_client/resources/threads.d.ts +13 -9
  48. package/dist/_openapi_client/resources/threads.js +14 -11
  49. package/dist/_openapi_client/resources/traces.cjs +8 -5
  50. package/dist/_openapi_client/resources/traces.d.ts +7 -4
  51. package/dist/_openapi_client/resources/traces.js +8 -5
  52. package/dist/client.cjs +318 -40
  53. package/dist/client.d.ts +111 -25
  54. package/dist/client.js +318 -40
  55. package/dist/evaluation/evaluate_comparative.cjs +7 -4
  56. package/dist/evaluation/evaluate_comparative.js +7 -4
  57. package/dist/index.cjs +1 -1
  58. package/dist/index.d.ts +1 -1
  59. package/dist/index.js +1 -1
  60. package/dist/sandbox/command_handle.cjs +38 -11
  61. package/dist/sandbox/command_handle.d.ts +1 -0
  62. package/dist/sandbox/command_handle.js +39 -12
  63. package/dist/sandbox/errors.cjs +16 -1
  64. package/dist/sandbox/errors.d.ts +11 -0
  65. package/dist/sandbox/errors.js +14 -0
  66. package/dist/sandbox/index.cjs +2 -1
  67. package/dist/sandbox/index.d.ts +1 -1
  68. package/dist/sandbox/index.js +1 -1
  69. package/dist/sandbox/sandbox.cjs +22 -4
  70. package/dist/sandbox/sandbox.js +24 -6
  71. package/dist/sandbox/ws_execute.cjs +82 -11
  72. package/dist/sandbox/ws_execute.d.ts +12 -2
  73. package/dist/sandbox/ws_execute.js +79 -11
  74. package/dist/utils/v2_migration.cjs +18 -0
  75. package/dist/utils/v2_migration.d.ts +8 -0
  76. package/dist/utils/v2_migration.js +16 -0
  77. package/dist/utils/warn.cjs +30 -4
  78. package/dist/utils/warn.d.ts +4 -1
  79. package/dist/utils/warn.js +29 -4
  80. package/package.json +1 -1
  81. package/dist/utils/constants.cjs +0 -4
  82. package/dist/utils/constants.d.ts +0 -1
  83. package/dist/utils/constants.js +0 -1
@@ -5,6 +5,14 @@
5
5
  * Install with: npm install ws
6
6
  */
7
7
  import type { WsMessage, WsRunOptions } from "./types.js";
8
+ export declare const WS_OPEN_TIMEOUT: number | undefined;
9
+ export declare const WS_CONNECT_BUDGET: number | undefined;
10
+ /** Instant after which connect attempts must stop, if bounded. */
11
+ export declare function connectDeadline(): number | undefined;
12
+ /** Seconds left in the connect budget, or undefined when unbounded. */
13
+ export declare function remainingBudget(deadline: number | undefined): number | undefined;
14
+ /** Per-attempt open timeout, clamped so it cannot outlive `deadline`. */
15
+ export declare function openTimeoutFor(deadline: number | undefined): number | undefined;
8
16
  type WsWebSocket = any;
9
17
  /** Whether the optional `ws` package could be loaded (resolved once). */
10
18
  export declare function isWsAvailable(): Promise<boolean>;
@@ -62,8 +70,10 @@ export declare function runWsStream(dataplaneUrl: string, apiKey: string | undef
62
70
  * Reconnect to an existing command over WebSocket.
63
71
  *
64
72
  * Returns a tuple of [async_message_iterator, control], same as runWsStream.
65
- * The iterator yields stdout, stderr, exit, and error messages.
66
- * No 'started' message is sent on reconnection.
73
+ * The iterator yields the server's 'started' acknowledgement, then stdout,
74
+ * stderr, exit, and error messages. That acknowledgement is the only evidence a
75
+ * reattachment landed for a command producing no output, so it is forwarded
76
+ * rather than dropped.
67
77
  */
68
78
  export declare function reconnectWsStream(dataplaneUrl: string, apiKey: string | undefined, commandId: string, options?: {
69
79
  stdoutOffset?: number;
@@ -4,7 +4,47 @@
4
4
  * Uses the `ws` npm package (optional peer dependency).
5
5
  * Install with: npm install ws
6
6
  */
7
- import { LangSmithCommandTimeoutError, LangSmithSandboxConnectionError, LangSmithSandboxOperationError, LangSmithSandboxServerReloadError, } from "./errors.js";
7
+ import { LangSmithCommandTimeoutError, LangSmithSandboxConnectionError, LangSmithSandboxConnectTimeoutError, LangSmithSandboxOperationError, LangSmithSandboxServerReloadError, } from "./errors.js";
8
+ import { getLangSmithEnvironmentVariable } from "../utils/env.js";
9
+ /** Read a WebSocket timeout override, in seconds. `<= 0` disables it. */
10
+ function envTimeout(name, defaultSeconds) {
11
+ const raw = getLangSmithEnvironmentVariable(name);
12
+ if (raw === undefined || raw.trim() === "")
13
+ return defaultSeconds;
14
+ const value = Number(raw);
15
+ if (!Number.isFinite(value)) {
16
+ console.warn(`Ignoring invalid LANGSMITH_${name}=${raw}, using ${defaultSeconds}`);
17
+ return defaultSeconds;
18
+ }
19
+ return value > 0 ? value : undefined;
20
+ }
21
+ // A slow cold start is recovered by the retry loop in run(), not by waiting here.
22
+ export const WS_OPEN_TIMEOUT = envTimeout("SANDBOX_WS_TIMEOUT_OPEN", 30);
23
+ // Ceiling on the whole connect phase. Without it, retrying a blackholed
24
+ // handshake costs MAX_AUTO_RECONNECTS + 1 full open timeouts plus backoff.
25
+ export const WS_CONNECT_BUDGET = envTimeout("SANDBOX_WS_TIMEOUT_CONNECT_BUDGET", 120);
26
+ function nowSeconds() {
27
+ return performance.now() / 1000;
28
+ }
29
+ /** Instant after which connect attempts must stop, if bounded. */
30
+ export function connectDeadline() {
31
+ return WS_CONNECT_BUDGET === undefined
32
+ ? undefined
33
+ : nowSeconds() + WS_CONNECT_BUDGET;
34
+ }
35
+ /** Seconds left in the connect budget, or undefined when unbounded. */
36
+ export function remainingBudget(deadline) {
37
+ return deadline === undefined ? undefined : deadline - nowSeconds();
38
+ }
39
+ /** Per-attempt open timeout, clamped so it cannot outlive `deadline`. */
40
+ export function openTimeoutFor(deadline) {
41
+ if (deadline === undefined)
42
+ return WS_OPEN_TIMEOUT;
43
+ const remaining = Math.max(deadline - nowSeconds(), 0);
44
+ return WS_OPEN_TIMEOUT === undefined
45
+ ? remaining
46
+ : Math.min(WS_OPEN_TIMEOUT, remaining);
47
+ }
8
48
  // Load the optional 'ws' package once, at module load, instead of importing on
9
49
  // every call. Resolves to the WebSocket constructor, or null if 'ws' isn't
10
50
  // installed. run() reads isWsAvailable() to choose WS vs the HTTP fallback.
@@ -130,18 +170,42 @@ export function raiseForWsError(msg, commandId = "") {
130
170
  /**
131
171
  * Create a ws WebSocket connection and return a promise that resolves when open
132
172
  * or rejects on error.
173
+ *
174
+ * A socket-level failure rejects with the retryable connect-timeout error; a
175
+ * non-101 response rejects with the permanent connection error.
133
176
  */
134
- async function connectWs(url, headers) {
177
+ async function connectWs(url, headers, openTimeout = WS_OPEN_TIMEOUT) {
135
178
  const { WebSocket: WS } = await ensureWs();
136
179
  return new Promise((resolve, reject) => {
137
- const ws = new WS(url, { headers });
180
+ const ws = new WS(url, {
181
+ headers,
182
+ handshakeTimeout: openTimeout === undefined ? undefined : openTimeout * 1000,
183
+ });
184
+ let settled = false;
138
185
  ws.on("open", () => {
139
- ws.removeAllListeners("error");
186
+ if (settled)
187
+ return;
188
+ settled = true;
140
189
  resolve(ws);
141
190
  });
191
+ // Attaching this suppresses ws's own "error" for a non-101 response, so the
192
+ // rejected upgrade cannot be misreported as a retryable socket failure. ws
193
+ // leaves cleanup to the handler once a listener is present.
194
+ ws.on("unexpected-response", (req, res) => {
195
+ res.resume?.();
196
+ req.destroy?.();
197
+ if (settled)
198
+ return;
199
+ settled = true;
200
+ reject(new LangSmithSandboxConnectionError(`WebSocket upgrade to ${url} rejected by server (HTTP ${res.statusCode})`));
201
+ });
202
+ // Stays attached after settling so a late error has a listener and cannot
203
+ // become an unhandled 'error' event.
142
204
  ws.on("error", (err) => {
143
- ws.removeAllListeners("open");
144
- reject(new LangSmithSandboxConnectionError(`Failed to connect to sandbox WebSocket: ${err.message}`));
205
+ if (settled)
206
+ return;
207
+ settled = true;
208
+ reject(new LangSmithSandboxConnectTimeoutError(`Failed to connect to sandbox WebSocket: ${err.message}`));
145
209
  });
146
210
  });
147
211
  }
@@ -239,14 +303,14 @@ async function* readWsMessages(ws) {
239
303
  * data arrives in addition to yielding the messages.
240
304
  */
241
305
  export async function runWsStream(dataplaneUrl, apiKey, command, options = {}) {
242
- const { timeout = 60, env, cwd, shell = "/bin/bash", onStdout, onStderr, commandId, idleTimeout = 300, killOnDisconnect = false, ttlSeconds = 600, pty, headers: extraHeaders, } = options;
306
+ const { timeout = 60, env, cwd, shell = "/bin/bash", onStdout, onStderr, commandId, idleTimeout = 300, killOnDisconnect = false, ttlSeconds = 600, pty, headers: extraHeaders, openTimeout = WS_OPEN_TIMEOUT, } = options;
243
307
  const wsUrl = buildWsUrl(dataplaneUrl);
244
308
  const headers = buildAuthHeaders(apiKey, extraHeaders);
245
309
  const control = new WSStreamControl();
246
310
  async function* stream() {
247
311
  let ws;
248
312
  try {
249
- ws = await connectWs(wsUrl, headers);
313
+ ws = await connectWs(wsUrl, headers, openTimeout);
250
314
  control._bind(ws);
251
315
  // Send execute request
252
316
  const payload = {
@@ -305,8 +369,10 @@ export async function runWsStream(dataplaneUrl, apiKey, command, options = {}) {
305
369
  * Reconnect to an existing command over WebSocket.
306
370
  *
307
371
  * Returns a tuple of [async_message_iterator, control], same as runWsStream.
308
- * The iterator yields stdout, stderr, exit, and error messages.
309
- * No 'started' message is sent on reconnection.
372
+ * The iterator yields the server's 'started' acknowledgement, then stdout,
373
+ * stderr, exit, and error messages. That acknowledgement is the only evidence a
374
+ * reattachment landed for a command producing no output, so it is forwarded
375
+ * rather than dropped.
310
376
  */
311
377
  export async function reconnectWsStream(dataplaneUrl, apiKey, commandId, options = {}) {
312
378
  const { stdoutOffset = 0, stderrOffset = 0, headers: extraHeaders } = options;
@@ -328,7 +394,9 @@ export async function reconnectWsStream(dataplaneUrl, apiKey, commandId, options
328
394
  // Read messages until exit or error
329
395
  for await (const msg of readWsMessages(ws)) {
330
396
  const msgType = msg.type;
331
- if (msgType === "stdout" || msgType === "stderr") {
397
+ if (msgType === "started" ||
398
+ msgType === "stdout" ||
399
+ msgType === "stderr") {
332
400
  yield msg;
333
401
  }
334
402
  else if (msgType === "exit") {
@@ -1,7 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QueryBackend = void 0;
4
+ exports.getQueryBackend = getQueryBackend;
3
5
  exports.v2RunToRun = v2RunToRun;
4
6
  exports.loadTracesV2 = loadTracesV2;
7
+ exports.QueryBackend = {
8
+ CLICKHOUSE_ONLY: "clickhouse_only",
9
+ SMITHDB_ONLY: "smithdb_only",
10
+ DUAL: "dual",
11
+ };
12
+ /** Which backend(s) `/info`'s `instance_flags` indicate for run/trace queries. */
13
+ function getQueryBackend(instanceFlags) {
14
+ const flags = instanceFlags ?? {};
15
+ const chEnabled = Boolean(flags.ch_query_enabled ?? true);
16
+ const sdbEnabled = Boolean(flags.sdb_query_enabled ?? false);
17
+ if (!chEnabled && sdbEnabled)
18
+ return exports.QueryBackend.SMITHDB_ONLY;
19
+ if (chEnabled && sdbEnabled)
20
+ return exports.QueryBackend.DUAL;
21
+ return exports.QueryBackend.CLICKHOUSE_ONLY;
22
+ }
5
23
  // Omitting selects from `/v2/runs/query` returns only the run ID.
6
24
  const V2_RUN_SELECTS = [
7
25
  "ID",
@@ -1,6 +1,14 @@
1
1
  import type { Run as V2Run } from "../_openapi_client/resources/runs/runs.js";
2
2
  import type { Client } from "../client.js";
3
3
  import type { Run, TracerSession } from "../schemas.js";
4
+ export declare const QueryBackend: {
5
+ readonly CLICKHOUSE_ONLY: "clickhouse_only";
6
+ readonly SMITHDB_ONLY: "smithdb_only";
7
+ readonly DUAL: "dual";
8
+ };
9
+ export type QueryBackend = (typeof QueryBackend)[keyof typeof QueryBackend];
10
+ /** Which backend(s) `/info`'s `instance_flags` indicate for run/trace queries. */
11
+ export declare function getQueryBackend(instanceFlags?: Record<string, unknown> | null): QueryBackend;
4
12
  export declare function v2RunToRun(run: V2Run): Run;
5
13
  export declare function loadTracesV2(client: Client, project: TracerSession, options: {
6
14
  isRoot?: boolean;
@@ -1,3 +1,19 @@
1
+ export const QueryBackend = {
2
+ CLICKHOUSE_ONLY: "clickhouse_only",
3
+ SMITHDB_ONLY: "smithdb_only",
4
+ DUAL: "dual",
5
+ };
6
+ /** Which backend(s) `/info`'s `instance_flags` indicate for run/trace queries. */
7
+ export function getQueryBackend(instanceFlags) {
8
+ const flags = instanceFlags ?? {};
9
+ const chEnabled = Boolean(flags.ch_query_enabled ?? true);
10
+ const sdbEnabled = Boolean(flags.sdb_query_enabled ?? false);
11
+ if (!chEnabled && sdbEnabled)
12
+ return QueryBackend.SMITHDB_ONLY;
13
+ if (chEnabled && sdbEnabled)
14
+ return QueryBackend.DUAL;
15
+ return QueryBackend.CLICKHOUSE_ONLY;
16
+ }
1
17
  // Omitting selects from `/v2/runs/query` returns only the run ID.
2
18
  const V2_RUN_SELECTS = [
3
19
  "ID",
@@ -1,10 +1,36 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports._resetWarnedMessages = _resetWarnedMessages;
3
4
  exports.warnOnce = warnOnce;
4
5
  const warnedMessages = {};
5
- function warnOnce(message) {
6
- if (!warnedMessages[message]) {
7
- console.warn(message);
8
- warnedMessages[message] = true;
6
+ /**
7
+ * Clear the warn-once record so a later call warns again.
8
+ *
9
+ * Test-only. `warnedMessages` is module-global and never otherwise reset, so
10
+ * without this a test asserting "warning X was (not) emitted" depends on whether
11
+ * an earlier test in the same file already consumed X.
12
+ *
13
+ * @internal
14
+ */
15
+ function _resetWarnedMessages() {
16
+ for (const key of Object.keys(warnedMessages)) {
17
+ delete warnedMessages[key];
18
+ }
19
+ }
20
+ function warnOnce(message, options) {
21
+ const key = options?.code ?? message;
22
+ if (!warnedMessages[key]) {
23
+ warnedMessages[key] = true;
24
+ if (options?.type &&
25
+ typeof process !== "undefined" &&
26
+ typeof process.emitWarning === "function") {
27
+ process.emitWarning(message, { type: options.type, code: options.code });
28
+ }
29
+ else if (options?.type && options?.code) {
30
+ console.warn(`${options.type} [${options.code}]: ${message}`);
31
+ }
32
+ else {
33
+ console.warn(message);
34
+ }
9
35
  }
10
36
  }
@@ -1 +1,4 @@
1
- export declare function warnOnce(message: string): void;
1
+ export declare function warnOnce(message: string, options?: {
2
+ type?: string;
3
+ code?: string;
4
+ }): void;
@@ -1,7 +1,32 @@
1
1
  const warnedMessages = {};
2
- export function warnOnce(message) {
3
- if (!warnedMessages[message]) {
4
- console.warn(message);
5
- warnedMessages[message] = true;
2
+ /**
3
+ * Clear the warn-once record so a later call warns again.
4
+ *
5
+ * Test-only. `warnedMessages` is module-global and never otherwise reset, so
6
+ * without this a test asserting "warning X was (not) emitted" depends on whether
7
+ * an earlier test in the same file already consumed X.
8
+ *
9
+ * @internal
10
+ */
11
+ export function _resetWarnedMessages() {
12
+ for (const key of Object.keys(warnedMessages)) {
13
+ delete warnedMessages[key];
14
+ }
15
+ }
16
+ export function warnOnce(message, options) {
17
+ const key = options?.code ?? message;
18
+ if (!warnedMessages[key]) {
19
+ warnedMessages[key] = true;
20
+ if (options?.type &&
21
+ typeof process !== "undefined" &&
22
+ typeof process.emitWarning === "function") {
23
+ process.emitWarning(message, { type: options.type, code: options.code });
24
+ }
25
+ else if (options?.type && options?.code) {
26
+ console.warn(`${options.type} [${options.code}]: ${message}`);
27
+ }
28
+ else {
29
+ console.warn(message);
30
+ }
6
31
  }
7
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.8.7",
3
+ "version": "0.8.9",
4
4
  "description": "Client library to connect to the LangSmith Observability and Evaluation Platform.",
5
5
  "packageManager": "pnpm@10.33.0",
6
6
  "files": [
@@ -1,4 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._MIN_BACKEND_VERSION = void 0;
4
- exports._MIN_BACKEND_VERSION = "0.16.14rc1";
@@ -1 +0,0 @@
1
- export declare const _MIN_BACKEND_VERSION = "0.16.14rc1";
@@ -1 +0,0 @@
1
- export const _MIN_BACKEND_VERSION = "0.16.14rc1";