@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.
Files changed (52) hide show
  1. package/AGENTS.md +35 -0
  2. package/README.md +20 -3
  3. package/dist/agent-repositories.d.ts +15 -0
  4. package/dist/agent-repositories.d.ts.map +1 -0
  5. package/dist/app-server-management.d.ts +10 -7
  6. package/dist/app-server-management.d.ts.map +1 -1
  7. package/dist/app-server-models.d.ts +4 -0
  8. package/dist/app-server-models.d.ts.map +1 -0
  9. package/dist/app-server-session.d.ts +3 -3
  10. package/dist/app-server-session.d.ts.map +1 -1
  11. package/dist/client-base.d.ts +5 -0
  12. package/dist/client-base.d.ts.map +1 -1
  13. package/dist/client-entry.js +3347 -641
  14. package/dist/client-entry.js.map +85 -13
  15. package/dist/cloud-client.d.ts +7 -0
  16. package/dist/cloud-client.d.ts.map +1 -0
  17. package/dist/cloud-management.d.ts +21 -18
  18. package/dist/cloud-management.d.ts.map +1 -1
  19. package/dist/cloud-session.d.ts +5 -5
  20. package/dist/cloud-session.d.ts.map +1 -1
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +3363 -657
  24. package/dist/index.js.map +86 -14
  25. package/dist/management-types.d.ts +85 -64
  26. package/dist/management-types.d.ts.map +1 -1
  27. package/dist/management.d.ts +11 -9
  28. package/dist/management.d.ts.map +1 -1
  29. package/dist/remote-session-protocol.d.ts +1 -1
  30. package/dist/remote-session-protocol.d.ts.map +1 -1
  31. package/dist/remote.d.ts +4 -5
  32. package/dist/remote.d.ts.map +1 -1
  33. package/dist/repositories.d.ts +3 -2
  34. package/dist/repositories.d.ts.map +1 -1
  35. package/dist/types.d.ts +12 -32
  36. package/dist/types.d.ts.map +1 -1
  37. package/package.json +3 -2
  38. package/src/agent-repositories.ts +159 -0
  39. package/src/app-server-management.ts +56 -116
  40. package/src/app-server-models.ts +20 -0
  41. package/src/app-server-session.ts +71 -146
  42. package/src/client-base.ts +72 -20
  43. package/src/cloud-client.ts +46 -0
  44. package/src/cloud-management.ts +128 -275
  45. package/src/cloud-session.ts +79 -262
  46. package/src/index.ts +6 -0
  47. package/src/management-types.ts +107 -64
  48. package/src/management.ts +46 -39
  49. package/src/remote-session-protocol.ts +2 -2
  50. package/src/remote.ts +18 -63
  51. package/src/repositories.ts +26 -99
  52. 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 RuntimeStartResponse = ProtocolMessage & {
50
- type: "runtime_start_response";
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 = ProtocolMessage & {
81
- type: "list_models_response";
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: Record<string, unknown> | null | undefined,
74
+ agent: object | null | undefined,
108
75
  ): string[] | undefined {
109
- const tools = agent?.tools;
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 normalizeListModelsResponse(response: ListModelsResponse): ListModelsResult {
432
- if (!response.success) {
433
- throw new Error(response.error ?? "listModels failed");
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
- const result: UpdateModelResult = {};
482
- if (response.applied_to === "agent" || response.applied_to === "conversation") {
483
- result.appliedTo = response.applied_to;
484
- }
485
- if (typeof response.model_id === "string") result.modelId = response.model_id;
486
- if (typeof response.model_handle === "string") result.modelHandle = response.model_handle;
487
- if (response.model_settings === null) {
488
- result.modelSettings = null;
489
- } else if (response.model_settings && typeof response.model_settings === "object") {
490
- result.modelSettings = { ...(response.model_settings as Record<string, unknown>) };
491
- }
492
- return result;
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<ProtocolMessage> {
611
- const request = this.client.request.bind(this.client) as unknown as (
612
- commandType: string,
613
- commandBody: Record<string, unknown>,
614
- requestOptions?: {
615
- timeoutMs?: number;
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
- ) => Promise<ProtocolMessage>;
619
- return request(type, body, options);
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 = (await this.request(
546
+ const response = await this.request<ListModelsResponse>(
624
547
  "list_models",
625
548
  {},
626
549
  { predicate: (message) => message.type === "list_models_response" },
627
- )) as ListModelsResponse;
628
- return normalizeListModelsResponse(response);
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 = (await this.request(
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
- )) as UpdateModelResponse;
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 = (await this.request(
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
- )) as ConversationMessagesListResponse;
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(client: AppServerClient): Promise<RuntimeStartResponse> {
748
+ private async startRuntime(
749
+ client: AppServerClient,
750
+ ): Promise<RuntimeStartResponseMessage> {
826
751
  const command = await this.buildRuntimeStartCommand(client);
827
- const response = (await client.runtimeStart(command)) as unknown as RuntimeStartResponse;
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 request = client.request.bind(client) as unknown as (
901
- commandType: string,
902
- commandBody: Record<string, unknown>,
903
- options?: { predicate?: (message: ProtocolMessage) => boolean },
904
- ) => Promise<ProtocolMessage>;
905
- const response = (await request(
906
- "conversation_retrieve",
907
- { conversation_id: conversationId },
908
- { predicate: (message) => message.type === "conversation_retrieve_response" },
909
- )) as ConversationRetrieveResponse;
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
  }
@@ -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(() => this.getManagementTransport());
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.cloudOptions(), options);
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(this.cloudOptions(), {
240
- kind: "session",
241
- agentId,
242
- newConversation: true,
243
- options,
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(this.cloudOptions(), {
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
- conversationId: id,
307
+ agentId: id,
308
+ defaultConversation: true,
283
309
  options,
284
- });
285
- }
286
- return new CloudEnvironmentSession(this.cloudOptions(), {
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(this.cloudOptions());
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.cloudOptions(),
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
+ }