tensorlake 0.5.35 → 0.5.36

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/index.js CHANGED
@@ -19,7 +19,7 @@ var SDK_VERSION, API_URL, API_KEY, NAMESPACE, SANDBOX_PROXY_URL, DEFAULT_HTTP_TI
19
19
  var init_defaults = __esm({
20
20
  "src/defaults.ts"() {
21
21
  "use strict";
22
- SDK_VERSION = "0.5.35";
22
+ SDK_VERSION = "0.5.36";
23
23
  API_URL = process.env.TENSORLAKE_API_URL ?? "https://api.tensorlake.ai";
24
24
  API_KEY = process.env.TENSORLAKE_API_KEY ?? void 0;
25
25
  NAMESPACE = process.env.INDEXIFY_NAMESPACE ?? "default";
@@ -139,6 +139,56 @@ var init_errors = __esm({
139
139
  }
140
140
  });
141
141
 
142
+ // src/sdk-timings.ts
143
+ function sdkTimingsEnabled() {
144
+ const value = process.env[SDK_TIMINGS_ENV_VAR];
145
+ return value === "1" || value === "true" || value === "yes";
146
+ }
147
+ function sdkTimingPayloadsEnabled() {
148
+ const value = process.env[SDK_TIMING_PAYLOADS_ENV_VAR];
149
+ return value === "1" || value === "true" || value === "yes";
150
+ }
151
+ function nowMs() {
152
+ return performance.now();
153
+ }
154
+ function logSdkTiming(op, phase, startedAt, fields = {}) {
155
+ if (!sdkTimingsEnabled()) return;
156
+ logSdkTimingEvent(op, phase, {
157
+ ...fields,
158
+ duration_ms: Math.round((nowMs() - startedAt) * 100) / 100
159
+ });
160
+ }
161
+ function logSdkTimingEvent(op, phase, fields = {}) {
162
+ if (!sdkTimingsEnabled()) return;
163
+ const parts = [
164
+ "[tensorlake:sdk-timing]",
165
+ `op=${op}`,
166
+ `phase=${phase}`
167
+ ];
168
+ for (const [key, value] of Object.entries(fields)) {
169
+ if (value == null) continue;
170
+ parts.push(`${key}=${formatSdkTimingValue(value)}`);
171
+ }
172
+ console.error(parts.join(" "));
173
+ }
174
+ function formatSdkTimingValue(value) {
175
+ if (typeof value === "number" || typeof value === "boolean") {
176
+ return String(value);
177
+ }
178
+ if (/^[A-Za-z0-9_./:@-]+$/.test(value)) {
179
+ return value;
180
+ }
181
+ return JSON.stringify(value);
182
+ }
183
+ var SDK_TIMINGS_ENV_VAR, SDK_TIMING_PAYLOADS_ENV_VAR;
184
+ var init_sdk_timings = __esm({
185
+ "src/sdk-timings.ts"() {
186
+ "use strict";
187
+ SDK_TIMINGS_ENV_VAR = "TENSORLAKE_SDK_TIMINGS";
188
+ SDK_TIMING_PAYLOADS_ENV_VAR = "TENSORLAKE_SDK_TIMING_PAYLOADS";
189
+ }
190
+ });
191
+
142
192
  // src/http.ts
143
193
  import {
144
194
  Agent,
@@ -164,6 +214,10 @@ function normalizeRequestBody(body) {
164
214
  }
165
215
  return body;
166
216
  }
217
+ function stripPathPayload(path2) {
218
+ const queryStart = path2.search(/[?#]/);
219
+ return queryStart === -1 ? path2 : path2.slice(0, queryStart);
220
+ }
167
221
  function throwMappedError(status, body, path2) {
168
222
  let message = body;
169
223
  try {
@@ -213,6 +267,7 @@ var init_http = __esm({
213
267
  "use strict";
214
268
  init_defaults();
215
269
  init_errors();
270
+ init_sdk_timings();
216
271
  REQUEST_TIMEOUT_HEADER = "X-Tensorlake-Request-Timeout-Ms";
217
272
  setGlobalDispatcher(
218
273
  new Agent({
@@ -339,9 +394,18 @@ var init_http = __esm({
339
394
  const { traceparent, traceId } = _HttpClient.makeTraceparent();
340
395
  headers["traceparent"] = traceparent;
341
396
  let lastError;
397
+ const operationStart = nowMs();
398
+ const timingPath = sdkTimingPayloadsEnabled() ? path2 : stripPathPayload(path2);
342
399
  for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
343
400
  if (attempt > 0) {
344
401
  const delay = this.retryBackoffMs * Math.pow(2, attempt - 1);
402
+ logSdkTimingEvent("http.request", "retry_sleep_start", {
403
+ method,
404
+ path: timingPath,
405
+ attempt,
406
+ delay_ms: delay,
407
+ server_trace_id: traceId
408
+ });
345
409
  await sleep(delay);
346
410
  }
347
411
  this.abortController = new AbortController();
@@ -351,6 +415,7 @@ var init_http = __esm({
351
415
  this.abortController?.abort();
352
416
  }, this.timeoutMs);
353
417
  const combinedSignal = signal ? anySignal([signal, this.abortController.signal]) : this.abortController.signal;
418
+ const attemptStart = nowMs();
354
419
  try {
355
420
  const response = await undiciFetch(url, {
356
421
  method,
@@ -359,15 +424,45 @@ var init_http = __esm({
359
424
  signal: combinedSignal
360
425
  });
361
426
  if (timeoutId != null) clearTimeout(timeoutId);
362
- if (response.ok) return { response, traceId };
427
+ logSdkTiming("http.request", "headers", attemptStart, {
428
+ method,
429
+ path: timingPath,
430
+ status: response.status,
431
+ attempt,
432
+ server_trace_id: traceId
433
+ });
434
+ if (response.ok) {
435
+ logSdkTiming("http.request", "complete", operationStart, {
436
+ method,
437
+ path: timingPath,
438
+ status: response.status,
439
+ attempts: attempt + 1,
440
+ server_trace_id: traceId
441
+ });
442
+ return { response, traceId };
443
+ }
363
444
  if (retryableStatusCodes.has(response.status) && attempt < this.maxRetries) {
364
445
  lastError = new RemoteAPIError(
365
446
  response.status,
366
447
  await response.text().catch(() => "")
367
448
  );
449
+ logSdkTimingEvent("http.request", "retryable_status", {
450
+ method,
451
+ path: timingPath,
452
+ status: response.status,
453
+ attempt,
454
+ server_trace_id: traceId
455
+ });
368
456
  continue;
369
457
  }
370
458
  if (allowHttpErrors || allowedErrorStatusCodes.has(response.status)) {
459
+ logSdkTiming("http.request", "complete", operationStart, {
460
+ method,
461
+ path: timingPath,
462
+ status: response.status,
463
+ attempts: attempt + 1,
464
+ server_trace_id: traceId
465
+ });
371
466
  return { response, traceId };
372
467
  }
373
468
  const errorBody = await response.text().catch(() => "");
@@ -383,6 +478,13 @@ var init_http = __esm({
383
478
  });
384
479
  }
385
480
  lastError = err instanceof Error ? err : new Error(String(err));
481
+ logSdkTiming("http.request", "error", attemptStart, {
482
+ method,
483
+ path: timingPath,
484
+ attempt,
485
+ server_trace_id: traceId,
486
+ error: timedOut ? `request timed out after ${this.timeoutMs}ms` : describeError(err)
487
+ });
386
488
  if (attempt >= this.maxRetries) {
387
489
  const detail = timedOut ? `request timed out after ${this.timeoutMs}ms` : describeError(err);
388
490
  throw new SandboxConnectionError(detail, { cause: err });
@@ -3097,6 +3199,7 @@ var init_sandbox = __esm({
3097
3199
  init_models();
3098
3200
  init_tunnel();
3099
3201
  init_sse();
3202
+ init_sdk_timings();
3100
3203
  init_url();
3101
3204
  DEFAULT_PROCESS_USER = "tl-user";
3102
3205
  SandboxProxyConnection = class {
@@ -3124,7 +3227,12 @@ var init_sandbox = __esm({
3124
3227
  if (this.resolvePromise != null) {
3125
3228
  return this.resolvePromise;
3126
3229
  }
3127
- this.resolvePromise = this.resolveProxyInfo(this.sandbox._getLifecycleIdentifier()).then((info) => {
3230
+ const identifier = this.sandbox._getLifecycleIdentifier();
3231
+ const resolveStart = nowMs();
3232
+ logSdkTimingEvent("sandbox.proxy", "resolve_start", {
3233
+ sandbox_id: identifier
3234
+ });
3235
+ this.resolvePromise = this.resolveProxyInfo(identifier).then((info) => {
3128
3236
  this.resolveProxyInfo = void 0;
3129
3237
  this.sandbox.traceId = info.traceId;
3130
3238
  this.sandbox._setLifecycleIdentifier(info.sandboxId);
@@ -3134,6 +3242,12 @@ var init_sandbox = __esm({
3134
3242
  const nextHttp = this.configureProxy(proxyUrl, info.sandboxId, this.routingHint);
3135
3243
  this.http.close();
3136
3244
  this.http = nextHttp;
3245
+ logSdkTiming("sandbox.proxy", "resolve_complete", resolveStart, {
3246
+ sandbox_id: info.sandboxId,
3247
+ server_trace_id: info.traceId,
3248
+ routing_hint: this.routingHint,
3249
+ ingress_endpoint: info.ingressEndpoint
3250
+ });
3137
3251
  }).finally(() => {
3138
3252
  this.resolvePromise = null;
3139
3253
  });
@@ -3594,6 +3708,7 @@ var init_sandbox = __esm({
3594
3708
  * the process, streams output, and delivers the exit code over one connection.
3595
3709
  */
3596
3710
  async run(command, options) {
3711
+ const opStart = nowMs();
3597
3712
  const body = { command };
3598
3713
  if (options?.args) body.args = options.args;
3599
3714
  if (options?.env) body.env = options.env;
@@ -3601,15 +3716,28 @@ var init_sandbox = __esm({
3601
3716
  if (options?.timeout != null) body.timeout = options.timeout;
3602
3717
  const user = processUserPayload(options?.user);
3603
3718
  body.user = user;
3719
+ logSdkTimingEvent("sandbox.run", "start", {
3720
+ sandbox_id: this.sandboxId,
3721
+ command: sdkTimingPayloadsEnabled() ? command : void 0,
3722
+ command_length: command.length
3723
+ });
3724
+ const requestStart = nowMs();
3604
3725
  const sseStream = await this.http.requestStream(
3605
3726
  "POST",
3606
3727
  "/api/v1/processes/run",
3607
3728
  { json: body }
3608
3729
  );
3609
3730
  const traceId = sseStream.traceId;
3731
+ logSdkTiming("sandbox.run", "stream_headers", requestStart, {
3732
+ sandbox_id: this.sandboxId,
3733
+ server_trace_id: traceId,
3734
+ command: sdkTimingPayloadsEnabled() ? command : void 0,
3735
+ command_length: command.length
3736
+ });
3610
3737
  const stdoutLines = [];
3611
3738
  const stderrLines = [];
3612
3739
  let exitCode = -1;
3740
+ const streamStart = nowMs();
3613
3741
  for await (const raw of parseSSEStream(sseStream)) {
3614
3742
  if (typeof raw.line === "string") {
3615
3743
  if (raw.stream === "stderr") {
@@ -3625,6 +3753,20 @@ var init_sandbox = __esm({
3625
3753
  }
3626
3754
  }
3627
3755
  }
3756
+ logSdkTiming("sandbox.run", "stream_complete", streamStart, {
3757
+ sandbox_id: this.sandboxId,
3758
+ server_trace_id: traceId,
3759
+ command: sdkTimingPayloadsEnabled() ? command : void 0,
3760
+ command_length: command.length,
3761
+ exit_code: exitCode
3762
+ });
3763
+ logSdkTiming("sandbox.run", "complete", opStart, {
3764
+ sandbox_id: this.sandboxId,
3765
+ server_trace_id: traceId,
3766
+ command: sdkTimingPayloadsEnabled() ? command : void 0,
3767
+ command_length: command.length,
3768
+ exit_code: exitCode
3769
+ });
3628
3770
  return Object.assign(
3629
3771
  { exitCode, stdout: stdoutLines.join("\n"), stderr: stderrLines.join("\n") },
3630
3772
  { traceId }
@@ -4102,6 +4244,7 @@ var init_client = __esm({
4102
4244
  init_http();
4103
4245
  init_models();
4104
4246
  init_sandbox();
4247
+ init_sdk_timings();
4105
4248
  init_url();
4106
4249
  CREATE_SANDBOX_RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([502, 503]);
4107
4250
  CREATE_SANDBOX_ALLOWED_ERROR_STATUS_CODES = /* @__PURE__ */ new Set([504]);
@@ -4631,9 +4774,21 @@ var init_client = __esm({
4631
4774
  if (options?.poolId != null && options?.cloudInit != null) {
4632
4775
  throw new SandboxError("cloud-init cannot be used with poolId");
4633
4776
  }
4777
+ const opStart = nowMs();
4634
4778
  const requestTimeout = options?.requestTimeout ?? options?.startupTimeout ?? this.requestTimeoutMs / 1e3;
4635
4779
  const requestClient = this.withRequestTimeout(requestTimeout);
4780
+ logSdkTimingEvent("sandbox.create", "start", {
4781
+ request_timeout_s: requestTimeout,
4782
+ image: options?.image,
4783
+ pool_id: options?.poolId
4784
+ });
4785
+ const createStart = nowMs();
4636
4786
  const result = options?.poolId != null ? await requestClient.claim(options.poolId) : await requestClient.create(options);
4787
+ logSdkTiming("sandbox.create", options?.poolId != null ? "claim_response" : "create_response", createStart, {
4788
+ sandbox_id: result.sandboxId,
4789
+ status: result.status,
4790
+ server_trace_id: result.traceId
4791
+ });
4637
4792
  const requestedName = options?.poolId != null ? null : options?.name ?? null;
4638
4793
  const finishConnect = (routingHint, name, ingressEndpoint) => {
4639
4794
  const sandbox = requestClient.connect(
@@ -4646,6 +4801,13 @@ var init_client = __esm({
4646
4801
  sandbox.traceId = result.traceId;
4647
4802
  sandbox._setLifecycleIdentifier(result.sandboxId);
4648
4803
  sandbox._setName(name ?? requestedName);
4804
+ logSdkTiming("sandbox.create", "complete", opStart, {
4805
+ sandbox_id: result.sandboxId,
4806
+ status: "running" /* RUNNING */,
4807
+ server_trace_id: result.traceId,
4808
+ routing_hint: routingHint,
4809
+ ingress_endpoint: ingressEndpoint
4810
+ });
4649
4811
  return sandbox;
4650
4812
  };
4651
4813
  if (result.status === "running" /* RUNNING */) {
@@ -4670,7 +4832,13 @@ var init_client = __esm({
4670
4832
  }
4671
4833
  const deadline = Date.now() + secondsToMillis4(requestTimeout);
4672
4834
  while (Date.now() < deadline) {
4835
+ const pollStart = nowMs();
4673
4836
  const info = await requestClient.get(result.sandboxId);
4837
+ logSdkTiming("sandbox.create", "poll_response", pollStart, {
4838
+ sandbox_id: result.sandboxId,
4839
+ status: info.status,
4840
+ server_trace_id: info.traceId
4841
+ });
4674
4842
  if (info.status === "running" /* RUNNING */) {
4675
4843
  return finishConnect(info.routingHint, info.name, info.ingressEndpoint);
4676
4844
  }