tensorlake 0.4.45 → 0.4.47

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.
@@ -76,6 +76,7 @@ interface UpdateSandboxOptions {
76
76
  interface CreateSandboxResponse {
77
77
  sandboxId: string;
78
78
  status: SandboxStatus;
79
+ routingHint?: string;
79
80
  }
80
81
  interface SandboxInfo {
81
82
  sandboxId: string;
@@ -267,6 +268,7 @@ interface SandboxOptions {
267
268
  apiKey?: string;
268
269
  organizationId?: string;
269
270
  projectId?: string;
271
+ routingHint?: string;
270
272
  }
271
273
  interface CreateAndConnectOptions extends CreateSandboxOptions {
272
274
  poolId?: string;
@@ -76,6 +76,7 @@ interface UpdateSandboxOptions {
76
76
  interface CreateSandboxResponse {
77
77
  sandboxId: string;
78
78
  status: SandboxStatus;
79
+ routingHint?: string;
79
80
  }
80
81
  interface SandboxInfo {
81
82
  sandboxId: string;
@@ -267,6 +268,7 @@ interface SandboxOptions {
267
268
  apiKey?: string;
268
269
  organizationId?: string;
269
270
  projectId?: string;
271
+ routingHint?: string;
270
272
  }
271
273
  interface CreateAndConnectOptions extends CreateSandboxOptions {
272
274
  poolId?: string;
@@ -177,6 +177,9 @@ var HttpClient = class {
177
177
  if (options.hostHeader) {
178
178
  this.headers["Host"] = options.hostHeader;
179
179
  }
180
+ if (options.routingHint) {
181
+ this.headers["X-Tensorlake-Route-Hint"] = options.routingHint;
182
+ }
180
183
  }
181
184
  close() {
182
185
  this.abortController?.abort();
@@ -211,12 +214,13 @@ var HttpClient = class {
211
214
  const buffer = await response.arrayBuffer();
212
215
  return new Uint8Array(buffer);
213
216
  }
214
- /** Make a request and return the raw Response (for SSE streaming). */
217
+ /** Make a request and return the response body as an SSE stream. */
215
218
  async requestStream(method, path2, options) {
216
219
  const response = await this.requestResponse(
217
220
  method,
218
221
  path2,
219
222
  {
223
+ json: options?.json,
220
224
  headers: { Accept: "text/event-stream" },
221
225
  signal: options?.signal
222
226
  }
@@ -3070,7 +3074,8 @@ var Sandbox = class {
3070
3074
  apiKey: options.apiKey,
3071
3075
  organizationId: options.organizationId,
3072
3076
  projectId: options.projectId,
3073
- hostHeader
3077
+ hostHeader,
3078
+ routingHint: options.routingHint
3074
3079
  });
3075
3080
  }
3076
3081
  /** @internal Used by SandboxClient.createAndConnect to set ownership. */
@@ -3091,37 +3096,45 @@ var Sandbox = class {
3091
3096
  }
3092
3097
  }
3093
3098
  // --- High-level convenience ---
3099
+ /**
3100
+ * Run a command to completion and return its output.
3101
+ *
3102
+ * Uses a single streaming `POST /api/v1/processes/run` request that starts
3103
+ * the process, streams output, and delivers the exit code over one connection.
3104
+ */
3094
3105
  async run(command, options) {
3095
- const proc = await this.startProcess(command, {
3096
- args: options?.args,
3097
- env: options?.env,
3098
- workingDir: options?.workingDir
3099
- });
3100
- const deadline = options?.timeout ? Date.now() + options.timeout * 1e3 : null;
3101
- let info;
3102
- while (true) {
3103
- info = await this.getProcess(proc.pid);
3104
- if (info.status !== "running" /* RUNNING */) break;
3105
- if (deadline && Date.now() > deadline) {
3106
- await this.killProcess(proc.pid);
3107
- throw new SandboxError(`Command timed out after ${options.timeout}s`);
3106
+ const body = { command };
3107
+ if (options?.args) body.args = options.args;
3108
+ if (options?.env) body.env = options.env;
3109
+ if (options?.workingDir) body.working_dir = options.workingDir;
3110
+ if (options?.timeout != null) body.timeout = options.timeout;
3111
+ const sseStream = await this.http.requestStream(
3112
+ "POST",
3113
+ "/api/v1/processes/run",
3114
+ { json: body }
3115
+ );
3116
+ const stdoutLines = [];
3117
+ const stderrLines = [];
3118
+ let exitCode = -1;
3119
+ for await (const raw of parseSSEStream(sseStream)) {
3120
+ if (typeof raw.line === "string") {
3121
+ if (raw.stream === "stderr") {
3122
+ stderrLines.push(raw.line);
3123
+ } else {
3124
+ stdoutLines.push(raw.line);
3125
+ }
3126
+ } else if ("exit_code" in raw || "signal" in raw) {
3127
+ if (typeof raw.exit_code === "number") {
3128
+ exitCode = raw.exit_code;
3129
+ } else if (typeof raw.signal === "number") {
3130
+ exitCode = -raw.signal;
3131
+ }
3108
3132
  }
3109
- await sleep2(100);
3110
- }
3111
- const stdoutResp = await this.getStdout(proc.pid);
3112
- const stderrResp = await this.getStderr(proc.pid);
3113
- let exitCode;
3114
- if (info.exitCode != null) {
3115
- exitCode = info.exitCode;
3116
- } else if (info.signal != null) {
3117
- exitCode = -info.signal;
3118
- } else {
3119
- exitCode = -1;
3120
3133
  }
3121
3134
  return {
3122
3135
  exitCode,
3123
- stdout: stdoutResp.lines.join("\n"),
3124
- stderr: stderrResp.lines.join("\n")
3136
+ stdout: stdoutLines.join("\n"),
3137
+ stderr: stderrLines.join("\n")
3125
3138
  };
3126
3139
  }
3127
3140
  // --- Process management ---
@@ -3370,9 +3383,6 @@ var Sandbox = class {
3370
3383
  return fromSnakeKeys(raw);
3371
3384
  }
3372
3385
  };
3373
- function sleep2(ms) {
3374
- return new Promise((resolve) => setTimeout(resolve, ms));
3375
- }
3376
3386
 
3377
3387
  // src/client.ts
3378
3388
  var SandboxClient = class _SandboxClient {
@@ -3588,7 +3598,7 @@ var SandboxClient = class _SandboxClient {
3588
3598
  `Snapshot ${result.snapshotId} failed: ${info.error}`
3589
3599
  );
3590
3600
  }
3591
- await sleep3(pollInterval * 1e3);
3601
+ await sleep2(pollInterval * 1e3);
3592
3602
  }
3593
3603
  throw new SandboxError(
3594
3604
  `Snapshot ${result.snapshotId} did not complete within ${timeout}s`
@@ -3660,14 +3670,15 @@ var SandboxClient = class _SandboxClient {
3660
3670
  );
3661
3671
  }
3662
3672
  // --- Connect ---
3663
- connect(identifier, proxyUrl) {
3673
+ connect(identifier, proxyUrl, routingHint) {
3664
3674
  const resolvedProxy = proxyUrl ?? resolveProxyUrl(this.apiUrl);
3665
3675
  return new Sandbox({
3666
3676
  sandboxId: identifier,
3667
3677
  proxyUrl: resolvedProxy,
3668
3678
  apiKey: this.apiKey,
3669
3679
  organizationId: this.organizationId,
3670
- projectId: this.projectId
3680
+ projectId: this.projectId,
3681
+ routingHint
3671
3682
  });
3672
3683
  }
3673
3684
  async createAndConnect(options) {
@@ -3678,6 +3689,11 @@ var SandboxClient = class _SandboxClient {
3678
3689
  } else {
3679
3690
  result = await this.create(options);
3680
3691
  }
3692
+ if (result.status === "running" /* RUNNING */) {
3693
+ const sandbox = this.connect(result.sandboxId, options?.proxyUrl, result.routingHint);
3694
+ sandbox._setOwner(this);
3695
+ return sandbox;
3696
+ }
3681
3697
  const deadline = Date.now() + startupTimeout * 1e3;
3682
3698
  while (Date.now() < deadline) {
3683
3699
  const info = await this.get(result.sandboxId);
@@ -3691,7 +3707,7 @@ var SandboxClient = class _SandboxClient {
3691
3707
  `Sandbox ${result.sandboxId} terminated during startup`
3692
3708
  );
3693
3709
  }
3694
- await sleep3(500);
3710
+ await sleep2(500);
3695
3711
  }
3696
3712
  try {
3697
3713
  await this.delete(result.sandboxId);
@@ -3702,7 +3718,7 @@ var SandboxClient = class _SandboxClient {
3702
3718
  );
3703
3719
  }
3704
3720
  };
3705
- function sleep3(ms) {
3721
+ function sleep2(ms) {
3706
3722
  return new Promise((resolve) => setTimeout(resolve, ms));
3707
3723
  }
3708
3724
  var RESERVED_SANDBOX_MANAGEMENT_PORT = 9501;
@@ -4125,7 +4141,7 @@ async function runChecked(sandbox, command, args, env, workingDir) {
4125
4141
  }
4126
4142
  return result;
4127
4143
  }
4128
- async function runStreaming(sandbox, emit, sleep4, command, args = [], env, workingDir) {
4144
+ async function runStreaming(sandbox, emit, sleep3, command, args = [], env, workingDir) {
4129
4145
  const proc = await sandbox.startProcess(command, {
4130
4146
  args,
4131
4147
  env,
@@ -4150,13 +4166,13 @@ async function runStreaming(sandbox, emit, sleep4, command, args = [], env, work
4150
4166
  emitOutputLines(emit, "stderr", finalStderr, stderrSeen);
4151
4167
  break;
4152
4168
  }
4153
- await sleep4(300);
4169
+ await sleep3(300);
4154
4170
  }
4155
4171
  for (let i = 0; i < 10; i++) {
4156
4172
  if (info.exitCode != null || info.signal != null) {
4157
4173
  break;
4158
4174
  }
4159
- await sleep4(200);
4175
+ await sleep3(200);
4160
4176
  info = await sandbox.getProcess(proc.pid);
4161
4177
  }
4162
4178
  const exitCode = info.exitCode != null ? info.exitCode : info.signal != null ? -info.signal : 0;
@@ -4254,7 +4270,7 @@ async function copyFromContext(sandbox, emit, contextDir, sources, destination,
4254
4270
  await copyLocalPathToSandbox(sandbox, localSource, remoteDestination);
4255
4271
  }
4256
4272
  }
4257
- async function addUrlToSandbox(sandbox, emit, url, destination, workingDir, processEnv, sleep4) {
4273
+ async function addUrlToSandbox(sandbox, emit, url, destination, workingDir, processEnv, sleep3) {
4258
4274
  let destinationPath = resolveContainerPath(destination, workingDir);
4259
4275
  const parsedUrl = new URL(url);
4260
4276
  const fileName = import_node_path.default.posix.basename(parsedUrl.pathname.replace(/\/$/, "")) || "downloaded";
@@ -4270,7 +4286,7 @@ async function addUrlToSandbox(sandbox, emit, url, destination, workingDir, proc
4270
4286
  await runStreaming(
4271
4287
  sandbox,
4272
4288
  emit,
4273
- sleep4,
4289
+ sleep3,
4274
4290
  "sh",
4275
4291
  [
4276
4292
  "-c",
@@ -4280,7 +4296,7 @@ async function addUrlToSandbox(sandbox, emit, url, destination, workingDir, proc
4280
4296
  workingDir
4281
4297
  );
4282
4298
  }
4283
- async function executeDockerfilePlan(sandbox, plan, emit, sleep4) {
4299
+ async function executeDockerfilePlan(sandbox, plan, emit, sleep3) {
4284
4300
  const processEnv = { ...BUILD_SANDBOX_PIP_ENV };
4285
4301
  let workingDir = "/";
4286
4302
  for (const instruction of plan.instructions) {
@@ -4290,7 +4306,7 @@ async function executeDockerfilePlan(sandbox, plan, emit, sleep4) {
4290
4306
  await runStreaming(
4291
4307
  sandbox,
4292
4308
  emit,
4293
- sleep4,
4309
+ sleep3,
4294
4310
  "sh",
4295
4311
  ["-c", value],
4296
4312
  processEnv,
@@ -4347,7 +4363,7 @@ async function executeDockerfilePlan(sandbox, plan, emit, sleep4) {
4347
4363
  destination,
4348
4364
  workingDir,
4349
4365
  processEnv,
4350
- sleep4
4366
+ sleep3
4351
4367
  );
4352
4368
  } else {
4353
4369
  await copyFromContext(
@@ -4415,7 +4431,7 @@ async function registerImage(context, name, dockerfile, snapshotId, snapshotUri,
4415
4431
  }
4416
4432
  async function createSandboxImage(source, options = {}, deps = {}) {
4417
4433
  const emit = deps.emit ?? defaultEmit;
4418
- const sleep4 = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
4434
+ const sleep3 = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
4419
4435
  const context = buildContextFromEnv();
4420
4436
  const clientFactory = deps.createClient ?? createDefaultClient;
4421
4437
  const register = deps.registerImage ?? ((...args) => registerImage(...args));
@@ -4438,7 +4454,7 @@ async function createSandboxImage(source, options = {}, deps = {}) {
4438
4454
  type: "status",
4439
4455
  message: `Materializing image in sandbox ${sandbox.sandboxId}...`
4440
4456
  });
4441
- await executeDockerfilePlan(sandbox, plan, emit, sleep4);
4457
+ await executeDockerfilePlan(sandbox, plan, emit, sleep3);
4442
4458
  emit({ type: "status", message: "Creating snapshot..." });
4443
4459
  const snapshot = await client.snapshotAndWait(sandbox.sandboxId, {
4444
4460
  contentMode: "filesystem_only"