@letta-ai/letta-agent-sdk 0.3.0 → 0.3.2
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 +29 -1
- package/dist/app-server-management.d.ts +61 -1
- package/dist/app-server-management.d.ts.map +1 -1
- package/dist/app-server-session.d.ts +7 -4
- package/dist/app-server-session.d.ts.map +1 -1
- package/dist/client-base.d.ts +9 -1
- package/dist/client-base.d.ts.map +1 -1
- package/dist/client-entry.js +677 -61
- package/dist/client-entry.js.map +12 -11
- package/dist/client.d.ts.map +1 -1
- package/dist/cloud-management.d.ts +3 -1
- package/dist/cloud-management.d.ts.map +1 -1
- package/dist/cloud-session.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +733 -71
- package/dist/index.js.map +16 -15
- package/dist/interactiveToolPolicy.d.ts +7 -0
- package/dist/interactiveToolPolicy.d.ts.map +1 -1
- package/dist/local-app-server-session.d.ts +1 -1
- package/dist/local-app-server-session.d.ts.map +1 -1
- package/dist/management-types.d.ts +11 -1
- package/dist/management-types.d.ts.map +1 -1
- package/dist/management.d.ts +12 -1
- package/dist/management.d.ts.map +1 -1
- package/dist/remote-client-session-core.d.ts +24 -1
- package/dist/remote-client-session-core.d.ts.map +1 -1
- package/dist/request-ids.d.ts +24 -0
- package/dist/request-ids.d.ts.map +1 -0
- package/dist/session.d.ts +13 -2
- package/dist/session.d.ts.map +1 -1
- package/dist/types.d.ts +133 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/client-entry.js
CHANGED
|
@@ -682,18 +682,101 @@ function createAppServerClient(options) {
|
|
|
682
682
|
return new AppServerClient(options);
|
|
683
683
|
}
|
|
684
684
|
|
|
685
|
+
// src/request-ids.ts
|
|
686
|
+
var processRequestCounter = 0;
|
|
687
|
+
function createRequestIdGenerator() {
|
|
688
|
+
const nonce = Math.random().toString(36).slice(2, 10);
|
|
689
|
+
return (prefix = "req") => `${prefix}-${nonce}-${++processRequestCounter}`;
|
|
690
|
+
}
|
|
691
|
+
function applyUniqueRequestIds(client) {
|
|
692
|
+
client.nextRequestId = createRequestIdGenerator();
|
|
693
|
+
return client;
|
|
694
|
+
}
|
|
695
|
+
|
|
685
696
|
// src/app-server-management.ts
|
|
697
|
+
var DEFAULT_IDLE_LINGER_MS = 250;
|
|
698
|
+
var registeredTransportsByUrl = new Map;
|
|
699
|
+
function appServerUrlKey(value) {
|
|
700
|
+
try {
|
|
701
|
+
const url = new URL(value);
|
|
702
|
+
if (url.protocol === "http:")
|
|
703
|
+
url.protocol = "ws:";
|
|
704
|
+
if (url.protocol === "https:")
|
|
705
|
+
url.protocol = "wss:";
|
|
706
|
+
url.hash = "";
|
|
707
|
+
url.searchParams.delete("channel");
|
|
708
|
+
return url.toString();
|
|
709
|
+
} catch {
|
|
710
|
+
return value;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
function registerManagementTransport(url, transport) {
|
|
714
|
+
const key = appServerUrlKey(url);
|
|
715
|
+
const registration = { transport };
|
|
716
|
+
const transports = registeredTransportsByUrl.get(key) ?? new Set;
|
|
717
|
+
transports.add(registration);
|
|
718
|
+
registeredTransportsByUrl.set(key, transports);
|
|
719
|
+
return () => {
|
|
720
|
+
transports.delete(registration);
|
|
721
|
+
if (transports.size === 0) {
|
|
722
|
+
registeredTransportsByUrl.delete(key);
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
async function releaseAppServerManagementConnections(url) {
|
|
727
|
+
const key = appServerUrlKey(url);
|
|
728
|
+
while (true) {
|
|
729
|
+
const transports = [...registeredTransportsByUrl.get(key) ?? []];
|
|
730
|
+
if (transports.length === 0)
|
|
731
|
+
return;
|
|
732
|
+
await Promise.all(transports.map(({ transport }) => transport.releaseIdleConnection()));
|
|
733
|
+
}
|
|
734
|
+
}
|
|
686
735
|
function ensureResponse(response, value, fallback) {
|
|
687
736
|
if (!response.success || value == null) {
|
|
688
737
|
throw new Error(response.error ?? fallback);
|
|
689
738
|
}
|
|
690
739
|
return value;
|
|
691
740
|
}
|
|
741
|
+
function modelEntries(value) {
|
|
742
|
+
if (!Array.isArray(value))
|
|
743
|
+
return [];
|
|
744
|
+
return value.flatMap((entry) => {
|
|
745
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
746
|
+
return [];
|
|
747
|
+
const record = entry;
|
|
748
|
+
if (typeof record.id !== "string" || typeof record.handle !== "string" || typeof record.label !== "string" || typeof record.description !== "string") {
|
|
749
|
+
return [];
|
|
750
|
+
}
|
|
751
|
+
return [{
|
|
752
|
+
...record,
|
|
753
|
+
id: record.id,
|
|
754
|
+
handle: record.handle,
|
|
755
|
+
label: record.label,
|
|
756
|
+
description: record.description
|
|
757
|
+
}];
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
function stringRecord(value) {
|
|
761
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
const entries = Object.entries(value).filter((entry) => typeof entry[1] === "string");
|
|
765
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
766
|
+
}
|
|
692
767
|
|
|
693
768
|
class AppServerManagementTransport {
|
|
694
769
|
options;
|
|
770
|
+
connectionPromise = null;
|
|
771
|
+
releasePromise = null;
|
|
772
|
+
closingConnections = new Set;
|
|
773
|
+
inFlightRequests = 0;
|
|
774
|
+
idleWaiters = new Set;
|
|
775
|
+
idleTimer = null;
|
|
776
|
+
idleLingerMs;
|
|
695
777
|
constructor(options) {
|
|
696
778
|
this.options = options;
|
|
779
|
+
this.idleLingerMs = options.idleLingerMs ?? DEFAULT_IDLE_LINGER_MS;
|
|
697
780
|
}
|
|
698
781
|
async listAgents(query) {
|
|
699
782
|
const response = await this.request("agent_list", { query }, "agent_list_response");
|
|
@@ -710,6 +793,30 @@ class AppServerManagementTransport {
|
|
|
710
793
|
const response = await this.request("agent_update", { agent_id: agentId, body }, "agent_update_response");
|
|
711
794
|
return ensureResponse(response, response.agent, `Failed to update agent ${agentId}.`);
|
|
712
795
|
}
|
|
796
|
+
async deleteAgent(agentId) {
|
|
797
|
+
const response = await this.request("agent_delete", { agent_id: agentId }, "agent_delete_response");
|
|
798
|
+
if (!response.success) {
|
|
799
|
+
throw new Error(response.error ?? `Failed to delete agent ${agentId}.`);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
async listModels() {
|
|
803
|
+
const response = await this.request("list_models", {}, "list_models_response");
|
|
804
|
+
if (!response.success) {
|
|
805
|
+
throw new Error(response.error ?? "Failed to list models.");
|
|
806
|
+
}
|
|
807
|
+
const result = {
|
|
808
|
+
entries: modelEntries(response.entries)
|
|
809
|
+
};
|
|
810
|
+
if (response.available_handles === null) {
|
|
811
|
+
result.availableHandles = null;
|
|
812
|
+
} else if (Array.isArray(response.available_handles)) {
|
|
813
|
+
result.availableHandles = response.available_handles.filter((handle) => typeof handle === "string");
|
|
814
|
+
}
|
|
815
|
+
const aliases = stringRecord(response.byok_provider_aliases);
|
|
816
|
+
if (aliases)
|
|
817
|
+
result.byokProviderAliases = aliases;
|
|
818
|
+
return result;
|
|
819
|
+
}
|
|
713
820
|
async listConversations(query) {
|
|
714
821
|
const response = await this.request("conversation_list", { query }, "conversation_list_response");
|
|
715
822
|
if (!response.success) {
|
|
@@ -736,38 +843,206 @@ class AppServerManagementTransport {
|
|
|
736
843
|
}
|
|
737
844
|
return { messages: response.messages };
|
|
738
845
|
}
|
|
846
|
+
releaseIdleConnection() {
|
|
847
|
+
this.clearIdleTimer();
|
|
848
|
+
if (this.releasePromise)
|
|
849
|
+
return this.releasePromise;
|
|
850
|
+
const release = this.releaseConnectionWhenIdle();
|
|
851
|
+
this.releasePromise = release;
|
|
852
|
+
release.then(() => {
|
|
853
|
+
if (this.releasePromise === release) {
|
|
854
|
+
this.releasePromise = null;
|
|
855
|
+
}
|
|
856
|
+
}, () => {
|
|
857
|
+
if (this.releasePromise === release) {
|
|
858
|
+
this.releasePromise = null;
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
return release;
|
|
862
|
+
}
|
|
739
863
|
async request(type, body, responseType) {
|
|
740
|
-
|
|
864
|
+
if (this.releasePromise) {
|
|
865
|
+
await this.releasePromise;
|
|
866
|
+
}
|
|
867
|
+
if (this.closingConnections.size > 0) {
|
|
868
|
+
await Promise.all([...this.closingConnections]);
|
|
869
|
+
}
|
|
870
|
+
this.clearIdleTimer();
|
|
871
|
+
this.inFlightRequests += 1;
|
|
872
|
+
try {
|
|
873
|
+
const { client } = await this.acquireConnection();
|
|
874
|
+
const command = {
|
|
875
|
+
type,
|
|
876
|
+
request_id: client.nextRequestId(type),
|
|
877
|
+
...body
|
|
878
|
+
};
|
|
879
|
+
const response = await client.request(command, {
|
|
880
|
+
predicate: (message) => message.type === responseType
|
|
881
|
+
});
|
|
882
|
+
return response;
|
|
883
|
+
} finally {
|
|
884
|
+
this.inFlightRequests -= 1;
|
|
885
|
+
if (this.inFlightRequests === 0) {
|
|
886
|
+
const waiters = [...this.idleWaiters];
|
|
887
|
+
this.idleWaiters.clear();
|
|
888
|
+
for (const resolve of waiters)
|
|
889
|
+
resolve();
|
|
890
|
+
if (!this.releasePromise) {
|
|
891
|
+
this.scheduleIdleRelease();
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
async releaseConnectionWhenIdle() {
|
|
897
|
+
if (this.inFlightRequests > 0) {
|
|
898
|
+
await new Promise((resolve) => {
|
|
899
|
+
this.idleWaiters.add(resolve);
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
this.clearIdleTimer();
|
|
903
|
+
const promise = this.connectionPromise;
|
|
904
|
+
try {
|
|
905
|
+
if (promise) {
|
|
906
|
+
this.connectionPromise = null;
|
|
907
|
+
await this.trackClosingConnection(await promise);
|
|
908
|
+
}
|
|
909
|
+
if (this.closingConnections.size > 0) {
|
|
910
|
+
await Promise.all([...this.closingConnections]);
|
|
911
|
+
}
|
|
912
|
+
} catch {}
|
|
913
|
+
}
|
|
914
|
+
acquireConnection() {
|
|
915
|
+
if (this.connectionPromise)
|
|
916
|
+
return this.connectionPromise;
|
|
917
|
+
const promise = this.openConnection().then((connection) => {
|
|
918
|
+
connection.detachDisconnect = connection.client.onDisconnect(() => {
|
|
919
|
+
this.discardConnection(promise, connection);
|
|
920
|
+
});
|
|
921
|
+
return connection;
|
|
922
|
+
}, (error) => {
|
|
923
|
+
if (this.connectionPromise === promise) {
|
|
924
|
+
this.connectionPromise = null;
|
|
925
|
+
}
|
|
926
|
+
throw error;
|
|
927
|
+
});
|
|
928
|
+
this.connectionPromise = promise;
|
|
929
|
+
return promise;
|
|
930
|
+
}
|
|
931
|
+
async openConnection() {
|
|
932
|
+
const ownedConnection = this.options.url ? null : await this.options.connect?.() ?? null;
|
|
741
933
|
const url = this.options.url ?? ownedConnection?.url;
|
|
742
934
|
if (!url) {
|
|
743
935
|
throw new Error("App-server management requires a url or connect hook.");
|
|
744
936
|
}
|
|
937
|
+
const unregister = registerManagementTransport(url, this);
|
|
745
938
|
let client = null;
|
|
746
939
|
try {
|
|
747
|
-
client = createAppServerClient({
|
|
940
|
+
client = applyUniqueRequestIds(createAppServerClient({
|
|
748
941
|
url,
|
|
749
942
|
...this.options.authToken !== undefined ? { authToken: this.options.authToken } : {},
|
|
750
943
|
...this.options.WebSocket ? {
|
|
751
944
|
WebSocket: this.options.WebSocket
|
|
752
945
|
} : {},
|
|
753
946
|
...this.options.requestTimeoutMs !== undefined ? { requestTimeoutMs: this.options.requestTimeoutMs } : {}
|
|
754
|
-
});
|
|
947
|
+
}));
|
|
755
948
|
await client.connect();
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
949
|
+
} catch (error) {
|
|
950
|
+
try {
|
|
951
|
+
if (client) {
|
|
952
|
+
const controlClosed = waitForSocketClose(client.control);
|
|
953
|
+
client.close();
|
|
954
|
+
ownedConnection?.close();
|
|
955
|
+
await controlClosed;
|
|
956
|
+
} else {
|
|
957
|
+
ownedConnection?.close();
|
|
958
|
+
}
|
|
959
|
+
} catch {} finally {
|
|
960
|
+
unregister();
|
|
961
|
+
}
|
|
962
|
+
throw error;
|
|
768
963
|
}
|
|
964
|
+
return {
|
|
965
|
+
client,
|
|
966
|
+
ownedConnection,
|
|
967
|
+
detachDisconnect: () => {},
|
|
968
|
+
unregister
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
discardConnection(promise, connection) {
|
|
972
|
+
if (this.connectionPromise === promise) {
|
|
973
|
+
this.connectionPromise = null;
|
|
974
|
+
this.clearIdleTimer();
|
|
975
|
+
}
|
|
976
|
+
this.trackClosingConnection(connection);
|
|
977
|
+
}
|
|
978
|
+
trackClosingConnection(connection) {
|
|
979
|
+
const closing = closeConnection(connection);
|
|
980
|
+
this.closingConnections.add(closing);
|
|
981
|
+
closing.then(() => this.closingConnections.delete(closing), () => this.closingConnections.delete(closing));
|
|
982
|
+
return closing;
|
|
983
|
+
}
|
|
984
|
+
scheduleIdleRelease() {
|
|
985
|
+
if (!this.connectionPromise)
|
|
986
|
+
return;
|
|
987
|
+
this.clearIdleTimer();
|
|
988
|
+
const timer = setTimeout(() => {
|
|
989
|
+
this.idleTimer = null;
|
|
990
|
+
this.releaseIdleConnection();
|
|
991
|
+
}, this.idleLingerMs);
|
|
992
|
+
this.idleTimer = timer;
|
|
993
|
+
timer.unref?.();
|
|
994
|
+
}
|
|
995
|
+
clearIdleTimer() {
|
|
996
|
+
if (this.idleTimer === null)
|
|
997
|
+
return;
|
|
998
|
+
clearTimeout(this.idleTimer);
|
|
999
|
+
this.idleTimer = null;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
async function closeConnection(connection) {
|
|
1003
|
+
connection.detachDisconnect();
|
|
1004
|
+
const controlClosed = waitForSocketClose(connection.client.control);
|
|
1005
|
+
try {
|
|
1006
|
+
connection.client.close();
|
|
1007
|
+
connection.ownedConnection?.close();
|
|
1008
|
+
await controlClosed;
|
|
1009
|
+
} finally {
|
|
1010
|
+
connection.unregister();
|
|
769
1011
|
}
|
|
770
1012
|
}
|
|
1013
|
+
function waitForSocketClose(socket) {
|
|
1014
|
+
if (socket.readyState === 3)
|
|
1015
|
+
return Promise.resolve();
|
|
1016
|
+
return new Promise((resolve) => {
|
|
1017
|
+
let settled = false;
|
|
1018
|
+
let detach = () => {};
|
|
1019
|
+
const finish = () => {
|
|
1020
|
+
if (settled)
|
|
1021
|
+
return;
|
|
1022
|
+
settled = true;
|
|
1023
|
+
clearTimeout(timeout);
|
|
1024
|
+
detach();
|
|
1025
|
+
resolve();
|
|
1026
|
+
};
|
|
1027
|
+
if (socket.addEventListener) {
|
|
1028
|
+
socket.addEventListener("close", finish);
|
|
1029
|
+
detach = () => socket.removeEventListener?.("close", finish);
|
|
1030
|
+
} else if (socket.once) {
|
|
1031
|
+
socket.once("close", finish);
|
|
1032
|
+
detach = () => socket.off?.("close", finish);
|
|
1033
|
+
} else if (socket.on) {
|
|
1034
|
+
socket.on("close", finish);
|
|
1035
|
+
detach = () => socket.off?.("close", finish);
|
|
1036
|
+
} else {
|
|
1037
|
+
resolve();
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
const timeout = setTimeout(finish, 1000);
|
|
1041
|
+
timeout.unref?.();
|
|
1042
|
+
if (socket.readyState === 3)
|
|
1043
|
+
finish();
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
771
1046
|
|
|
772
1047
|
// node_modules/@letta-ai/letta-code/dist/agent-presets.js
|
|
773
1048
|
var LETTA_CODE_ORIGIN_TAG = "origin:letta-code";
|
|
@@ -5405,6 +5680,36 @@ function requiresRuntimeUserInput(toolName) {
|
|
|
5405
5680
|
function isHeadlessAutoAllowTool(toolName) {
|
|
5406
5681
|
return HEADLESS_AUTO_ALLOW_TOOLS.has(toolName);
|
|
5407
5682
|
}
|
|
5683
|
+
function normalizePermissionSuggestions(value) {
|
|
5684
|
+
if (!Array.isArray(value))
|
|
5685
|
+
return;
|
|
5686
|
+
const suggestions = [];
|
|
5687
|
+
for (const entry of value) {
|
|
5688
|
+
if (!entry || typeof entry !== "object")
|
|
5689
|
+
continue;
|
|
5690
|
+
const record = entry;
|
|
5691
|
+
if (typeof record.id === "string" && typeof record.text === "string") {
|
|
5692
|
+
suggestions.push({ id: record.id, text: record.text });
|
|
5693
|
+
}
|
|
5694
|
+
}
|
|
5695
|
+
return suggestions;
|
|
5696
|
+
}
|
|
5697
|
+
function buildCanUseToolContext(request, requestId) {
|
|
5698
|
+
const context = {};
|
|
5699
|
+
if (typeof requestId === "string")
|
|
5700
|
+
context.requestId = requestId;
|
|
5701
|
+
if (typeof request.tool_call_id === "string")
|
|
5702
|
+
context.toolCallId = request.tool_call_id;
|
|
5703
|
+
const suggestions = normalizePermissionSuggestions(request.permission_suggestions);
|
|
5704
|
+
if (suggestions !== undefined)
|
|
5705
|
+
context.permissionSuggestions = suggestions;
|
|
5706
|
+
if (typeof request.blocked_path === "string" || request.blocked_path === null) {
|
|
5707
|
+
context.blockedPath = request.blocked_path;
|
|
5708
|
+
}
|
|
5709
|
+
if (Array.isArray(request.diffs))
|
|
5710
|
+
context.diffs = request.diffs;
|
|
5711
|
+
return context;
|
|
5712
|
+
}
|
|
5408
5713
|
|
|
5409
5714
|
// src/remote-client-session-core.ts
|
|
5410
5715
|
var FAILURE_STOP_REASONS = new Set([
|
|
@@ -5682,6 +5987,121 @@ function queueItems(message) {
|
|
|
5682
5987
|
];
|
|
5683
5988
|
});
|
|
5684
5989
|
}
|
|
5990
|
+
function deviceStatusRecord(message) {
|
|
5991
|
+
if (message.type !== "update_device_status")
|
|
5992
|
+
return null;
|
|
5993
|
+
const status = message.device_status;
|
|
5994
|
+
return status && typeof status === "object" && !Array.isArray(status) ? status : null;
|
|
5995
|
+
}
|
|
5996
|
+
function pendingControlRequests(status) {
|
|
5997
|
+
const pending = status.pending_control_requests;
|
|
5998
|
+
if (!Array.isArray(pending))
|
|
5999
|
+
return [];
|
|
6000
|
+
return pending.flatMap((item) => {
|
|
6001
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
6002
|
+
return [];
|
|
6003
|
+
const record = item;
|
|
6004
|
+
if (typeof record.request_id !== "string")
|
|
6005
|
+
return [];
|
|
6006
|
+
const request = record.request && typeof record.request === "object" && !Array.isArray(record.request) ? record.request : null;
|
|
6007
|
+
if (!request || typeof request.tool_name !== "string")
|
|
6008
|
+
return [];
|
|
6009
|
+
const entry = {
|
|
6010
|
+
requestId: record.request_id,
|
|
6011
|
+
toolName: request.tool_name,
|
|
6012
|
+
permissionSuggestions: permissionSuggestions(request.permission_suggestions),
|
|
6013
|
+
blockedPath: typeof request.blocked_path === "string" || request.blocked_path === null ? request.blocked_path : null
|
|
6014
|
+
};
|
|
6015
|
+
if (typeof request.tool_call_id === "string")
|
|
6016
|
+
entry.toolCallId = request.tool_call_id;
|
|
6017
|
+
if (request.input && typeof request.input === "object" && !Array.isArray(request.input)) {
|
|
6018
|
+
entry.toolInput = request.input;
|
|
6019
|
+
}
|
|
6020
|
+
const previews = diffPreviews(request.diffs);
|
|
6021
|
+
if (previews !== undefined)
|
|
6022
|
+
entry.diffs = previews;
|
|
6023
|
+
return [entry];
|
|
6024
|
+
});
|
|
6025
|
+
}
|
|
6026
|
+
function permissionSuggestions(value) {
|
|
6027
|
+
if (!Array.isArray(value))
|
|
6028
|
+
return [];
|
|
6029
|
+
return value.flatMap((item) => {
|
|
6030
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
6031
|
+
return [];
|
|
6032
|
+
const record = item;
|
|
6033
|
+
return typeof record.id === "string" && typeof record.text === "string" ? [{ id: record.id, text: record.text }] : [];
|
|
6034
|
+
});
|
|
6035
|
+
}
|
|
6036
|
+
function diffPreviews(value) {
|
|
6037
|
+
if (!Array.isArray(value))
|
|
6038
|
+
return;
|
|
6039
|
+
return value.flatMap((item) => {
|
|
6040
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
6041
|
+
return [];
|
|
6042
|
+
const record = item;
|
|
6043
|
+
if (record.mode === "advanced" && typeof record.fileName === "string" && Array.isArray(record.hunks)) {
|
|
6044
|
+
return [{
|
|
6045
|
+
mode: "advanced",
|
|
6046
|
+
fileName: record.fileName,
|
|
6047
|
+
hunks: diffHunks(record.hunks)
|
|
6048
|
+
}];
|
|
6049
|
+
}
|
|
6050
|
+
if ((record.mode === "fallback" || record.mode === "unpreviewable") && typeof record.fileName === "string" && typeof record.reason === "string") {
|
|
6051
|
+
return [{
|
|
6052
|
+
mode: record.mode,
|
|
6053
|
+
fileName: record.fileName,
|
|
6054
|
+
reason: record.reason
|
|
6055
|
+
}];
|
|
6056
|
+
}
|
|
6057
|
+
return [];
|
|
6058
|
+
});
|
|
6059
|
+
}
|
|
6060
|
+
function diffHunks(value) {
|
|
6061
|
+
return value.flatMap((item) => {
|
|
6062
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
6063
|
+
return [];
|
|
6064
|
+
const record = item;
|
|
6065
|
+
if (typeof record.oldStart !== "number" || typeof record.oldLines !== "number" || typeof record.newStart !== "number" || typeof record.newLines !== "number" || !Array.isArray(record.lines)) {
|
|
6066
|
+
return [];
|
|
6067
|
+
}
|
|
6068
|
+
const lines = [];
|
|
6069
|
+
for (const line of record.lines) {
|
|
6070
|
+
if (!line || typeof line !== "object" || Array.isArray(line))
|
|
6071
|
+
continue;
|
|
6072
|
+
const lineRecord = line;
|
|
6073
|
+
const type = lineRecord.type;
|
|
6074
|
+
if (type !== "context" && type !== "add" && type !== "remove" || typeof lineRecord.content !== "string") {
|
|
6075
|
+
continue;
|
|
6076
|
+
}
|
|
6077
|
+
lines.push({
|
|
6078
|
+
type,
|
|
6079
|
+
content: lineRecord.content
|
|
6080
|
+
});
|
|
6081
|
+
}
|
|
6082
|
+
return [{
|
|
6083
|
+
oldStart: record.oldStart,
|
|
6084
|
+
oldLines: record.oldLines,
|
|
6085
|
+
newStart: record.newStart,
|
|
6086
|
+
newLines: record.newLines,
|
|
6087
|
+
lines
|
|
6088
|
+
}];
|
|
6089
|
+
});
|
|
6090
|
+
}
|
|
6091
|
+
function toSessionDeviceStatus(status) {
|
|
6092
|
+
const permissionMode = normalizePermissionMode(status.current_permission_mode);
|
|
6093
|
+
if (typeof status.is_online !== "boolean" || typeof status.is_processing !== "boolean" || permissionMode === undefined || !(typeof status.current_working_directory === "string" || status.current_working_directory === null)) {
|
|
6094
|
+
return null;
|
|
6095
|
+
}
|
|
6096
|
+
return {
|
|
6097
|
+
isOnline: status.is_online,
|
|
6098
|
+
isProcessing: status.is_processing,
|
|
6099
|
+
permissionMode,
|
|
6100
|
+
workingDirectory: status.current_working_directory,
|
|
6101
|
+
pendingControlRequests: pendingControlRequests(status),
|
|
6102
|
+
raw: { ...status }
|
|
6103
|
+
};
|
|
6104
|
+
}
|
|
5685
6105
|
function normalizeSendMessage(message) {
|
|
5686
6106
|
return message;
|
|
5687
6107
|
}
|
|
@@ -5700,6 +6120,7 @@ class RemoteClientSessionCore {
|
|
|
5700
6120
|
_modelSettings = null;
|
|
5701
6121
|
label;
|
|
5702
6122
|
requestTimeoutMs;
|
|
6123
|
+
initializePromise = null;
|
|
5703
6124
|
streamQueue = [];
|
|
5704
6125
|
streamResolvers = [];
|
|
5705
6126
|
removeMessageHandler = null;
|
|
@@ -5709,49 +6130,80 @@ class RemoteClientSessionCore {
|
|
|
5709
6130
|
messageCounter = 0;
|
|
5710
6131
|
clientMessageCounter = 0;
|
|
5711
6132
|
toolNames;
|
|
6133
|
+
deviceStatusListeners = new Set;
|
|
6134
|
+
deviceStatusRefreshCancels = new Set;
|
|
5712
6135
|
constructor(mode, config) {
|
|
5713
6136
|
this.mode = mode;
|
|
5714
6137
|
this.label = config.label;
|
|
5715
6138
|
this.requestTimeoutMs = config.requestTimeoutMs;
|
|
5716
6139
|
}
|
|
5717
6140
|
async initialize() {
|
|
6141
|
+
if (this.closed) {
|
|
6142
|
+
throw new Error("Session is closed");
|
|
6143
|
+
}
|
|
6144
|
+
if (this.initializePromise) {
|
|
6145
|
+
return this.initializePromise;
|
|
6146
|
+
}
|
|
5718
6147
|
if (this.initialized) {
|
|
5719
6148
|
throw new Error("Session already initialized");
|
|
5720
6149
|
}
|
|
6150
|
+
const attempt = this.performInitialize();
|
|
6151
|
+
const memo = attempt.catch((error) => {
|
|
6152
|
+
this.cleanupFailedInitialize();
|
|
6153
|
+
throw error;
|
|
6154
|
+
}).finally(() => {
|
|
6155
|
+
if (this.initializePromise === memo) {
|
|
6156
|
+
this.initializePromise = null;
|
|
6157
|
+
}
|
|
6158
|
+
});
|
|
6159
|
+
this.initializePromise = memo;
|
|
6160
|
+
return memo;
|
|
6161
|
+
}
|
|
6162
|
+
async performInitialize() {
|
|
6163
|
+
const init = await this.initializeRuntimeController();
|
|
6164
|
+
this.controller = init.controller;
|
|
6165
|
+
this.runtime = init.runtime;
|
|
6166
|
+
this._agentId = init.runtime.agent_id;
|
|
6167
|
+
this._conversationId = init.runtime.conversation_id;
|
|
6168
|
+
this._sessionId = `${init.runtime.agent_id}:${init.runtime.conversation_id}`;
|
|
6169
|
+
this._modelSettings = init.modelSettings ?? null;
|
|
6170
|
+
this._model = typeof init.model === "string" ? init.model : typeof this._modelSettings?.model === "string" ? this._modelSettings.model : "";
|
|
6171
|
+
this.toolNames = init.tools;
|
|
6172
|
+
this.removeMessageHandler = this.controller.onMessage(this.handleProtocolMessage);
|
|
6173
|
+
await this.afterRuntimeInitialized();
|
|
6174
|
+
await this.applyPostInitializeOptions();
|
|
5721
6175
|
if (this.closed) {
|
|
5722
6176
|
throw new Error("Session is closed");
|
|
5723
6177
|
}
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
this.
|
|
5729
|
-
|
|
5730
|
-
this.
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
await this.afterRuntimeInitialized();
|
|
5737
|
-
await this.applyPostInitializeOptions();
|
|
5738
|
-
const initMessage = {
|
|
5739
|
-
type: "init",
|
|
5740
|
-
agentId: init.runtime.agent_id,
|
|
5741
|
-
sessionId: this._sessionId,
|
|
5742
|
-
conversationId: init.runtime.conversation_id,
|
|
5743
|
-
model: this._model
|
|
5744
|
-
};
|
|
5745
|
-
if (this.toolNames !== undefined)
|
|
5746
|
-
initMessage.tools = this.toolNames;
|
|
5747
|
-
if (init.skillSources !== undefined) {
|
|
5748
|
-
initMessage.skillSources = init.skillSources;
|
|
5749
|
-
}
|
|
5750
|
-
return initMessage;
|
|
5751
|
-
} catch (error) {
|
|
5752
|
-
this.close();
|
|
5753
|
-
throw error;
|
|
6178
|
+
this.initialized = true;
|
|
6179
|
+
const initMessage = {
|
|
6180
|
+
type: "init",
|
|
6181
|
+
agentId: init.runtime.agent_id,
|
|
6182
|
+
sessionId: this._sessionId,
|
|
6183
|
+
conversationId: init.runtime.conversation_id,
|
|
6184
|
+
model: this._model
|
|
6185
|
+
};
|
|
6186
|
+
if (this.toolNames !== undefined)
|
|
6187
|
+
initMessage.tools = this.toolNames;
|
|
6188
|
+
if (init.skillSources !== undefined) {
|
|
6189
|
+
initMessage.skillSources = init.skillSources;
|
|
5754
6190
|
}
|
|
6191
|
+
return initMessage;
|
|
6192
|
+
}
|
|
6193
|
+
cleanupFailedInitialize() {
|
|
6194
|
+
this.removeMessageHandler?.();
|
|
6195
|
+
this.removeMessageHandler = null;
|
|
6196
|
+
this.controller?.close();
|
|
6197
|
+
this.controller = null;
|
|
6198
|
+
this.onCoreClose();
|
|
6199
|
+
this.runtime = null;
|
|
6200
|
+
this._agentId = null;
|
|
6201
|
+
this._conversationId = null;
|
|
6202
|
+
this._sessionId = null;
|
|
6203
|
+
this._modelSettings = null;
|
|
6204
|
+
this._model = "";
|
|
6205
|
+
this.toolNames = undefined;
|
|
6206
|
+
this.initialized = false;
|
|
5755
6207
|
}
|
|
5756
6208
|
async send(message) {
|
|
5757
6209
|
if (!this.initialized) {
|
|
@@ -5848,6 +6300,12 @@ class RemoteClientSessionCore {
|
|
|
5848
6300
|
if (!this.initialized) {
|
|
5849
6301
|
await this.initialize();
|
|
5850
6302
|
}
|
|
6303
|
+
if (!this.controller || !this.runtime) {
|
|
6304
|
+
throw new Error("Session is not initialized");
|
|
6305
|
+
}
|
|
6306
|
+
return this.applyModelUpdate(update);
|
|
6307
|
+
}
|
|
6308
|
+
async applyModelUpdate(update) {
|
|
5851
6309
|
if (!this.controller || !this.runtime) {
|
|
5852
6310
|
throw new Error("Session is not initialized");
|
|
5853
6311
|
}
|
|
@@ -5899,6 +6357,86 @@ class RemoteClientSessionCore {
|
|
|
5899
6357
|
removed: response.success
|
|
5900
6358
|
};
|
|
5901
6359
|
}
|
|
6360
|
+
async getDeviceStatus(options = {}) {
|
|
6361
|
+
if (!this.initialized) {
|
|
6362
|
+
await this.initialize();
|
|
6363
|
+
}
|
|
6364
|
+
if (!this.controller || !this.runtime) {
|
|
6365
|
+
throw new Error("Session is not initialized");
|
|
6366
|
+
}
|
|
6367
|
+
const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs ?? 30000;
|
|
6368
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {
|
|
6369
|
+
throw new Error("Invalid device status timeout. Expected a positive integer.");
|
|
6370
|
+
}
|
|
6371
|
+
return this.refreshDeviceStatus(timeoutMs);
|
|
6372
|
+
}
|
|
6373
|
+
onDeviceStatus(listener) {
|
|
6374
|
+
if (typeof listener !== "function") {
|
|
6375
|
+
throw new Error("Invalid device status listener. Expected a function.");
|
|
6376
|
+
}
|
|
6377
|
+
this.deviceStatusListeners.add(listener);
|
|
6378
|
+
return () => {
|
|
6379
|
+
this.deviceStatusListeners.delete(listener);
|
|
6380
|
+
};
|
|
6381
|
+
}
|
|
6382
|
+
refreshDeviceStatus(timeoutMs) {
|
|
6383
|
+
const controller = this.controller;
|
|
6384
|
+
const runtime = this.runtime;
|
|
6385
|
+
if (!controller || !runtime) {
|
|
6386
|
+
return Promise.reject(new Error("Session is not initialized"));
|
|
6387
|
+
}
|
|
6388
|
+
return new Promise((resolve, reject) => {
|
|
6389
|
+
let status = null;
|
|
6390
|
+
let syncAcknowledged = false;
|
|
6391
|
+
let settled = false;
|
|
6392
|
+
const cleanup = () => {
|
|
6393
|
+
clearTimeout(timer);
|
|
6394
|
+
unsubscribe();
|
|
6395
|
+
this.deviceStatusRefreshCancels.delete(cancel);
|
|
6396
|
+
};
|
|
6397
|
+
const rejectOnce = (error) => {
|
|
6398
|
+
if (settled)
|
|
6399
|
+
return;
|
|
6400
|
+
settled = true;
|
|
6401
|
+
cleanup();
|
|
6402
|
+
reject(error);
|
|
6403
|
+
};
|
|
6404
|
+
const resolveIfComplete = () => {
|
|
6405
|
+
if (settled || !syncAcknowledged || !status)
|
|
6406
|
+
return;
|
|
6407
|
+
settled = true;
|
|
6408
|
+
cleanup();
|
|
6409
|
+
resolve(status);
|
|
6410
|
+
};
|
|
6411
|
+
const cancel = (error) => rejectOnce(error);
|
|
6412
|
+
const timer = setTimeout(() => {
|
|
6413
|
+
rejectOnce(new Error(`Timed out waiting for ${this.label} device status`));
|
|
6414
|
+
}, timeoutMs);
|
|
6415
|
+
timer.unref?.();
|
|
6416
|
+
const unsubscribe = this.onDeviceStatus((nextStatus) => {
|
|
6417
|
+
status = nextStatus;
|
|
6418
|
+
resolveIfComplete();
|
|
6419
|
+
});
|
|
6420
|
+
this.deviceStatusRefreshCancels.add(cancel);
|
|
6421
|
+
controller.request("sync", {
|
|
6422
|
+
runtime,
|
|
6423
|
+
recover_approvals: false,
|
|
6424
|
+
force_device_status: true
|
|
6425
|
+
}, {
|
|
6426
|
+
timeoutMs,
|
|
6427
|
+
predicate: (message) => message.type === "sync_response"
|
|
6428
|
+
}).then((response) => {
|
|
6429
|
+
if (response.success === false) {
|
|
6430
|
+
rejectOnce(new Error(typeof response.error === "string" ? response.error : `Failed to refresh ${this.label} device status`));
|
|
6431
|
+
return;
|
|
6432
|
+
}
|
|
6433
|
+
syncAcknowledged = true;
|
|
6434
|
+
resolveIfComplete();
|
|
6435
|
+
}, (error) => {
|
|
6436
|
+
rejectOnce(error instanceof Error ? error : new Error(String(error)));
|
|
6437
|
+
});
|
|
6438
|
+
});
|
|
6439
|
+
}
|
|
5902
6440
|
async listMessages(options = {}) {
|
|
5903
6441
|
if (!this.initialized) {
|
|
5904
6442
|
await this.initialize();
|
|
@@ -5951,6 +6489,11 @@ class RemoteClientSessionCore {
|
|
|
5951
6489
|
}
|
|
5952
6490
|
this.activeTurn = null;
|
|
5953
6491
|
this.pendingTurns.length = 0;
|
|
6492
|
+
for (const cancel of [...this.deviceStatusRefreshCancels]) {
|
|
6493
|
+
cancel(new Error(`Session closed while waiting for ${this.label} device status`));
|
|
6494
|
+
}
|
|
6495
|
+
this.deviceStatusRefreshCancels.clear();
|
|
6496
|
+
this.deviceStatusListeners.clear();
|
|
5954
6497
|
this.controller?.close();
|
|
5955
6498
|
this.controller = null;
|
|
5956
6499
|
this.onCoreClose();
|
|
@@ -6179,7 +6722,7 @@ class RemoteClientSessionCore {
|
|
|
6179
6722
|
if (this.mode.kind !== "session")
|
|
6180
6723
|
return;
|
|
6181
6724
|
if (this.mode.options.model !== undefined || this.mode.options.reasoningEffort !== undefined) {
|
|
6182
|
-
await this.
|
|
6725
|
+
await this.applyModelUpdate({
|
|
6183
6726
|
...this.mode.options.model !== undefined ? { model: this.mode.options.model } : {},
|
|
6184
6727
|
...this.mode.options.reasoningEffort !== undefined ? { reasoningEffort: this.mode.options.reasoningEffort } : {}
|
|
6185
6728
|
});
|
|
@@ -6188,6 +6731,18 @@ class RemoteClientSessionCore {
|
|
|
6188
6731
|
handleProtocolMessage = (message) => {
|
|
6189
6732
|
if (!this.runtime || !sameRuntime2(message, this.runtime))
|
|
6190
6733
|
return;
|
|
6734
|
+
const deviceStatus = deviceStatusRecord(message);
|
|
6735
|
+
if (deviceStatus) {
|
|
6736
|
+
const status = toSessionDeviceStatus(deviceStatus);
|
|
6737
|
+
if (!status)
|
|
6738
|
+
return;
|
|
6739
|
+
for (const listener of [...this.deviceStatusListeners]) {
|
|
6740
|
+
try {
|
|
6741
|
+
listener(status);
|
|
6742
|
+
} catch {}
|
|
6743
|
+
}
|
|
6744
|
+
return;
|
|
6745
|
+
}
|
|
6191
6746
|
if (message.type === "update_queue") {
|
|
6192
6747
|
const sdkMessage2 = {
|
|
6193
6748
|
type: "queue_update",
|
|
@@ -6617,7 +7172,7 @@ function createExternalToolCallHandler(externalTools) {
|
|
|
6617
7172
|
};
|
|
6618
7173
|
};
|
|
6619
7174
|
}
|
|
6620
|
-
async function resolveAppServerToolApproval(options, toolName, toolInput) {
|
|
7175
|
+
async function resolveAppServerToolApproval(options, toolName, toolInput, context) {
|
|
6621
7176
|
const hasCallback = typeof options.canUseTool === "function";
|
|
6622
7177
|
const toolNeedsRuntimeUserInput = requiresRuntimeUserInput(toolName);
|
|
6623
7178
|
if (toolNeedsRuntimeUserInput && !hasCallback) {
|
|
@@ -6632,7 +7187,7 @@ async function resolveAppServerToolApproval(options, toolName, toolInput) {
|
|
|
6632
7187
|
}
|
|
6633
7188
|
if (hasCallback) {
|
|
6634
7189
|
try {
|
|
6635
|
-
const result = await options.canUseTool(toolName, toolInput);
|
|
7190
|
+
const result = await options.canUseTool(toolName, toolInput, context);
|
|
6636
7191
|
if (result.behavior === "allow") {
|
|
6637
7192
|
return {
|
|
6638
7193
|
behavior: "allow",
|
|
@@ -6692,7 +7247,7 @@ function toAppServerApprovalDecision(decision) {
|
|
|
6692
7247
|
selected_permission_suggestion_ids: selectedPermissionSuggestionIds
|
|
6693
7248
|
};
|
|
6694
7249
|
}
|
|
6695
|
-
function
|
|
7250
|
+
function stringRecord2(value) {
|
|
6696
7251
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
6697
7252
|
return;
|
|
6698
7253
|
const record = {};
|
|
@@ -6738,7 +7293,7 @@ function normalizeListModelsResponse(response) {
|
|
|
6738
7293
|
} else if (Array.isArray(response.available_handles)) {
|
|
6739
7294
|
result.availableHandles = response.available_handles.filter((handle) => typeof handle === "string");
|
|
6740
7295
|
}
|
|
6741
|
-
const aliases =
|
|
7296
|
+
const aliases = stringRecord2(response.byok_provider_aliases);
|
|
6742
7297
|
if (aliases)
|
|
6743
7298
|
result.byokProviderAliases = aliases;
|
|
6744
7299
|
return result;
|
|
@@ -6793,7 +7348,7 @@ async function respondToAppServerControlRequest(config, message) {
|
|
|
6793
7348
|
return;
|
|
6794
7349
|
const toolName = typeof requestRecord.tool_name === "string" ? requestRecord.tool_name : "unknown";
|
|
6795
7350
|
const toolInput = requestRecord.input && typeof requestRecord.input === "object" && !Array.isArray(requestRecord.input) ? requestRecord.input : {};
|
|
6796
|
-
const decision = await resolveAppServerToolApproval(config.getOptions(), toolName, toolInput);
|
|
7351
|
+
const decision = await resolveAppServerToolApproval(config.getOptions(), toolName, toolInput, buildCanUseToolContext(requestRecord, requestId));
|
|
6797
7352
|
config.client.input({
|
|
6798
7353
|
runtime,
|
|
6799
7354
|
payload: {
|
|
@@ -6930,13 +7485,15 @@ class AppServerSession extends RemoteClientSessionCore {
|
|
|
6930
7485
|
return options.memfs !== false;
|
|
6931
7486
|
}
|
|
6932
7487
|
async initializeRuntimeController() {
|
|
7488
|
+
await this.remoteOptions.beforeConnect?.();
|
|
6933
7489
|
const url = await this.resolveAppServerUrl();
|
|
6934
|
-
|
|
7490
|
+
await releaseAppServerManagementConnections(url);
|
|
7491
|
+
const client = applyUniqueRequestIds(createAppServerClient({
|
|
6935
7492
|
url,
|
|
6936
7493
|
...this.remoteOptions.authToken !== undefined ? { authToken: this.remoteOptions.authToken } : {},
|
|
6937
7494
|
...this.remoteOptions.WebSocket ? { WebSocket: this.remoteOptions.WebSocket } : {},
|
|
6938
7495
|
...this.remoteOptions.requestTimeoutMs !== undefined ? { requestTimeoutMs: this.remoteOptions.requestTimeoutMs } : {}
|
|
6939
|
-
});
|
|
7496
|
+
}));
|
|
6940
7497
|
this.removeControlRequestHandler = registerAppServerControlRequestHandler({
|
|
6941
7498
|
client,
|
|
6942
7499
|
getRuntime: () => this.runtime,
|
|
@@ -7136,6 +7693,19 @@ function asArray(body, action) {
|
|
|
7136
7693
|
}
|
|
7137
7694
|
return body;
|
|
7138
7695
|
}
|
|
7696
|
+
function cloudModelEntry(raw) {
|
|
7697
|
+
if (typeof raw.handle !== "string" || raw.handle.length === 0) {
|
|
7698
|
+
return null;
|
|
7699
|
+
}
|
|
7700
|
+
const label = typeof raw.display_name === "string" ? raw.display_name : typeof raw.name === "string" ? raw.name : raw.handle;
|
|
7701
|
+
return {
|
|
7702
|
+
...raw,
|
|
7703
|
+
id: typeof raw.id === "string" && raw.id.length > 0 ? raw.id : raw.handle,
|
|
7704
|
+
handle: raw.handle,
|
|
7705
|
+
label,
|
|
7706
|
+
description: typeof raw.description === "string" ? raw.description : ""
|
|
7707
|
+
};
|
|
7708
|
+
}
|
|
7139
7709
|
|
|
7140
7710
|
class CloudManagementTransport {
|
|
7141
7711
|
options;
|
|
@@ -7151,6 +7721,20 @@ class CloudManagementTransport {
|
|
|
7151
7721
|
updateAgent(agentId, body) {
|
|
7152
7722
|
return this.requestObject(`/v1/agents/${encodeURIComponent(agentId)}`, "PATCH", body, "Cloud update agent");
|
|
7153
7723
|
}
|
|
7724
|
+
async deleteAgent(agentId) {
|
|
7725
|
+
await this.requestUrl(this.url(`/v1/agents/${encodeURIComponent(agentId)}`), "DELETE", undefined, "Cloud delete agent");
|
|
7726
|
+
}
|
|
7727
|
+
async listModels() {
|
|
7728
|
+
const entries = await this.getArray("/v1/models", {}, "Cloud list models");
|
|
7729
|
+
const normalized = entries.flatMap((entry) => {
|
|
7730
|
+
const model = cloudModelEntry(entry);
|
|
7731
|
+
return model ? [model] : [];
|
|
7732
|
+
});
|
|
7733
|
+
return {
|
|
7734
|
+
entries: normalized,
|
|
7735
|
+
availableHandles: normalized.map((entry) => entry.handle)
|
|
7736
|
+
};
|
|
7737
|
+
}
|
|
7154
7738
|
listConversations(query) {
|
|
7155
7739
|
return this.getArray("/v1/conversations/", query, "Cloud list conversations");
|
|
7156
7740
|
}
|
|
@@ -7780,14 +8364,14 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
7780
8364
|
apiKey,
|
|
7781
8365
|
authMode: this.cloudOptions.webSocketAuth ?? "header"
|
|
7782
8366
|
});
|
|
7783
|
-
const client = createAppServerClient({
|
|
8367
|
+
const client = applyUniqueRequestIds(createAppServerClient({
|
|
7784
8368
|
url,
|
|
7785
8369
|
WebSocket: createCloudStatusWebSocketConstructor({
|
|
7786
8370
|
cloudOptions: this.cloudOptions,
|
|
7787
8371
|
runtime: resolved.runtime
|
|
7788
8372
|
}),
|
|
7789
8373
|
requestTimeoutMs: this.cloudOptions.requestTimeoutMs ?? DEFAULT_TURN_TIMEOUT_MS
|
|
7790
|
-
});
|
|
8374
|
+
}));
|
|
7791
8375
|
this.removeControlRequestHandler = registerAppServerControlRequestHandler({
|
|
7792
8376
|
client,
|
|
7793
8377
|
getRuntime: () => this.runtime,
|
|
@@ -8235,6 +8819,11 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
8235
8819
|
function definedEntries(values) {
|
|
8236
8820
|
return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== undefined));
|
|
8237
8821
|
}
|
|
8822
|
+
function assertNonEmptyId(value, name) {
|
|
8823
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
8824
|
+
throw new Error(`Invalid ${name}. Expected a non-empty string.`);
|
|
8825
|
+
}
|
|
8826
|
+
}
|
|
8238
8827
|
function agentListQuery(options) {
|
|
8239
8828
|
const orderBy = options.orderBy?.replace(/[A-Z]/g, (character) => `_${character.toLowerCase()}`);
|
|
8240
8829
|
return {
|
|
@@ -8307,7 +8896,16 @@ function createAgentsClient(transport) {
|
|
|
8307
8896
|
return {
|
|
8308
8897
|
list: (options = {}) => transport().listAgents(agentListQuery(options)),
|
|
8309
8898
|
retrieve: (agentId) => transport().retrieveAgent(agentId),
|
|
8310
|
-
update: (agentId, options) => transport().updateAgent(agentId, agentUpdateBody(options))
|
|
8899
|
+
update: (agentId, options) => transport().updateAgent(agentId, agentUpdateBody(options)),
|
|
8900
|
+
delete: async (agentId) => {
|
|
8901
|
+
assertNonEmptyId(agentId, "agent id");
|
|
8902
|
+
await transport().deleteAgent(agentId);
|
|
8903
|
+
}
|
|
8904
|
+
};
|
|
8905
|
+
}
|
|
8906
|
+
function createModelsClient(transport) {
|
|
8907
|
+
return {
|
|
8908
|
+
list: () => transport().listModels()
|
|
8311
8909
|
};
|
|
8312
8910
|
}
|
|
8313
8911
|
function createConversationsClient(transport) {
|
|
@@ -8478,6 +9076,7 @@ class LettaAgentClientBase {
|
|
|
8478
9076
|
environment;
|
|
8479
9077
|
agents;
|
|
8480
9078
|
conversations;
|
|
9079
|
+
models;
|
|
8481
9080
|
options;
|
|
8482
9081
|
repositoriesClient = null;
|
|
8483
9082
|
managementTransport = null;
|
|
@@ -8491,6 +9090,7 @@ class LettaAgentClientBase {
|
|
|
8491
9090
|
this.options = options;
|
|
8492
9091
|
this.agents = createAgentsClient(() => this.getManagementTransport());
|
|
8493
9092
|
this.conversations = createConversationsClient(() => this.getManagementTransport());
|
|
9093
|
+
this.models = createModelsClient(() => this.getManagementTransport());
|
|
8494
9094
|
if (this.backend === "local" && this.environment !== undefined) {
|
|
8495
9095
|
throw new Error('LettaAgentClient environment is only valid with backend: "cloud".');
|
|
8496
9096
|
}
|
|
@@ -8509,6 +9109,10 @@ class LettaAgentClientBase {
|
|
|
8509
9109
|
if (requestTimeoutMs !== undefined && (!Number.isInteger(requestTimeoutMs) || requestTimeoutMs <= 0)) {
|
|
8510
9110
|
throw new Error("Invalid appServer.requestTimeoutMs. Expected a positive integer.");
|
|
8511
9111
|
}
|
|
9112
|
+
const idleLingerMs = localOptions.appServer?.idleLingerMs;
|
|
9113
|
+
if (idleLingerMs !== undefined && (!Number.isInteger(idleLingerMs) || idleLingerMs < 0)) {
|
|
9114
|
+
throw new Error("Invalid appServer.idleLingerMs. Expected a non-negative integer.");
|
|
9115
|
+
}
|
|
8512
9116
|
const startupTimeoutMs = localOptions.appServer?.startupTimeoutMs;
|
|
8513
9117
|
if (startupTimeoutMs !== undefined && (!Number.isInteger(startupTimeoutMs) || startupTimeoutMs <= 0)) {
|
|
8514
9118
|
throw new Error("Invalid appServer.startupTimeoutMs. Expected a positive integer.");
|
|
@@ -8521,6 +9125,9 @@ class LettaAgentClientBase {
|
|
|
8521
9125
|
if (options.requestTimeoutMs !== undefined && (!Number.isInteger(options.requestTimeoutMs) || options.requestTimeoutMs <= 0)) {
|
|
8522
9126
|
throw new Error("Invalid requestTimeoutMs. Expected a positive integer.");
|
|
8523
9127
|
}
|
|
9128
|
+
if (options.idleLingerMs !== undefined && (!Number.isInteger(options.idleLingerMs) || options.idleLingerMs < 0)) {
|
|
9129
|
+
throw new Error("Invalid idleLingerMs. Expected a non-negative integer.");
|
|
9130
|
+
}
|
|
8524
9131
|
}
|
|
8525
9132
|
if (this.backend === "cloud") {
|
|
8526
9133
|
validateCloudClientOptions(options);
|
|
@@ -8535,7 +9142,7 @@ class LettaAgentClientBase {
|
|
|
8535
9142
|
}
|
|
8536
9143
|
validateCreateAgentOptions(options);
|
|
8537
9144
|
if (this.backend === "remote") {
|
|
8538
|
-
const session = new AppServerSession(this.
|
|
9145
|
+
const session = new AppServerSession(this.appServerSessionOptions(), {
|
|
8539
9146
|
kind: "create-agent",
|
|
8540
9147
|
options
|
|
8541
9148
|
});
|
|
@@ -8558,7 +9165,7 @@ class LettaAgentClientBase {
|
|
|
8558
9165
|
if (!agentId) {
|
|
8559
9166
|
throw new Error("App-server createSession() requires an agent id. Call createAgent() first or pass an agent id.");
|
|
8560
9167
|
}
|
|
8561
|
-
return new AppServerSession(this.
|
|
9168
|
+
return new AppServerSession(this.appServerSessionOptions(), {
|
|
8562
9169
|
kind: "session",
|
|
8563
9170
|
agentId,
|
|
8564
9171
|
newConversation: true,
|
|
@@ -8584,13 +9191,13 @@ class LettaAgentClientBase {
|
|
|
8584
9191
|
validateCreateSessionOptions(sessionOptions);
|
|
8585
9192
|
if (this.backend === "remote") {
|
|
8586
9193
|
if (looksLikeConversationId(id)) {
|
|
8587
|
-
return new AppServerSession(this.
|
|
9194
|
+
return new AppServerSession(this.appServerSessionOptions(), {
|
|
8588
9195
|
kind: "session",
|
|
8589
9196
|
conversationId: id,
|
|
8590
9197
|
options
|
|
8591
9198
|
});
|
|
8592
9199
|
}
|
|
8593
|
-
return new AppServerSession(this.
|
|
9200
|
+
return new AppServerSession(this.appServerSessionOptions(), {
|
|
8594
9201
|
kind: "session",
|
|
8595
9202
|
agentId: id,
|
|
8596
9203
|
defaultConversation: true,
|
|
@@ -8689,6 +9296,12 @@ class LettaAgentClientBase {
|
|
|
8689
9296
|
}
|
|
8690
9297
|
return this.options;
|
|
8691
9298
|
}
|
|
9299
|
+
appServerSessionOptions() {
|
|
9300
|
+
return {
|
|
9301
|
+
...this.remoteOptions(),
|
|
9302
|
+
beforeConnect: () => this.releaseIdleManagementConnection()
|
|
9303
|
+
};
|
|
9304
|
+
}
|
|
8692
9305
|
getRepositoriesClient() {
|
|
8693
9306
|
if (this.backend !== "cloud") {
|
|
8694
9307
|
throw new Error('client.repositories is only available with backend: "cloud".');
|
|
@@ -8696,6 +9309,9 @@ class LettaAgentClientBase {
|
|
|
8696
9309
|
this.repositoriesClient ??= new RepositoriesClient(this.cloudOptions());
|
|
8697
9310
|
return this.repositoriesClient;
|
|
8698
9311
|
}
|
|
9312
|
+
async releaseIdleManagementConnection() {
|
|
9313
|
+
await this.managementTransport?.releaseIdleConnection?.();
|
|
9314
|
+
}
|
|
8699
9315
|
getManagementTransport() {
|
|
8700
9316
|
if (this.managementTransport)
|
|
8701
9317
|
return this.managementTransport;
|
|
@@ -8803,4 +9419,4 @@ export {
|
|
|
8803
9419
|
CloudManagedSandboxExpiredError
|
|
8804
9420
|
};
|
|
8805
9421
|
|
|
8806
|
-
//# debugId=
|
|
9422
|
+
//# debugId=EACEDA2AA17A075B64756E2164756E21
|