@letta-ai/letta-agent-sdk 0.8.78 → 0.8.80

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.
@@ -15,7 +15,8 @@ import type { CreateAgentOptions, LettaCodeBackend, LettaCodeClientOptions, Lett
15
15
  * protocol.
16
16
  * `remote` connects to a user-managed Letta Code app-server websocket endpoint.
17
17
  * `cloud` uses agents hosted on Letta Cloud, with an explicit remote
18
- * environment or SDK-managed sandbox.
18
+ * environment or SDK-managed sandbox. With `registerComputer`, the SDK also
19
+ * starts a local app-server that registers this machine as that computer.
19
20
  */
20
21
  export declare class LettaAgentClientBase implements AsyncDisposable {
21
22
  readonly backend: LettaCodeBackend;
@@ -72,6 +73,14 @@ export declare class LettaAgentClientBase implements AsyncDisposable {
72
73
  query(params: QueryParams): Query;
73
74
  private createQuerySession;
74
75
  private assertSessionBackend;
76
+ /**
77
+ * Build a Cloud session. Sessions that run on the computer this client
78
+ * registers start the local app-server first and wait for it to come online.
79
+ */
80
+ private createCloudSession;
81
+ private connectRegisteredComputer;
82
+ /** Start the app-server that registers this machine; overridden by the Node client. */
83
+ protected startRegisteredComputer(): Promise<void>;
75
84
  protected createLocalAgent(_options: CreateAgentOptions): Promise<string>;
76
85
  /**
77
86
  * Node-only skill seeding support (directory loading, memory-repo git
@@ -99,7 +108,10 @@ export declare class LettaAgentClientBase implements AsyncDisposable {
99
108
  * prompts, with or without an open session.
100
109
  */
101
110
  registerTools(options: RegisterToolsOptions): Promise<ToolRegistration>;
102
- /** How the local backend reaches its App Server; overridden by the Node client. */
111
+ /**
112
+ * How the local backend, or a Cloud client's registered computer, reaches
113
+ * its App Server; overridden by the Node client.
114
+ */
103
115
  protected localAppServerConnection(): AppServerSessionOptions;
104
116
  /**
105
117
  * Release resources owned directly by this client, including its pooled
@@ -1 +1 @@
1
- {"version":3,"file":"client-base.d.ts","sourceRoot":"","sources":["../src/client-base.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client-base.d.ts","sourceRoot":"","sources":["../src/client-base.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"client-entry.d.ts","sourceRoot":"","sources":["../src/client-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EACV,2BAA2B,EAC3B,4BAA4B,EAC7B,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,+BAA+B,GACvC,4BAA4B,GAC5B,2BAA2B,CAAC;AAEhC;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,oBAAoB;gBAC5C,OAAO,EAAE,+BAA+B;CAMrD;AAED,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACrF,mBAAmB,oBAAoB,CAAC;AACxC,YAAY,EACV,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,mBAAmB,uBAAuB,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,qCAAqC,EAAE,MAAM,gBAAgB,CAAC;AACvE,mBAAmB,YAAY,CAAC;AAChC,mBAAmB,kBAAkB,CAAC"}
1
+ {"version":3,"file":"client-entry.d.ts","sourceRoot":"","sources":["../src/client-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EACV,2BAA2B,EAC3B,4BAA4B,EAC7B,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,+BAA+B,GACvC,4BAA4B,GAC5B,2BAA2B,CAAC;AAEhC;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,oBAAoB;gBAC5C,OAAO,EAAE,+BAA+B;CAWrD;AAED,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACrF,mBAAmB,oBAAoB,CAAC;AACxC,YAAY,EACV,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,mBAAmB,uBAAuB,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,qCAAqC,EAAE,MAAM,gBAAgB,CAAC;AACvE,mBAAmB,YAAY,CAAC;AAChC,mBAAmB,kBAAkB,CAAC"}
@@ -9481,18 +9481,39 @@ function onceSocketEvent(socket, type, listener) {
9481
9481
  });
9482
9482
  return detach;
9483
9483
  }
9484
- function waitForSocketOpen(socket) {
9484
+ function waitForSocketOpen(socket, timeoutMs) {
9485
9485
  if (socket.readyState === WEBSOCKET_OPEN_STATE) {
9486
9486
  return Promise.resolve();
9487
9487
  }
9488
- return new Promise((resolve, reject) => {
9488
+ return new Promise((resolvePromise, rejectPromise) => {
9489
+ let settled = false;
9490
+ const resolve = () => {
9491
+ if (settled)
9492
+ return;
9493
+ settled = true;
9494
+ resolvePromise();
9495
+ };
9496
+ const reject = (error) => {
9497
+ if (settled)
9498
+ return;
9499
+ settled = true;
9500
+ rejectPromise(error);
9501
+ };
9489
9502
  let detachOpen = () => {};
9490
9503
  let detachError = () => {};
9504
+ let detachClose = () => {};
9491
9505
  let detachResponse = () => {};
9492
9506
  let detachBody = () => {};
9507
+ let upgradeRejected = false;
9508
+ const timer = timeoutMs > 0 ? setTimeout(() => {
9509
+ cleanup();
9510
+ reject(new Error(`App-server WebSocket failed to open: timed out after ${timeoutMs}ms`));
9511
+ }, timeoutMs) : undefined;
9493
9512
  const cleanup = () => {
9513
+ clearTimeout(timer);
9494
9514
  detachOpen();
9495
9515
  detachError();
9516
+ detachClose();
9496
9517
  detachResponse();
9497
9518
  detachBody();
9498
9519
  };
@@ -9504,6 +9525,7 @@ function waitForSocketOpen(socket) {
9504
9525
  const onResponse = (_request, response) => {
9505
9526
  if (!response)
9506
9527
  return;
9528
+ upgradeRejected = true;
9507
9529
  const request = _request;
9508
9530
  let body = Buffer.alloc(0);
9509
9531
  let finished = false;
@@ -9545,6 +9567,12 @@ function waitForSocketOpen(socket) {
9545
9567
  cleanup();
9546
9568
  reject(new Error(`App-server WebSocket failed to open: ${String(event)}`));
9547
9569
  });
9570
+ detachClose = onceSocketEvent(socket, "close", () => {
9571
+ if (upgradeRejected)
9572
+ return;
9573
+ cleanup();
9574
+ reject(new Error("App-server WebSocket failed to open: closed before opening"));
9575
+ });
9548
9576
  });
9549
9577
  }
9550
9578
  function rawEventData(event) {
@@ -9612,7 +9640,7 @@ class AppServerClient {
9612
9640
  });
9613
9641
  }
9614
9642
  async connect() {
9615
- await waitForSocketOpen(this.socket);
9643
+ await waitForSocketOpen(this.socket, this.requestTimeoutMs);
9616
9644
  return this;
9617
9645
  }
9618
9646
  close() {
@@ -13236,6 +13264,7 @@ function externalToolGroups(tools) {
13236
13264
  return;
13237
13265
  return [
13238
13266
  {
13267
+ capabilities: { external_tool_call_cancel: true },
13239
13268
  tools: tools.map((tool) => ({
13240
13269
  name: tool.name,
13241
13270
  label: tool.label,
@@ -13248,14 +13277,14 @@ function externalToolGroups(tools) {
13248
13277
  var MAX_REMEMBERED_EXTERNAL_TOOL_CALLS = 200;
13249
13278
  function createExternalToolCallHandler(externalTools, fallbackRuntime) {
13250
13279
  const calls = new Map;
13251
- const execute = async (request) => {
13280
+ const execute = async (request, signal) => {
13252
13281
  const tool = externalTools.get(request.tool_name);
13253
13282
  if (!tool) {
13254
13283
  throw new Error(`Unknown external tool: ${request.tool_name}`);
13255
13284
  }
13256
13285
  const runtime = request.runtime ?? fallbackRuntime?.() ?? null;
13257
13286
  const context = runtime ? { toolCallId: request.tool_call_id, agentId: runtime.agent_id, conversationId: runtime.conversation_id } : undefined;
13258
- const result = await tool.execute(request.tool_call_id, request.input, undefined, undefined, context);
13287
+ const result = await tool.execute(request.tool_call_id, request.input, signal, undefined, context);
13259
13288
  return {
13260
13289
  content: result.content.map((part) => ({
13261
13290
  type: part.type,
@@ -13266,15 +13295,15 @@ function createExternalToolCallHandler(externalTools, fallbackRuntime) {
13266
13295
  ...result.isError === true ? { is_error: true } : {}
13267
13296
  };
13268
13297
  };
13269
- return (request) => {
13298
+ return (request, signal) => {
13270
13299
  const requestId = request.request_id;
13271
13300
  if (typeof requestId !== "string" || requestId.length === 0) {
13272
- return execute(request);
13301
+ return execute(request, signal);
13273
13302
  }
13274
13303
  const existing = calls.get(requestId);
13275
13304
  if (existing)
13276
13305
  return existing;
13277
- const call = execute(request);
13306
+ const call = execute(request, signal);
13278
13307
  calls.set(requestId, call);
13279
13308
  while (calls.size > MAX_REMEMBERED_EXTERNAL_TOOL_CALLS) {
13280
13309
  const oldest = calls.keys().next().value;
@@ -13285,6 +13314,49 @@ function createExternalToolCallHandler(externalTools, fallbackRuntime) {
13285
13314
  return call;
13286
13315
  };
13287
13316
  }
13317
+ function registerExternalToolCallHandler(client, handler) {
13318
+ const pending = new Map;
13319
+ const completed = new Set;
13320
+ const remove = client.onMessage((raw, channel) => {
13321
+ if (channel !== "control")
13322
+ return;
13323
+ const message = raw;
13324
+ const requestId = message.request_id;
13325
+ if (typeof requestId !== "string")
13326
+ return;
13327
+ if (message.type === "external_tool_call_cancel") {
13328
+ const call = pending.get(requestId);
13329
+ if (!call)
13330
+ return;
13331
+ call.finish({ error: "cancelled" });
13332
+ call.controller.abort(message.reason);
13333
+ return;
13334
+ }
13335
+ if (message.type !== "external_tool_call_request" || pending.has(requestId) || completed.has(requestId))
13336
+ return;
13337
+ const controller = new AbortController;
13338
+ const finish = (response) => {
13339
+ if (!pending.delete(requestId))
13340
+ return;
13341
+ completed.add(requestId);
13342
+ if (completed.size > MAX_REMEMBERED_EXTERNAL_TOOL_CALLS)
13343
+ completed.delete(completed.values().next().value);
13344
+ client.send({ type: "external_tool_call_response", request_id: requestId, ...response });
13345
+ };
13346
+ pending.set(requestId, { controller, finish });
13347
+ try {
13348
+ Promise.resolve(handler(raw, controller.signal)).then((result) => finish({ result }), (error) => finish({ error: error instanceof Error ? error.message : String(error) }));
13349
+ } catch (error) {
13350
+ finish({ error: error instanceof Error ? error.message : String(error) });
13351
+ }
13352
+ });
13353
+ return () => {
13354
+ remove();
13355
+ for (const call of pending.values())
13356
+ call.controller.abort();
13357
+ pending.clear();
13358
+ };
13359
+ }
13288
13360
 
13289
13361
  // src/runtime-tool-policy.ts
13290
13362
  var RUNTIME_TOOL_POLICY_CAPABILITY = "runtime_tool_policy";
@@ -15109,7 +15181,7 @@ class AppServerSession extends RemoteClientSessionCore {
15109
15181
  getOptions: () => this.currentOptions()
15110
15182
  });
15111
15183
  if (this.externalTools.size > 0 || this.inheritedTools) {
15112
- this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools, () => this.runtime));
15184
+ this.removeExternalToolHandler = registerExternalToolCallHandler(client, createExternalToolCallHandler(this.externalTools, () => this.runtime));
15113
15185
  }
15114
15186
  try {
15115
15187
  await client.connect();
@@ -15949,6 +16021,19 @@ function validateCloudClientOptions(options) {
15949
16021
  const field = options.computer !== undefined ? "computer" : "environment";
15950
16022
  throw new Error(`Letta Cloud sessions cannot specify both ${field} and sandbox options.`);
15951
16023
  }
16024
+ if (options.registerComputer !== undefined) {
16025
+ const name = options.registerComputer?.name;
16026
+ if (typeof name !== "string" || !name.trim()) {
16027
+ throw new Error("Invalid registerComputer.name. Expected a non-empty string.");
16028
+ }
16029
+ if (options.computer !== undefined || options.environment !== undefined) {
16030
+ const field = options.computer !== undefined ? "computer" : "environment";
16031
+ throw new Error(`Letta Cloud clients cannot specify both ${field} and registerComputer. Use computer for a machine that is already connected, or registerComputer to connect this one.`);
16032
+ }
16033
+ if (options.sandbox !== undefined) {
16034
+ throw new Error("Letta Cloud clients cannot specify both registerComputer and sandbox options.");
16035
+ }
16036
+ }
15952
16037
  if (options.webSocketAuth !== undefined && options.webSocketAuth !== "header" && options.webSocketAuth !== "query") {
15953
16038
  throw new Error("Invalid webSocketAuth. Valid values: header, query.");
15954
16039
  }
@@ -16042,6 +16127,7 @@ function assertCloudSessionOptionsSupported(action, options) {
16042
16127
  class CloudEnvironmentSession extends RemoteClientSessionCore {
16043
16128
  cloudOptions;
16044
16129
  apiClient;
16130
+ connectRegisteredComputer;
16045
16131
  sandbox;
16046
16132
  connectionId = null;
16047
16133
  removeExternalToolHandler = null;
@@ -16057,13 +16143,14 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
16057
16143
  repositoryIdsRequiringCleanupRecompile = new Set;
16058
16144
  repositoryManagement;
16059
16145
  cloudMode;
16060
- constructor(cloudOptions, mode, apiClient = createCloudClient(cloudOptions)) {
16146
+ constructor(cloudOptions, mode, apiClient = createCloudClient(cloudOptions), connectRegisteredComputer) {
16061
16147
  super(mode, {
16062
16148
  label: "cloud",
16063
16149
  requestTimeoutMs: cloudOptions.requestTimeoutMs ?? DEFAULT_TURN_TIMEOUT_MS
16064
16150
  });
16065
16151
  this.cloudOptions = cloudOptions;
16066
16152
  this.apiClient = apiClient;
16153
+ this.connectRegisteredComputer = connectRegisteredComputer;
16067
16154
  this.cloudMode = mode;
16068
16155
  this.repositoryManagement = new CloudManagementTransport(apiClient);
16069
16156
  this.sandbox = this.effectiveEnvironment() === undefined ? {
@@ -16199,7 +16286,7 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
16199
16286
  getOptions: () => this.currentOptions()
16200
16287
  });
16201
16288
  if (this.externalTools.size > 0) {
16202
- this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools, () => this.runtime));
16289
+ this.removeExternalToolHandler = registerExternalToolCallHandler(client, createExternalToolCallHandler(this.externalTools, () => this.runtime));
16203
16290
  }
16204
16291
  }
16205
16292
  cleanupTransportHandlers() {
@@ -16466,6 +16553,8 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
16466
16553
  return this.createManagedSandboxConnection(runtime);
16467
16554
  }
16468
16555
  async resolveExplicitConnection(environment) {
16556
+ if (this.connectRegisteredComputer)
16557
+ return this.connectRegisteredComputer();
16469
16558
  const target = environmentToRemoteTarget(environment);
16470
16559
  const resolved = await this.remoteEnvironmentClient().resolveEnvironment(target);
16471
16560
  return { connectionId: resolved.connectionId };
@@ -16955,12 +17044,12 @@ class ToolRegistry {
16955
17044
  ...this.options.WebSocket ? { WebSocket: this.options.WebSocket } : {},
16956
17045
  ...this.options.requestTimeoutMs !== undefined ? { requestTimeoutMs: this.options.requestTimeoutMs } : {}
16957
17046
  }));
16958
- client.onExternalToolCall(async (request) => {
17047
+ registerExternalToolCallHandler(client, async (request, signal) => {
16959
17048
  const runtime = request.runtime;
16960
17049
  const entry = runtime && [...this.entries].find((candidate) => candidate.runtimes.some((r) => runtimeKey(r) === runtimeKey(runtime)));
16961
17050
  if (!entry)
16962
17051
  throw new Error(`No tools registered for conversation ${runtime?.conversation_id}`);
16963
- return entry.call(request);
17052
+ return entry.call(request, signal);
16964
17053
  });
16965
17054
  try {
16966
17055
  await client.connect();
@@ -17265,6 +17354,15 @@ function stripCloudExecutionOptions(options) {
17265
17354
  delete sessionOptions.filesystemConfinement;
17266
17355
  return sessionOptions;
17267
17356
  }
17357
+ var REGISTERED_COMPUTER_READY_TIMEOUT_MS = 30000;
17358
+ var REGISTERED_COMPUTER_POLL_INTERVAL_MS = 500;
17359
+ function registeredComputerName(options) {
17360
+ return options.backend === "cloud" ? options.registerComputer?.name : undefined;
17361
+ }
17362
+ function isRegisteredComputerPending(error) {
17363
+ const message = error instanceof Error ? error.message : String(error);
17364
+ return message.startsWith("Computer not found") || message.startsWith("Computer is offline");
17365
+ }
17268
17366
  function hasRepositoryResources(options) {
17269
17367
  return options.resources !== undefined && options.resources.length > 0;
17270
17368
  }
@@ -17323,7 +17421,8 @@ class LettaAgentClientBase {
17323
17421
  throw new Error(`Invalid Letta Code backend '${String(backend)}'. Valid values: local, remote, cloud.`);
17324
17422
  }
17325
17423
  this.backend = backend;
17326
- this.computer = getOptionsComputer(options);
17424
+ const registeredName = registeredComputerName(options);
17425
+ this.computer = getOptionsComputer(options) ?? (registeredName !== undefined ? { name: registeredName } : undefined);
17327
17426
  this.environment = this.computer;
17328
17427
  this.options = options;
17329
17428
  this.agents = createAgentsClient(() => this.getManagementTransport(), () => this.getAgentRepositoriesClient());
@@ -17419,12 +17518,12 @@ class LettaAgentClientBase {
17419
17518
  });
17420
17519
  }
17421
17520
  if (this.backend === "cloud") {
17422
- return new CloudEnvironmentSession(this.cloudOptions(), {
17521
+ return this.createCloudSession({
17423
17522
  kind: "session",
17424
17523
  agentId,
17425
17524
  newConversation: true,
17426
17525
  options
17427
- }, this.getCloudClient());
17526
+ });
17428
17527
  }
17429
17528
  return this.createLocalSession(agentId, options);
17430
17529
  }
@@ -17450,19 +17549,7 @@ class LettaAgentClientBase {
17450
17549
  return session2;
17451
17550
  }
17452
17551
  if (this.backend === "cloud") {
17453
- if (looksLikeConversationId(id)) {
17454
- return new CloudEnvironmentSession(this.cloudOptions(), {
17455
- kind: "session",
17456
- conversationId: id,
17457
- options
17458
- }, this.getCloudClient());
17459
- }
17460
- return new CloudEnvironmentSession(this.cloudOptions(), {
17461
- kind: "session",
17462
- agentId: id,
17463
- defaultConversation: true,
17464
- options
17465
- }, this.getCloudClient());
17552
+ return this.createCloudSession(looksLikeConversationId(id) ? { kind: "session", conversationId: id, options } : { kind: "session", agentId: id, defaultConversation: true, options });
17466
17553
  }
17467
17554
  const session = this.resumeLocalSession(id, options);
17468
17555
  if (inherited && session instanceof AppServerSession)
@@ -17528,11 +17615,11 @@ class LettaAgentClientBase {
17528
17615
  if (!conversation || typeof conversation !== "object" || typeof conversation.id !== "string") {
17529
17616
  throw new Error("Cloud query conversation response did not include a conversation id.");
17530
17617
  }
17531
- return new CloudEnvironmentSession(this.cloudOptions(), {
17618
+ return this.createCloudSession({
17532
17619
  kind: "conversation",
17533
17620
  conversationId: conversation.id,
17534
17621
  options: sessionOptions
17535
- }, this.getCloudClient());
17622
+ });
17536
17623
  }
17537
17624
  return this.createLocalQuerySession(options, sessionOptions);
17538
17625
  }
@@ -17597,6 +17684,29 @@ class LettaAgentClientBase {
17597
17684
  }
17598
17685
  throw new Error(`LettaAgentClient backend '${this.backend}' is not implemented yet. ${action} currently supports backend 'local' only.`);
17599
17686
  }
17687
+ createCloudSession(mode) {
17688
+ const name = registeredComputerName(this.options);
17689
+ const sessionComputer = mode.options.computer ?? mode.options.environment;
17690
+ return new CloudEnvironmentSession(this.cloudOptions(), mode, this.getCloudClient(), name !== undefined && sessionComputer === undefined ? () => this.connectRegisteredComputer(name) : undefined);
17691
+ }
17692
+ async connectRegisteredComputer(name) {
17693
+ await this.startRegisteredComputer();
17694
+ const deadline = Date.now() + REGISTERED_COMPUTER_READY_TIMEOUT_MS;
17695
+ while (true) {
17696
+ try {
17697
+ const resolved = await this.getComputersClient().resolve({ name });
17698
+ return { connectionId: resolved.connectionId };
17699
+ } catch (error) {
17700
+ if (!isRegisteredComputerPending(error) || Date.now() >= deadline) {
17701
+ throw error;
17702
+ }
17703
+ await new Promise((resolve) => setTimeout(resolve, REGISTERED_COMPUTER_POLL_INTERVAL_MS));
17704
+ }
17705
+ }
17706
+ }
17707
+ startRegisteredComputer() {
17708
+ return Promise.reject(this.localBackendUnavailableError());
17709
+ }
17600
17710
  createLocalAgent(_options) {
17601
17711
  throw this.localBackendUnavailableError();
17602
17712
  }
@@ -17677,8 +17787,8 @@ class LettaAgentClientBase {
17677
17787
  }
17678
17788
  registerTools(options) {
17679
17789
  this.assertOpen();
17680
- if (this.backend === "cloud") {
17681
- return Promise.reject(new Error('registerTools() requires backend: "local" or "remote". Cloud sessions register tools through the tools session option.'));
17790
+ if (this.backend === "cloud" && registeredComputerName(this.options) === undefined) {
17791
+ return Promise.reject(new Error('registerTools() requires backend: "local" or "remote", or backend: "cloud" with registerComputer. Other Cloud sessions register tools through the tools session option.'));
17682
17792
  }
17683
17793
  this.toolRegistry ??= new ToolRegistry(this.backend === "remote" ? this.remoteOptions() : this.localAppServerConnection());
17684
17794
  return this.toolRegistry.register(options);
@@ -17709,7 +17819,8 @@ class LettaAgentClientBase {
17709
17819
  if (this.backend !== "cloud") {
17710
17820
  throw new Error('Letta Cloud options requested for non-"cloud" backend.');
17711
17821
  }
17712
- return this.options;
17822
+ const options = this.options;
17823
+ return options.registerComputer !== undefined ? { ...options, computer: { name: options.registerComputer.name } } : options;
17713
17824
  }
17714
17825
  }
17715
17826
  // src/stream-events.ts
@@ -18224,6 +18335,9 @@ class LettaAgentClient extends LettaAgentClientBase {
18224
18335
  if (this.backend === "local") {
18225
18336
  throw this.localBackendUnavailableError();
18226
18337
  }
18338
+ if (options.backend === "cloud" && options.registerComputer !== undefined) {
18339
+ throw new Error('registerComputer starts a local Letta Code app-server. Import from "@letta-ai/letta-agent-sdk" in Node.js to use it.');
18340
+ }
18227
18341
  }
18228
18342
  }
18229
18343
  export {
@@ -18236,4 +18350,4 @@ export {
18236
18350
  CloudManagedSandboxExpiredError
18237
18351
  };
18238
18352
 
18239
- //# debugId=E1CFC3CF63B8416B64756E2164756E21
18353
+ //# debugId=56DE4B3DCF03FA0964756E2164756E21