@letta-ai/letta-agent-sdk 0.3.3 → 0.5.0

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 (55) hide show
  1. package/AGENTS.md +0 -3
  2. package/README.md +12 -0
  3. package/dist/app-server-management.d.ts +3 -48
  4. package/dist/app-server-management.d.ts.map +1 -1
  5. package/dist/app-server-session.d.ts +0 -6
  6. package/dist/app-server-session.d.ts.map +1 -1
  7. package/dist/client-base.d.ts +7 -15
  8. package/dist/client-base.d.ts.map +1 -1
  9. package/dist/client-entry.js +369 -468
  10. package/dist/client-entry.js.map +13 -12
  11. package/dist/client.d.ts +3 -3
  12. package/dist/client.d.ts.map +1 -1
  13. package/dist/cloud-session.d.ts.map +1 -1
  14. package/dist/cloud-status-transport.d.ts +53 -0
  15. package/dist/cloud-status-transport.d.ts.map +1 -0
  16. package/dist/index.d.ts +7 -16
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +896 -2019
  19. package/dist/index.js.map +18 -18
  20. package/dist/local-app-server-session.d.ts +1 -1
  21. package/dist/local-app-server-session.d.ts.map +1 -1
  22. package/dist/local-app-server.d.ts +11 -0
  23. package/dist/local-app-server.d.ts.map +1 -1
  24. package/dist/management.d.ts +0 -7
  25. package/dist/management.d.ts.map +1 -1
  26. package/dist/remote-session-protocol.d.ts +2 -0
  27. package/dist/remote-session-protocol.d.ts.map +1 -1
  28. package/dist/remote-turn-coordinator.d.ts.map +1 -1
  29. package/dist/types.d.ts +57 -66
  30. package/dist/types.d.ts.map +1 -1
  31. package/dist/validation.d.ts.map +1 -1
  32. package/package.json +2 -2
  33. package/src/app-server-management.ts +20 -256
  34. package/src/app-server-session.ts +0 -32
  35. package/src/client-base.ts +47 -73
  36. package/src/client.ts +31 -70
  37. package/src/cloud-session.ts +9 -267
  38. package/src/cloud-status-transport.ts +305 -0
  39. package/src/index.ts +11 -29
  40. package/src/local-app-server-session.ts +13 -3
  41. package/src/local-app-server.ts +97 -3
  42. package/src/management.ts +0 -7
  43. package/src/remote-session-protocol.ts +14 -0
  44. package/src/remote-turn-coordinator.ts +20 -2
  45. package/src/types.ts +64 -111
  46. package/src/validation.ts +21 -6
  47. package/dist/protocol.d.ts +0 -205
  48. package/dist/protocol.d.ts.map +0 -1
  49. package/dist/session.d.ts +0 -155
  50. package/dist/session.d.ts.map +0 -1
  51. package/dist/transport.d.ts +0 -53
  52. package/dist/transport.d.ts.map +0 -1
  53. package/src/protocol.ts +0 -249
  54. package/src/session.ts +0 -1638
  55. package/src/transport.ts +0 -484
@@ -244,6 +244,18 @@ class RepositoriesClient {
244
244
  }
245
245
 
246
246
  // node_modules/@letta-ai/letta-code/dist/app-server-client.js
247
+ function isAppServerInfoResponseMessage(message) {
248
+ if (!message || typeof message !== "object" || Array.isArray(message)) {
249
+ return false;
250
+ }
251
+ const candidate = message;
252
+ const capabilities = candidate.capabilities;
253
+ if (!capabilities || typeof capabilities !== "object" || Array.isArray(capabilities)) {
254
+ return false;
255
+ }
256
+ const capabilityRecord = capabilities;
257
+ return candidate.type === "app_server_info_response" && typeof candidate.request_id === "string" && candidate.request_id.length > 0 && candidate.success === true && (candidate.backend === "local" || candidate.backend === "api") && typeof candidate.letta_code_version === "string" && typeof candidate.protocol_version === "number" && Number.isInteger(candidate.protocol_version) && typeof capabilityRecord.agent_management === "boolean" && typeof capabilityRecord.conversation_management === "boolean" && typeof capabilityRecord.memory_management === "boolean" && typeof capabilityRecord.runtime_start === "boolean" && typeof capabilityRecord.split_channels === "boolean";
258
+ }
247
259
  var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
248
260
  var WEBSOCKET_OPEN_STATE = 1;
249
261
  function getGlobalWebSocket() {
@@ -263,9 +275,9 @@ function normalizeBaseUrl(url) {
263
275
  }
264
276
  return parsed;
265
277
  }
