@letta-ai/letta-agent-sdk 0.5.1 → 0.5.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/AGENTS.md +35 -0
- package/README.md +20 -3
- package/dist/agent-repositories.d.ts +15 -0
- package/dist/agent-repositories.d.ts.map +1 -0
- package/dist/app-server-management.d.ts +10 -7
- package/dist/app-server-management.d.ts.map +1 -1
- package/dist/app-server-models.d.ts +4 -0
- package/dist/app-server-models.d.ts.map +1 -0
- package/dist/app-server-session.d.ts +3 -3
- package/dist/app-server-session.d.ts.map +1 -1
- package/dist/client-base.d.ts +5 -0
- package/dist/client-base.d.ts.map +1 -1
- package/dist/client-entry.js +3347 -641
- package/dist/client-entry.js.map +85 -13
- package/dist/cloud-client.d.ts +7 -0
- package/dist/cloud-client.d.ts.map +1 -0
- package/dist/cloud-management.d.ts +21 -18
- package/dist/cloud-management.d.ts.map +1 -1
- package/dist/cloud-session.d.ts +5 -5
- package/dist/cloud-session.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3363 -657
- package/dist/index.js.map +86 -14
- package/dist/management-types.d.ts +85 -64
- package/dist/management-types.d.ts.map +1 -1
- package/dist/management.d.ts +11 -9
- package/dist/management.d.ts.map +1 -1
- package/dist/remote-session-protocol.d.ts +1 -1
- package/dist/remote-session-protocol.d.ts.map +1 -1
- package/dist/remote.d.ts +4 -5
- package/dist/remote.d.ts.map +1 -1
- package/dist/repositories.d.ts +3 -2
- package/dist/repositories.d.ts.map +1 -1
- package/dist/types.d.ts +12 -32
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/agent-repositories.ts +159 -0
- package/src/app-server-management.ts +56 -116
- package/src/app-server-models.ts +20 -0
- package/src/app-server-session.ts +71 -146
- package/src/client-base.ts +72 -20
- package/src/cloud-client.ts +46 -0
- package/src/cloud-management.ts +128 -275
- package/src/cloud-session.ts +79 -262
- package/src/index.ts +6 -0
- package/src/management-types.ts +107 -64
- package/src/management.ts +46 -39
- package/src/remote-session-protocol.ts +2 -2
- package/src/remote.ts +18 -63
- package/src/repositories.ts +26 -99
- package/src/types.ts +12 -33
|
@@ -4,12 +4,20 @@ import {
|
|
|
4
4
|
type AppServerExternalToolCallHandler,
|
|
5
5
|
type AppServerSocketConstructor,
|
|
6
6
|
} from "@letta-ai/letta-code/app-server-client";
|
|
7
|
+
import type {
|
|
8
|
+
ConversationMessagesListResponseMessage,
|
|
9
|
+
ConversationRetrieveResponseMessage,
|
|
10
|
+
ListModelsResponseMessage,
|
|
11
|
+
RuntimeStartResponseMessage,
|
|
12
|
+
UpdateModelResponseMessage,
|
|
13
|
+
} from "@letta-ai/letta-code/app-server-protocol";
|
|
7
14
|
import {
|
|
8
15
|
buildCreateAgentRequestForPersonality,
|
|
9
16
|
buildSystemPrompt,
|
|
10
17
|
GIT_MEMORY_ENABLED_TAG,
|
|
11
18
|
LETTA_CODE_ORIGIN_TAG,
|
|
12
19
|
} from "@letta-ai/letta-code/agent-presets";
|
|
20
|
+
import { normalizeAppServerModels } from "./app-server-models.js";
|
|
13
21
|
import {
|
|
14
22
|
buildCanUseToolContext,
|
|
15
23
|
isHeadlessAutoAllowTool,
|
|
@@ -46,55 +54,14 @@ import type {
|
|
|
46
54
|
UpdateModelResult,
|
|
47
55
|
} from "./types.js";
|
|
48
56
|
|
|
49
|
-
type
|
|
50
|
-
|
|
51
|
-
success: boolean;
|
|
52
|
-
runtime: RuntimeScope | null;
|
|
53
|
-
agent: (Record<string, unknown> & {
|
|
54
|
-
id?: string;
|
|
55
|
-
model?: string | null;
|
|
56
|
-
model_settings?: Record<string, unknown> | null;
|
|
57
|
-
}) | null;
|
|
58
|
-
conversation: (Record<string, unknown> & { id?: string; agent_id?: string }) | null;
|
|
59
|
-
error?: string;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
type ConversationRetrieveResponse = ProtocolMessage & {
|
|
63
|
-
type: "conversation_retrieve_response";
|
|
64
|
-
success: boolean;
|
|
65
|
-
conversation: (Record<string, unknown> & { id?: string; agent_id?: string }) | null;
|
|
66
|
-
error?: string;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
type ConversationMessagesListResponse = ProtocolMessage & {
|
|
70
|
-
type: "conversation_messages_list_response";
|
|
71
|
-
success: boolean;
|
|
72
|
-
messages: unknown[];
|
|
73
|
-
next_before?: string | null;
|
|
57
|
+
type ConversationMessagesListResponse = ConversationMessagesListResponseMessage &
|
|
58
|
+
ProtocolMessage & {
|
|
74
59
|
nextBefore?: string | null;
|
|
75
|
-
has_more?: boolean;
|
|
76
60
|
hasMore?: boolean;
|
|
77
|
-
error?: string;
|
|
78
61
|
};
|
|
79
62
|
|
|
80
|
-
type ListModelsResponse =
|
|
81
|
-
|
|
82
|
-
success: boolean;
|
|
83
|
-
entries?: unknown;
|
|
84
|
-
available_handles?: unknown;
|
|
85
|
-
byok_provider_aliases?: unknown;
|
|
86
|
-
error?: string;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
type UpdateModelResponse = ProtocolMessage & {
|
|
90
|
-
type: "update_model_response";
|
|
91
|
-
success: boolean;
|
|
92
|
-
applied_to?: unknown;
|
|
93
|
-
model_id?: unknown;
|
|
94
|
-
model_handle?: unknown;
|
|
95
|
-
model_settings?: unknown;
|
|
96
|
-
error?: string;
|
|
97
|
-
};
|
|
63
|
+
type ListModelsResponse = ListModelsResponseMessage & ProtocolMessage;
|
|
64
|
+
type UpdateModelResponse = UpdateModelResponseMessage & ProtocolMessage;
|
|
98
65
|
|
|
99
66
|
type UpdateModelPayload = {
|
|
100
67
|
model_id?: string;
|
|
@@ -104,9 +71,9 @@ type UpdateModelPayload = {
|
|
|
104
71
|
type RuntimeStartCommand = Parameters<AppServerClient["runtimeStart"]>[0];
|
|
105
72
|
|
|
106
73
|
export function agentToolNames(
|
|
107
|
-
agent:
|
|
74
|
+
agent: object | null | undefined,
|
|
108
75
|
): string[] | undefined {
|
|
109
|
-
const tools = agent
|
|
76
|
+
const tools = agent && "tools" in agent ? agent.tools : undefined;
|
|
110
77
|
if (!Array.isArray(tools)) return undefined;
|
|
111
78
|
return tools.flatMap((tool) => {
|
|
112
79
|
if (typeof tool === "string" && tool.length > 0) return [tool];
|
|
@@ -414,82 +381,29 @@ export function toAppServerApprovalDecision(
|
|
|
414
381
|
};
|
|
415
382
|
}
|
|
416
383
|
|
|
417
|
-
function stringRecord(value: unknown): Record<string, string> | undefined {
|
|
418
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
419
|
-
const record: Record<string, string> = {};
|
|
420
|
-
for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {
|
|
421
|
-
if (typeof entry === "string") record[key] = entry;
|
|
422
|
-
}
|
|
423
|
-
return record;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
384
|
function objectRecord(value: unknown): Record<string, unknown> | undefined {
|
|
427
385
|
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
428
386
|
return { ...(value as Record<string, unknown>) };
|
|
429
387
|
}
|
|
430
388
|
|
|
431
|
-
function
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
const entries = Array.isArray(response.entries)
|
|
437
|
-
? response.entries.flatMap((entry) => {
|
|
438
|
-
if (!entry || typeof entry !== "object") return [];
|
|
439
|
-
const record = entry as Record<string, unknown>;
|
|
440
|
-
if (
|
|
441
|
-
typeof record.id !== "string" ||
|
|
442
|
-
typeof record.handle !== "string" ||
|
|
443
|
-
typeof record.label !== "string" ||
|
|
444
|
-
typeof record.description !== "string"
|
|
445
|
-
) {
|
|
446
|
-
return [];
|
|
447
|
-
}
|
|
448
|
-
const updateArgs = objectRecord(record.updateArgs);
|
|
449
|
-
return [
|
|
450
|
-
{
|
|
451
|
-
id: record.id,
|
|
452
|
-
handle: record.handle,
|
|
453
|
-
label: record.label,
|
|
454
|
-
description: record.description,
|
|
455
|
-
...(typeof record.isDefault === "boolean" ? { isDefault: record.isDefault } : {}),
|
|
456
|
-
...(typeof record.isFeatured === "boolean" ? { isFeatured: record.isFeatured } : {}),
|
|
457
|
-
...(typeof record.free === "boolean" ? { free: record.free } : {}),
|
|
458
|
-
...(updateArgs ? { updateArgs } : {}),
|
|
459
|
-
},
|
|
460
|
-
];
|
|
461
|
-
})
|
|
462
|
-
: [];
|
|
463
|
-
|
|
464
|
-
const result: ListModelsResult = { entries };
|
|
465
|
-
if (response.available_handles === null) {
|
|
466
|
-
result.availableHandles = null;
|
|
467
|
-
} else if (Array.isArray(response.available_handles)) {
|
|
468
|
-
result.availableHandles = response.available_handles.filter(
|
|
469
|
-
(handle): handle is string => typeof handle === "string",
|
|
470
|
-
);
|
|
471
|
-
}
|
|
472
|
-
const aliases = stringRecord(response.byok_provider_aliases);
|
|
473
|
-
if (aliases) result.byokProviderAliases = aliases;
|
|
474
|
-
return result;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
function normalizeUpdateModelResponse(response: UpdateModelResponse): UpdateModelResult {
|
|
389
|
+
function normalizeUpdateModelResponse(
|
|
390
|
+
response: UpdateModelResponseMessage,
|
|
391
|
+
): UpdateModelResult {
|
|
478
392
|
if (!response.success) {
|
|
479
393
|
throw new Error(response.error ?? "Failed to update model");
|
|
480
394
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
395
|
+
return {
|
|
396
|
+
...(response.applied_to !== undefined
|
|
397
|
+
? { appliedTo: response.applied_to }
|
|
398
|
+
: {}),
|
|
399
|
+
...(response.model_id !== undefined ? { modelId: response.model_id } : {}),
|
|
400
|
+
...(response.model_handle !== undefined
|
|
401
|
+
? { modelHandle: response.model_handle }
|
|
402
|
+
: {}),
|
|
403
|
+
...(response.model_settings !== undefined
|
|
404
|
+
? { modelSettings: response.model_settings }
|
|
405
|
+
: {}),
|
|
406
|
+
};
|
|
493
407
|
}
|
|
494
408
|
|
|
495
409
|
function runtimeScopeFromMessage(message: ProtocolMessage): RuntimeScope | null {
|
|
@@ -603,43 +517,52 @@ export class AppServerRuntimeController implements RemoteClientRuntimeController
|
|
|
603
517
|
await this.client.abort({ runtime } as Parameters<AppServerClient["abort"]>[0]);
|
|
604
518
|
}
|
|
605
519
|
|
|
606
|
-
request(
|
|
520
|
+
request<TResponse extends ProtocolMessage = ProtocolMessage>(
|
|
607
521
|
type: string,
|
|
608
522
|
body: Record<string, unknown>,
|
|
609
523
|
options: { timeoutMs?: number; predicate?: (message: ProtocolMessage) => boolean } = {},
|
|
610
|
-
): Promise<
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
predicate?: (message: ProtocolMessage) => boolean;
|
|
524
|
+
): Promise<TResponse> {
|
|
525
|
+
return this.client.requestRaw<TResponse>(
|
|
526
|
+
{
|
|
527
|
+
type,
|
|
528
|
+
request_id: this.client.nextRequestId(type),
|
|
529
|
+
...body,
|
|
617
530
|
},
|
|
618
|
-
|
|
619
|
-
|
|
531
|
+
{
|
|
532
|
+
...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
|
|
533
|
+
predicate: (message): message is TResponse => {
|
|
534
|
+
if (!message || typeof message !== "object" || Array.isArray(message)) {
|
|
535
|
+
return false;
|
|
536
|
+
}
|
|
537
|
+
const candidate = message as ProtocolMessage;
|
|
538
|
+
return typeof candidate.type === "string" &&
|
|
539
|
+
(options.predicate?.(candidate) ?? true);
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
);
|
|
620
543
|
}
|
|
621
544
|
|
|
622
545
|
async listModels(): Promise<ListModelsResult> {
|
|
623
|
-
const response =
|
|
546
|
+
const response = await this.request<ListModelsResponse>(
|
|
624
547
|
"list_models",
|
|
625
548
|
{},
|
|
626
549
|
{ predicate: (message) => message.type === "list_models_response" },
|
|
627
|
-
)
|
|
628
|
-
return
|
|
550
|
+
);
|
|
551
|
+
return normalizeAppServerModels(response);
|
|
629
552
|
}
|
|
630
553
|
|
|
631
554
|
async updateModel(
|
|
632
555
|
runtime: RuntimeScope,
|
|
633
556
|
payload: UpdateModelPayload,
|
|
634
557
|
): Promise<UpdateModelResult> {
|
|
635
|
-
const response =
|
|
558
|
+
const response = await this.request<UpdateModelResponse>(
|
|
636
559
|
"update_model",
|
|
637
560
|
{
|
|
638
561
|
runtime,
|
|
639
562
|
payload,
|
|
640
563
|
},
|
|
641
564
|
{ predicate: (message) => message.type === "update_model_response" },
|
|
642
|
-
)
|
|
565
|
+
);
|
|
643
566
|
return normalizeUpdateModelResponse(response);
|
|
644
567
|
}
|
|
645
568
|
|
|
@@ -677,14 +600,14 @@ export class AppServerRuntimeController implements RemoteClientRuntimeController
|
|
|
677
600
|
if (options.order !== undefined) query.order = options.order;
|
|
678
601
|
if (options.limit !== undefined) query.limit = options.limit;
|
|
679
602
|
|
|
680
|
-
const response =
|
|
603
|
+
const response = await this.request<ConversationMessagesListResponse>(
|
|
681
604
|
"conversation_messages_list",
|
|
682
605
|
{
|
|
683
606
|
conversation_id: conversationId,
|
|
684
607
|
...(Object.keys(query).length > 0 ? { query } : {}),
|
|
685
608
|
},
|
|
686
609
|
{ predicate: (message) => message.type === "conversation_messages_list_response" },
|
|
687
|
-
)
|
|
610
|
+
);
|
|
688
611
|
|
|
689
612
|
if (!response.success) {
|
|
690
613
|
throw new Error(response.error ?? "listMessages failed");
|
|
@@ -784,7 +707,7 @@ export class AppServerSession extends RemoteClientSessionCore {
|
|
|
784
707
|
),
|
|
785
708
|
runtime: response.runtime,
|
|
786
709
|
model: typeof response.agent?.model === "string" ? response.agent.model : "",
|
|
787
|
-
modelSettings: response.agent?.model_settings ?? null,
|
|
710
|
+
modelSettings: objectRecord(response.agent?.model_settings) ?? null,
|
|
788
711
|
...(tools !== undefined ? { tools } : {}),
|
|
789
712
|
...(skillSources !== undefined ? { skillSources: [...skillSources] } : {}),
|
|
790
713
|
};
|
|
@@ -822,10 +745,11 @@ export class AppServerSession extends RemoteClientSessionCore {
|
|
|
822
745
|
return connection.url;
|
|
823
746
|
}
|
|
824
747
|
|
|
825
|
-
private async startRuntime(
|
|
748
|
+
private async startRuntime(
|
|
749
|
+
client: AppServerClient,
|
|
750
|
+
): Promise<RuntimeStartResponseMessage> {
|
|
826
751
|
const command = await this.buildRuntimeStartCommand(client);
|
|
827
|
-
|
|
828
|
-
return response;
|
|
752
|
+
return client.runtimeStart(command);
|
|
829
753
|
}
|
|
830
754
|
|
|
831
755
|
private async buildRuntimeStartCommand(client: AppServerClient): Promise<RuntimeStartCommand> {
|
|
@@ -897,16 +821,17 @@ export class AppServerSession extends RemoteClientSessionCore {
|
|
|
897
821
|
client: AppServerClient,
|
|
898
822
|
conversationId: string,
|
|
899
823
|
): Promise<string> {
|
|
900
|
-
const
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
824
|
+
const response = await client.request<ConversationRetrieveResponseMessage>(
|
|
825
|
+
{
|
|
826
|
+
type: "conversation_retrieve",
|
|
827
|
+
request_id: client.nextRequestId("conversation_retrieve"),
|
|
828
|
+
conversation_id: conversationId,
|
|
829
|
+
},
|
|
830
|
+
{
|
|
831
|
+
predicate: (message): message is ConversationRetrieveResponseMessage =>
|
|
832
|
+
message.type === "conversation_retrieve_response",
|
|
833
|
+
},
|
|
834
|
+
);
|
|
910
835
|
if (!response.success || !response.conversation?.agent_id) {
|
|
911
836
|
throw new Error(response.error ?? `Failed to retrieve conversation ${conversationId}`);
|
|
912
837
|
}
|
package/src/client-base.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import type Letta from "@letta-ai/letta-client";
|
|
1
2
|
import { RepositoriesClient } from "./repositories.js";
|
|
3
|
+
import { createAgentRepositoriesClient } from "./agent-repositories.js";
|
|
2
4
|
import { AppServerManagementTransport } from "./app-server-management.js";
|
|
3
5
|
import {
|
|
4
6
|
AppServerSession,
|
|
5
7
|
type AppServerSessionOptions,
|
|
6
8
|
} from "./app-server-session.js";
|
|
7
9
|
import { CloudManagementTransport } from "./cloud-management.js";
|
|
10
|
+
import { createCloudClient } from "./cloud-client.js";
|
|
8
11
|
import {
|
|
9
12
|
CloudEnvironmentSession,
|
|
10
13
|
assertCloudSessionOptionsSupported,
|
|
@@ -18,6 +21,7 @@ import {
|
|
|
18
21
|
type ManagementTransport,
|
|
19
22
|
} from "./management.js";
|
|
20
23
|
import type {
|
|
24
|
+
AgentRepositoriesClient,
|
|
21
25
|
AgentsClient,
|
|
22
26
|
ConversationsClient,
|
|
23
27
|
ModelsClient,
|
|
@@ -104,6 +108,8 @@ export class LettaAgentClientBase {
|
|
|
104
108
|
readonly models: ModelsClient;
|
|
105
109
|
protected readonly options: LettaCodeClientOptions;
|
|
106
110
|
private repositoriesClient: RepositoriesClient | null = null;
|
|
111
|
+
private agentRepositoriesClient: AgentRepositoriesClient | null = null;
|
|
112
|
+
private cloudClient: Letta | null = null;
|
|
107
113
|
private managementTransport: ManagementTransport | null = null;
|
|
108
114
|
|
|
109
115
|
constructor(options: LettaCodeClientOptions = {}) {
|
|
@@ -117,7 +123,10 @@ export class LettaAgentClientBase {
|
|
|
117
123
|
this.backend = backend;
|
|
118
124
|
this.environment = getOptionsEnvironment(options);
|
|
119
125
|
this.options = options;
|
|
120
|
-
this.agents = createAgentsClient(
|
|
126
|
+
this.agents = createAgentsClient(
|
|
127
|
+
() => this.getManagementTransport(),
|
|
128
|
+
() => this.getAgentRepositoriesClient(),
|
|
129
|
+
);
|
|
121
130
|
this.conversations = createConversationsClient(
|
|
122
131
|
() => this.getManagementTransport(),
|
|
123
132
|
);
|
|
@@ -206,7 +215,7 @@ export class LettaAgentClientBase {
|
|
|
206
215
|
return initMsg.agentId;
|
|
207
216
|
}
|
|
208
217
|
if (this.backend === "cloud") {
|
|
209
|
-
return createCloudAgent(this.
|
|
218
|
+
return createCloudAgent(this.getCloudClient(), options);
|
|
210
219
|
}
|
|
211
220
|
return this.createLocalAgent(options);
|
|
212
221
|
}
|
|
@@ -236,12 +245,16 @@ export class LettaAgentClientBase {
|
|
|
236
245
|
});
|
|
237
246
|
}
|
|
238
247
|
if (this.backend === "cloud") {
|
|
239
|
-
return new CloudEnvironmentSession(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
248
|
+
return new CloudEnvironmentSession(
|
|
249
|
+
this.cloudOptions(),
|
|
250
|
+
{
|
|
251
|
+
kind: "session",
|
|
252
|
+
agentId,
|
|
253
|
+
newConversation: true,
|
|
254
|
+
options,
|
|
255
|
+
},
|
|
256
|
+
this.getCloudClient(),
|
|
257
|
+
);
|
|
245
258
|
}
|
|
246
259
|
return this.createLocalSession(agentId, options);
|
|
247
260
|
}
|
|
@@ -277,18 +290,26 @@ export class LettaAgentClientBase {
|
|
|
277
290
|
}
|
|
278
291
|
if (this.backend === "cloud") {
|
|
279
292
|
if (looksLikeConversationId(id)) {
|
|
280
|
-
return new CloudEnvironmentSession(
|
|
293
|
+
return new CloudEnvironmentSession(
|
|
294
|
+
this.cloudOptions(),
|
|
295
|
+
{
|
|
296
|
+
kind: "session",
|
|
297
|
+
conversationId: id,
|
|
298
|
+
options,
|
|
299
|
+
},
|
|
300
|
+
this.getCloudClient(),
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
return new CloudEnvironmentSession(
|
|
304
|
+
this.cloudOptions(),
|
|
305
|
+
{
|
|
281
306
|
kind: "session",
|
|
282
|
-
|
|
307
|
+
agentId: id,
|
|
308
|
+
defaultConversation: true,
|
|
283
309
|
options,
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
kind: "session",
|
|
288
|
-
agentId: id,
|
|
289
|
-
defaultConversation: true,
|
|
290
|
-
options,
|
|
291
|
-
});
|
|
310
|
+
},
|
|
311
|
+
this.getCloudClient(),
|
|
312
|
+
);
|
|
292
313
|
}
|
|
293
314
|
return this.resumeLocalSession(id, options);
|
|
294
315
|
}
|
|
@@ -427,10 +448,41 @@ export class LettaAgentClientBase {
|
|
|
427
448
|
if (this.backend !== "cloud") {
|
|
428
449
|
throw new Error('client.repositories is only available with backend: "cloud".');
|
|
429
450
|
}
|
|
430
|
-
this.repositoriesClient ??= new RepositoriesClient(
|
|
451
|
+
this.repositoriesClient ??= new RepositoriesClient(
|
|
452
|
+
this.cloudOptions(),
|
|
453
|
+
this.getCloudClient(),
|
|
454
|
+
);
|
|
431
455
|
return this.repositoriesClient;
|
|
432
456
|
}
|
|
433
457
|
|
|
458
|
+
private getAgentRepositoriesClient(): AgentRepositoriesClient {
|
|
459
|
+
if (this.backend !== "cloud") {
|
|
460
|
+
throw new Error(
|
|
461
|
+
'client.agents.repositories is only available with backend: "cloud".',
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
this.agentRepositoriesClient ??= createAgentRepositoriesClient(
|
|
465
|
+
() => this.getCloudManagementTransport(),
|
|
466
|
+
);
|
|
467
|
+
return this.agentRepositoriesClient;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
private getCloudManagementTransport(): CloudManagementTransport {
|
|
471
|
+
const transport = this.getManagementTransport();
|
|
472
|
+
if (!(transport instanceof CloudManagementTransport)) {
|
|
473
|
+
throw new Error("Cloud management requested for non-cloud backend.");
|
|
474
|
+
}
|
|
475
|
+
return transport;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
private getCloudClient(): Letta {
|
|
479
|
+
if (this.backend !== "cloud") {
|
|
480
|
+
throw new Error("Letta client requested for non-cloud backend.");
|
|
481
|
+
}
|
|
482
|
+
this.cloudClient ??= createCloudClient(this.cloudOptions());
|
|
483
|
+
return this.cloudClient;
|
|
484
|
+
}
|
|
485
|
+
|
|
434
486
|
private getManagementTransport(): ManagementTransport {
|
|
435
487
|
if (this.managementTransport) return this.managementTransport;
|
|
436
488
|
if (this.backend === "remote") {
|
|
@@ -439,7 +491,7 @@ export class LettaAgentClientBase {
|
|
|
439
491
|
);
|
|
440
492
|
} else if (this.backend === "cloud") {
|
|
441
493
|
this.managementTransport = new CloudManagementTransport(
|
|
442
|
-
this.
|
|
494
|
+
this.getCloudClient(),
|
|
443
495
|
);
|
|
444
496
|
} else {
|
|
445
497
|
this.managementTransport = this.createLocalManagementTransport();
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import Letta from "@letta-ai/letta-client";
|
|
2
|
+
import type { LettaCodeCloudClientOptions } from "./types.js";
|
|
3
|
+
|
|
4
|
+
const DEFAULT_CLOUD_API_BASE_URL = "https://api.letta.com";
|
|
5
|
+
|
|
6
|
+
function defaultApiKey(): string | undefined {
|
|
7
|
+
const env = (
|
|
8
|
+
globalThis as {
|
|
9
|
+
process?: { env?: Record<string, string | undefined> };
|
|
10
|
+
}
|
|
11
|
+
).process?.env;
|
|
12
|
+
return env?.LETTA_API_KEY ?? env?.LETTA_CLOUD_API_KEY;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function bearerToken(
|
|
16
|
+
headers: Record<string, string> | undefined,
|
|
17
|
+
): string | undefined {
|
|
18
|
+
const authorization = headers?.Authorization ?? headers?.authorization;
|
|
19
|
+
return authorization?.match(/^Bearer\s+(.+)$/i)?.[1];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getCloudApiKey(
|
|
23
|
+
options: LettaCodeCloudClientOptions,
|
|
24
|
+
): string | undefined {
|
|
25
|
+
return options.apiKey ?? bearerToken(options.headers) ?? defaultApiKey();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function normalizeCloudApiBaseUrl(url: string | undefined): string {
|
|
29
|
+
const parsed = new URL(url ?? DEFAULT_CLOUD_API_BASE_URL);
|
|
30
|
+
parsed.pathname = parsed.pathname.replace(/\/+$/, "");
|
|
31
|
+
parsed.search = "";
|
|
32
|
+
parsed.hash = "";
|
|
33
|
+
return parsed.toString().replace(/\/$/, "");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Build the canonical Letta API client shared by one Agent SDK client. */
|
|
37
|
+
export function createCloudClient(
|
|
38
|
+
options: LettaCodeCloudClientOptions,
|
|
39
|
+
): Letta {
|
|
40
|
+
return new Letta({
|
|
41
|
+
apiKey: getCloudApiKey(options) ?? null,
|
|
42
|
+
baseURL: normalizeCloudApiBaseUrl(options.apiBaseUrl),
|
|
43
|
+
defaultHeaders: options.headers,
|
|
44
|
+
fetch: options.fetch,
|
|
45
|
+
});
|
|
46
|
+
}
|