@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
@@ -1,3 +1,5 @@
1
+ import type Letta from "@letta-ai/letta-client";
2
+ import { createCloudClient } from "./cloud-client.js";
1
3
  import type {
2
4
  CreateRepositoryFileParams,
3
5
  CreateRepositoryParams,
@@ -17,81 +19,6 @@ import type {
17
19
  UpdateRepositoryFileParams,
18
20
  } from "./types.js";
19
21
 
20
- const DEFAULT_CLOUD_API_BASE_URL = "https://api.letta.com";
21
-
22
- type FetchLike = typeof fetch;
23
-
24
- function getDefaultApiKey(): string | undefined {
25
- const env = (globalThis as { process?: { env?: Record<string, string | undefined> } })
26
- .process?.env;
27
- return env?.LETTA_API_KEY ?? env?.LETTA_CLOUD_API_KEY;
28
- }
29
-
30
- function bearerTokenFromHeaders(headers: Record<string, string> | undefined): string | undefined {
31
- const authorization = headers?.Authorization ?? headers?.authorization;
32
- if (!authorization) return undefined;
33
- const match = /^Bearer\s+(.+)$/i.exec(authorization);
34
- return match?.[1];
35
- }
36
-
37
- function getCloudApiKey(options: LettaCodeCloudClientOptions): string | undefined {
38
- return options.apiKey ?? bearerTokenFromHeaders(options.headers) ?? getDefaultApiKey();
39
- }
40
-
41
- function getFetch(fetchOverride?: FetchLike): FetchLike {
42
- const resolved = fetchOverride ?? globalThis.fetch;
43
- if (!resolved) throw new Error("No fetch implementation available for cloud backend.");
44
- return resolved.bind(globalThis) as FetchLike;
45
- }
46
-
47
- function normalizeCloudApiBaseUrl(url: string | undefined): string {
48
- const parsed = new URL(url ?? DEFAULT_CLOUD_API_BASE_URL);
49
- parsed.pathname = parsed.pathname.replace(/\/+$/, "");
50
- parsed.search = "";
51
- parsed.hash = "";
52
- return parsed.toString().replace(/\/$/, "");
53
- }
54
-
55
- function cloudHeaders(options: LettaCodeCloudClientOptions): Record<string, string> {
56
- const headers: Record<string, string> = {
57
- "Content-Type": "application/json",
58
- ...(options.headers ?? {}),
59
- };
60
- const apiKey = getCloudApiKey(options);
61
- if (apiKey && !headers.Authorization && !headers.authorization) {
62
- headers.Authorization = `Bearer ${apiKey}`;
63
- }
64
- return headers;
65
- }
66
-
67
- async function parseJsonResponse(response: Response): Promise<unknown> {
68
- const text = await response.text();
69
- if (!text) return null;
70
- try {
71
- return JSON.parse(text) as unknown;
72
- } catch {
73
- return text;
74
- }
75
- }
76
-
77
- function responseErrorMessage(body: unknown, fallback: string): string {
78
- if (body && typeof body === "object") {
79
- const record = body as Record<string, unknown>;
80
- const message = record.message ?? record.error ?? record.detail;
81
- const reasonText = record.reason_text;
82
- const pieces = [message, reasonText]
83
- .filter((value): value is string => typeof value === "string" && value.length > 0);
84
- if (pieces.length > 0) return pieces.join(": ");
85
- }
86
- return fallback;
87
- }
88
-
89
- function assertOkResponse(response: Response, body: unknown, action: string): void {
90
- if (!response.ok) {
91
- throw new Error(responseErrorMessage(body, `${action} failed with HTTP ${response.status}`));
92
- }
93
- }
94
-
95
22
  function optionalString(value: unknown): string | undefined {
96
23
  return typeof value === "string" ? value : undefined;
97
24
  }
@@ -131,17 +58,20 @@ function addOptionalSearchParam(url: URL, key: string, value: string | number |
131
58
  }
132
59
 
133
60
  export class RepositoriesClient {
134
- constructor(private readonly options: LettaCodeCloudClientOptions) {}
61
+ constructor(
62
+ options: LettaCodeCloudClientOptions,
63
+ private readonly client: Letta = createCloudClient(options),
64
+ ) {}
135
65
 
136
66
  async create(params: CreateRepositoryParams): Promise<Repository> {
137
- return toRepository(await this.request("/v1/repositories", "POST", { name: params.name }, "Cloud create repository"));
67
+ return toRepository(await this.request("/v1/repositories", "POST", { name: params.name }));
138
68
  }
139
69
 
140
70
  async list(params: ListRepositoriesParams = {}): Promise<ListRepositoriesResult> {
141
71
  const url = this.url("/v1/repositories");
142
72
  addOptionalSearchParam(url, "limit", params.limit);
143
73
  addOptionalSearchParam(url, "offset", params.offset);
144
- const body = await this.requestUrl(url, "GET", undefined, "Cloud list repositories");
74
+ const body = await this.requestUrl(url, "GET", undefined);
145
75
  if (!body || typeof body !== "object") {
146
76
  throw new Error("Cloud list repositories response did not include repositories.");
147
77
  }
@@ -156,7 +86,7 @@ export class RepositoriesClient {
156
86
  }
157
87
 
158
88
  async get(repositoryId: string): Promise<Repository> {
159
- return toRepository(await this.request(`/v1/repositories/${encodeURIComponent(repositoryId)}`, "GET", undefined, "Cloud get repository"));
89
+ return toRepository(await this.request(`/v1/repositories/${encodeURIComponent(repositoryId)}`, "GET", undefined));
160
90
  }
161
91
 
162
92
  /**
@@ -169,7 +99,6 @@ export class RepositoriesClient {
169
99
  `/v1/repositories/${encodeURIComponent(repositoryId)}`,
170
100
  "DELETE",
171
101
  undefined,
172
- "Cloud delete repository",
173
102
  );
174
103
  }
175
104
 
@@ -182,7 +111,7 @@ export class RepositoriesClient {
182
111
  addOptionalSearchParam(url, "path_prefix", params.pathPrefix);
183
112
  addOptionalSearchParam(url, "depth", params.depth);
184
113
  addOptionalSearchParam(url, "ref", params.ref);
185
- const body = await this.requestUrl(url, "GET", undefined, "Cloud list repository files");
114
+ const body = await this.requestUrl(url, "GET", undefined);
186
115
  if (!body || typeof body !== "object") {
187
116
  throw new Error("Cloud list repository files response did not include files.");
188
117
  }
@@ -210,14 +139,13 @@ export class RepositoriesClient {
210
139
  `/v1/repositories/${encodeURIComponent(repositoryId)}/files`,
211
140
  "POST",
212
141
  { path: params.path, content: params.content },
213
- "Cloud create repository file",
214
142
  )),
215
143
 
216
144
  read: async (repositoryId: string, params: { path: string; ref?: string }): Promise<RepositoryFile> => {
217
145
  const url = this.url(`/v1/repositories/${encodeURIComponent(repositoryId)}/files/content`);
218
146
  url.searchParams.set("path", params.path);
219
147
  addOptionalSearchParam(url, "ref", params.ref);
220
- const body = await this.requestUrl(url, "GET", undefined, "Cloud read repository file");
148
+ const body = await this.requestUrl(url, "GET", undefined);
221
149
  if (!body || typeof body !== "object") {
222
150
  throw new Error("Cloud read repository file response did not include file content.");
223
151
  }
@@ -249,7 +177,6 @@ export class RepositoriesClient {
249
177
  }
250
178
  : {}),
251
179
  },
252
- "Cloud update repository file",
253
180
  )),
254
181
 
255
182
  delete: async (
@@ -260,7 +187,6 @@ export class RepositoriesClient {
260
187
  `/v1/repositories/${encodeURIComponent(repositoryId)}/files/content`,
261
188
  "DELETE",
262
189
  { path: params.path },
263
- "Cloud delete repository file",
264
190
  );
265
191
  if (!body || typeof body !== "object") {
266
192
  throw new Error("Cloud delete repository file response did not include delete details.");
@@ -278,7 +204,7 @@ export class RepositoriesClient {
278
204
  const url = this.url(`/v1/repositories/${encodeURIComponent(repositoryId)}/versions`);
279
205
  addOptionalSearchParam(url, "path", params.path);
280
206
  addOptionalSearchParam(url, "limit", params.limit);
281
- const body = await this.requestUrl(url, "GET", undefined, "Cloud list repository versions");
207
+ const body = await this.requestUrl(url, "GET", undefined);
282
208
  if (Array.isArray(body)) return body as RepositoryVersion[];
283
209
  if (body && typeof body === "object") {
284
210
  const record = body as Record<string, unknown>;
@@ -295,7 +221,7 @@ export class RepositoriesClient {
295
221
  ): Promise<RepositoryFile> => {
296
222
  const url = this.url(`/v1/repositories/${encodeURIComponent(repositoryId)}/versions/${encodeURIComponent(sha)}`);
297
223
  url.searchParams.set("path", params.path);
298
- const body = await this.requestUrl(url, "GET", undefined, "Cloud get repository version");
224
+ const body = await this.requestUrl(url, "GET", undefined);
299
225
  if (!body || typeof body !== "object") {
300
226
  throw new Error("Cloud get repository version response did not include file content.");
301
227
  }
@@ -310,31 +236,32 @@ export class RepositoriesClient {
310
236
  };
311
237
 
312
238
  private url(path: string): URL {
313
- return new URL(`${normalizeCloudApiBaseUrl(this.options.apiBaseUrl)}${path}`);
239
+ return new URL(`${this.client.baseURL}${path}`);
314
240
  }
315
241
 
316
242
  private async request(
317
243
  path: string,
318
244
  method: string,
319
245
  body: unknown,
320
- action: string,
321
246
  ): Promise<unknown> {
322
- return this.requestUrl(this.url(path), method, body, action);
247
+ return this.requestUrl(this.url(path), method, body);
323
248
  }
324
249
 
325
250
  private async requestUrl(
326
251
  url: URL,
327
252
  method: string,
328
253
  body: unknown,
329
- action: string,
330
254
  ): Promise<unknown> {
331
- const response = await getFetch(this.options.fetch)(url, {
332
- method,
333
- headers: cloudHeaders(this.options),
334
- ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
335
- });
336
- const parsed = await parseJsonResponse(response);
337
- assertOkResponse(response, parsed, action);
338
- return parsed;
255
+ const options = body !== undefined ? { body } : undefined;
256
+ switch (method) {
257
+ case "GET":
258
+ return this.client.get(url.toString(), options);
259
+ case "POST":
260
+ return this.client.post(url.toString(), options);
261
+ case "DELETE":
262
+ return this.client.delete(url.toString(), options);
263
+ default:
264
+ throw new Error(`Unsupported repository request method: ${method}`);
265
+ }
339
266
  }
340
267
  }
package/src/types.ts CHANGED
@@ -6,7 +6,11 @@
6
6
  */
7
7
 
8
8
  import type { PersonalityId } from "@letta-ai/letta-code/agent-presets";
9
+ import type { ListModelsResponseModelEntry } from "@letta-ai/letta-code/app-server-protocol";
10
+ import type { Message as LettaMessage } from "@letta-ai/letta-client/resources/agents/messages";
11
+ import type { CreateBlock } from "@letta-ai/letta-client/resources/blocks/blocks";
9
12
  import type { LettaCodeCloudSandboxOptions } from "./cloud-sandbox.js";
13
+ export type { CreateBlock } from "@letta-ai/letta-client/resources/blocks/blocks";
10
14
  export type {
11
15
  GitHubRepositoryRef,
12
16
  LettaCodeCloudSandboxOptions,
@@ -15,26 +19,6 @@ export type {
15
19
  /** Letta Code personality preset used to seed a new agent. */
16
20
  export type LettaCodePersonalityId = PersonalityId;
17
21
 
18
- /** Custom memory block definition accepted when creating agents. */
19
- export interface CreateBlock {
20
- label: string;
21
- value: string;
22
- base_template_id?: string | null;
23
- deployment_id?: string | null;
24
- description?: string | null;
25
- entity_id?: string | null;
26
- hidden?: boolean | null;
27
- is_template?: boolean;
28
- limit?: number;
29
- metadata?: Record<string, unknown> | null;
30
- preserve_on_migration?: boolean | null;
31
- project_id?: string | null;
32
- read_only?: boolean;
33
- tags?: string[] | null;
34
- template_id?: string | null;
35
- template_name?: string | null;
36
- }
37
-
38
22
  export interface LettaCodeSocketLike {
39
23
  readyState: number;
40
24
  send(data: string): void;
@@ -564,16 +548,7 @@ export type ReasoningEffort =
564
548
  | "high"
565
549
  | "xhigh";
566
550
 
567
- export type LettaCodeModelEntry = Record<string, unknown> & {
568
- id: string;
569
- handle: string;
570
- label: string;
571
- description: string;
572
- isDefault?: boolean;
573
- isFeatured?: boolean;
574
- free?: boolean;
575
- updateArgs?: Record<string, unknown>;
576
- };
551
+ export type LettaCodeModelEntry = ListModelsResponseModelEntry;
577
552
 
578
553
  export interface ListModelsResult {
579
554
  entries: LettaCodeModelEntry[];
@@ -674,7 +649,11 @@ export interface CreateSessionOptions {
674
649
  */
675
650
  approvalRecoveryTimeoutMs?: number;
676
651
 
677
- /** Cloud repository resources to attach for the lifetime of the SDK session. */
652
+ /**
653
+ * Cloud repository resources to attach for the lifetime of the SDK session.
654
+ * For relationships that should outlive the session, use
655
+ * `client.agents.repositories.attach()` instead.
656
+ */
678
657
  resources?: RepositoryResource[];
679
658
 
680
659
  }
@@ -1219,7 +1198,7 @@ export interface ListMessagesOptions {
1219
1198
  * authoritative pagination answer.
1220
1199
  */
1221
1200
  export interface ListMessagesResult {
1222
- messages: unknown[];
1201
+ messages: LettaMessage[];
1223
1202
  /** ID of the oldest message in this page; use as `before` for the next page when present. */
1224
1203
  nextBefore?: string | null;
1225
1204
  /** Whether more pages exist in the requested direction, when known. */
@@ -1259,7 +1238,7 @@ export interface BootstrapStateResult {
1259
1238
  /** Whether memfs (git-backed memory) is enabled, when known. */
1260
1239
  memfsEnabled?: boolean;
1261
1240
  /** Initial history page (same shape as listMessages.messages). */
1262
- messages: unknown[];
1241
+ messages: LettaMessage[];
1263
1242
  /** Cursor to fetch older messages. Null when the backend knows there are no more pages. */
1264
1243
  nextBefore?: string | null;
1265
1244
  /** Whether more history pages exist, when known. */