266
- function resolveAppServerChannelUrl(url, channel) {
278
+ function resolveAppServerUrl(url) {
267
279
  const parsed = normalizeBaseUrl(url);
268
- parsed.searchParams.set("channel", channel);
280
+ parsed.searchParams.delete("channel");
269
281
  return parsed.toString();
270
282
  }
271
283
  function attachSocketListener(socket, type, listener) {
@@ -378,6 +390,7 @@ function streamDeltaErrorMessage(message) {
378
390
  }
379
391
 
380
392
  class AppServerClient {
393
+ socket;
381
394
  control;
382
395
  stream;
383
396
  requestTimeoutMs;
@@ -396,26 +409,18 @@ class AppServerClient {
396
409
  }
397
410
  this.requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
398
411
  const socketOptions = appServerSocketOptions(options.authToken);
399
- this.control = new WebSocket(resolveAppServerChannelUrl(options.url, "control"), socketOptions);
400
- this.stream = new WebSocket(resolveAppServerChannelUrl(options.url, "stream"), socketOptions);
401
- attachSocketListener(this.control, "message", (event) => {
412
+ this.socket = new WebSocket(resolveAppServerUrl(options.url), socketOptions);
413
+ this.control = this.socket;
414
+ this.stream = this.socket;
415
+ attachSocketListener(this.socket, "message", (event) => {
402
416
  this.handleMessage(event, "control");
403
417
  });
404
- attachSocketListener(this.stream, "message", (event) => {
405
- this.handleMessage(event, "stream");
406
- });
407
- attachSocketListener(this.control, "close", (event) => {
418
+ attachSocketListener(this.socket, "close", (event) => {
408
419
  this.handleDisconnect("control", event);
409
420
  });
410
- attachSocketListener(this.stream, "close", (event) => {
411
- this.handleDisconnect("stream", event);
412
- });
413
421
  }
414
422
  async connect() {
415
- await Promise.all([
416
- waitForSocketOpen(this.control),
417
- waitForSocketOpen(this.stream)
418
- ]);
423
+ await waitForSocketOpen(this.socket);
419
424
  return this;
420
425
  }
421
426
  close() {
@@ -423,8 +428,7 @@ class AppServerClient {
423
428
  return;
424
429
  this.explicitlyClosed = true;
425
430
  this.rejectAllPending("App-server client closed");
426
- this.control.close();
427
- this.stream.close();
431
+ this.socket.close();
428
432
  }
429
433
  onMessage(handler) {
430
434
  this.messageHandlers.add(handler);
@@ -443,10 +447,38 @@ class AppServerClient {
443
447
  return `${prefix}-${this.nextRequestNumber}`;
444
448
  }
445
449
  send(command) {
450
+ this.writeCommand(command);
451
+ }
452
+ writeCommand(command) {
446
453
  for (const handler of this.sendHandlers) {
447
454
  handler(command);
448
455
  }
449
- this.control.send(JSON.stringify(command));
456
+ this.socket.send(JSON.stringify(command));
457
+ }
458
+ sendRaw(command) {
459
+ this.writeCommand(command);
460
+ }
461
+ requestRaw(command, options) {
462
+ const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;
463
+ return new Promise((resolve, reject) => {
464
+ const timeout = setTimeout(() => {
465
+ this.pending.delete(command.request_id);
466
+ reject(new Error(`Timed out waiting for ${command.request_id}`));
467
+ }, timeoutMs);
468
+ this.pending.set(command.request_id, {
469
+ resolve: (message) => resolve(message),
470
+ reject,
471
+ predicate: options.predicate,
472
+ timeout
473
+ });
474
+ try {
475
+ this.sendRaw(command);
476
+ } catch (error) {
477
+ clearTimeout(timeout);
478
+ this.pending.delete(command.request_id);
479
+ reject(error instanceof Error ? error : new Error(String(error)));
480
+ }
481
+ });
450
482
  }
451
483
  request(commandOrType, bodyOrOptions = {}, maybeOptions = {}) {
452
484
  const isTypeRequest = typeof commandOrType === "string";
@@ -477,6 +509,15 @@ class AppServerClient {
477
509
  }
478
510
  });
479
511
  }
512
+ info(options = {}) {
513
+ return this.request({
514
+ type: "app_server_info",
515
+ request_id: this.nextRequestId("app-server-info")
516
+ }, {
517
+ ...options,
518
+ predicate: isAppServerInfoResponseMessage
519
+ });
520
+ }
480
521
  runtimeStart(command, options = {}) {
481
522
  return this.request({
482
523
  type: "runtime_start",
@@ -696,44 +737,6 @@ function applyUniqueRequestIds(client) {
696
737
  }
697
738
 
698
739
  // src/app-server-management.ts
699
- var DEFAULT_IDLE_LINGER_MS = 250;
700
- var registeredTransportsByUrl = new Map;
701
- function appServerUrlKey(value) {
702
- try {
703
- const url = new URL(value);
704
- if (url.protocol === "http:")
705
- url.protocol = "ws:";
706
- if (url.protocol === "https:")
707
- url.protocol = "wss:";
708
- url.hash = "";
709
- url.searchParams.delete("channel");
710
- return url.toString();
711
- } catch {
712
- return value;
713
- }
714
- }
715
- function registerManagementTransport(url, transport) {
716
- const key = appServerUrlKey(url);
717
- const registration = { transport };
718
- const transports = registeredTransportsByUrl.get(key) ?? new Set;
719
- transports.add(registration);
720
- registeredTransportsByUrl.set(key, transports);
721
- return () => {
722
- transports.delete(registration);
723
- if (transports.size === 0) {
724
- registeredTransportsByUrl.delete(key);
725
- }
726
- };
727
- }
728
- async function releaseAppServerManagementConnections(url) {
729
- const key = appServerUrlKey(url);
730
- while (true) {
731
- const transports = [...registeredTransportsByUrl.get(key) ?? []];
732
- if (transports.length === 0)
733
- return;
734
- await Promise.all(transports.map(({ transport }) => transport.releaseIdleConnection()));
735
- }
736
- }
737
740
  function ensureResponse(response, value, fallback) {
738
741
  if (!response.success || value == null) {
739
742
  throw new Error(response.error ?? fallback);
@@ -770,15 +773,9 @@ function stringRecord(value) {
770
773
  class AppServerManagementTransport {
771
774
  options;
772
775
  connectionPromise = null;
773
- releasePromise = null;
774
776
  closingConnections = new Set;
775
- inFlightRequests = 0;
776
- idleWaiters = new Set;
777
- idleTimer = null;
778
- idleLingerMs;
779
777
  constructor(options) {
780
778
  this.options = options;
781
- this.idleLingerMs = options.idleLingerMs ?? DEFAULT_IDLE_LINGER_MS;
782
779
  }
783
780
  async listAgents(query) {
784
781
  const response = await this.request("agent_list", { query }, "agent_list_response");
@@ -845,73 +842,20 @@ class AppServerManagementTransport {
845
842
  }
846
843
  return { messages: response.messages };
847
844
  }
848
- releaseIdleConnection() {
849
- this.clearIdleTimer();
850
- if (this.releasePromise)
851
- return this.releasePromise;
852
- const release = this.releaseConnectionWhenIdle();
853
- this.releasePromise = release;
854
- release.then(() => {
855
- if (this.releasePromise === release) {
856
- this.releasePromise = null;
857
- }
858
- }, () => {
859
- if (this.releasePromise === release) {
860
- this.releasePromise = null;
861
- }
862
- });
863
- return release;
864
- }
865
845
  async request(type, body, responseType) {
866
- if (this.releasePromise) {
867
- await this.releasePromise;
868
- }
869
846
  if (this.closingConnections.size > 0) {
870
847
  await Promise.all([...this.closingConnections]);
871
848
  }
872
- this.clearIdleTimer();
873
- this.inFlightRequests += 1;
874
- try {
875
- const { client } = await this.acquireConnection();
876
- const command = {
877
- type,
878
- request_id: client.nextRequestId(type),
879
- ...body
880
- };
881
- const response = await client.request(command, {
882
- predicate: (message) => message.type === responseType
883
- });
884
- return response;
885
- } finally {
886
- this.inFlightRequests -= 1;
887
- if (this.inFlightRequests === 0) {
888
- const waiters = [...this.idleWaiters];
889
- this.idleWaiters.clear();
890
- for (const resolve of waiters)
891
- resolve();
892
- if (!this.releasePromise) {
893
- this.scheduleIdleRelease();
894
- }
895
- }
896
- }
897
- }
898
- async releaseConnectionWhenIdle() {
899
- if (this.inFlightRequests > 0) {
900
- await new Promise((resolve) => {
901
- this.idleWaiters.add(resolve);
902
- });
903
- }
904
- this.clearIdleTimer();
905
- const promise = this.connectionPromise;
906
- try {
907
- if (promise) {
908
- this.connectionPromise = null;
909
- await this.trackClosingConnection(await promise);
910
- }
911
- if (this.closingConnections.size > 0) {
912
- await Promise.all([...this.closingConnections]);
913
- }
914
- } catch {}
849
+ const { client } = await this.acquireConnection();
850
+ const command = {
851
+ type,
852
+ request_id: client.nextRequestId(type),
853
+ ...body
854
+ };
855
+ const response = await client.request(command, {
856
+ predicate: (message) => message.type === responseType
857
+ });
858
+ return response;
915
859
  }
916
860
  acquireConnection() {
917
861
  if (this.connectionPromise)
@@ -936,7 +880,6 @@ class AppServerManagementTransport {
936
880
  if (!url) {
937
881
  throw new Error("App-server management requires a url or connect hook.");
938
882
  }
939
- const unregister = registerManagementTransport(url, this);
940
883
  let client = null;
941
884
  try {
942
885
  client = applyUniqueRequestIds(createAppServerClient({
@@ -951,29 +894,23 @@ class AppServerManagementTransport {
951
894
  } catch (error) {
952
895
  try {
953
896
  if (client) {
954
- const controlClosed = waitForSocketClose(client.control);
955
897
  client.close();
956
898
  ownedConnection?.close();
957
- await controlClosed;
958
899
  } else {
959
900
  ownedConnection?.close();
960
901
  }
961
- } catch {} finally {
962
- unregister();
963
- }
902
+ } catch {}
964
903
  throw error;
965
904
  }
966
905
  return {
967
906
  client,
968
907
  ownedConnection,
969
- detachDisconnect: () => {},
970
- unregister
908
+ detachDisconnect: () => {}
971
909
  };
972
910
  }
973
911
  discardConnection(promise, connection) {
974
912
  if (this.connectionPromise === promise) {
975
913
  this.connectionPromise = null;
976
- this.clearIdleTimer();
977
914
  }
978
915
  this.trackClosingConnection(connection);
979
916
  }
@@ -983,67 +920,11 @@ class AppServerManagementTransport {
983
920
  closing.then(() => this.closingConnections.delete(closing), () => this.closingConnections.delete(closing));
984
921
  return closing;
985
922
  }
986
- scheduleIdleRelease() {
987
- if (!this.connectionPromise)
988
- return;
989
- this.clearIdleTimer();
990
- const timer = setTimeout(() => {
991
- this.idleTimer = null;
992
- this.releaseIdleConnection();
993
- }, this.idleLingerMs);
994
- this.idleTimer = timer;
995
- timer.unref?.();
996
- }
997
- clearIdleTimer() {
998
- if (this.idleTimer === null)
999
- return;
1000
- clearTimeout(this.idleTimer);
1001
- this.idleTimer = null;
1002
- }
1003
923
  }
1004
924
  async function closeConnection(connection) {
1005
925
  connection.detachDisconnect();
1006
- const controlClosed = waitForSocketClose(connection.client.control);
1007
- try {
1008
- connection.client.close();
1009
- connection.ownedConnection?.close();
1010
- await controlClosed;
1011
- } finally {
1012
- connection.unregister();
1013
- }
1014
- }
1015
- function waitForSocketClose(socket) {
1016
- if (socket.readyState === 3)
1017
- return Promise.resolve();
1018
- return new Promise((resolve) => {
1019
- let settled = false;
1020
- let detach = () => {};
1021
- const finish = () => {
1022
- if (settled)
1023
- return;
1024
- settled = true;
1025
- clearTimeout(timeout);
1026
- detach();
1027
- resolve();
1028
- };
1029
- if (socket.addEventListener) {
1030
- socket.addEventListener("close", finish);
1031
- detach = () => socket.removeEventListener?.("close", finish);
1032
- } else if (socket.once) {
1033
- socket.once("close", finish);
1034
- detach = () => socket.off?.("close", finish);
1035
- } else if (socket.on) {
1036
- socket.on("close", finish);
1037
- detach = () => socket.off?.("close", finish);
1038
- } else {
1039
- resolve();
1040
- return;
1041
- }
1042
- const timeout = setTimeout(finish, 1000);
1043
- timeout.unref?.();
1044
- if (socket.readyState === 3)
1045
- finish();
1046
- });
926
+ connection.client.close();
927
+ connection.ownedConnection?.close();
1047
928
  }
1048
929
 
1049
930
  // node_modules/@letta-ai/letta-code/dist/agent-presets.js
@@ -5950,6 +5831,12 @@ function streamDeltaMessageType2(delta) {
5950
5831
  function streamDeltaRunId2(delta) {
5951
5832
  return typeof delta.run_id === "string" ? delta.run_id : undefined;
5952
5833
  }
5834
+ function streamDeltaOtid(delta) {
5835
+ return typeof delta.otid === "string" || delta.otid === null ? delta.otid : undefined;
5836
+ }
5837
+ function streamDeltaSeqId(delta) {
5838
+ return typeof delta.seq_id === "number" ? delta.seq_id : undefined;
5839
+ }
5953
5840
  function streamDeltaStopReason2(delta) {
5954
5841
  return typeof delta.stop_reason === "string" ? delta.stop_reason : undefined;
5955
5842
  }
@@ -6359,6 +6246,8 @@ class RemoteTurnCoordinator {
6359
6246
  transformStreamDelta(delta) {
6360
6247
  const messageType = typeof delta.message_type === "string" ? delta.message_type : undefined;
6361
6248
  const runId = typeof delta.run_id === "string" ? delta.run_id : undefined;
6249
+ const otid = streamDeltaOtid(delta);
6250
+ const seqId = streamDeltaSeqId(delta);
6362
6251
  const uuid = typeof delta.id === "string" ? delta.id : `${this.label}-${++this.messageCounter}`;
6363
6252
  if (messageType === "assistant_message") {
6364
6253
  const content = extractTextFromContent(delta.content);
@@ -6366,13 +6255,27 @@ class RemoteTurnCoordinator {
6366
6255
  return null;
6367
6256
  if (this.activeTurn)
6368
6257
  this.activeTurn.assistantText += content;
6369
- return { type: "assistant", content, uuid, runId };
6258
+ return {
6259
+ type: "assistant",
6260
+ content,
6261
+ uuid,
6262
+ ...otid !== undefined ? { otid } : {},
6263
+ ...seqId !== undefined ? { seqId } : {},
6264
+ runId
6265
+ };
6370
6266
  }
6371
6267
  if (messageType === "reasoning_message") {
6372
6268
  const content = typeof delta.reasoning === "string" ? delta.reasoning : extractTextFromContent(delta.content);
6373
6269
  if (!content)
6374
6270
  return null;
6375
- return { type: "reasoning", content, uuid, runId };
6271
+ return {
6272
+ type: "reasoning",
6273
+ content,
6274
+ uuid,
6275
+ ...otid !== undefined ? { otid } : {},
6276
+ ...seqId !== undefined ? { seqId } : {},
6277
+ runId
6278
+ };
6376
6279
  }
6377
6280
  if (messageType === "tool_call_message" || messageType === "approval_request_message") {
6378
6281
  const toolCall = firstToolCall(delta);
@@ -7075,26 +6978,6 @@ function assertRemoteCreateAgentOptionsSupported(options) {
7075
6978
  throw new Error("App-server createAgent() does not yet support dreaming.behavior overrides.");
7076
6979
  }
7077
6980
  }
7078
- function assertRemoteSessionOptionsSupported(action, options) {
7079
- if (options.systemPrompt !== undefined) {
7080
- throw new Error(`App-server ${action}() does not yet support systemPrompt overrides for existing agents.`);
7081
- }
7082
- if (options.disallowedTools !== undefined) {
7083
- throw new Error(`App-server ${action}() does not yet support disallowedTools.`);
7084
- }
7085
- if (options.systemInfoReminder !== undefined) {
7086
- throw new Error(`App-server ${action}() does not yet support systemInfoReminder overrides.`);
7087
- }
7088
- if (options.dreaming?.behavior !== undefined) {
7089
- throw new Error(`App-server ${action}() does not yet support dreaming.behavior overrides.`);
7090
- }
7091
- if (options.memfsStartup !== undefined) {
7092
- throw new Error(`App-server ${action}() does not support memfsStartup.`);
7093
- }
7094
- if (options.includePartialMessages !== undefined) {
7095
- throw new Error(`App-server ${action}() streams app-server deltas directly and does not support includePartialMessages.`);
7096
- }
7097
- }
7098
6981
  function normalizeMemoryBlock(block) {
7099
6982
  const normalized = { ...block };
7100
6983
  if (normalized.value === undefined && typeof normalized.content === "string") {
@@ -7525,9 +7408,7 @@ class AppServerSession extends RemoteClientSessionCore {
7525
7408
  return options.memfs !== false;
7526
7409
  }
7527
7410
  async initializeRuntimeController() {
7528
- await this.remoteOptions.beforeConnect?.();
7529
7411
  const url = await this.resolveAppServerUrl();
7530
- await releaseAppServerManagementConnections(url);
7531
7412
  const client = applyUniqueRequestIds(createAppServerClient({
7532
7413
  url,
7533
7414
  ...this.remoteOptions.authToken !== undefined ? { authToken: this.remoteOptions.authToken } : {},
@@ -7837,6 +7718,222 @@ class CloudManagementTransport {
7837
7718
  }
7838
7719
  }
7839
7720
 
7721
+ // src/cloud-status-transport.ts
7722
+ var CONNECTING = 0;
7723
+ var OPEN = 1;
7724
+ var CLOSING = 2;
7725
+ var CLOSED = 3;
7726
+ var MAX_IDEMPOTENCY_KEYS = 1000;
7727
+ function addSocketListener(socket, type, listener) {
7728
+ if (socket.addEventListener) {
7729
+ socket.addEventListener(type, listener);
7730
+ return () => socket.removeEventListener?.(type, listener);
7731
+ }
7732
+ if (socket.on) {
7733
+ socket.on(type, listener);
7734
+ return () => socket.off?.(type, listener);
7735
+ }
7736
+ throw new Error("WebSocket implementation does not support event listeners.");
7737
+ }
7738
+ function messageEventData(event) {
7739
+ if (typeof event === "string")
7740
+ return event;
7741
+ if (!event || typeof event !== "object")
7742
+ return null;
7743
+ const data = event.data;
7744
+ if (typeof data === "string")
7745
+ return data;
7746
+ if (data instanceof ArrayBuffer) {
7747
+ return new TextDecoder().decode(data);
7748
+ }
7749
+ if (data instanceof Uint8Array) {
7750
+ return new TextDecoder().decode(data);
7751
+ }
7752
+ return null;
7753
+ }
7754
+ function channelUrl(url, channel) {
7755
+ const parsed = new URL(url);
7756
+ parsed.searchParams.set("channel", channel);
7757
+ return parsed.toString();
7758
+ }
7759
+
7760
+ class CloudStatusTransport {
7761
+ options;
7762
+ controlSocket;
7763
+ streamSocket;
7764
+ state = CONNECTING;
7765
+ openedChannels = new Set;
7766
+ listeners = new Map;
7767
+ removers = [];
7768
+ seenIdempotencyKeys = new Set;
7769
+ seenIdempotencyOrder = [];
7770
+ lastEventSeq = null;
7771
+ pingTimer = null;
7772
+ closeEmitted = false;
7773
+ constructor(options) {
7774
+ this.options = options;
7775
+ const socketOptions = options.headers ? { headers: options.headers } : undefined;
7776
+ this.controlSocket = new options.WebSocket(channelUrl(options.url, "control"), socketOptions);
7777
+ this.streamSocket = new options.WebSocket(channelUrl(options.url, "stream"), socketOptions);
7778
+ this.bindSocket("control", this.controlSocket);
7779
+ this.bindSocket("stream", this.streamSocket);
7780
+ this.startPing();
7781
+ }
7782
+ get readyState() {
7783
+ return this.state;
7784
+ }
7785
+ send(data) {
7786
+ if (this.state !== OPEN || this.controlSocket.readyState !== OPEN) {
7787
+ throw new Error("Cloud status control socket is not open");
7788
+ }
7789
+ this.controlSocket.send(data);
7790
+ }
7791
+ close() {
7792
+ if (this.state === CLOSED || this.state === CLOSING)
7793
+ return;
7794
+ this.state = CLOSING;
7795
+ this.stopPing();
7796
+ this.closeUnderlyingSockets();
7797
+ this.finishClose({});
7798
+ }
7799
+ addEventListener(type, listener) {
7800
+ let listeners = this.listeners.get(type);
7801
+ if (!listeners) {
7802
+ listeners = new Set;
7803
+ this.listeners.set(type, listeners);
7804
+ }
7805
+ listeners.add(listener);
7806
+ }
7807
+ removeEventListener(type, listener) {
7808
+ this.listeners.get(type)?.delete(listener);
7809
+ }
7810
+ bindSocket(channel, socket) {
7811
+ this.removers.push(addSocketListener(socket, "open", () => {
7812
+ this.openedChannels.add(channel);
7813
+ if (this.openedChannels.size === 2 && this.state === CONNECTING) {
7814
+ this.state = OPEN;
7815
+ this.emit("open", {});
7816
+ }
7817
+ }), addSocketListener(socket, "message", (event) => {
7818
+ if (this.shouldForwardMessage(channel, socket, event)) {
7819
+ this.emit("message", event);
7820
+ }
7821
+ }), addSocketListener(socket, "error", (event) => {
7822
+ this.emit("error", event);
7823
+ }), addSocketListener(socket, "close", (event) => {
7824
+ if (this.state !== CLOSED) {
7825
+ this.state = CLOSING;
7826
+ this.stopPing();
7827
+ this.closeUnderlyingSockets(socket);
7828
+ this.finishClose(event);
7829
+ }
7830
+ }));
7831
+ }
7832
+ shouldForwardMessage(channel, socket, event) {
7833
+ const data = messageEventData(event);
7834
+ if (!data)
7835
+ return true;
7836
+ let message;
7837
+ try {
7838
+ message = JSON.parse(data);
7839
+ } catch {
7840
+ return true;
7841
+ }
7842
+ this.ackIfSequenced(socket, message);
7843
+ if (channel === "control" && message.type === "stream_delta") {
7844
+ return false;
7845
+ }
7846
+ if (this.isDuplicate(message))
7847
+ return false;
7848
+ this.trackEventSequence(message);
7849
+ return true;
7850
+ }
7851
+ ackIfSequenced(socket, message) {
7852
+ if (typeof message.seq !== "number")
7853
+ return;
7854
+ this.sendCommand(socket, { type: "ack", seq: message.seq });
7855
+ }
7856
+ isDuplicate(message) {
7857
+ const key = typeof message.idempotency_key === "string" ? message.idempotency_key : null;
7858
+ if (!key)
7859
+ return false;
7860
+ if (this.seenIdempotencyKeys.has(key))
7861
+ return true;
7862
+ this.seenIdempotencyKeys.add(key);
7863
+ this.seenIdempotencyOrder.push(key);
7864
+ while (this.seenIdempotencyOrder.length > MAX_IDEMPOTENCY_KEYS) {
7865
+ const oldest = this.seenIdempotencyOrder.shift();
7866
+ if (oldest)
7867
+ this.seenIdempotencyKeys.delete(oldest);
7868
+ }
7869
+ return false;
7870
+ }
7871
+ trackEventSequence(message) {
7872
+ if (typeof message.event_seq !== "number")
7873
+ return;
7874
+ if (this.lastEventSeq !== null && message.event_seq > this.lastEventSeq + 1) {
7875
+ this.sendCommand(this.controlSocket, {
7876
+ type: "sync",
7877
+ runtime: this.options.runtime,
7878
+ recover_approvals: true,
7879
+ force_device_status: true
7880
+ });
7881
+ }
7882
+ if (this.lastEventSeq === null || message.event_seq > this.lastEventSeq) {
7883
+ this.lastEventSeq = message.event_seq;
7884
+ }
7885
+ }
7886
+ sendCommand(socket, command) {
7887
+ if (socket.readyState !== OPEN)
7888
+ return;
7889
+ try {
7890
+ socket.send(JSON.stringify(command));
7891
+ } catch {}
7892
+ }
7893
+ startPing() {
7894
+ this.pingTimer = setInterval(() => {
7895
+ this.sendCommand(this.controlSocket, { type: "ping" });
7896
+ this.sendCommand(this.streamSocket, { type: "ping" });
7897
+ }, this.options.pingIntervalMs);
7898
+ this.pingTimer.unref?.();
7899
+ }
7900
+ stopPing() {
7901
+ if (!this.pingTimer)
7902
+ return;
7903
+ clearInterval(this.pingTimer);
7904
+ this.pingTimer = null;
7905
+ }
7906
+ closeUnderlyingSockets(except) {
7907
+ for (const socket of [this.controlSocket, this.streamSocket]) {
7908
+ if (socket !== except && (socket.readyState === CONNECTING || socket.readyState === OPEN)) {
7909
+ socket.close();
7910
+ }
7911
+ }
7912
+ }
7913
+ finishClose(event) {
7914
+ if (this.closeEmitted)
7915
+ return;
7916
+ this.closeEmitted = true;
7917
+ this.state = CLOSED;
7918
+ this.stopPing();
7919
+ for (const remove of this.removers.splice(0))
7920
+ remove();
7921
+ this.emit("close", event);
7922
+ }
7923
+ emit(type, event) {
7924
+ for (const listener of this.listeners.get(type) ?? []) {
7925
+ listener(event);
7926
+ }
7927
+ }
7928
+ }
7929
+ function createCloudStatusTransportConstructor(options) {
7930
+ return class CloudStatusTransportSocket extends CloudStatusTransport {
7931
+ constructor(_url, _socketOptions) {
7932
+ super(options);
7933
+ }
7934
+ };
7935
+ }
7936
+
7840
7937
  // src/remote.ts
7841
7938
  function getDefaultApiKey2() {
7842
7939
  if (typeof process === "undefined") {
@@ -8145,191 +8242,6 @@ function buildCloudStatusWebSocketUrl(params) {
8145
8242
  }
8146
8243
  return base.toString();
8147
8244
  }
8148
- function addSocketListener(socket, type, listener) {
8149
- if (socket.addEventListener) {
8150
- socket.addEventListener(type, listener);
8151
- return () => socket.removeEventListener?.(type, listener);
8152
- }
8153
- if (socket.on) {
8154
- socket.on(type, listener);
8155
- return () => socket.off?.(type, listener);
8156
- }
8157
- throw new Error("WebSocket implementation does not support event listeners.");
8158
- }
8159
- function messageEventData(event) {
8160
- if (typeof event === "string")
8161
- return event;
8162
- if (event && typeof event === "object") {
8163
- const data = event.data;
8164
- if (typeof data === "string")
8165
- return data;
8166
- if (data instanceof ArrayBuffer) {
8167
- return new TextDecoder().decode(data);
8168
- }
8169
- if (data instanceof Uint8Array) {
8170
- return new TextDecoder().decode(data);
8171
- }
8172
- }
8173
- return null;
8174
- }
8175
- function createCloudStatusWebSocketConstructor(params) {
8176
- const WebSocketCtor = getWebSocketConstructor(params.cloudOptions.WebSocket);
8177
- const authMode = params.cloudOptions.webSocketAuth ?? "header";
8178
- const cloudHeaders3 = authMode === "header" ? cloudWebSocketHeaders(params.cloudOptions) : undefined;
8179
- const pingIntervalMs = params.cloudOptions.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS;
8180
- const state = {
8181
- runtime: params.runtime,
8182
- seenIdempotencyKeys: new Set,
8183
- seenIdempotencyOrder: [],
8184
- lastEventSeq: null,
8185
- controlSocket: null
8186
- };
8187
-
8188
- class CloudStatusSocketAdapter {
8189
- socket;
8190
- channel;
8191
- listenerRemovers = new Map;
8192
- pingTimer = null;
8193
- removeCloseListener = null;
8194
- constructor(url, options) {
8195
- this.channel = new URL(url).searchParams.get("channel");
8196
- const mergedHeaders = authMode === "header" ? {
8197
- ...options?.headers ?? {},
8198
- ...cloudHeaders3 ?? {}
8199
- } : undefined;
8200
- const socketOptions = mergedHeaders && Object.keys(mergedHeaders).length > 0 ? { headers: mergedHeaders } : undefined;
8201
- this.socket = new WebSocketCtor(url, socketOptions);
8202
- if (this.channel === "control") {
8203
- state.controlSocket = this;
8204
- }
8205
- this.removeCloseListener = addSocketListener(this.socket, "close", () => {
8206
- this.stopPing();
8207
- if (state.controlSocket === this)
8208
- state.controlSocket = null;
8209
- });
8210
- this.startPing(pingIntervalMs);
8211
- }
8212
- get readyState() {
8213
- return this.socket.readyState;
8214
- }
8215
- send(data) {
8216
- this.socket.send(data);
8217
- }
8218
- close() {
8219
- this.stopPing();
8220
- this.removeCloseListener?.();
8221
- this.removeCloseListener = null;
8222
- if (state.controlSocket === this)
8223
- state.controlSocket = null;
8224
- this.socket.close();
8225
- }
8226
- addEventListener(type, listener) {
8227
- const wrapped = type === "message" ? (event) => {
8228
- if (this.handleIncomingMessage(event)) {
8229
- listener(event);
8230
- }
8231
- } : listener;
8232
- const remove = addSocketListener(this.socket, type, wrapped);
8233
- let typeRemovers = this.listenerRemovers.get(type);
8234
- if (!typeRemovers) {
8235
- typeRemovers = new Map;
8236
- this.listenerRemovers.set(type, typeRemovers);
8237
- }
8238
- typeRemovers.set(listener, remove);
8239
- }
8240
- removeEventListener(type, listener) {
8241
- const typeRemovers = this.listenerRemovers.get(type);
8242
- const remove = typeRemovers?.get(listener);
8243
- if (!remove)
8244
- return;
8245
- remove();
8246
- typeRemovers?.delete(listener);
8247
- if (typeRemovers?.size === 0) {
8248
- this.listenerRemovers.delete(type);
8249
- }
8250
- }
8251
- handleIncomingMessage(event) {
8252
- const data = messageEventData(event);
8253
- if (!data)
8254
- return true;
8255
- let message;
8256
- try {
8257
- message = JSON.parse(data);
8258
- } catch {
8259
- return true;
8260
- }
8261
- this.ackIfSequenced(message);
8262
- if (this.channel === "control" && message.type === "stream_delta") {
8263
- return false;
8264
- }
8265
- if (this.isDuplicate(message))
8266
- return false;
8267
- this.trackEventSeq(message);
8268
- return true;
8269
- }
8270
- ackIfSequenced(message) {
8271
- if (typeof message.seq !== "number")
8272
- return;
8273
- this.sendCloudCommand({ type: "ack", seq: message.seq });
8274
- }
8275
- isDuplicate(message) {
8276
- const idempotencyKey = typeof message.idempotency_key === "string" ? message.idempotency_key : undefined;
8277
- if (!idempotencyKey)
8278
- return false;
8279
- if (state.seenIdempotencyKeys.has(idempotencyKey))
8280
- return true;
8281
- state.seenIdempotencyKeys.add(idempotencyKey);
8282
- state.seenIdempotencyOrder.push(idempotencyKey);
8283
- while (state.seenIdempotencyOrder.length > 1000) {
8284
- const oldest = state.seenIdempotencyOrder.shift();
8285
- if (oldest)
8286
- state.seenIdempotencyKeys.delete(oldest);
8287
- }
8288
- return false;
8289
- }
8290
- trackEventSeq(message) {
8291
- if (typeof message.event_seq !== "number")
8292
- return;
8293
- if (state.lastEventSeq !== null && message.event_seq > state.lastEventSeq + 1) {
8294
- this.sendSync(true);
8295
- }
8296
- if (state.lastEventSeq === null || message.event_seq > state.lastEventSeq) {
8297
- state.lastEventSeq = message.event_seq;
8298
- }
8299
- }
8300
- sendSync(recoverApprovals) {
8301
- const target = state.controlSocket?.readyState === 1 ? state.controlSocket : this;
8302
- target.sendCloudCommand({
8303
- type: "sync",
8304
- runtime: state.runtime,
8305
- recover_approvals: recoverApprovals,
8306
- force_device_status: true
8307
- });
8308
- }
8309
- sendCloudCommand(command) {
8310
- if (this.readyState !== 1)
8311
- return;
8312
- try {
8313
- this.socket.send(JSON.stringify(command));
8314
- } catch {}
8315
- }
8316
- startPing(intervalMs) {
8317
- if (this.pingTimer)
8318
- return;
8319
- this.pingTimer = setInterval(() => {
8320
- this.sendCloudCommand({ type: "ping" });
8321
- }, intervalMs);
8322
- this.pingTimer.unref?.();
8323
- }
8324
- stopPing() {
8325
- if (!this.pingTimer)
8326
- return;
8327
- clearInterval(this.pingTimer);
8328
- this.pingTimer = null;
8329
- }
8330
- }
8331
- return CloudStatusSocketAdapter;
8332
- }
8333
8245
  function isCloudConversation(value) {
8334
8246
  return Boolean(value && typeof value === "object" && typeof value.id === "string");
8335
8247
  }
@@ -8373,24 +8285,6 @@ function assertCloudSessionOptionsSupported(action, options) {
8373
8285
  if (options.environment !== undefined && options.sandbox !== undefined) {
8374
8286
  throw new Error(`Letta Cloud ${action}() cannot specify both environment and sandbox options.`);
8375
8287
  }
8376
- if (options.systemPrompt !== undefined) {
8377
- throw new Error(`Letta Cloud ${action}() cannot rewrite an existing agent's systemPrompt from the SDK adapter yet.`);
8378
- }
8379
- if (options.disallowedTools !== undefined) {
8380
- throw new Error(`Letta Cloud ${action}() has not wired disallowedTools to the remote device protocol yet.`);
8381
- }
8382
- if (options.systemInfoReminder !== undefined) {
8383
- throw new Error(`Letta Cloud ${action}() has not wired systemInfoReminder to the remote device protocol yet.`);
8384
- }
8385
- if (options.dreaming?.behavior !== undefined) {
8386
- throw new Error(`Letta Cloud ${action}() does not yet support dreaming.behavior overrides.`);
8387
- }
8388
- if (options.memfsStartup !== undefined) {
8389
- throw new Error(`Letta Cloud ${action}() does not support memfsStartup.`);
8390
- }
8391
- if (options.includePartialMessages !== undefined) {
8392
- throw new Error(`Letta Cloud ${action}() streams Remote Client deltas directly; includePartialMessages is not a separate toggle.`);
8393
- }
8394
8288
  }
8395
8289
 
8396
8290
  class CloudEnvironmentSession extends RemoteClientSessionCore {
@@ -8430,8 +8324,11 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
8430
8324
  });
8431
8325
  const client = applyUniqueRequestIds(createAppServerClient({
8432
8326
  url,
8433
- WebSocket: createCloudStatusWebSocketConstructor({
8434
- cloudOptions: this.cloudOptions,
8327
+ WebSocket: createCloudStatusTransportConstructor({
8328
+ url,
8329
+ WebSocket: getWebSocketConstructor(this.cloudOptions.WebSocket),
8330
+ ...(this.cloudOptions.webSocketAuth ?? "header") === "header" ? { headers: cloudWebSocketHeaders(this.cloudOptions) } : {},
8331
+ pingIntervalMs: this.cloudOptions.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS,
8435
8332
  runtime: resolved.runtime
8436
8333
  }),
8437
8334
  requestTimeoutMs: this.cloudOptions.requestTimeoutMs ?? DEFAULT_TURN_TIMEOUT_MS
@@ -9019,7 +8916,23 @@ function validateApprovalRecoveryOptions(options) {
9019
8916
  }
9020
8917
  }
9021
8918
  function validateRemovedSessionOptions(options) {
9022
- if (options.memfsStartup !== undefined) {
8919
+ const removedOptions = options;
8920
+ if (removedOptions.systemPrompt !== undefined) {
8921
+ throw new Error("systemPrompt is not supported when opening an existing agent session.");
8922
+ }
8923
+ if (removedOptions.disallowedTools !== undefined) {
8924
+ throw new Error("disallowedTools is not supported when opening an existing agent session.");
8925
+ }
8926
+ if (removedOptions.systemInfoReminder !== undefined) {
8927
+ throw new Error("systemInfoReminder is not supported when opening an existing agent session.");
8928
+ }
8929
+ if (removedOptions.includePartialMessages !== undefined) {
8930
+ throw new Error("includePartialMessages is not supported by app-server sessions.");
8931
+ }
8932
+ if (options.dreaming && "behavior" in options.dreaming && options.dreaming.behavior !== undefined) {
8933
+ throw new Error("dreaming.behavior is not supported when opening an existing agent session.");
8934
+ }
8935
+ if (removedOptions.memfsStartup !== undefined) {
9023
8936
  throw new Error("memfsStartup is not supported by the SDK.");
9024
8937
  }
9025
8938
  }
@@ -9069,9 +8982,6 @@ function validateReasoningEffort(value) {
9069
8982
  }
9070
8983
  }
9071
8984
  function validateCreateSessionOptions(options) {
9072
- if (options.systemPrompt !== undefined) {
9073
- validateSystemPromptPreset(options.systemPrompt);
9074
- }
9075
8985
  validateSkillSources(options.skillSources);
9076
8986
  validateReasoningEffort(options.reasoningEffort);
9077
8987
  validateDreamingOptions(options.dreaming);
@@ -9127,6 +9037,7 @@ function stripCloudExecutionOptions(options) {
9127
9037
  const sessionOptions = { ...options };
9128
9038
  delete sessionOptions.environment;
9129
9039
  delete sessionOptions.sandbox;
9040
+ delete sessionOptions.filesystemConfinement;
9130
9041
  return sessionOptions;
9131
9042
  }
9132
9043
  function hasRepositoryResources(options) {
@@ -9170,17 +9081,13 @@ class LettaAgentClientBase {
9170
9081
  }
9171
9082
  if (this.backend === "local") {
9172
9083
  const localOptions = options;
9173
- if (localOptions.transport !== undefined && localOptions.transport !== "app-server" && localOptions.transport !== "stdio") {
9174
- throw new Error("Invalid local transport. Valid values: app-server, stdio.");
9084
+ if ("transport" in localOptions) {
9085
+ throw new Error("Local transport selection has been removed. The local backend always uses the app-server protocol.");
9175
9086
  }
9176
9087
  const requestTimeoutMs = localOptions.appServer?.requestTimeoutMs;
9177
9088
  if (requestTimeoutMs !== undefined && (!Number.isInteger(requestTimeoutMs) || requestTimeoutMs <= 0)) {
9178
9089
  throw new Error("Invalid appServer.requestTimeoutMs. Expected a positive integer.");
9179
9090
  }
9180
- const idleLingerMs = localOptions.appServer?.idleLingerMs;
9181
- if (idleLingerMs !== undefined && (!Number.isInteger(idleLingerMs) || idleLingerMs < 0)) {
9182
- throw new Error("Invalid appServer.idleLingerMs. Expected a non-negative integer.");
9183
- }
9184
9091
  const startupTimeoutMs = localOptions.appServer?.startupTimeoutMs;
9185
9092
  if (startupTimeoutMs !== undefined && (!Number.isInteger(startupTimeoutMs) || startupTimeoutMs <= 0)) {
9186
9093
  throw new Error("Invalid appServer.startupTimeoutMs. Expected a positive integer.");
@@ -9193,9 +9100,6 @@ class LettaAgentClientBase {
9193
9100
  if (options.requestTimeoutMs !== undefined && (!Number.isInteger(options.requestTimeoutMs) || options.requestTimeoutMs <= 0)) {
9194
9101
  throw new Error("Invalid requestTimeoutMs. Expected a positive integer.");
9195
9102
  }
9196
- if (options.idleLingerMs !== undefined && (!Number.isInteger(options.idleLingerMs) || options.idleLingerMs < 0)) {
9197
- throw new Error("Invalid idleLingerMs. Expected a non-negative integer.");
9198
- }
9199
9103
  }
9200
9104
  if (this.backend === "cloud") {
9201
9105
  validateCloudClientOptions(options);
@@ -9223,40 +9127,35 @@ class LettaAgentClientBase {
9223
9127
  }
9224
9128
  return this.createLocalAgent(options);
9225
9129
  }
9226
- createSession(agentIdOrOptions, options = {}) {
9227
- const agentId = typeof agentIdOrOptions === "string" ? agentIdOrOptions : undefined;
9228
- const resolvedOptions = typeof agentIdOrOptions === "string" ? options : agentIdOrOptions ?? {};
9229
- this.assertSessionBackend("createSession", resolvedOptions);
9230
- const sessionOptions = stripCloudExecutionOptions(resolvedOptions);
9130
+ createSession(agentId, options = {}) {
9131
+ if (typeof agentId !== "string" || agentId.length === 0) {
9132
+ throw new Error("createSession() requires a non-empty agent id.");
9133
+ }
9134
+ const sessionOptions = stripCloudExecutionOptions(options);
9231
9135
  validateCreateSessionOptions(sessionOptions);
9136
+ this.assertSessionBackend("createSession", options);
9232
9137
  if (this.backend === "remote") {
9233
- if (!agentId) {
9234
- throw new Error("App-server createSession() requires an agent id. Call createAgent() first or pass an agent id.");
9235
- }
9236
9138
  return new AppServerSession(this.appServerSessionOptions(), {
9237
9139
  kind: "session",
9238
9140
  agentId,
9239
9141
  newConversation: true,
9240
- options: resolvedOptions
9142
+ options
9241
9143
  });
9242
9144
  }
9243
9145
  if (this.backend === "cloud") {
9244
- if (!agentId) {
9245
- throw new Error("Letta Cloud createSession() requires an agent id. Call createAgent() first or pass an agent id.");
9246
- }
9247
9146
  return new CloudEnvironmentSession(this.cloudOptions(), {
9248
9147
  kind: "session",
9249
9148
  agentId,
9250
9149
  newConversation: true,
9251
- options: resolvedOptions
9150
+ options
9252
9151
  });
9253
9152
  }
9254
- return this.createLocalSession(agentId, resolvedOptions, sessionOptions);
9153
+ return this.createLocalSession(agentId, options);
9255
9154
  }
9256
9155
  resumeSession(id, options = {}) {
9257
- this.assertSessionBackend("resumeSession", options);
9258
9156
  const sessionOptions = stripCloudExecutionOptions(options);
9259
9157
  validateCreateSessionOptions(sessionOptions);
9158
+ this.assertSessionBackend("resumeSession", options);
9260
9159
  if (this.backend === "remote") {
9261
9160
  if (looksLikeConversationId(id)) {
9262
9161
  return new AppServerSession(this.appServerSessionOptions(), {
@@ -9287,10 +9186,10 @@ class LettaAgentClientBase {
9287
9186
  options
9288
9187
  });
9289
9188
  }
9290
- return this.resumeLocalSession(id, options, sessionOptions);
9189
+ return this.resumeLocalSession(id, options);
9291
9190
  }
9292
9191
  async prompt(message, agentId, options = {}) {
9293
- const session = agentId ? this.createSession(agentId, options) : this.createSession(options);
9192
+ const session = this.createSession(agentId, options);
9294
9193
  try {
9295
9194
  return await session.runTurn(message);
9296
9195
  } finally {
@@ -9298,6 +9197,9 @@ class LettaAgentClientBase {
9298
9197
  }
9299
9198
  }
9300
9199
  assertSessionBackend(action, options) {
9200
+ if (options.filesystemConfinement !== undefined && options.filesystemConfinement !== "memory") {
9201
+ throw new Error(`Invalid filesystemConfinement '${String(options.filesystemConfinement)}'. Valid value: memory.`);
9202
+ }
9301
9203
  const effectiveEnvironment = options.environment ?? this.environment;
9302
9204
  if (this.backend === "local") {
9303
9205
  if (effectiveEnvironment !== undefined) {
@@ -9309,12 +9211,18 @@ class LettaAgentClientBase {
9309
9211
  if (hasRepositoryResources(options)) {
9310
9212
  throw new Error(`${action}() repository resources are only valid with backend: "cloud".`);
9311
9213
  }
9312
- if (!this.useLegacyLocalStdio()) {
9313
- assertRemoteSessionOptionsSupported(action, options);
9214
+ if (options.filesystemConfinement !== undefined) {
9215
+ const localOptions = this.options;
9216
+ if (localOptions.appServer?.url !== undefined) {
9217
+ throw new Error(`${action}() filesystemConfinement requires an SDK-owned local app-server process.`);
9218
+ }
9314
9219
  }
9315
9220
  return;
9316
9221
  }
9317
9222
  if (this.backend === "remote") {
9223
+ if (options.filesystemConfinement !== undefined) {
9224
+ throw new Error(`${action}() filesystemConfinement requires an SDK-owned local app-server process.`);
9225
+ }
9318
9226
  if (options.environment !== undefined) {
9319
9227
  throw new Error(`${action}() environment overrides are only valid with backend: "cloud"; remote url selects the app-server runtime.`);
9320
9228
  }
@@ -9324,10 +9232,12 @@ class LettaAgentClientBase {
9324
9232
  if (hasRepositoryResources(options)) {
9325
9233
  throw new Error(`${action}() repository resources are only valid with backend: "cloud".`);
9326
9234
  }
9327
- assertRemoteSessionOptionsSupported(action, options);
9328
9235
  return;
9329
9236
  }
9330
9237
  if (this.backend === "cloud") {
9238
+ if (options.filesystemConfinement !== undefined) {
9239
+ throw new Error(`${action}() filesystemConfinement is only supported with backend: "local".`);
9240
+ }
9331
9241
  const cloudOptions = this.cloudOptions();
9332
9242
  if (cloudOptions.environment !== undefined && options.sandbox !== undefined) {
9333
9243
  throw new Error(`Letta Cloud ${action}() cannot specify sandbox options when the client has a default environment.`);
@@ -9340,16 +9250,13 @@ class LettaAgentClientBase {
9340
9250
  }
9341
9251
  throw new Error(`LettaAgentClient backend '${this.backend}' is not implemented yet. ${action} currently supports backend 'local' only.`);
9342
9252
  }
9343
- useLegacyLocalStdio() {
9344
- return this.options.transport === "stdio";
9345
- }
9346
9253
  createLocalAgent(_options) {
9347
9254
  throw this.localBackendUnavailableError();
9348
9255
  }
9349
- createLocalSession(_agentId, _options, _sessionOptions) {
9256
+ createLocalSession(_agentId, _options) {
9350
9257
  throw this.localBackendUnavailableError();
9351
9258
  }
9352
- resumeLocalSession(_id, _options, _sessionOptions) {
9259
+ resumeLocalSession(_id, _options) {
9353
9260
  throw this.localBackendUnavailableError();
9354
9261
  }
9355
9262
  localBackendUnavailableError() {
@@ -9365,10 +9272,7 @@ class LettaAgentClientBase {
9365
9272
  return this.options;
9366
9273
  }
9367
9274
  appServerSessionOptions() {
9368
- return {
9369
- ...this.remoteOptions(),
9370
- beforeConnect: () => this.releaseIdleManagementConnection()
9371
- };
9275
+ return this.remoteOptions();
9372
9276
  }
9373
9277
  getRepositoriesClient() {
9374
9278
  if (this.backend !== "cloud") {
@@ -9377,9 +9281,6 @@ class LettaAgentClientBase {
9377
9281
  this.repositoriesClient ??= new RepositoriesClient(this.cloudOptions());
9378
9282
  return this.repositoriesClient;
9379
9283
  }
9380
- async releaseIdleManagementConnection() {
9381
- await this.managementTransport?.releaseIdleConnection?.();
9382
- }
9383
9284
  getManagementTransport() {
9384
9285
  if (this.managementTransport)
9385
9286
  return this.managementTransport;
@@ -9487,4 +9388,4 @@ export {
9487
9388
  CloudManagedSandboxExpiredError
9488
9389
  };
9489
9390
 
9490
- //# debugId=0186899B952456A764756E2164756E21
9391
+ //# debugId=AAFE1DD6848E90C364756E2164756E21