@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/index.js
CHANGED
|
@@ -9514,6 +9514,9 @@ class RemoteClientSessionCore {
|
|
|
9514
9514
|
initializePromise = null;
|
|
9515
9515
|
removeMessageHandler = null;
|
|
9516
9516
|
detachTransportDisconnect = null;
|
|
9517
|
+
idleTransportDisconnected = false;
|
|
9518
|
+
transportRecoveryPromise = null;
|
|
9519
|
+
transportDisconnectGeneration = 0;
|
|
9517
9520
|
turns;
|
|
9518
9521
|
toolNames;
|
|
9519
9522
|
deviceStatusListeners = new Set;
|
|
@@ -9603,16 +9606,24 @@ class RemoteClientSessionCore {
|
|
|
9603
9606
|
this.initialized = false;
|
|
9604
9607
|
}
|
|
9605
9608
|
async send(message) {
|
|
9609
|
+
if (this.closed)
|
|
9610
|
+
throw new Error("Session is closed");
|
|
9606
9611
|
if (!this.initialized) {
|
|
9607
9612
|
await this.initialize();
|
|
9608
9613
|
}
|
|
9614
|
+
await this.recoverIdleTransportIfNeeded();
|
|
9609
9615
|
if (!this.controller || !this.runtime) {
|
|
9610
9616
|
throw new Error("Session is not initialized");
|
|
9611
9617
|
}
|
|
9612
9618
|
await this.beforeTurn();
|
|
9613
|
-
const
|
|
9619
|
+
const controller = this.controller;
|
|
9620
|
+
const runtime = this.runtime;
|
|
9621
|
+
if (!controller || !runtime) {
|
|
9622
|
+
throw new Error("Session transport disconnected before the turn was sent");
|
|
9623
|
+
}
|
|
9624
|
+
const turn = this.turns.trackSentTurn(runtime);
|
|
9614
9625
|
try {
|
|
9615
|
-
|
|
9626
|
+
controller.sendTurnMessage(runtime, message, {
|
|
9616
9627
|
clientMessageId: turn.clientMessageId
|
|
9617
9628
|
});
|
|
9618
9629
|
} catch (error) {
|
|
@@ -9887,6 +9898,7 @@ class RemoteClientSessionCore {
|
|
|
9887
9898
|
this.deviceStatusListeners.clear();
|
|
9888
9899
|
this.controller?.close();
|
|
9889
9900
|
this.controller = null;
|
|
9901
|
+
this.idleTransportDisconnected = false;
|
|
9890
9902
|
this.onCoreClose();
|
|
9891
9903
|
}
|
|
9892
9904
|
get agentId() {
|
|
@@ -9939,15 +9951,78 @@ class RemoteClientSessionCore {
|
|
|
9939
9951
|
}, { predicate: (message) => message.type === "update_toolset_response" });
|
|
9940
9952
|
ensureSuccess(response, "Failed to update toolset");
|
|
9941
9953
|
}
|
|
9942
|
-
watchTransportDisconnect(client) {
|
|
9954
|
+
watchTransportDisconnect(client, options = {}) {
|
|
9943
9955
|
this.detachTransportDisconnect?.();
|
|
9944
9956
|
this.detachTransportDisconnect = client.onDisconnect(() => {
|
|
9945
9957
|
if (this.closed)
|
|
9946
9958
|
return;
|
|
9959
|
+
this.transportDisconnectGeneration += 1;
|
|
9960
|
+
if (options.recoverWhenIdle && !this.turns.hasInFlightTurn()) {
|
|
9961
|
+
this.detachTransportDisconnect?.();
|
|
9962
|
+
this.detachTransportDisconnect = null;
|
|
9963
|
+
this.removeMessageHandler?.();
|
|
9964
|
+
this.removeMessageHandler = null;
|
|
9965
|
+
this.controller?.close();
|
|
9966
|
+
this.controller = null;
|
|
9967
|
+
const error = new Error(`${this.label} connection closed before send`);
|
|
9968
|
+
for (const cancel of [...this.deviceStatusRefreshCancels])
|
|
9969
|
+
cancel(error);
|
|
9970
|
+
this.deviceStatusRefreshCancels.clear();
|
|
9971
|
+
this.onIdleTransportDisconnect();
|
|
9972
|
+
this.idleTransportDisconnected = true;
|
|
9973
|
+
return;
|
|
9974
|
+
}
|
|
9947
9975
|
this.turns.closeWithError(`The ${this.label} connection closed unexpectedly; resume the conversation to continue.`);
|
|
9948
9976
|
this.close();
|
|
9949
9977
|
});
|
|
9950
9978
|
}
|
|
9979
|
+
async recoverIdleTransportIfNeeded() {
|
|
9980
|
+
if (!this.idleTransportDisconnected)
|
|
9981
|
+
return;
|
|
9982
|
+
if (this.transportRecoveryPromise) {
|
|
9983
|
+
await this.transportRecoveryPromise;
|
|
9984
|
+
return;
|
|
9985
|
+
}
|
|
9986
|
+
const runtime = this.runtime;
|
|
9987
|
+
if (!runtime)
|
|
9988
|
+
throw new Error("Session transport disconnected without a runtime");
|
|
9989
|
+
const generation = this.transportDisconnectGeneration;
|
|
9990
|
+
const recovery = this.recoverIdleTransport(runtime).then(async (init) => {
|
|
9991
|
+
if (this.closed || generation !== this.transportDisconnectGeneration) {
|
|
9992
|
+
init.controller.close();
|
|
9993
|
+
this.onRecoveredTransportDiscarded();
|
|
9994
|
+
throw new Error(`${this.label} connection closed during recovery`);
|
|
9995
|
+
}
|
|
9996
|
+
if (init.runtime.agent_id !== runtime.agent_id || init.runtime.conversation_id !== runtime.conversation_id) {
|
|
9997
|
+
init.controller.close();
|
|
9998
|
+
this.onRecoveredTransportDiscarded();
|
|
9999
|
+
throw new Error(`${this.label} transport recovered a different runtime`);
|
|
10000
|
+
}
|
|
10001
|
+
this.controller = init.controller;
|
|
10002
|
+
this.runtime = init.runtime;
|
|
10003
|
+
this._modelSettings = init.modelSettings ?? this._modelSettings;
|
|
10004
|
+
if (typeof init.model === "string" && init.model)
|
|
10005
|
+
this._model = init.model;
|
|
10006
|
+
if (init.tools !== undefined)
|
|
10007
|
+
this.toolNames = init.tools;
|
|
10008
|
+
this.removeMessageHandler = this.controller.onMessage((message) => {
|
|
10009
|
+
if (this.runtime)
|
|
10010
|
+
this.turns.handleProtocolMessage(message, this.runtime);
|
|
10011
|
+
});
|
|
10012
|
+
this.idleTransportDisconnected = false;
|
|
10013
|
+
await this.afterRuntimeInitialized();
|
|
10014
|
+
}).finally(() => {
|
|
10015
|
+
if (this.transportRecoveryPromise === recovery)
|
|
10016
|
+
this.transportRecoveryPromise = null;
|
|
10017
|
+
});
|
|
10018
|
+
this.transportRecoveryPromise = recovery;
|
|
10019
|
+
await recovery;
|
|
10020
|
+
}
|
|
10021
|
+
async recoverIdleTransport(_runtime) {
|
|
10022
|
+
throw new Error(`${this.label} sessions do not support idle transport recovery`);
|
|
10023
|
+
}
|
|
10024
|
+
onIdleTransportDisconnect() {}
|
|
10025
|
+
onRecoveredTransportDiscarded() {}
|
|
9951
10026
|
async afterRuntimeInitialized() {}
|
|
9952
10027
|
async beforeTurn() {}
|
|
9953
10028
|
onCoreClose() {}
|
|
@@ -10691,6 +10766,132 @@ class CloudManagementTransport {
|
|
|
10691
10766
|
}
|
|
10692
10767
|
}
|
|
10693
10768
|
|
|
10769
|
+
// src/remote.ts
|
|
10770
|
+
function ensureOnline(environment, target) {
|
|
10771
|
+
if (!environment.connectionId) {
|
|
10772
|
+
const label = "deviceId" in target ? target.deviceId : ("environmentId" in target) ? target.environmentId : ("connectionName" in target) ? target.connectionName : environment.deviceId;
|
|
10773
|
+
throw new Error(`Computer is offline: ${label}`);
|
|
10774
|
+
}
|
|
10775
|
+
return {
|
|
10776
|
+
connectionId: environment.connectionId,
|
|
10777
|
+
environment,
|
|
10778
|
+
target
|
|
10779
|
+
};
|
|
10780
|
+
}
|
|
10781
|
+
|
|
10782
|
+
class RemoteEnvironmentClient {
|
|
10783
|
+
client;
|
|
10784
|
+
constructor(options = {}, client = createCloudClient({
|
|
10785
|
+
backend: "cloud",
|
|
10786
|
+
apiBaseUrl: options.baseUrl,
|
|
10787
|
+
apiKey: options.apiKey,
|
|
10788
|
+
headers: options.headers,
|
|
10789
|
+
fetch: options.fetch
|
|
10790
|
+
})) {
|
|
10791
|
+
this.client = client;
|
|
10792
|
+
}
|
|
10793
|
+
async listEnvironments(options = {}) {
|
|
10794
|
+
return await this.client.environments.list({
|
|
10795
|
+
after: options.after,
|
|
10796
|
+
limit: options.limit === undefined ? undefined : String(options.limit),
|
|
10797
|
+
onlineOnly: options.onlineOnly === undefined ? undefined : String(options.onlineOnly)
|
|
10798
|
+
});
|
|
10799
|
+
}
|
|
10800
|
+
async getEnvironmentByDeviceId(deviceId) {
|
|
10801
|
+
return await this.client.environments.retrieve(deviceId);
|
|
10802
|
+
}
|
|
10803
|
+
async resolveEnvironment(target) {
|
|
10804
|
+
if ("connectionId" in target) {
|
|
10805
|
+
return { connectionId: target.connectionId, target };
|
|
10806
|
+
}
|
|
10807
|
+
if ("deviceId" in target) {
|
|
10808
|
+
return ensureOnline(await this.getEnvironmentByDeviceId(target.deviceId), target);
|
|
10809
|
+
}
|
|
10810
|
+
const connections = [];
|
|
10811
|
+
let after;
|
|
10812
|
+
do {
|
|
10813
|
+
const page = await this.listEnvironments({ limit: 100, after });
|
|
10814
|
+
connections.push(...page.connections);
|
|
10815
|
+
if (!page.hasNextPage || page.connections.length === 0)
|
|
10816
|
+
break;
|
|
10817
|
+
after = page.connections.at(-1)?.id;
|
|
10818
|
+
} while (after !== undefined);
|
|
10819
|
+
if ("environmentId" in target) {
|
|
10820
|
+
const match = connections.find((env) => env.id === target.environmentId);
|
|
10821
|
+
if (!match) {
|
|
10822
|
+
throw new Error(`Remote environment not found: ${target.environmentId}`);
|
|
10823
|
+
}
|
|
10824
|
+
return ensureOnline(match, target);
|
|
10825
|
+
}
|
|
10826
|
+
const matches = connections.filter((env) => env.connectionName === target.connectionName);
|
|
10827
|
+
if (matches.length === 0) {
|
|
10828
|
+
throw new Error(`Computer not found: ${target.connectionName}`);
|
|
10829
|
+
}
|
|
10830
|
+
const onlineMatches = matches.filter((environment) => environment.connectionId !== null);
|
|
10831
|
+
if (onlineMatches.length === 0) {
|
|
10832
|
+
throw new Error(`Computer is offline: ${target.connectionName}`);
|
|
10833
|
+
}
|
|
10834
|
+
if (onlineMatches.length > 1) {
|
|
10835
|
+
const candidates = onlineMatches.map((environment) => `${environment.connectionName} (${environment.deviceId}, online)`).join(", ");
|
|
10836
|
+
throw new Error(`Computer name is ambiguous: ${target.connectionName}. Matches: ${candidates}. Select one by deviceId.`);
|
|
10837
|
+
}
|
|
10838
|
+
return ensureOnline(onlineMatches[0], target);
|
|
10839
|
+
}
|
|
10840
|
+
}
|
|
10841
|
+
|
|
10842
|
+
// src/computers.ts
|
|
10843
|
+
function selectorToRemoteTarget(selector) {
|
|
10844
|
+
if (typeof selector === "string")
|
|
10845
|
+
return { connectionName: selector };
|
|
10846
|
+
if ("name" in selector)
|
|
10847
|
+
return { connectionName: selector.name };
|
|
10848
|
+
if ("id" in selector)
|
|
10849
|
+
return { environmentId: selector.id };
|
|
10850
|
+
if ("connectionId" in selector) {
|
|
10851
|
+
return { connectionId: selector.connectionId };
|
|
10852
|
+
}
|
|
10853
|
+
return { deviceId: selector.deviceId };
|
|
10854
|
+
}
|
|
10855
|
+
function toComputer(environment) {
|
|
10856
|
+
return {
|
|
10857
|
+
id: environment.id,
|
|
10858
|
+
deviceId: environment.deviceId,
|
|
10859
|
+
connectionId: environment.connectionId,
|
|
10860
|
+
name: environment.connectionName,
|
|
10861
|
+
status: environment.connectionId ? "online" : "offline",
|
|
10862
|
+
connectedAt: environment.connectedAt,
|
|
10863
|
+
lastSeenAt: environment.lastSeenAt,
|
|
10864
|
+
metadata: environment.metadata
|
|
10865
|
+
};
|
|
10866
|
+
}
|
|
10867
|
+
|
|
10868
|
+
class ComputersClientImpl {
|
|
10869
|
+
environments;
|
|
10870
|
+
constructor(client) {
|
|
10871
|
+
this.environments = new RemoteEnvironmentClient({}, client);
|
|
10872
|
+
}
|
|
10873
|
+
async list(options = {}) {
|
|
10874
|
+
const result = await this.environments.listEnvironments(options);
|
|
10875
|
+
return {
|
|
10876
|
+
computers: result.connections.map(toComputer),
|
|
10877
|
+
hasNextPage: result.hasNextPage
|
|
10878
|
+
};
|
|
10879
|
+
}
|
|
10880
|
+
async get(deviceId) {
|
|
10881
|
+
if (typeof deviceId !== "string" || deviceId.trim().length === 0) {
|
|
10882
|
+
throw new Error("Invalid deviceId. Expected a non-empty string.");
|
|
10883
|
+
}
|
|
10884
|
+
return toComputer(await this.environments.getEnvironmentByDeviceId(deviceId));
|
|
10885
|
+
}
|
|
10886
|
+
async resolve(selector) {
|
|
10887
|
+
const result = await this.environments.resolveEnvironment(selectorToRemoteTarget(selector));
|
|
10888
|
+
return {
|
|
10889
|
+
connectionId: result.connectionId,
|
|
10890
|
+
computer: result.environment ? toComputer(result.environment) : undefined
|
|
10891
|
+
};
|
|
10892
|
+
}
|
|
10893
|
+
}
|
|
10894
|
+
|
|
10694
10895
|
// src/cloud-status-transport.ts
|
|
10695
10896
|
var CONNECTING = 0;
|
|
10696
10897
|
var OPEN = 1;
|
|
@@ -10907,66 +11108,6 @@ function createCloudStatusTransportConstructor(options) {
|
|
|
10907
11108
|
};
|
|
10908
11109
|
}
|
|
10909
11110
|
|
|
10910
|
-
// src/remote.ts
|
|
10911
|
-
function ensureOnline(environment, target) {
|
|
10912
|
-
if (!environment.connectionId) {
|
|
10913
|
-
const label = "deviceId" in target ? target.deviceId : ("environmentId" in target) ? target.environmentId : ("connectionName" in target) ? target.connectionName : environment.deviceId;
|
|
10914
|
-
throw new Error(`Remote environment is offline: ${label}`);
|
|
10915
|
-
}
|
|
10916
|
-
return {
|
|
10917
|
-
connectionId: environment.connectionId,
|
|
10918
|
-
environment,
|
|
10919
|
-
target
|
|
10920
|
-
};
|
|
10921
|
-
}
|
|
10922
|
-
|
|
10923
|
-
class RemoteEnvironmentClient {
|
|
10924
|
-
client;
|
|
10925
|
-
constructor(options = {}, client = createCloudClient({
|
|
10926
|
-
backend: "cloud",
|
|
10927
|
-
apiBaseUrl: options.baseUrl,
|
|
10928
|
-
apiKey: options.apiKey,
|
|
10929
|
-
headers: options.headers,
|
|
10930
|
-
fetch: options.fetch
|
|
10931
|
-
})) {
|
|
10932
|
-
this.client = client;
|
|
10933
|
-
}
|
|
10934
|
-
async listEnvironments() {
|
|
10935
|
-
return await this.client.environments.list();
|
|
10936
|
-
}
|
|
10937
|
-
async getEnvironmentByDeviceId(deviceId) {
|
|
10938
|
-
return await this.client.environments.retrieve(deviceId);
|
|
10939
|
-
}
|
|
10940
|
-
async resolveEnvironment(target) {
|
|
10941
|
-
if ("connectionId" in target) {
|
|
10942
|
-
return { connectionId: target.connectionId, target };
|
|
10943
|
-
}
|
|
10944
|
-
if ("deviceId" in target) {
|
|
10945
|
-
return ensureOnline(await this.getEnvironmentByDeviceId(target.deviceId), target);
|
|
10946
|
-
}
|
|
10947
|
-
const { connections } = await this.listEnvironments();
|
|
10948
|
-
if ("environmentId" in target) {
|
|
10949
|
-
const match2 = connections.find((env) => env.id === target.environmentId);
|
|
10950
|
-
if (!match2) {
|
|
10951
|
-
throw new Error(`Remote environment not found: ${target.environmentId}`);
|
|
10952
|
-
}
|
|
10953
|
-
return ensureOnline(match2, target);
|
|
10954
|
-
}
|
|
10955
|
-
const matches = connections.filter((env) => env.connectionName === target.connectionName);
|
|
10956
|
-
if (matches.length === 0) {
|
|
10957
|
-
throw new Error(`Remote environment not found: ${target.connectionName}`);
|
|
10958
|
-
}
|
|
10959
|
-
if (matches.length > 1) {
|
|
10960
|
-
throw new Error(`Remote environment name is ambiguous: ${target.connectionName}`);
|
|
10961
|
-
}
|
|
10962
|
-
const match = matches[0];
|
|
10963
|
-
if (!match) {
|
|
10964
|
-
throw new Error(`Remote environment not found: ${target.connectionName}`);
|
|
10965
|
-
}
|
|
10966
|
-
return ensureOnline(match, target);
|
|
10967
|
-
}
|
|
10968
|
-
}
|
|
10969
|
-
|
|
10970
11111
|
// src/cloud-sandbox.ts
|
|
10971
11112
|
var MIN_TTL_MINUTES = 1;
|
|
10972
11113
|
var MAX_TTL_MINUTES = 60;
|
|
@@ -11065,8 +11206,12 @@ function validatePositiveInteger3(value, name) {
|
|
|
11065
11206
|
function validateCloudClientOptions(options) {
|
|
11066
11207
|
validatePositiveInteger3(options.requestTimeoutMs, "requestTimeoutMs");
|
|
11067
11208
|
validateCloudSandboxOptions(options.sandbox, "sandbox");
|
|
11068
|
-
if (options.
|
|
11069
|
-
throw new Error("Letta Cloud
|
|
11209
|
+
if (options.computer !== undefined && options.environment !== undefined) {
|
|
11210
|
+
throw new Error("Letta Cloud clients cannot specify both computer and deprecated environment.");
|
|
11211
|
+
}
|
|
11212
|
+
if ((options.computer !== undefined || options.environment !== undefined) && options.sandbox !== undefined) {
|
|
11213
|
+
const field = options.computer !== undefined ? "computer" : "environment";
|
|
11214
|
+
throw new Error(`Letta Cloud sessions cannot specify both ${field} and sandbox options.`);
|
|
11070
11215
|
}
|
|
11071
11216
|
if (options.webSocketAuth !== undefined && options.webSocketAuth !== "header" && options.webSocketAuth !== "query") {
|
|
11072
11217
|
throw new Error("Invalid webSocketAuth. Valid values: header, query.");
|
|
@@ -11183,12 +11328,30 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
11183
11328
|
throw error;
|
|
11184
11329
|
});
|
|
11185
11330
|
this.connectionId = connection.connectionId;
|
|
11331
|
+
const options = this.currentOptions();
|
|
11332
|
+
this.mcpBridge = await connectMcpServers("mcpServers" in options ? options.mcpServers : undefined, {
|
|
11333
|
+
cwd: options.cwd,
|
|
11334
|
+
reservedToolNames: this.externalTools.keys()
|
|
11335
|
+
});
|
|
11336
|
+
for (const tool of this.mcpBridge.tools) {
|
|
11337
|
+
this.externalTools.set(tool.name, tool);
|
|
11338
|
+
}
|
|
11339
|
+
try {
|
|
11340
|
+
return await this.openCloudTransport(resolved.runtime, connection.connectionId);
|
|
11341
|
+
} catch (error) {
|
|
11342
|
+
await this.closeMcpBridge();
|
|
11343
|
+
await this.cleanupManagedSandbox();
|
|
11344
|
+
await this.cleanupSessionRepositories(resolved.runtime.agent_id, resolved.runtime.conversation_id);
|
|
11345
|
+
throw error;
|
|
11346
|
+
}
|
|
11347
|
+
}
|
|
11348
|
+
async openCloudTransport(runtime, connectionId) {
|
|
11186
11349
|
const apiKey = getCloudApiKey(this.cloudOptions);
|
|
11187
11350
|
const url = buildCloudStatusWebSocketUrl({
|
|
11188
11351
|
apiBaseUrl: this.cloudOptions.apiBaseUrl,
|
|
11189
|
-
connectionId
|
|
11190
|
-
agentId:
|
|
11191
|
-
conversationId:
|
|
11352
|
+
connectionId,
|
|
11353
|
+
agentId: runtime.agent_id,
|
|
11354
|
+
conversationId: runtime.conversation_id,
|
|
11192
11355
|
apiKey,
|
|
11193
11356
|
authMode: this.cloudOptions.webSocketAuth ?? "header"
|
|
11194
11357
|
});
|
|
@@ -11199,33 +11362,19 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
11199
11362
|
WebSocket: getWebSocketConstructor(this.cloudOptions.WebSocket),
|
|
11200
11363
|
...(this.cloudOptions.webSocketAuth ?? "header") === "header" ? { headers: cloudWebSocketHeaders(this.cloudOptions) } : {},
|
|
11201
11364
|
pingIntervalMs: this.cloudOptions.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS,
|
|
11202
|
-
runtime
|
|
11365
|
+
runtime
|
|
11203
11366
|
}),
|
|
11204
11367
|
requestTimeoutMs: this.cloudOptions.requestTimeoutMs ?? DEFAULT_TURN_TIMEOUT_MS
|
|
11205
11368
|
}));
|
|
11206
11369
|
const options = this.currentOptions();
|
|
11207
|
-
this.
|
|
11208
|
-
cwd: options.cwd,
|
|
11209
|
-
reservedToolNames: this.externalTools.keys()
|
|
11210
|
-
});
|
|
11211
|
-
for (const tool of this.mcpBridge.tools) {
|
|
11212
|
-
this.externalTools.set(tool.name, tool);
|
|
11213
|
-
}
|
|
11214
|
-
this.removeControlRequestHandler = registerAppServerControlRequestHandler({
|
|
11215
|
-
client,
|
|
11216
|
-
getRuntime: () => this.runtime,
|
|
11217
|
-
getOptions: () => this.currentOptions()
|
|
11218
|
-
});
|
|
11219
|
-
if (this.externalTools.size > 0) {
|
|
11220
|
-
this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools));
|
|
11221
|
-
}
|
|
11370
|
+
this.installTransportHandlers(client);
|
|
11222
11371
|
try {
|
|
11223
11372
|
await client.connect();
|
|
11224
|
-
const response = await this.startCloudRuntime(client,
|
|
11373
|
+
const response = await this.startCloudRuntime(client, runtime);
|
|
11225
11374
|
if (!response.success || !response.runtime) {
|
|
11226
11375
|
throw new Error(response.error ?? "Failed to start Cloud status runtime");
|
|
11227
11376
|
}
|
|
11228
|
-
this.watchTransportDisconnect(client);
|
|
11377
|
+
this.watchTransportDisconnect(client, { recoverWhenIdle: true });
|
|
11229
11378
|
const tools = agentToolNames(response.agent);
|
|
11230
11379
|
const skillSources = options.skillSources;
|
|
11231
11380
|
const clientToolset = "toolset" in options ? options.toolset : undefined;
|
|
@@ -11243,17 +11392,51 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
11243
11392
|
...skillSources !== undefined ? { skillSources: [...skillSources] } : {}
|
|
11244
11393
|
};
|
|
11245
11394
|
} catch (error) {
|
|
11246
|
-
this.
|
|
11247
|
-
this.removeExternalToolHandler = null;
|
|
11248
|
-
this.removeControlRequestHandler?.();
|
|
11249
|
-
this.removeControlRequestHandler = null;
|
|
11250
|
-
await this.closeMcpBridge();
|
|
11395
|
+
this.cleanupTransportHandlers();
|
|
11251
11396
|
client.close();
|
|
11252
|
-
await this.cleanupManagedSandbox();
|
|
11253
|
-
await this.cleanupSessionRepositories(resolved.runtime.agent_id, resolved.runtime.conversation_id);
|
|
11254
11397
|
throw error;
|
|
11255
11398
|
}
|
|
11256
11399
|
}
|
|
11400
|
+
installTransportHandlers(client) {
|
|
11401
|
+
this.cleanupTransportHandlers();
|
|
11402
|
+
this.removeControlRequestHandler = registerAppServerControlRequestHandler({
|
|
11403
|
+
client,
|
|
11404
|
+
getRuntime: () => this.runtime,
|
|
11405
|
+
getOptions: () => this.currentOptions()
|
|
11406
|
+
});
|
|
11407
|
+
if (this.externalTools.size > 0) {
|
|
11408
|
+
this.removeExternalToolHandler = client.onExternalToolCall(createExternalToolCallHandler(this.externalTools));
|
|
11409
|
+
}
|
|
11410
|
+
}
|
|
11411
|
+
cleanupTransportHandlers() {
|
|
11412
|
+
this.removeExternalToolHandler?.();
|
|
11413
|
+
this.removeExternalToolHandler = null;
|
|
11414
|
+
this.removeControlRequestHandler?.();
|
|
11415
|
+
this.removeControlRequestHandler = null;
|
|
11416
|
+
}
|
|
11417
|
+
async recoverIdleTransport(runtime) {
|
|
11418
|
+
const connection = await this.resolveRecoveryConnection(runtime);
|
|
11419
|
+
this.connectionId = connection.connectionId;
|
|
11420
|
+
return this.openCloudTransport(runtime, connection.connectionId);
|
|
11421
|
+
}
|
|
11422
|
+
async resolveRecoveryConnection(runtime) {
|
|
11423
|
+
const sandbox = this.managedSandbox;
|
|
11424
|
+
if (sandbox) {
|
|
11425
|
+
await this.refreshManagedSandbox(sandbox);
|
|
11426
|
+
return this.waitForManagedSandboxConnection(sandbox);
|
|
11427
|
+
}
|
|
11428
|
+
const environment = this.effectiveEnvironment();
|
|
11429
|
+
if (!environment) {
|
|
11430
|
+
throw new Error("Cloud idle transport recovery lost its execution target");
|
|
11431
|
+
}
|
|
11432
|
+
return this.resolveExplicitConnection(environment);
|
|
11433
|
+
}
|
|
11434
|
+
onIdleTransportDisconnect() {
|
|
11435
|
+
this.cleanupTransportHandlers();
|
|
11436
|
+
}
|
|
11437
|
+
onRecoveredTransportDiscarded() {
|
|
11438
|
+
this.cleanupTransportHandlers();
|
|
11439
|
+
}
|
|
11257
11440
|
async startCloudRuntime(client, runtime) {
|
|
11258
11441
|
const options = this.currentOptions();
|
|
11259
11442
|
const command = {
|
|
@@ -11296,10 +11479,7 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
11296
11479
|
await this.refreshManagedSandbox(sandbox);
|
|
11297
11480
|
}
|
|
11298
11481
|
onCoreClose() {
|
|
11299
|
-
this.
|
|
11300
|
-
this.removeExternalToolHandler = null;
|
|
11301
|
-
this.removeControlRequestHandler?.();
|
|
11302
|
-
this.removeControlRequestHandler = null;
|
|
11482
|
+
this.cleanupTransportHandlers();
|
|
11303
11483
|
this.mcpCleanup = this.closeMcpBridge();
|
|
11304
11484
|
this.cleanupManagedSandbox();
|
|
11305
11485
|
if (this.runtime?.agent_id) {
|
|
@@ -11623,8 +11803,8 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
11623
11803
|
return new RemoteEnvironmentClient({}, this.apiClient);
|
|
11624
11804
|
}
|
|
11625
11805
|
effectiveEnvironment() {
|
|
11626
|
-
const
|
|
11627
|
-
return
|
|
11806
|
+
const modeComputer = this.mode.kind === "session" ? this.mode.options.computer ?? this.mode.options.environment : undefined;
|
|
11807
|
+
return modeComputer ?? this.cloudOptions.computer ?? this.cloudOptions.environment;
|
|
11628
11808
|
}
|
|
11629
11809
|
effectiveSandboxOptions() {
|
|
11630
11810
|
const modeSandbox = this.mode.kind === "session" ? this.mode.options.sandbox : undefined;
|
|
@@ -11924,14 +12104,17 @@ var VALID_BACKENDS = new Set([
|
|
|
11924
12104
|
function isLettaCodeBackend(value) {
|
|
11925
12105
|
return VALID_BACKENDS.has(value);
|
|
11926
12106
|
}
|
|
11927
|
-
function
|
|
11928
|
-
if ("environment" in options)
|
|
11929
|
-
return
|
|
12107
|
+
function getOptionsComputer(options) {
|
|
12108
|
+
if (!("computer" in options) && !("environment" in options))
|
|
12109
|
+
return;
|
|
12110
|
+
if (options.computer !== undefined && options.environment !== undefined) {
|
|
12111
|
+
throw new Error('Specify either "computer" or deprecated "environment", not both.');
|
|
11930
12112
|
}
|
|
11931
|
-
return;
|
|
12113
|
+
return options.computer ?? options.environment;
|
|
11932
12114
|
}
|
|
11933
12115
|
function stripCloudExecutionOptions(options) {
|
|
11934
12116
|
const sessionOptions = { ...options };
|
|
12117
|
+
delete sessionOptions.computer;
|
|
11935
12118
|
delete sessionOptions.environment;
|
|
11936
12119
|
delete sessionOptions.sandbox;
|
|
11937
12120
|
delete sessionOptions.filesystemConfinement;
|
|
@@ -11949,12 +12132,14 @@ function looksLikeConversationId(id) {
|
|
|
11949
12132
|
|
|
11950
12133
|
class LettaAgentClientBase {
|
|
11951
12134
|
backend;
|
|
12135
|
+
computer;
|
|
11952
12136
|
environment;
|
|
11953
12137
|
agents;
|
|
11954
12138
|
conversations;
|
|
11955
12139
|
models;
|
|
11956
12140
|
options;
|
|
11957
12141
|
repositoriesClient = null;
|
|
12142
|
+
computersClient = null;
|
|
11958
12143
|
agentRepositoriesClient = null;
|
|
11959
12144
|
cloudClient = null;
|
|
11960
12145
|
managementTransport = null;
|
|
@@ -11964,16 +12149,19 @@ class LettaAgentClientBase {
|
|
|
11964
12149
|
throw new Error(`Invalid Letta Code backend '${String(backend)}'. Valid values: local, remote, cloud.`);
|
|
11965
12150
|
}
|
|
11966
12151
|
this.backend = backend;
|
|
11967
|
-
this.
|
|
12152
|
+
this.computer = getOptionsComputer(options);
|
|
12153
|
+
this.environment = this.computer;
|
|
11968
12154
|
this.options = options;
|
|
11969
12155
|
this.agents = createAgentsClient(() => this.getManagementTransport(), () => this.getAgentRepositoriesClient());
|
|
11970
12156
|
this.conversations = createConversationsClient(() => this.getManagementTransport());
|
|
11971
12157
|
this.models = createModelsClient(() => this.getManagementTransport());
|
|
11972
|
-
if (this.backend === "local" && this.
|
|
11973
|
-
|
|
12158
|
+
if (this.backend === "local" && this.computer !== undefined) {
|
|
12159
|
+
const field = "computer" in options && options.computer !== undefined ? "computer" : "environment";
|
|
12160
|
+
throw new Error(`LettaAgentClient ${field} is only valid with backend: "cloud".`);
|
|
11974
12161
|
}
|
|
11975
|
-
if (this.backend === "remote" && this.
|
|
11976
|
-
|
|
12162
|
+
if (this.backend === "remote" && this.computer !== undefined) {
|
|
12163
|
+
const field = "computer" in options && options.computer !== undefined ? "computer" : "environment";
|
|
12164
|
+
throw new Error(`LettaAgentClient ${field} is only valid with backend: "cloud"; remote url selects the app-server runtime.`);
|
|
11977
12165
|
}
|
|
11978
12166
|
if (this.backend !== "cloud" && options.sandbox !== undefined) {
|
|
11979
12167
|
throw new Error('LettaAgentClient sandbox options are only valid with backend: "cloud".');
|
|
@@ -12007,6 +12195,9 @@ class LettaAgentClientBase {
|
|
|
12007
12195
|
get repositories() {
|
|
12008
12196
|
return this.getRepositoriesClient();
|
|
12009
12197
|
}
|
|
12198
|
+
get computers() {
|
|
12199
|
+
return this.getComputersClient();
|
|
12200
|
+
}
|
|
12010
12201
|
async createAgent(options = {}) {
|
|
12011
12202
|
if (hasCreateAgentEnvironment(options)) {
|
|
12012
12203
|
throw new Error("createAgent() does not accept environment. Set a client default or pass environment to resumeSession()/createSession().");
|
|
@@ -12096,13 +12287,17 @@ class LettaAgentClientBase {
|
|
|
12096
12287
|
}
|
|
12097
12288
|
}
|
|
12098
12289
|
assertSessionBackend(action, options) {
|
|
12290
|
+
if (options.computer !== undefined && options.environment !== undefined) {
|
|
12291
|
+
throw new Error(`${action}() cannot specify both computer and deprecated environment.`);
|
|
12292
|
+
}
|
|
12099
12293
|
if (options.filesystemConfinement !== undefined && options.filesystemConfinement !== "memory") {
|
|
12100
12294
|
throw new Error(`Invalid filesystemConfinement '${String(options.filesystemConfinement)}'. Valid value: memory.`);
|
|
12101
12295
|
}
|
|
12102
|
-
const
|
|
12296
|
+
const effectiveComputer = options.computer ?? options.environment ?? this.computer;
|
|
12103
12297
|
if (this.backend === "local") {
|
|
12104
|
-
if (
|
|
12105
|
-
|
|
12298
|
+
if (effectiveComputer !== undefined) {
|
|
12299
|
+
const field = options.computer !== undefined ? "computer" : "environment";
|
|
12300
|
+
throw new Error(`${action}() ${field} overrides are only valid with backend: "cloud".`);
|
|
12106
12301
|
}
|
|
12107
12302
|
if (options.sandbox !== undefined) {
|
|
12108
12303
|
throw new Error(`${action}() sandbox options are only valid with backend: "cloud".`);
|
|
@@ -12122,8 +12317,9 @@ class LettaAgentClientBase {
|
|
|
12122
12317
|
if (options.filesystemConfinement !== undefined) {
|
|
12123
12318
|
throw new Error(`${action}() filesystemConfinement requires an SDK-owned local app-server process.`);
|
|
12124
12319
|
}
|
|
12125
|
-
if (options.environment !== undefined) {
|
|
12126
|
-
|
|
12320
|
+
if (options.computer !== undefined || options.environment !== undefined) {
|
|
12321
|
+
const field = options.computer !== undefined ? "computer" : "environment";
|
|
12322
|
+
throw new Error(`${action}() ${field} overrides are only valid with backend: "cloud"; remote url selects the app-server runtime.`);
|
|
12127
12323
|
}
|
|
12128
12324
|
if (options.sandbox !== undefined) {
|
|
12129
12325
|
throw new Error(`${action}() sandbox options are only valid with backend: "cloud"; remote url selects the app-server runtime.`);
|
|
@@ -12138,11 +12334,13 @@ class LettaAgentClientBase {
|
|
|
12138
12334
|
throw new Error(`${action}() filesystemConfinement is only supported with backend: "local".`);
|
|
12139
12335
|
}
|
|
12140
12336
|
const cloudOptions = this.cloudOptions();
|
|
12141
|
-
if (
|
|
12142
|
-
|
|
12337
|
+
if (this.computer !== undefined && options.sandbox !== undefined) {
|
|
12338
|
+
const field = cloudOptions.computer !== undefined ? "computer" : "environment";
|
|
12339
|
+
throw new Error(`Letta Cloud ${action}() cannot specify sandbox options when the client has a default ${field}.`);
|
|
12143
12340
|
}
|
|
12144
|
-
if (cloudOptions.sandbox !== undefined && options.environment !== undefined) {
|
|
12145
|
-
|
|
12341
|
+
if (cloudOptions.sandbox !== undefined && (options.computer !== undefined || options.environment !== undefined)) {
|
|
12342
|
+
const field = options.computer !== undefined ? "a computer" : "an environment";
|
|
12343
|
+
throw new Error(`Letta Cloud ${action}() cannot specify ${field} when the client has default sandbox options.`);
|
|
12146
12344
|
}
|
|
12147
12345
|
assertCloudSessionOptionsSupported(action, options);
|
|
12148
12346
|
return;
|
|
@@ -12173,6 +12371,13 @@ class LettaAgentClientBase {
|
|
|
12173
12371
|
appServerSessionOptions() {
|
|
12174
12372
|
return this.remoteOptions();
|
|
12175
12373
|
}
|
|
12374
|
+
getComputersClient() {
|
|
12375
|
+
if (this.backend !== "cloud") {
|
|
12376
|
+
throw new Error('client.computers is only available with backend: "cloud".');
|
|
12377
|
+
}
|
|
12378
|
+
this.computersClient ??= new ComputersClientImpl(this.getCloudClient());
|
|
12379
|
+
return this.computersClient;
|
|
12380
|
+
}
|
|
12176
12381
|
getRepositoriesClient() {
|
|
12177
12382
|
if (this.backend !== "cloud") {
|
|
12178
12383
|
throw new Error('client.repositories is only available with backend: "cloud".');
|
|
@@ -29929,4 +30134,4 @@ export {
|
|
|
29929
30134
|
CloudManagedSandboxExpiredError
|
|
29930
30135
|
};
|
|
29931
30136
|
|
|
29932
|
-
//# debugId=
|
|
30137
|
+
//# debugId=C079C2D0B42E0C4F64756E2164756E21
|