@letta-ai/letta-agent-sdk 0.6.2 → 0.6.3
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/README.md +37 -1
- package/dist/client-base.d.ts +7 -0
- package/dist/client-base.d.ts.map +1 -1
- package/dist/client-entry.d.ts +1 -0
- package/dist/client-entry.d.ts.map +1 -1
- package/dist/client-entry.js +323 -118
- package/dist/client-entry.js.map +9 -8
- package/dist/cloud-session.d.ts +8 -1
- package/dist/cloud-session.d.ts.map +1 -1
- package/dist/computers.d.ts +67 -0
- package/dist/computers.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +323 -118
- package/dist/index.js.map +9 -8
- package/dist/remote-client-session-core.d.ts +11 -14
- package/dist/remote-client-session-core.d.ts.map +1 -1
- package/dist/remote.d.ts +6 -1
- package/dist/remote.d.ts.map +1 -1
- package/dist/types.d.ts +12 -20
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/client-base.ts +66 -19
- package/src/client-entry.ts +9 -0
- package/src/cloud-session.ts +111 -45
- package/src/computers.ts +132 -0
- package/src/index.ts +9 -0
- package/src/remote-client-session-core.ts +90 -19
- package/src/remote.ts +41 -12
- package/src/types.ts +12 -17
package/dist/client-entry.js
CHANGED
|
@@ -9493,6 +9493,9 @@ class RemoteClientSessionCore {
|
|
|
9493
9493
|
initializePromise = null;
|
|
9494
9494
|
removeMessageHandler = null;
|
|
9495
9495
|
detachTransportDisconnect = null;
|
|
9496
|
+
idleTransportDisconnected = false;
|
|
9497
|
+
transportRecoveryPromise = null;
|
|
9498
|
+
transportDisconnectGeneration = 0;
|
|
9496
9499
|
turns;
|
|
9497
9500
|
toolNames;
|
|
9498
9501
|
deviceStatusListeners = new Set;
|
|
@@ -9582,16 +9585,24 @@ class RemoteClientSessionCore {
|
|
|
9582
9585
|
this.initialized = false;
|
|
9583
9586
|
}
|
|
9584
9587
|
async send(message) {
|
|
9588
|
+
if (this.closed)
|
|
9589
|
+
throw new Error("Session is closed");
|
|
9585
9590
|
if (!this.initialized) {
|
|
9586
9591
|
await this.initialize();
|
|
9587
9592
|
}
|
|
9593
|
+
await this.recoverIdleTransportIfNeeded();
|
|
9588
9594
|
if (!this.controller || !this.runtime) {
|
|
9589
9595
|
throw new Error("Session is not initialized");
|
|
9590
9596
|
}
|
|
9591
9597
|
await this.beforeTurn();
|
|
9592
|
-
const
|
|
9598
|
+
const controller = this.controller;
|
|
9599
|
+
const runtime = this.runtime;
|
|
9600
|
+
if (!controller || !runtime) {
|
|
9601
|
+
throw new Error("Session transport disconnected before the turn was sent");
|
|
9602
|
+
}
|
|
9603
|
+
const turn = this.turns.trackSentTurn(runtime);
|
|
9593
9604
|
try {
|
|
9594
|
-
|
|
9605
|
+
controller.sendTurnMessage(runtime, message, {
|
|
9595
9606
|
clientMessageId: turn.clientMessageId
|
|
9596
9607
|
});
|
|
9597
9608
|
} catch (error) {
|
|
@@ -9866,6 +9877,7 @@ class RemoteClientSessionCore {
|
|
|
9866
9877
|
this.deviceStatusListeners.clear();
|
|
9867
9878
|
this.controller?.close();
|
|
9868
9879
|
this.controller = null;
|
|
9880
|
+
this.idleTransportDisconnected = false;
|
|
9869
9881
|
this.onCoreClose();
|
|
9870
9882
|
}
|
|
9871
9883
|
get agentId() {
|
|
@@ -9918,15 +9930,78 @@ class RemoteClientSessionCore {
|
|
|
9918
9930
|
}, { predicate: (message) => message.type === "update_toolset_response" });
|
|
9919
9931
|
ensureSuccess(response, "Failed to update toolset");
|
|
9920
9932
|
}
|
|
9921
|
-
watchTransportDisconnect(client) {
|
|
9933
|
+
watchTransportDisconnect(client, options = {}) {
|
|
9922
9934
|
this.detachTransportDisconnect?.();
|
|
9923
9935
|
this.detachTransportDisconnect = client.onDisconnect(() => {
|
|
9924
9936
|
if (this.closed)
|
|
9925
9937
|
return;
|
|
9938
|
+
this.transportDisconnectGeneration += 1;
|
|
9939
|
+
if (options.recoverWhenIdle && !this.turns.hasInFlightTurn()) {
|
|
9940
|
+
this.detachTransportDisconnect?.();
|
|
9941
|
+
this.detachTransportDisconnect = null;
|
|
9942
|
+
this.removeMessageHandler?.();
|
|
9943
|
+
this.removeMessageHandler = null;
|
|
9944
|
+
this.controller?.close();
|
|
9945
|
+
this.controller = null;
|
|
9946
|
+
const error = new Error(`${this.label} connection closed before send`);
|
|
9947
|
+
for (const cancel of [...this.deviceStatusRefreshCancels])
|
|
9948
|
+
cancel(error);
|
|
9949
|
+
this.deviceStatusRefreshCancels.clear();
|
|
9950
|
+
this.onIdleTransportDisconnect();
|
|
9951
|
+
this.idleTransportDisconnected = true;
|
|
9952
|
+
return;
|
|
9953
|
+
}
|
|
9926
9954
|
this.turns.closeWithError(`The ${this.label} connection closed unexpectedly; resume the conversation to continue.`);
|
|
9927
9955
|
this.close();
|
|
9928
9956
|
});
|
|
9929
9957
|
}
|
|
9958
|
+
async recoverIdleTransportIfNeeded() {
|
|
9959
|
+
if (!this.idleTransportDisconnected)
|
|
9960
|
+
return;
|
|
9961
|
+
if (this.transportRecoveryPromise) {
|
|
9962
|
+
await this.transportRecoveryPromise;
|
|
9963
|
+
return;
|
|
9964
|
+
}
|
|
9965
|
+
const runtime = this.runtime;
|
|
9966
|
+
if (!runtime)
|
|
9967
|
+
throw new Error("Session transport disconnected without a runtime");
|
|
9968
|
+
const generation = this.transportDisconnectGeneration;
|
|
9969
|
+
const recovery = this.recoverIdleTransport(runtime).then(async (init) => {
|
|
9970
|
+
if (this.closed || generation !== this.transportDisconnectGeneration) {
|
|
9971
|
+
init.controller.close();
|
|
9972
|
+
this.onRecoveredTransportDiscarded();
|
|
9973
|
+
throw new Error(`${this.label} connection closed during recovery`);
|
|
9974
|
+
}
|
|
9975
|
+
if (init.runtime.agent_id !== runtime.agent_id || init.runtime.conversation_id !== runtime.conversation_id) {
|
|
9976
|
+
init.controller.close();
|
|
9977
|
+
this.onRecoveredTransportDiscarded();
|
|
9978
|
+
throw new Error(`${this.label} transport recovered a different runtime`);
|
|
9979
|
+
}
|
|
9980
|
+
this.controller = init.controller;
|
|
9981
|
+
this.runtime = init.runtime;
|
|
9982
|
+
this._modelSettings = init.modelSettings ?? this._modelSettings;
|
|
9983
|
+
if (typeof init.model === "string" && init.model)
|
|
9984
|
+
this._model = init.model;
|
|
9985
|
+
if (init.tools !== undefined)
|
|
9986
|
+
this.toolNames = init.tools;
|
|
9987
|
+
this.removeMessageHandler = this.controller.onMessage((message) => {
|
|
9988
|
+
if (this.runtime)
|
|
9989
|
+
this.turns.handleProtocolMessage(message, this.runtime);
|
|
9990
|
+
});
|
|
9991
|
+
this.idleTransportDisconnected = false;
|
|
9992
|
+
await this.afterRuntimeInitialized();
|
|
9993
|
+
}).finally(() => {
|
|
9994
|
+
if (this.transportRecoveryPromise === recovery)
|
|
9995
|
+
this.transportRecoveryPromise = null;
|
|
9996
|
+
});
|
|
9997
|
+
this.transportRecoveryPromise = recovery;
|
|
9998
|
+
await recovery;
|
|
9999
|
+
}
|
|
10000
|
+
async recoverIdleTransport(_runtime) {
|
|
10001
|
+
throw new Error(`${this.label} sessions do not support idle transport recovery`);
|
|
10002
|
+
}
|
|
10003
|
+
onIdleTransportDisconnect() {}
|
|
10004
|
+
onRecoveredTransportDiscarded() {}
|
|
9930
10005
|
async afterRuntimeInitialized() {}
|
|
9931
10006
|
async beforeTurn() {}
|
|
9932
10007
|
onCoreClose() {}
|
|
@@ -10670,6 +10745,132 @@ class CloudManagementTransport {
|
|
|
10670
10745
|
}
|
|
10671
10746
|
}
|
|
10672
10747
|
|
|
10748
|
+
// src/remote.ts
|
|
10749
|
+
function ensureOnline(environment, target) {
|
|
10750
|
+
if (!environment.connectionId) {
|
|
10751
|
+
const label = "deviceId" in target ? target.deviceId : ("environmentId" in target) ? target.environmentId : ("connectionName" in target) ? target.connectionName : environment.deviceId;
|
|
10752
|
+
throw new Error(`Computer is offline: ${label}`);
|
|
10753
|
+
}
|
|
10754
|
+
return {
|
|
10755
|
+
connectionId: environment.connectionId,
|
|
10756
|
+
environment,
|
|
10757
|
+
target
|
|
10758
|
+
};
|
|
10759
|
+
}
|
|
10760
|
+
|
|
10761
|
+
class RemoteEnvironmentClient {
|
|
10762
|
+
client;
|
|
10763
|
+
constructor(options = {}, client = createCloudClient({
|
|
10764
|
+
backend: "cloud",
|
|
10765
|
+
apiBaseUrl: options.baseUrl,
|
|
10766
|
+
apiKey: options.apiKey,
|
|
10767
|
+
headers: options.headers,
|
|
10768
|
+
fetch: options.fetch
|
|
10769
|
+
})) {
|
|
10770
|
+
this.client = client;
|
|
10771
|
+
}
|
|
10772
|
+
async listEnvironments(options = {}) {
|
|
10773
|
+
return await this.client.environments.list({
|
|
10774
|
+
after: options.after,
|
|
10775
|
+
limit: options.limit === undefined ? undefined : String(options.limit),
|
|
10776
|
+
onlineOnly: options.onlineOnly === undefined ? undefined : String(options.onlineOnly)
|
|
10777
|
+
});
|
|
10778
|
+
}
|
|
10779
|
+
async getEnvironmentByDeviceId(deviceId) {
|
|
10780
|
+
return await this.client.environments.retrieve(deviceId);
|
|
10781
|
+
}
|
|
10782
|
+
async resolveEnvironment(target) {
|
|
10783
|
+
if ("connectionId" in target) {
|
|
10784
|
+
return { connectionId: target.connectionId, target };
|
|
10785
|
+
}
|
|
10786
|
+
if ("deviceId" in target) {
|
|
10787
|
+
return ensureOnline(await this.getEnvironmentByDeviceId(target.deviceId), target);
|
|
10788
|
+
}
|
|
10789
|
+
const connections = [];
|
|
10790
|
+
let after;
|
|
10791
|
+
do {
|
|
10792
|
+
const page = await this.listEnvironments({ limit: 100, after });
|
|
10793
|
+
connections.push(...page.connections);
|
|
10794
|
+
if (!page.hasNextPage || page.connections.length === 0)
|
|
10795
|
+
break;
|
|
10796
|
+
after = page.connections.at(-1)?.id;
|
|
10797
|
+
} while (after !== undefined);
|
|
10798
|
+
if ("environmentId" in target) {
|
|
10799
|
+
const match = connections.find((env) => env.id === target.environmentId);
|
|
10800
|
+
if (!match) {
|
|
10801
|
+
throw new Error(`Remote environment not found: ${target.environmentId}`);
|
|
10802
|
+
}
|
|
10803
|
+
return ensureOnline(match, target);
|
|
10804
|
+
}
|
|
10805
|
+
const matches = connections.filter((env) => env.connectionName === target.connectionName);
|
|
10806
|
+
if (matches.length === 0) {
|
|
10807
|
+
throw new Error(`Computer not found: ${target.connectionName}`);
|
|
10808
|
+
}
|
|
10809
|
+
const onlineMatches = matches.filter((environment) => environment.connectionId !== null);
|
|
10810
|
+
if (onlineMatches.length === 0) {
|
|
10811
|
+
throw new Error(`Computer is offline: ${target.connectionName}`);
|
|
10812
|
+
}
|
|
10813
|
+
if (onlineMatches.length > 1) {
|
|
10814
|
+
const candidates = onlineMatches.map((environment) => `${environment.connectionName} (${environment.deviceId}, online)`).join(", ");
|
|
10815
|
+
throw new Error(`Computer name is ambiguous: ${target.connectionName}. Matches: ${candidates}. Select one by deviceId.`);
|
|
10816
|
+
}
|
|
10817
|
+
return ensureOnline(onlineMatches[0], target);
|
|
10818
|
+
}
|
|
10819
|
+
}
|
|
10820
|
+
|
|
10821
|
+
// src/computers.ts
|
|
10822
|
+
function selectorToRemoteTarget(selector) {
|
|
10823
|
+
if (typeof selector === "string")
|
|
10824
|
+
return { connectionName: selector };
|
|
10825
|
+
if ("name" in selector)
|
|
10826
|
+
return { connectionName: selector.name };
|
|
10827
|
+
if ("id" in selector)
|
|
10828
|
+
return { environmentId: selector.id };
|
|
10829
|
+
if ("connectionId" in selector) {
|
|
10830
|
+
return { connectionId: selector.connectionId };
|
|
10831
|
+
}
|
|
10832
|
+
return { deviceId: selector.deviceId };
|
|
10833
|
+
}
|
|
10834
|
+
function toComputer(environment) {
|
|
10835
|
+
return {
|
|
10836
|
+
id: environment.id,
|
|
10837
|
+
deviceId: environment.deviceId,
|
|
10838
|
+
connectionId: environment.connectionId,
|
|
10839
|
+
name: environment.connectionName,
|
|
10840
|
+
status: environment.connectionId ? "online" : "offline",
|
|
10841
|
+
connectedAt: environment.connectedAt,
|
|
10842
|
+
lastSeenAt: environment.lastSeenAt,
|
|
10843
|
+
metadata: environment.metadata
|
|
10844
|
+
};
|
|
10845
|
+
}
|
|
10846
|
+
|
|
10847
|
+
class ComputersClientImpl {
|
|
10848
|
+
environments;
|
|
10849
|
+
constructor(client) {
|
|
10850
|
+
this.environments = new RemoteEnvironmentClient({}, client);
|
|
10851
|
+
}
|
|
10852
|
+
async list(options = {}) {
|
|
10853
|
+
const result = await this.environments.listEnvironments(options);
|
|
10854
|
+
return {
|
|
10855
|
+
computers: result.connections.map(toComputer),
|
|
10856
|
+
hasNextPage: result.hasNextPage
|
|
10857
|
+
};
|
|
10858
|
+
}
|
|
10859
|
+
async get(deviceId) {
|
|
10860
|
+
if (typeof deviceId !== "string" || deviceId.trim().length === 0) {
|
|
10861
|
+
throw new Error("Invalid deviceId. Expected a non-empty string.");
|
|
10862
|
+
}
|
|
10863
|
+
return toComputer(await this.environments.getEnvironmentByDeviceId(deviceId));
|
|
10864
|
+
}
|
|
10865
|
+
async resolve(selector) {
|
|
10866
|
+
const result = await this.environments.resolveEnvironment(selectorToRemoteTarget(selector));
|
|
10867
|
+
return {
|
|
10868
|
+
connectionId: result.connectionId,
|
|
10869
|
+
computer: result.environment ? toComputer(result.environment) : undefined
|
|
10870
|
+
};
|
|
10871
|
+
}
|
|
10872
|
+
}
|
|
10873
|
+
|
|
10673
10874
|
// src/cloud-status-transport.ts
|
|
10674
10875
|
var CONNECTING = 0;
|
|
10675
10876
|
var OPEN = 1;
|
|
@@ -10886,66 +11087,6 @@ function createCloudStatusTransportConstructor(options) {
|
|
|
10886
11087
|
};
|
|
10887
11088
|
}
|
|
10888
11089
|
|
|
10889
|
-
// src/remote.ts
|
|
10890
|
-
function ensureOnline(environment, target) {
|
|
10891
|
-
if (!environment.connectionId) {
|
|
10892
|
-
const label = "deviceId" in target ? target.deviceId : ("environmentId" in target) ? target.environmentId : ("connectionName" in target) ? target.connectionName : environment.deviceId;
|
|
10893
|
-
throw new Error(`Remote environment is offline: ${label}`);
|
|
10894
|
-
}
|
|
10895
|
-
return {
|
|
10896
|
-
connectionId: environment.connectionId,
|
|
10897
|
-
environment,
|
|
10898
|
-
target
|
|
10899
|
-
};
|
|
10900
|
-
}
|
|
10901
|
-
|
|
10902
|
-
class RemoteEnvironmentClient {
|
|
10903
|
-
client;
|
|
10904
|
-
constructor(options = {}, client = createCloudClient({
|
|
10905
|
-
backend: "cloud",
|
|
10906
|
-
apiBaseUrl: options.baseUrl,
|
|
10907
|
-
apiKey: options.apiKey,
|
|
10908
|
-
headers: options.headers,
|
|
10909
|
-
fetch: options.fetch
|
|
10910
|
-
})) {
|
|
10911
|
-
this.client = client;
|
|
10912
|
-
}
|
|
10913
|
-
async listEnvironments() {
|
|
10914
|
-
return await this.client.environments.list();
|
|
10915
|
-
}
|
|
10916
|
-
async getEnvironmentByDeviceId(deviceId) {
|
|
10917
|
-
return await this.client.environments.retrieve(deviceId);
|
|
10918
|
-
}
|
|
10919
|
-
async resolveEnvironment(target) {
|
|
10920
|
-
if ("connectionId" in target) {
|
|
10921
|
-
return { connectionId: target.connectionId, target };
|
|
10922
|
-
}
|
|
10923
|
-
if ("deviceId" in target) {
|
|
10924
|
-
return ensureOnline(await this.getEnvironmentByDeviceId(target.deviceId), target);
|
|
10925
|
-
}
|
|
10926
|
-
const { connections } = await this.listEnvironments();
|
|
10927
|
-
if ("environmentId" in target) {
|
|
10928
|
-
const match2 = connections.find((env) => env.id === target.environmentId);
|
|
10929
|
-
if (!match2) {
|
|
10930
|
-
throw new Error(`Remote environment not found: ${target.environmentId}`);
|
|
10931
|
-
}
|
|
10932
|
-
return ensureOnline(match2, target);
|
|
10933
|
-
}
|
|
10934
|
-
const matches = connections.filter((env) => env.connectionName === target.connectionName);
|
|
10935
|
-
if (matches.length === 0) {
|
|
10936
|
-
throw new Error(`Remote environment not found: ${target.connectionName}`);
|
|
10937
|
-
}
|
|
10938
|
-
if (matches.length > 1) {
|
|
10939
|
-
throw new Error(`Remote environment name is ambiguous: ${target.connectionName}`);
|
|
10940
|
-
}
|
|
10941
|
-
const match = matches[0];
|
|
10942
|
-
if (!match) {
|
|
10943
|
-
throw new Error(`Remote environment not found: ${target.connectionName}`);
|
|
10944
|
-
}
|
|
10945
|
-
return ensureOnline(match, target);
|
|
10946
|
-
}
|
|
10947
|
-
}
|
|
10948
|
-
|
|
10949
11090
|
// src/cloud-sandbox.ts
|
|
10950
11091
|
var MIN_TTL_MINUTES = 1;
|
|
10951
11092
|
var MAX_TTL_MINUTES = 60;
|
|
@@ -11044,8 +11185,12 @@ function validatePositiveInteger3(value, name) {
|
|
|
11044
11185
|
function validateCloudClientOptions(options) {
|
|
11045
11186
|
validatePositiveInteger3(options.requestTimeoutMs, "requestTimeoutMs");
|
|
11046
11187
|
validateCloudSandboxOptions(options.sandbox, "sandbox");
|
|
11047
|
-
if (options.
|
|
11048
|
-
throw new Error("Letta Cloud
|
|
11188
|
+
if (options.computer !== undefined && options.environment !== undefined) {
|
|
11189
|
+
throw new Error("Letta Cloud clients cannot specify both computer and deprecated environment.");
|
|
11190
|
+
}
|
|
11191
|
+
if ((options.computer !== undefined || options.environment !== undefined) && options.sandbox !== undefined) {
|
|
11192
|
+
const field = options.computer !== undefined ? "computer" : "environment";
|
|
11193
|
+
throw new Error(`Letta Cloud sessions cannot specify both ${field} and sandbox options.`);
|
|
11049
11194
|
}
|
|
11050
11195
|
if (options.webSocketAuth !== undefined && options.webSocketAuth !== "header" && options.webSocketAuth !== "query") {
|
|
11051
11196
|
throw new Error("Invalid webSocketAuth. Valid values: header, query.");
|
|
@@ -11162,12 +11307,30 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
11162
11307
|
throw error;
|
|
11163
11308
|
});
|
|
11164
11309
|
this.connectionId = connection.connectionId;
|
|
11310
|
+
const options = this.currentOptions();
|
|
11311
|
+
this.mcpBridge = await connectMcpServers("mcpServers" in options ? options.mcpServers : undefined, {
|
|
11312
|
+
cwd: options.cwd,
|
|
11313
|
+
reservedToolNames: this.externalTools.keys()
|
|
11314
|
+
});
|
|
11315
|
+
for (const tool of this.mcpBridge.tools) {
|
|
11316
|
+
this.externalTools.set(tool.name, tool);
|
|
11317
|
+
}
|
|
11318
|
+
try {
|
|
11319
|
+
return await this.openCloudTransport(resolved.runtime, connection.connectionId);
|
|
11320
|
+
} catch (error) {
|
|
11321
|
+
await this.closeMcpBridge();
|
|
11322
|
+
await this.cleanupManagedSandbox();
|
|
11323
|
+
await this.cleanupSessionRepositories(resolved.runtime.agent_id, resolved.runtime.conversation_id);
|
|
11324
|
+
throw error;
|
|
11325
|
+
}
|
|
11326
|
+
}
|
|
11327
|
+
async openCloudTransport(runtime, connectionId) {
|
|
11165
11328
|
const apiKey = getCloudApiKey(this.cloudOptions);
|
|
11166
11329
|
const url = buildCloudStatusWebSocketUrl({
|
|
11167
11330
|
apiBaseUrl: this.cloudOptions.apiBaseUrl,
|
|
11168
|
-
connectionId
|
|
11169
|
-
agentId:
|
|
11170
|
-
conversationId:
|
|
11331
|
+
connectionId,
|
|
11332
|
+
agentId: runtime.agent_id,
|
|
11333
|
+
conversationId: runtime.conversation_id,
|
|
11171
11334
|
apiKey,
|
|
11172
11335
|
authMode: this.cloudOptions.webSocketAuth ?? "header"
|
|
11173
11336
|
});
|
|
@@ -11178,33 +11341,19 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
11178
11341
|
WebSocket: getWebSocketConstructor(this.cloudOptions.WebSocket),
|
|
11179
11342
|
...(this.cloudOptions.webSocketAuth ?? "header") === "header" ? { headers: cloudWebSocketHeaders(this.cloudOptions) } : {},
|
|
11180
11343
|
pingIntervalMs: this.cloudOptions.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS,
|
|
11181
|
-
runtime
|
|
11344
|
+
runtime
|
|
11182
11345
|
}),
|
|
11183
11346
|
requestTimeoutMs: this.cloudOptions.requestTimeoutMs ?? DEFAULT_TURN_TIMEOUT_MS
|
|
11184
11347
|
}));
|
|
11185
11348
|
const options = this.currentOptions();
|
|
11186
|
-
this.
|
|
11187
|
-
cwd: options.cwd,
|
|
11188
|
-
reservedToolNames: this.externalTools.keys()
|
|
11189
|
-
});
|
|
11190
|
-
for (const tool of this.mcpBridge.tools) {
|
|
11191
|
-
this.externalTools.set(tool.name, tool);
|
|
11192
|
-
}
|
|
11193
|
-
this.removeControlRequestHandler = registerAppServerControlRequestHandler({
|
|
11194
|
-
client,
|
|
11195
|
-
getRuntime: () => this.runtime,
|
|
11196
|
-
getOptions: () => this.currentOptions()
|
|
11197
|
-
});
|
|
11198
|
-
if (this.externalTools.size > 0) {
|
|
11199
|
-
this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools));
|
|
11200
|
-
}
|
|
11349
|
+
this.installTransportHandlers(client);
|
|
11201
11350
|
try {
|
|
11202
11351
|
await client.connect();
|
|
11203
|
-
const response = await this.startCloudRuntime(client,
|
|
11352
|
+
const response = await this.startCloudRuntime(client, runtime);
|
|
11204
11353
|
if (!response.success || !response.runtime) {
|
|
11205
11354
|
throw new Error(response.error ?? "Failed to start Cloud status runtime");
|
|
11206
11355
|
}
|
|
11207
|
-
this.watchTransportDisconnect(client);
|
|
11356
|
+
this.watchTransportDisconnect(client, { recoverWhenIdle: true });
|
|
11208
11357
|
const tools = agentToolNames(response.agent);
|
|
11209
11358
|
const skillSources = options.skillSources;
|
|
11210
11359
|
const clientToolset = "toolset" in options ? options.toolset : undefined;
|
|
@@ -11222,17 +11371,51 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
11222
11371
|
...skillSources !== undefined ? { skillSources: [...skillSources] } : {}
|
|
11223
11372
|
};
|
|
11224
11373
|
} catch (error) {
|
|
11225
|
-
this.
|
|
11226
|
-
this.removeExternalToolHandler = null;
|
|
11227
|
-
this.removeControlRequestHandler?.();
|
|
11228
|
-
this.removeControlRequestHandler = null;
|
|
11229
|
-
await this.closeMcpBridge();
|
|
11374
|
+
this.cleanupTransportHandlers();
|
|
11230
11375
|
client.close();
|
|
11231
|
-
await this.cleanupManagedSandbox();
|
|
11232
|
-
await this.cleanupSessionRepositories(resolved.runtime.agent_id, resolved.runtime.conversation_id);
|
|
11233
11376
|
throw error;
|
|
11234
11377
|
}
|
|
11235
11378
|
}
|
|
11379
|
+
installTransportHandlers(client) {
|
|
11380
|
+
this.cleanupTransportHandlers();
|
|
11381
|
+
this.removeControlRequestHandler = registerAppServerControlRequestHandler({
|
|
11382
|
+
client,
|
|
11383
|
+
getRuntime: () => this.runtime,
|
|
11384
|
+
getOptions: () => this.currentOptions()
|
|
11385
|
+
});
|
|
11386
|
+
if (this.externalTools.size > 0) {
|
|
11387
|
+
this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools));
|
|
11388
|
+
}
|
|
11389
|
+
}
|
|
11390
|
+
cleanupTransportHandlers() {
|
|
11391
|
+
this.removeExternalToolHandler?.();
|
|
11392
|
+
this.removeExternalToolHandler = null;
|
|
11393
|
+
this.removeControlRequestHandler?.();
|
|
11394
|
+
this.removeControlRequestHandler = null;
|
|
11395
|
+
}
|
|
11396
|
+
async recoverIdleTransport(runtime) {
|
|
11397
|
+
const connection = await this.resolveRecoveryConnection(runtime);
|
|
11398
|
+
this.connectionId = connection.connectionId;
|
|
11399
|
+
return this.openCloudTransport(runtime, connection.connectionId);
|
|
11400
|
+
}
|
|
11401
|
+
async resolveRecoveryConnection(runtime) {
|
|
11402
|
+
const sandbox = this.managedSandbox;
|
|
11403
|
+
if (sandbox) {
|
|
11404
|
+
await this.refreshManagedSandbox(sandbox);
|
|
11405
|
+
return this.waitForManagedSandboxConnection(sandbox);
|
|
11406
|
+
}
|
|
11407
|
+
const environment = this.effectiveEnvironment();
|
|
11408
|
+
if (!environment) {
|
|
11409
|
+
throw new Error("Cloud idle transport recovery lost its execution target");
|
|
11410
|
+
}
|
|
11411
|
+
return this.resolveExplicitConnection(environment);
|
|
11412
|
+
}
|
|
11413
|
+
onIdleTransportDisconnect() {
|
|
11414
|
+
this.cleanupTransportHandlers();
|
|
11415
|
+
}
|
|
11416
|
+
onRecoveredTransportDiscarded() {
|
|
11417
|
+
this.cleanupTransportHandlers();
|
|
11418
|
+
}
|
|
11236
11419
|
async startCloudRuntime(client, runtime) {
|
|
11237
11420
|
const options = this.currentOptions();
|
|
11238
11421
|
const command = {
|
|
@@ -11275,10 +11458,7 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
11275
11458
|
await this.refreshManagedSandbox(sandbox);
|
|
11276
11459
|
}
|
|
11277
11460
|
onCoreClose() {
|
|
11278
|
-
this.
|
|
11279
|
-
this.removeExternalToolHandler = null;
|
|
11280
|
-
this.removeControlRequestHandler?.();
|
|
11281
|
-
this.removeControlRequestHandler = null;
|
|
11461
|
+
this.cleanupTransportHandlers();
|
|
11282
11462
|
this.mcpCleanup = this.closeMcpBridge();
|
|
11283
11463
|
this.cleanupManagedSandbox();
|
|
11284
11464
|
if (this.runtime?.agent_id) {
|
|
@@ -11602,8 +11782,8 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
11602
11782
|
return new RemoteEnvironmentClient({}, this.apiClient);
|
|
11603
11783
|
}
|
|
11604
11784
|
effectiveEnvironment() {
|
|
11605
|
-
const
|
|
11606
|
-
return
|
|
11785
|
+
const modeComputer = this.mode.kind === "session" ? this.mode.options.computer ?? this.mode.options.environment : undefined;
|
|
11786
|
+
return modeComputer ?? this.cloudOptions.computer ?? this.cloudOptions.environment;
|
|
11607
11787
|
}
|
|
11608
11788
|
effectiveSandboxOptions() {
|
|
11609
11789
|
const modeSandbox = this.mode.kind === "session" ? this.mode.options.sandbox : undefined;
|
|
@@ -11903,14 +12083,17 @@ var VALID_BACKENDS = new Set([
|
|
|
11903
12083
|
function isLettaCodeBackend(value) {
|
|
11904
12084
|
return VALID_BACKENDS.has(value);
|
|
11905
12085
|
}
|
|
11906
|
-
function
|
|
11907
|
-
if ("environment" in options)
|
|
11908
|
-
return
|
|
12086
|
+
function getOptionsComputer(options) {
|
|
12087
|
+
if (!("computer" in options) && !("environment" in options))
|
|
12088
|
+
return;
|
|
12089
|
+
if (options.computer !== undefined && options.environment !== undefined) {
|
|
12090
|
+
throw new Error('Specify either "computer" or deprecated "environment", not both.');
|
|
11909
12091
|
}
|
|
11910
|
-
return;
|
|
12092
|
+
return options.computer ?? options.environment;
|
|
11911
12093
|
}
|
|
11912
12094
|
function stripCloudExecutionOptions(options) {
|
|
11913
12095
|
const sessionOptions = { ...options };
|
|
12096
|
+
delete sessionOptions.computer;
|
|
11914
12097
|
delete sessionOptions.environment;
|
|
11915
12098
|
delete sessionOptions.sandbox;
|
|
11916
12099
|
delete sessionOptions.filesystemConfinement;
|
|
@@ -11928,12 +12111,14 @@ function looksLikeConversationId(id) {
|
|
|
11928
12111
|
|
|
11929
12112
|
class LettaAgentClientBase {
|
|
11930
12113
|
backend;
|
|
12114
|
+
computer;
|
|
11931
12115
|
environment;
|
|
11932
12116
|
agents;
|
|
11933
12117
|
conversations;
|
|
11934
12118
|
models;
|
|
11935
12119
|
options;
|
|
11936
12120
|
repositoriesClient = null;
|
|
12121
|
+
computersClient = null;
|
|
11937
12122
|
agentRepositoriesClient = null;
|
|
11938
12123
|
cloudClient = null;
|
|
11939
12124
|
managementTransport = null;
|
|
@@ -11943,16 +12128,19 @@ class LettaAgentClientBase {
|
|
|
11943
12128
|
throw new Error(`Invalid Letta Code backend '${String(backend)}'. Valid values: local, remote, cloud.`);
|
|
11944
12129
|
}
|
|
11945
12130
|
this.backend = backend;
|
|
11946
|
-
this.
|
|
12131
|
+
this.computer = getOptionsComputer(options);
|
|
12132
|
+
this.environment = this.computer;
|
|
11947
12133
|
this.options = options;
|
|
11948
12134
|
this.agents = createAgentsClient(() => this.getManagementTransport(), () => this.getAgentRepositoriesClient());
|
|
11949
12135
|
this.conversations = createConversationsClient(() => this.getManagementTransport());
|
|
11950
12136
|
this.models = createModelsClient(() => this.getManagementTransport());
|
|
11951
|
-
if (this.backend === "local" && this.
|
|
11952
|
-
|
|
12137
|
+
if (this.backend === "local" && this.computer !== undefined) {
|
|
12138
|
+
const field = "computer" in options && options.computer !== undefined ? "computer" : "environment";
|
|
12139
|
+
throw new Error(`LettaAgentClient ${field} is only valid with backend: "cloud".`);
|
|
11953
12140
|
}
|
|
11954
|
-
if (this.backend === "remote" && this.
|
|
11955
|
-
|
|
12141
|
+
if (this.backend === "remote" && this.computer !== undefined) {
|
|
12142
|
+
const field = "computer" in options && options.computer !== undefined ? "computer" : "environment";
|
|
12143
|
+
throw new Error(`LettaAgentClient ${field} is only valid with backend: "cloud"; remote url selects the app-server runtime.`);
|
|
11956
12144
|
}
|
|
11957
12145
|
if (this.backend !== "cloud" && options.sandbox !== undefined) {
|
|
11958
12146
|
throw new Error('LettaAgentClient sandbox options are only valid with backend: "cloud".');
|
|
@@ -11986,6 +12174,9 @@ class LettaAgentClientBase {
|
|
|
11986
12174
|
get repositories() {
|
|
11987
12175
|
return this.getRepositoriesClient();
|
|
11988
12176
|
}
|
|
12177
|
+
get computers() {
|
|
12178
|
+
return this.getComputersClient();
|
|
12179
|
+
}
|
|
11989
12180
|
async createAgent(options = {}) {
|
|
11990
12181
|
if (hasCreateAgentEnvironment(options)) {
|
|
11991
12182
|
throw new Error("createAgent() does not accept environment. Set a client default or pass environment to resumeSession()/createSession().");
|
|
@@ -12075,13 +12266,17 @@ class LettaAgentClientBase {
|
|
|
12075
12266
|
}
|
|
12076
12267
|
}
|
|
12077
12268
|
assertSessionBackend(action, options) {
|
|
12269
|
+
if (options.computer !== undefined && options.environment !== undefined) {
|
|
12270
|
+
throw new Error(`${action}() cannot specify both computer and deprecated environment.`);
|
|
12271
|
+
}
|
|
12078
12272
|
if (options.filesystemConfinement !== undefined && options.filesystemConfinement !== "memory") {
|
|
12079
12273
|
throw new Error(`Invalid filesystemConfinement '${String(options.filesystemConfinement)}'. Valid value: memory.`);
|
|
12080
12274
|
}
|
|
12081
|
-
const
|
|
12275
|
+
const effectiveComputer = options.computer ?? options.environment ?? this.computer;
|
|
12082
12276
|
if (this.backend === "local") {
|
|
12083
|
-
if (
|
|
12084
|
-
|
|
12277
|
+
if (effectiveComputer !== undefined) {
|
|
12278
|
+
const field = options.computer !== undefined ? "computer" : "environment";
|
|
12279
|
+
throw new Error(`${action}() ${field} overrides are only valid with backend: "cloud".`);
|
|
12085
12280
|
}
|
|
12086
12281
|
if (options.sandbox !== undefined) {
|
|
12087
12282
|
throw new Error(`${action}() sandbox options are only valid with backend: "cloud".`);
|
|
@@ -12101,8 +12296,9 @@ class LettaAgentClientBase {
|
|
|
12101
12296
|
if (options.filesystemConfinement !== undefined) {
|
|
12102
12297
|
throw new Error(`${action}() filesystemConfinement requires an SDK-owned local app-server process.`);
|
|
12103
12298
|
}
|
|
12104
|
-
if (options.environment !== undefined) {
|
|
12105
|
-
|
|
12299
|
+
if (options.computer !== undefined || options.environment !== undefined) {
|
|
12300
|
+
const field = options.computer !== undefined ? "computer" : "environment";
|
|
12301
|
+
throw new Error(`${action}() ${field} overrides are only valid with backend: "cloud"; remote url selects the app-server runtime.`);
|
|
12106
12302
|
}
|
|
12107
12303
|
if (options.sandbox !== undefined) {
|
|
12108
12304
|
throw new Error(`${action}() sandbox options are only valid with backend: "cloud"; remote url selects the app-server runtime.`);
|
|
@@ -12117,11 +12313,13 @@ class LettaAgentClientBase {
|
|
|
12117
12313
|
throw new Error(`${action}() filesystemConfinement is only supported with backend: "local".`);
|
|
12118
12314
|
}
|
|
12119
12315
|
const cloudOptions = this.cloudOptions();
|
|
12120
|
-
if (
|
|
12121
|
-
|
|
12316
|
+
if (this.computer !== undefined && options.sandbox !== undefined) {
|
|
12317
|
+
const field = cloudOptions.computer !== undefined ? "computer" : "environment";
|
|
12318
|
+
throw new Error(`Letta Cloud ${action}() cannot specify sandbox options when the client has a default ${field}.`);
|
|
12122
12319
|
}
|
|
12123
|
-
if (cloudOptions.sandbox !== undefined && options.environment !== undefined) {
|
|
12124
|
-
|
|
12320
|
+
if (cloudOptions.sandbox !== undefined && (options.computer !== undefined || options.environment !== undefined)) {
|
|
12321
|
+
const field = options.computer !== undefined ? "a computer" : "an environment";
|
|
12322
|
+
throw new Error(`Letta Cloud ${action}() cannot specify ${field} when the client has default sandbox options.`);
|
|
12125
12323
|
}
|
|
12126
12324
|
assertCloudSessionOptionsSupported(action, options);
|
|
12127
12325
|
return;
|
|
@@ -12152,6 +12350,13 @@ class LettaAgentClientBase {
|
|
|
12152
12350
|
appServerSessionOptions() {
|
|
12153
12351
|
return this.remoteOptions();
|
|
12154
12352
|
}
|
|
12353
|
+
getComputersClient() {
|
|
12354
|
+
if (this.backend !== "cloud") {
|
|
12355
|
+
throw new Error('client.computers is only available with backend: "cloud".');
|
|
12356
|
+
}
|
|
12357
|
+
this.computersClient ??= new ComputersClientImpl(this.getCloudClient());
|
|
12358
|
+
return this.computersClient;
|
|
12359
|
+
}
|
|
12155
12360
|
getRepositoriesClient() {
|
|
12156
12361
|
if (this.backend !== "cloud") {
|
|
12157
12362
|
throw new Error('client.repositories is only available with backend: "cloud".');
|
|
@@ -12287,4 +12492,4 @@ export {
|
|
|
12287
12492
|
CloudManagedSandboxExpiredError
|
|
12288
12493
|
};
|
|
12289
12494
|
|
|
12290
|
-
//# debugId=
|
|
12495
|
+
//# debugId=6E490415C5923C8964756E2164756E21
|