@letta-ai/letta-agent-sdk 0.3.2 → 0.5.0

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 (70) hide show
  1. package/AGENTS.md +44 -0
  2. package/README.md +29 -0
  3. package/dist/app-server-management.d.ts +3 -48
  4. package/dist/app-server-management.d.ts.map +1 -1
  5. package/dist/app-server-session.d.ts +0 -6
  6. package/dist/app-server-session.d.ts.map +1 -1
  7. package/dist/client-base.d.ts +7 -15
  8. package/dist/client-base.d.ts.map +1 -1
  9. package/dist/client-entry.js +979 -1010
  10. package/dist/client-entry.js.map +15 -11
  11. package/dist/client.d.ts +3 -3
  12. package/dist/client.d.ts.map +1 -1
  13. package/dist/cloud-sandbox.d.ts +33 -0
  14. package/dist/cloud-sandbox.d.ts.map +1 -0
  15. package/dist/cloud-session.d.ts.map +1 -1
  16. package/dist/cloud-status-transport.d.ts +53 -0
  17. package/dist/cloud-status-transport.d.ts.map +1 -0
  18. package/dist/index.d.ts +7 -16
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +3242 -4298
  21. package/dist/index.js.map +20 -17
  22. package/dist/local-app-server-session.d.ts +1 -1
  23. package/dist/local-app-server-session.d.ts.map +1 -1
  24. package/dist/local-app-server.d.ts +11 -0
  25. package/dist/local-app-server.d.ts.map +1 -1
  26. package/dist/management.d.ts +0 -7
  27. package/dist/management.d.ts.map +1 -1
  28. package/dist/remote-client-session-core.d.ts +6 -93
  29. package/dist/remote-client-session-core.d.ts.map +1 -1
  30. package/dist/remote-session-protocol.d.ts +132 -0
  31. package/dist/remote-session-protocol.d.ts.map +1 -0
  32. package/dist/remote-turn-coordinator.d.ts +49 -0
  33. package/dist/remote-turn-coordinator.d.ts.map +1 -0
  34. package/dist/types.d.ts +59 -86
  35. package/dist/types.d.ts.map +1 -1
  36. package/dist/validation.d.ts.map +1 -1
  37. package/package.json +6 -3
  38. package/src/app-server-management.ts +405 -0
  39. package/src/app-server-session.ts +916 -0
  40. package/src/cli-resolver.ts +46 -0
  41. package/src/client-base.ts +456 -0
  42. package/src/client-entry.ts +31 -0
  43. package/src/client.ts +99 -0
  44. package/src/cloud-management.ts +360 -0
  45. package/src/cloud-sandbox.ts +117 -0
  46. package/src/cloud-session.ts +1055 -0
  47. package/src/cloud-status-transport.ts +305 -0
  48. package/src/index.ts +422 -0
  49. package/src/interactiveToolPolicy.ts +62 -0
  50. package/src/local-app-server-session.ts +49 -0
  51. package/src/local-app-server.ts +231 -0
  52. package/src/management-types.ts +133 -0
  53. package/src/management.ts +199 -0
  54. package/src/remote-client-session-core.ts +786 -0
  55. package/src/remote-session-protocol.ts +674 -0
  56. package/src/remote-turn-coordinator.ts +523 -0
  57. package/src/remote.ts +177 -0
  58. package/src/repositories.ts +340 -0
  59. package/src/request-ids.ts +33 -0
  60. package/src/stream-events.ts +88 -0
  61. package/src/tool-helpers.ts +147 -0
  62. package/src/types.ts +1281 -0
  63. package/src/validation.ts +238 -0
  64. package/src/websocket.ts +22 -0
  65. package/dist/protocol.d.ts +0 -205
  66. package/dist/protocol.d.ts.map +0 -1
  67. package/dist/session.d.ts +0 -155
  68. package/dist/session.d.ts.map +0 -1
  69. package/dist/transport.d.ts +0 -53
  70. package/dist/transport.d.ts.map +0 -1
package/src/types.ts ADDED
@@ -0,0 +1,1281 @@
1
+ /**
2
+ * SDK Types
3
+ *
4
+ * These are the public-facing types for SDK consumers.
5
+ * Protocol types are defined locally to avoid relying on broken package subpath exports.
6
+ */
7
+
8
+ import type { PersonalityId } from "@letta-ai/letta-code/agent-presets";
9
+ import type { LettaCodeCloudSandboxOptions } from "./cloud-sandbox.js";
10
+ export type {
11
+ GitHubRepositoryRef,
12
+ LettaCodeCloudSandboxOptions,
13
+ } from "./cloud-sandbox.js";
14
+
15
+ /** Letta Code personality preset used to seed a new agent. */
16
+ export type LettaCodePersonalityId = PersonalityId;
17
+
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
+ export interface LettaCodeSocketLike {
39
+ readyState: number;
40
+ send(data: string): void;
41
+ close(): void;
42
+ addEventListener?(type: string, listener: (event: unknown) => void): void;
43
+ removeEventListener?(type: string, listener: (event: unknown) => void): void;
44
+ on?(type: string, listener: (event: unknown) => void): void;
45
+ off?(type: string, listener: (event: unknown) => void): void;
46
+ once?(type: string, listener: (event: unknown) => void): void;
47
+ }
48
+
49
+ export interface LettaCodeSocketOptions {
50
+ headers?: Record<string, string>;
51
+ }
52
+
53
+ export type LettaCodeSocketConstructor = new (
54
+ url: string,
55
+ options?: LettaCodeSocketOptions,
56
+ ) => LettaCodeSocketLike;
57
+
58
+ /**
59
+ * React Native's WebSocket constructor accepts request headers as its third
60
+ * argument, unlike the Node-style constructor used by the SDK protocol layer.
61
+ */
62
+ export type LettaCodeReactNativeSocketConstructor = new (
63
+ url: string,
64
+ protocols?: string | string[] | null,
65
+ options?: LettaCodeSocketOptions,
66
+ ) => LettaCodeSocketLike;
67
+
68
+ // ═══════════════════════════════════════════════════════════════
69
+ // MESSAGE CONTENT TYPES (for multimodal support)
70
+ // ═══════════════════════════════════════════════════════════════
71
+
72
+ /**
73
+ * Text content in a message
74
+ */
75
+ export interface TextContent {
76
+ type: "text";
77
+ text: string;
78
+ }
79
+
80
+ export interface RunTurnOptions {
81
+ /**
82
+ * Max automatic approval-conflict recovery attempts for this turn.
83
+ * Overrides session-level maxApprovalRecoveryAttempts when provided.
84
+ */
85
+ maxApprovalRecoveryAttempts?: number;
86
+
87
+ /**
88
+ * Timeout in milliseconds for each approval recovery request.
89
+ * Overrides session-level approvalRecoveryTimeoutMs when provided.
90
+ */
91
+ recoveryTimeoutMs?: number;
92
+ }
93
+
94
+ export interface RecoverPendingApprovalsOptions {
95
+ /**
96
+ * Timeout in milliseconds for the recovery control request.
97
+ */
98
+ timeoutMs?: number;
99
+ }
100
+
101
+ export interface RecoverPendingApprovalsResult {
102
+ recovered: boolean;
103
+ /**
104
+ * Whether a pending approval is known to remain after recovery.
105
+ * Undefined means the SDK could not determine the state (for example, timeout).
106
+ */
107
+ pendingApproval?: boolean;
108
+ unsupported: boolean;
109
+ detail?: string;
110
+ }
111
+
112
+ /**
113
+ * Image content in a message (base64 encoded)
114
+ */
115
+ export interface ImageContent {
116
+ type: "image";
117
+ source: {
118
+ type: "base64";
119
+ media_type: "image/png" | "image/jpeg" | "image/gif" | "image/webp";
120
+ data: string;
121
+ };
122
+ }
123
+
124
+ /**
125
+ * A single content item (text or image)
126
+ */
127
+ export type MessageContentItem = TextContent | ImageContent;
128
+
129
+ /**
130
+ * What send() accepts - either a simple string or multimodal content array
131
+ */
132
+ export type SendMessage = string | MessageContentItem[];
133
+
134
+ // ═══════════════════════════════════════════════════════════════
135
+ // SKILLS / REMINDER / DREAMING TYPES
136
+ // ═══════════════════════════════════════════════════════════════
137
+
138
+ export type SkillSource = "bundled" | "global" | "agent" | "project";
139
+
140
+ export type DreamingTrigger = "off" | "step-count" | "compaction-event";
141
+
142
+ export type DreamingBehavior = "reminder" | "auto-launch";
143
+
144
+ /**
145
+ * Dreaming settings exposed through SDK options.
146
+ * Any omitted fields preserve server/CLI defaults.
147
+ */
148
+ export interface DreamingOptions {
149
+ trigger?: DreamingTrigger;
150
+ behavior?: DreamingBehavior;
151
+ stepCount?: number;
152
+ }
153
+
154
+ /** Dreaming settings that can be changed when opening an existing agent session. */
155
+ export type SessionDreamingOptions = Omit<DreamingOptions, "behavior">;
156
+
157
+ /**
158
+ * Fully-resolved dreaming settings emitted by init messages.
159
+ */
160
+ export interface EffectiveDreamingSettings {
161
+ trigger: DreamingTrigger;
162
+ behavior: DreamingBehavior;
163
+ stepCount: number;
164
+ }
165
+
166
+ // ═══════════════════════════════════════════════════════════════
167
+ // SYSTEM PROMPT TYPES
168
+ // ═══════════════════════════════════════════════════════════════
169
+
170
+ /**
171
+ * Available system prompt presets.
172
+ */
173
+ export type SystemPromptPreset =
174
+ | "default" // Alias for letta-claude
175
+ | "letta-claude" // Full Letta Code prompt (Claude-optimized)
176
+ | "letta-codex" // Full Letta Code prompt (Codex-optimized)
177
+ | "letta-gemini" // Full Letta Code prompt (Gemini-optimized)
178
+ | "claude" // Basic Claude (no skills/memory instructions)
179
+ | "codex" // Basic Codex
180
+ | "gemini"; // Basic Gemini
181
+
182
+ /**
183
+ * System prompt preset configuration.
184
+ */
185
+ export interface SystemPromptPresetConfigSDK {
186
+ type: "preset";
187
+ preset: SystemPromptPreset;
188
+ append?: string;
189
+ }
190
+
191
+ /**
192
+ * System prompt configuration - either a raw string or preset config.
193
+ */
194
+ export type SystemPromptConfig = string | SystemPromptPresetConfigSDK;
195
+
196
+ // ═══════════════════════════════════════════════════════════════
197
+ // MEMORY TYPES
198
+ // ═══════════════════════════════════════════════════════════════
199
+
200
+ /**
201
+ * Reference to an existing shared block by ID.
202
+ */
203
+ export interface BlockReference {
204
+ blockId: string;
205
+ }
206
+
207
+ /**
208
+ * Memory item - can be a preset name, custom block, or block reference.
209
+ */
210
+ export type MemoryItem =
211
+ | string // Preset name: "project", "persona", "human"
212
+ | CreateBlock // Custom block: { label, value, description? }
213
+ | BlockReference; // Shared block reference: { blockId }
214
+
215
+ /**
216
+ * Default memory block preset names.
217
+ */
218
+ export type MemoryPreset = "persona" | "human" | "skills" | "loaded_skills";
219
+
220
+ // ═══════════════════════════════════════════════════════════════
221
+ // TOOL TYPES (matches pi-agent-core)
222
+ // ═══════════════════════════════════════════════════════════════
223
+
224
+ /**
225
+ * Tool result content block
226
+ */
227
+ export interface AgentToolResultContent {
228
+ type: "text" | "image";
229
+ text?: string;
230
+ data?: string; // base64 for images
231
+ mimeType?: string;
232
+ }
233
+
234
+ /**
235
+ * Tool result (matches pi-agent-core)
236
+ */
237
+ export interface AgentToolResult<T> {
238
+ content: AgentToolResultContent[];
239
+ details?: T;
240
+ }
241
+
242
+ /**
243
+ * Tool update callback (for streaming tool progress)
244
+ */
245
+ export type AgentToolUpdateCallback<T> = (update: Partial<AgentToolResult<T>>) => void;
246
+
247
+ /**
248
+ * Agent tool definition (matches pi-agent-core)
249
+ */
250
+ export interface AgentTool<TParams, TResult> {
251
+ /** Display label */
252
+ label: string;
253
+
254
+ /** Tool name (used in API calls) */
255
+ name: string;
256
+
257
+ /** Description shown to the model */
258
+ description: string;
259
+
260
+ /** JSON Schema for parameters (TypeBox or plain object) */
261
+ parameters: TParams;
262
+
263
+ /** Execution function */
264
+ execute: (
265
+ toolCallId: string,
266
+ args: unknown,
267
+ signal?: AbortSignal,
268
+ onUpdate?: AgentToolUpdateCallback<TResult>,
269
+ ) => Promise<AgentToolResult<TResult>>;
270
+ }
271
+
272
+ /**
273
+ * Convenience type for tools with any params
274
+ */
275
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
276
+ export type AnyAgentTool = AgentTool<any, unknown>;
277
+
278
+ // ═══════════════════════════════════════════════════════════════
279
+ // TOP-LEVEL CLIENT TYPES
280
+ // ═══════════════════════════════════════════════════════════════
281
+
282
+ /**
283
+ * How the SDK reaches or runs the Letta Code harness.
284
+ *
285
+ * - local: spawn/manage a local Letta Code app-server over loopback websockets.
286
+ * - remote: connect to a user-managed app-server over websockets.
287
+ * - cloud: use agents hosted on Letta Cloud, with an explicit remote
288
+ * environment or SDK-managed sandbox.
289
+ */
290
+ export type LettaCodeBackend = "local" | "remote" | "cloud";
291
+
292
+ /**
293
+ * Stable execution target for remote/cloud runtimes.
294
+ *
295
+ * Strings are treated as human-readable environment names. Object forms allow
296
+ * callers to avoid relying on names as unique identifiers.
297
+ */
298
+ export type LettaCodeEnvironment =
299
+ | string
300
+ | { name: string }
301
+ | { id: string }
302
+ | { connectionId: string }
303
+ | { deviceId: string };
304
+
305
+ export interface LettaCodeLocalAppServerOptions {
306
+ /**
307
+ * Optional URL for tests or advanced users with a pre-started local app-server.
308
+ * Omit to let the SDK spawn and own a loopback app-server.
309
+ */
310
+ url?: string;
311
+ /**
312
+ * Which Letta Code backend the spawned app-server runs against:
313
+ * - "local": the in-process experimental backend (agents stored on this
314
+ * machine, `agent-local-*` ids). The default.
315
+ * - "api": Letta Cloud (real `agent-*` ids, cloud-side models such as
316
+ * letta/auto-memory) with tools still executing on this machine. Requires
317
+ * the harness to be authenticated (login or LETTA_API_KEY).
318
+ */
319
+ harnessBackend?: "api" | "local";
320
+ /** Optional WebSocket constructor for tests/non-standard runtimes. */
321
+ WebSocket?: LettaCodeSocketConstructor;
322
+ /** Timeout for websocket protocol request/turn correlation. */
323
+ requestTimeoutMs?: number;
324
+ /** Whether agents created through this app-server are added to Letta Code's global pinned-agent list. */
325
+ pinGlobalAgent?: boolean;
326
+ /** Local app-server listen URL when the SDK spawns it. Defaults to ws://127.0.0.1:0. */
327
+ listen?: string;
328
+ /** Timeout waiting for the spawned app-server to print its listening URL. */
329
+ startupTimeoutMs?: number;
330
+ }
331
+
332
+ export interface LettaCodeLocalClientOptions {
333
+ backend?: "local";
334
+ /** Advanced app-server overrides for local execution. */
335
+ appServer?: LettaCodeLocalAppServerOptions;
336
+ }
337
+
338
+ export interface LettaCodeRemoteClientOptions {
339
+ backend: "remote";
340
+ /** URL of the user-managed app-server / websocket endpoint. */
341
+ url: string;
342
+ /** Optional capability token sent as Authorization: Bearer <token> during websocket upgrade. */
343
+ authToken?: string;
344
+ /** Optional WebSocket constructor for non-browser runtimes and tests. */
345
+ WebSocket?: LettaCodeSocketConstructor;
346
+ /** Timeout for websocket protocol request/turn correlation. */
347
+ requestTimeoutMs?: number;
348
+ /** Whether agents created through this app-server are added to Letta Code's global pinned-agent list. */
349
+ pinGlobalAgent?: boolean;
350
+ }
351
+
352
+ export interface LettaCodeCloudClientOptions {
353
+ backend: "cloud";
354
+ /** Optional API key override. Defaults to LETTA_API_KEY / existing auth. */
355
+ apiKey?: string;
356
+ /** Optional API base URL override. Defaults to the Letta API. */
357
+ apiBaseUrl?: string;
358
+ /** Optional extra HTTP headers for Cloud API requests. */
359
+ headers?: Record<string, string>;
360
+ /** Optional fetch implementation for tests/non-standard runtimes. */
361
+ fetch?: typeof fetch;
362
+ /** Optional WebSocket constructor for non-browser runtimes and tests. */
363
+ WebSocket?: LettaCodeSocketConstructor;
364
+ /** Timeout for websocket protocol request/turn correlation. */
365
+ requestTimeoutMs?: number;
366
+ /**
367
+ * WebSocket authentication style. Defaults to Authorization headers; set to
368
+ * query for browser-style clients that cannot send WebSocket headers.
369
+ */
370
+ webSocketAuth?: "header" | "query";
371
+ /** Heartbeat interval for the Cloud status websocket. Defaults to 30s. */
372
+ pingIntervalMs?: number;
373
+ /**
374
+ * Execution target for Letta Cloud sessions. If omitted, the SDK creates
375
+ * and owns a sandbox for the session.
376
+ */
377
+ environment?: LettaCodeEnvironment;
378
+ /** Options for SDK-managed sandboxes when environment is omitted. */
379
+ sandbox?: LettaCodeCloudSandboxOptions;
380
+ }
381
+
382
+ export type LettaCodeClientOptions =
383
+ | LettaCodeLocalClientOptions
384
+ | LettaCodeRemoteClientOptions
385
+ | LettaCodeCloudClientOptions;
386
+
387
+ export interface Repository {
388
+ id: string;
389
+ name: string;
390
+ createdAt: string;
391
+ updatedAt: string;
392
+ }
393
+
394
+ export interface CreateRepositoryParams {
395
+ name: string;
396
+ }
397
+
398
+ export interface ListRepositoriesParams {
399
+ limit?: number;
400
+ offset?: number;
401
+ }
402
+
403
+ export interface ListRepositoriesResult {
404
+ repositories: Repository[];
405
+ hasNextPage: boolean;
406
+ }
407
+
408
+ export interface RepositoryResource {
409
+ type: "repository";
410
+ repositoryId: string;
411
+ }
412
+
413
+ export interface RepositoryFileEntry {
414
+ path: string;
415
+ type: "file" | "directory";
416
+ }
417
+
418
+ export interface ListRepositoryFilesParams {
419
+ pathPrefix?: string;
420
+ depth?: number;
421
+ ref?: string;
422
+ }
423
+
424
+ export interface ListRepositoryFilesResult {
425
+ files: RepositoryFileEntry[];
426
+ ref: string;
427
+ }
428
+
429
+ export interface CreateRepositoryFileParams {
430
+ path: string;
431
+ content: string;
432
+ }
433
+
434
+ export interface RepositoryFile {
435
+ path: string;
436
+ content: string;
437
+ contentSha256: string;
438
+ ref?: string;
439
+ }
440
+
441
+ export interface UpdateRepositoryFileParams {
442
+ path: string;
443
+ content?: string;
444
+ newPath?: string;
445
+ precondition?: {
446
+ contentSha256: string;
447
+ };
448
+ }
449
+
450
+ export interface RepositoryFileMutationResult {
451
+ path: string;
452
+ contentSha256: string;
453
+ commitSha: string;
454
+ }
455
+
456
+ export interface DeleteRepositoryFileParams {
457
+ path: string;
458
+ }
459
+
460
+ export interface DeleteRepositoryFileResult {
461
+ success: boolean;
462
+ commitSha: string;
463
+ }
464
+
465
+ export interface RepositoryVersion {
466
+ sha: string;
467
+ message: string;
468
+ timestamp: string;
469
+ author_name: string | null;
470
+ }
471
+
472
+ export interface ListRepositoryVersionsParams {
473
+ path?: string;
474
+ limit?: number;
475
+ }
476
+
477
+ export interface GetRepositoryVersionParams {
478
+ path: string;
479
+ }
480
+
481
+ // ═══════════════════════════════════════════════════════════════
482
+ // SESSION OPTIONS
483
+ // ═══════════════════════════════════════════════════════════════
484
+
485
+ /**
486
+ * A suggested permission grant attached to a `can_use_tool` approval request.
487
+ * Approval UIs can render these as selectable chips and echo the chosen ids
488
+ * back via `CanUseToolResponseAllow.updatedPermissions`.
489
+ */
490
+ export interface CanUseToolPermissionSuggestion {
491
+ id: string;
492
+ text: string;
493
+ }
494
+
495
+ export interface CanUseToolResponseAllow {
496
+ behavior: "allow";
497
+ message?: string;
498
+ updatedInput?: Record<string, unknown> | null;
499
+ updatedPermissions?: unknown[];
500
+ }
501
+
502
+ export interface CanUseToolResponseDeny {
503
+ behavior: "deny";
504
+ message: string;
505
+ interrupt?: boolean;
506
+ }
507
+
508
+ export type CanUseToolResponse =
509
+ | CanUseToolResponseAllow
510
+ | CanUseToolResponseDeny;
511
+
512
+ /**
513
+ * Additional context for a `can_use_tool` approval request, passed as the
514
+ * optional third argument to {@link CanUseToolCallback}.
515
+ *
516
+ * All fields are optional: transports pass through whatever subset the wire
517
+ * protocol provides, leaving absent fields undefined.
518
+ */
519
+ export interface CanUseToolContext {
520
+ /** Id of the control request carrying this approval (for logging/correlation). */
521
+ requestId?: string;
522
+ /** Tool call id — links the approval to its tool_call card in the message stream. */
523
+ toolCallId?: string;
524
+ /** Suggested permission grants the user can select. */
525
+ permissionSuggestions?: CanUseToolPermissionSuggestion[];
526
+ /** Path that triggered the permission check, when the tool was blocked on a path rule. */
527
+ blockedPath?: string | null;
528
+ /**
529
+ * Diff previews for file-editing tools, passed through verbatim.
530
+ * Shape matches letta-code's `DiffPreview` (mode: "advanced" | "fallback" | "unpreviewable").
531
+ */
532
+ diffs?: unknown[];
533
+ }
534
+
535
+ /**
536
+ * Callback for custom permission handling.
537
+ *
538
+ * The optional third argument carries approval context (tool call id,
539
+ * permission suggestions, diff previews). Two-argument callbacks remain
540
+ * fully supported.
541
+ */
542
+ export type CanUseToolCallback = (
543
+ toolName: string,
544
+ toolInput: Record<string, unknown>,
545
+ context?: CanUseToolContext,
546
+ ) => Promise<CanUseToolResponse> | CanUseToolResponse;
547
+
548
+ export type PermissionMode =
549
+ | "standard"
550
+ | "acceptEdits"
551
+ | "unrestricted";
552
+
553
+ export type ReasoningEffort =
554
+ | "none"
555
+ | "minimal"
556
+ | "low"
557
+ | "medium"
558
+ | "high"
559
+ | "xhigh";
560
+
561
+ export type LettaCodeModelEntry = Record<string, unknown> & {
562
+ id: string;
563
+ handle: string;
564
+ label: string;
565
+ description: string;
566
+ isDefault?: boolean;
567
+ isFeatured?: boolean;
568
+ free?: boolean;
569
+ updateArgs?: Record<string, unknown>;
570
+ };
571
+
572
+ export interface ListModelsResult {
573
+ entries: LettaCodeModelEntry[];
574
+ /** Handles available to this user. null means availability lookup failed. */
575
+ availableHandles?: string[] | null;
576
+ /** BYOK provider name -> base provider name, e.g. lc-anthropic -> anthropic. */
577
+ byokProviderAliases?: Record<string, string>;
578
+ }
579
+
580
+ export interface UpdateModelOptions {
581
+ /** Model id from listModels() or direct model handle. Model ids usually omit '/'. */
582
+ model?: string;
583
+ /** Explicit model id from listModels(). */
584
+ modelId?: string;
585
+ /** Explicit direct model handle, including BYOK handles. */
586
+ modelHandle?: string;
587
+ /** Select a reasoning tier for the target model handle. */
588
+ reasoningEffort?: ReasoningEffort;
589
+ }
590
+
591
+ export interface UpdateModelResult {
592
+ appliedTo?: "agent" | "conversation";
593
+ modelId?: string;
594
+ modelHandle?: string;
595
+ modelSettings?: Record<string, unknown> | null;
596
+ }
597
+
598
+ export type SDKProtocolMessage<TType extends string = string> = Record<string, unknown> & {
599
+ type: TType;
600
+ request_id?: string;
601
+ };
602
+
603
+ export type SDKProtocolCommand<TType extends string = string> = SDKProtocolMessage<TType>;
604
+
605
+ export interface SendCommandOptions<TResponseType extends string = string> {
606
+ /** Wait for a response with this protocol message type. Omit for fire-and-forget commands. */
607
+ responseType?: TResponseType;
608
+ /** Override the websocket protocol request timeout for this command. */
609
+ timeoutMs?: number;
610
+ /** Optional custom matcher for advanced protocol responses. */
611
+ predicate?: (message: SDKProtocolMessage) => boolean;
612
+ }
613
+
614
+ /**
615
+ * Options for createSession() and resumeSession() restricted to settings that
616
+ * can be applied to existing agents.
617
+ * For creating new agents with custom memory/persona, use createAgent().
618
+ */
619
+ export interface CreateSessionOptions {
620
+ /** Model to use (e.g., "claude-sonnet-4-20250514") - updates the agent's LLM config */
621
+ model?: string;
622
+
623
+ /** Reasoning effort tier to use with the selected/current model on websocket protocol sessions. */
624
+ reasoningEffort?: ReasoningEffort;
625
+
626
+ /**
627
+ * Exact client-side tool allowlist for the session, including custom SDK
628
+ * tools. When omitted, the harness default toolset and registered custom
629
+ * tools apply. Interactive user-input tools (AskUserQuestion) are always
630
+ * excluded for SDK sessions.
631
+ */
632
+ allowedTools?: string[];
633
+
634
+ /** Permission mode */
635
+ permissionMode?: PermissionMode;
636
+
637
+ /** Working directory for the CLI process */
638
+ cwd?: string;
639
+
640
+ /**
641
+ * Restrict available skills by source.
642
+ * Empty array disables all skills (`--no-skills`).
643
+ */
644
+ skillSources?: SkillSource[];
645
+
646
+ /**
647
+ * Configure dreaming settings.
648
+ */
649
+ dreaming?: SessionDreamingOptions;
650
+
651
+ /** Custom permission callback - called when tool needs approval */
652
+ canUseTool?: CanUseToolCallback;
653
+
654
+ /**
655
+ * Custom tools that execute locally in the SDK process.
656
+ * These tools are registered with the CLI and executed when the LLM calls them.
657
+ */
658
+ tools?: AnyAgentTool[];
659
+
660
+ /**
661
+ * Max automatic approval-conflict recovery attempts per runTurn() call.
662
+ * Set to 0 to disable automatic recovery.
663
+ */
664
+ maxApprovalRecoveryAttempts?: number;
665
+
666
+ /**
667
+ * Timeout in milliseconds for a single approval recovery request.
668
+ */
669
+ approvalRecoveryTimeoutMs?: number;
670
+
671
+ /** Cloud repository resources to attach for the lifetime of the SDK session. */
672
+ resources?: RepositoryResource[];
673
+
674
+ }
675
+
676
+ /**
677
+ * Session options accepted by LettaAgentClient methods.
678
+ *
679
+ * `environment` is a cloud execution-target override. It is deliberately
680
+ * session-scoped rather than part of createAgent() options.
681
+ */
682
+ export interface LettaCodeClientSessionOptions extends CreateSessionOptions {
683
+ environment?: LettaCodeEnvironment;
684
+ /** Per-session SDK-managed sandbox options when environment is omitted. */
685
+ sandbox?: LettaCodeCloudSandboxOptions;
686
+ /**
687
+ * Extra environment variables for the session's harness process. Each
688
+ * SDK-owned local app-server session runs in its own process, so this
689
+ * scopes cleanly per session — e.g. MEMORY_DIR / LETTA_MEMORY_DIR to point
690
+ * the harness's memory scoping (and its guard) at a session-specific
691
+ * memory copy. Ignored on remote and cloud transports.
692
+ */
693
+ env?: Record<string, string>;
694
+ /**
695
+ * Constrain an SDK-owned local session harness to memory-worker filesystem
696
+ * access. Agent-ID sessions derive the standard root; set `MEMORY_DIR` or
697
+ * `LETTA_MEMORY_DIR` for overrides and conversation-ID resumes. Fails closed
698
+ * without a root or supported kernel sandbox. Excludes agent creation,
699
+ * management calls, and remote/Cloud runtimes.
700
+ */
701
+ filesystemConfinement?: "memory";
702
+ }
703
+
704
+ export interface LettaCodeSession extends AsyncDisposable {
705
+ send(message: SendMessage): Promise<void>;
706
+ stream(): AsyncGenerator<SDKMessage>;
707
+ abort(): Promise<void>;
708
+ sendCommand(command: SDKProtocolCommand): Promise<void>;
709
+ sendCommand<TResponse extends SDKProtocolMessage = SDKProtocolMessage>(
710
+ command: SDKProtocolCommand,
711
+ options: SendCommandOptions,
712
+ ): Promise<TResponse>;
713
+ listMessages(options?: ListMessagesOptions): Promise<ListMessagesResult>;
714
+ listModels(): Promise<ListModelsResult>;
715
+ updateModel(update: string | UpdateModelOptions): Promise<UpdateModelResult>;
716
+ /**
717
+ * Fetch the initial conversation projection used to hydrate or reconcile a
718
+ * resumed session.
719
+ */
720
+ bootstrapState(options?: BootstrapStateOptions): Promise<BootstrapStateResult>;
721
+ /**
722
+ * Ask the runtime to recover any approval that was pending across a
723
+ * disconnect.
724
+ */
725
+ recoverPendingApprovals(
726
+ options?: RecoverPendingApprovalsOptions,
727
+ ): Promise<RecoverPendingApprovalsResult>;
728
+ /**
729
+ * Update runtime controls for subsequent work in this conversation.
730
+ *
731
+ * The current app-server protocol does not acknowledge this command. The
732
+ * promise confirms that the command was accepted for transport, not that the
733
+ * runtime has applied it.
734
+ */
735
+ changeDeviceState(updates: ChangeDeviceStateOptions): Promise<void>;
736
+ /**
737
+ * Remove one queued user message and wait for the runtime acknowledgement.
738
+ */
739
+ removeQueuedMessage(itemId: string): Promise<RemoveQueuedMessageResult>;
740
+ /**
741
+ * Read the device execution context (online/processing flags, permission
742
+ * mode, working directory, pending approvals).
743
+ *
744
+ * Sends a lightweight, request-correlated `sync` and resolves only after the
745
+ * runtime acknowledges it and pushes a fresh `update_device_status`
746
+ * snapshot for this runtime scope.
747
+ */
748
+ getDeviceStatus(options?: GetDeviceStatusOptions): Promise<SessionDeviceStatus>;
749
+ /**
750
+ * Subscribe to every incoming device-status update for this session's
751
+ * runtime scope. Returns an unsubscribe function.
752
+ */
753
+ onDeviceStatus(listener: (status: SessionDeviceStatus) => void): () => void;
754
+ close(): void;
755
+ readonly agentId: string | null;
756
+ readonly sessionId: string | null;
757
+ readonly conversationId: string | null;
758
+ }
759
+
760
+ export interface ChangeDeviceStateOptions {
761
+ cwd?: string;
762
+ permissionMode?: PermissionMode;
763
+ }
764
+
765
+ export interface RemoveQueuedMessageResult {
766
+ /** Queue item identifier echoed by the runtime. */
767
+ itemId: string;
768
+ /** False when the item was no longer present in the authoritative queue. */
769
+ removed: boolean;
770
+ }
771
+
772
+ export interface GetDeviceStatusOptions {
773
+ /**
774
+ * Timeout in milliseconds for the authoritative sync and status replay.
775
+ * Defaults to the session's request timeout.
776
+ */
777
+ timeoutMs?: number;
778
+ }
779
+
780
+ /** A suggested permission grant attached to a pending approval. */
781
+ export interface SessionPermissionSuggestion {
782
+ id: string;
783
+ text: string;
784
+ }
785
+
786
+ export interface SessionDiffHunkLine {
787
+ type: "context" | "add" | "remove";
788
+ content: string;
789
+ }
790
+
791
+ export interface SessionDiffHunk {
792
+ oldStart: number;
793
+ oldLines: number;
794
+ newStart: number;
795
+ newLines: number;
796
+ lines: SessionDiffHunkLine[];
797
+ }
798
+
799
+ /** Portable projection of a file-edit diff preview. */
800
+ export type SessionDiffPreview =
801
+ | {
802
+ mode: "advanced";
803
+ fileName: string;
804
+ hunks: SessionDiffHunk[];
805
+ }
806
+ | {
807
+ mode: "fallback" | "unpreviewable";
808
+ fileName: string;
809
+ reason: string;
810
+ };
811
+
812
+ /** One tool approval the device is still waiting on. */
813
+ export interface SessionPendingControlRequest {
814
+ /**
815
+ * Control request id for correlation only. Approval decisions must still
816
+ * resolve through `recoverPendingApprovals()` and `canUseTool`.
817
+ */
818
+ requestId: string;
819
+ /** Tool awaiting approval. */
820
+ toolName: string;
821
+ /** Tool call id awaiting approval, when reported. */
822
+ toolCallId?: string;
823
+ /** Tool input awaiting approval, when reported. */
824
+ toolInput?: Record<string, unknown>;
825
+ /** Permission grants offered by the runtime. */
826
+ permissionSuggestions: SessionPermissionSuggestion[];
827
+ /** Path that triggered the permission check, when reported. */
828
+ blockedPath: string | null;
829
+ /** File-edit previews supplied with the approval, when reported. */
830
+ diffs?: SessionDiffPreview[];
831
+ }
832
+
833
+ /**
834
+ * Typed projection of the wire `update_device_status` payload.
835
+ *
836
+ * `raw` carries the full wire `device_status` object for fields that are not
837
+ * projected (git context, toolsets, background processes, ...).
838
+ */
839
+ export interface SessionDeviceStatus {
840
+ /** Whether the executing device is connected. */
841
+ isOnline: boolean;
842
+ /** Whether the device is currently processing a turn. */
843
+ isProcessing: boolean;
844
+ /** Permission mode currently applied to this runtime scope. */
845
+ permissionMode: PermissionMode;
846
+ /** Working directory currently applied to this runtime scope. */
847
+ workingDirectory: string | null;
848
+ /** Approvals the device is still waiting on (foreground-resume UI). */
849
+ pendingControlRequests: SessionPendingControlRequest[];
850
+ /** Full wire `device_status` payload as an escape hatch. */
851
+ raw: Record<string, unknown>;
852
+ }
853
+
854
+ /**
855
+ * Options for createAgent() - full control over agent creation.
856
+ */
857
+ export interface CreateAgentOptions {
858
+ /**
859
+ * Letta Code personality preset. Defaults to "memo". The creation payload
860
+ * is built by `@letta-ai/letta-code/agent-presets`, matching Chat/Desktop.
861
+ */
862
+ personality?: LettaCodePersonalityId;
863
+
864
+ /** Model to use (e.g., "claude-sonnet-4-20250514") */
865
+ model?: string;
866
+
867
+ /** Embedding model to use (e.g., "text-embedding-ada-002") */
868
+ embedding?: string;
869
+
870
+ /**
871
+ * System prompt configuration.
872
+ * - string: Use as the complete system prompt
873
+ * - SystemPromptPreset: Use a preset
874
+ * - { type: 'preset', preset, append? }: Use a preset with optional appended text
875
+ */
876
+ systemPrompt?: string | SystemPromptPreset | SystemPromptPresetConfigSDK;
877
+
878
+ /**
879
+ * Memory block configuration. Each item can be:
880
+ * - string: Preset block name ("persona", "human", "skills", "loaded_skills")
881
+ * - CreateBlock: Custom block definition (e.g., { label: "project", value: "..." })
882
+ * - { blockId: string }: Reference to existing shared block
883
+ */
884
+ memory?: MemoryItem[];
885
+
886
+ /** Convenience: Set persona block value directly */
887
+ persona?: string;
888
+
889
+ /** Convenience: Set human block value directly */
890
+ human?: string;
891
+
892
+ /**
893
+ * Whether to enable the git-backed memory filesystem on the new agent
894
+ * (default true). Pass false for worker-style agents that should not carry
895
+ * their own memory repo — enabling memfs is a slow backend round trip, and
896
+ * concurrent sessions on a shared-memfs agent contend on its git state.
897
+ */
898
+ memfs?: boolean;
899
+
900
+ /** Display name for the agent. */
901
+ name?: string;
902
+
903
+ /** Description of the agent's purpose. */
904
+ description?: string;
905
+
906
+ /** Hide the agent from default listings (worker/subagent semantics). */
907
+ hidden?: boolean;
908
+
909
+ /**
910
+ * Server-side tools to attach at creation. When omitted, the harness
911
+ * applies its created-agent defaults (web_search, fetch_webpage). Pass []
912
+ * for none or an explicit list to override. Client-side tools (Bash,
913
+ * Edit, …) are provided by the harness at runtime and are unaffected.
914
+ */
915
+ baseTools?: string[];
916
+
917
+ /**
918
+ * Exact client-side tool allowlist for the session, including custom SDK
919
+ * tools. When omitted, the harness default toolset and registered custom
920
+ * tools apply. Interactive user-input tools (AskUserQuestion) are always
921
+ * excluded for SDK sessions.
922
+ */
923
+ allowedTools?: string[];
924
+
925
+ /** List of disallowed tool names */
926
+ disallowedTools?: string[];
927
+
928
+ /** Permission mode */
929
+ permissionMode?: PermissionMode;
930
+
931
+ /** Working directory for the CLI process */
932
+ cwd?: string;
933
+
934
+ /** Custom permission callback - called when tool needs approval */
935
+ canUseTool?: CanUseToolCallback;
936
+
937
+ /**
938
+ * Custom tools that execute locally in the SDK process.
939
+ * These tools are registered with the CLI and executed when the LLM calls them.
940
+ */
941
+ tools?: AnyAgentTool[];
942
+
943
+ /** Tags to organize and categorize the agent. */
944
+ tags?: string[];
945
+
946
+ /**
947
+ * Restrict available skills by source.
948
+ * Empty array disables all skills (`--no-skills`).
949
+ */
950
+ skillSources?: SkillSource[];
951
+
952
+ /**
953
+ * Toggle first-turn system info reminder (device/git/cwd context).
954
+ * false -> `--no-system-info-reminder`.
955
+ */
956
+ systemInfoReminder?: boolean;
957
+
958
+ /**
959
+ * Configure dreaming settings.
960
+ */
961
+ dreaming?: DreamingOptions;
962
+ }
963
+
964
+ // ═══════════════════════════════════════════════════════════════
965
+ // SDK MESSAGE TYPES
966
+ // ═══════════════════════════════════════════════════════════════
967
+
968
+ /**
969
+ * SDK message types - clean wrappers around wire types
970
+ */
971
+ export interface SDKInitMessage {
972
+ type: "init";
973
+ agentId: string;
974
+ sessionId: string;
975
+ conversationId: string;
976
+ model: string;
977
+ /** Backend-reported tool names, when the transport exposes an authoritative list. */
978
+ tools?: string[];
979
+ memfsEnabled?: boolean;
980
+ skillSources?: SkillSource[];
981
+ systemInfoReminderEnabled?: boolean;
982
+ dreaming?: EffectiveDreamingSettings;
983
+ }
984
+
985
+ export interface SDKAssistantMessage {
986
+ type: "assistant";
987
+ content: string;
988
+ /** Legacy transport identifier. Prefer `otid` for message lineage. */
989
+ uuid: string;
990
+ /** Stable lineage key for this typed message slice, when provided. */
991
+ otid?: string | null;
992
+ /** Per-run replay cursor. Compare only within the same `runId`. */
993
+ seqId?: number;
994
+ /** Run ID from the Letta API for this event (used for stale-run detection). */
995
+ runId?: string;
996
+ }
997
+
998
+ export interface SDKToolCallMessage {
999
+ type: "tool_call";
1000
+ toolCallId: string;
1001
+ toolName: string;
1002
+ toolInput: Record<string, unknown>;
1003
+ /** Raw unparsed arguments string from the wire for consumer-side accumulation. */
1004
+ rawArguments?: string;
1005
+ uuid: string;
1006
+ /** Run ID from the Letta API for this event (used for stale-run detection). */
1007
+ runId?: string;
1008
+ }
1009
+
1010
+ export interface SDKToolResultMessage {
1011
+ type: "tool_result";
1012
+ toolCallId: string;
1013
+ content: string;
1014
+ isError: boolean;
1015
+ uuid: string;
1016
+ /** Run ID from the Letta API for this event (used for stale-run detection). */
1017
+ runId?: string;
1018
+ }
1019
+
1020
+ export interface SDKReasoningMessage {
1021
+ type: "reasoning";
1022
+ content: string;
1023
+ /** Legacy transport identifier. Prefer `otid` for message lineage. */
1024
+ uuid: string;
1025
+ /** Stable lineage key for this typed message slice, when provided. */
1026
+ otid?: string | null;
1027
+ /** Per-run replay cursor. Compare only within the same `runId`. */
1028
+ seqId?: number;
1029
+ /** Run ID from the Letta API for this event (used for stale-run detection). */
1030
+ runId?: string;
1031
+ }
1032
+
1033
+ /** Canonical SDK error codes recognized by the SDK. */
1034
+ export type SDKErrorCode =
1035
+ | "approval_conflict"
1036
+ | "approval_conflict_terminal"
1037
+ | "protocol_error"
1038
+ | "error"
1039
+ | "llm_api_error"
1040
+ | "max_steps"
1041
+ | "interrupted"
1042
+ | "stream_closed";
1043
+
1044
+ export interface SDKResultMessage {
1045
+ type: "result";
1046
+ success: boolean;
1047
+ result?: string;
1048
+ /** Legacy error string (kept for compatibility). Prefer errorCode. */
1049
+ error?: string;
1050
+ /** Canonical typed error code for machine handling. */
1051
+ errorCode?: SDKErrorCode;
1052
+ /** True when the failure corresponds to an approval conflict/deadlock. */
1053
+ approvalConflict?: boolean;
1054
+ /** Whether another recovery attempt could still succeed. */
1055
+ recoverable?: boolean;
1056
+ /** Number of SDK-managed recovery attempts executed for this turn. */
1057
+ recoveryAttempts?: number;
1058
+ /** Best-effort human-readable approval-conflict detail (if available). */
1059
+ errorDetail?: string;
1060
+ stopReason?: string;
1061
+ durationMs: number;
1062
+ totalCostUsd?: number;
1063
+ conversationId: string | null;
1064
+ /** Run IDs associated with this turn (if provided by the CLI). */
1065
+ runIds?: string[];
1066
+ }
1067
+
1068
+ export interface SDKStreamEventDeltaPayload {
1069
+ type: string;
1070
+ index?: number;
1071
+ delta?: { type?: string; text?: string; reasoning?: string };
1072
+ content_block?: { type?: string; text?: string };
1073
+ [key: string]: unknown;
1074
+ }
1075
+
1076
+ export interface SDKStreamEventMessagePayload {
1077
+ message_type: string;
1078
+ id?: string;
1079
+ otid?: string | null;
1080
+ seq_id?: number;
1081
+ run_id?: string;
1082
+ content?: unknown;
1083
+ reasoning?: string;
1084
+ name?: string;
1085
+ tool_call?: unknown;
1086
+ tool_calls?: unknown;
1087
+ tool_call_id?: string;
1088
+ tool_return?: string;
1089
+ status?: string;
1090
+ [key: string]: unknown;
1091
+ }
1092
+
1093
+ export interface SDKUnknownStreamEventPayload {
1094
+ type?: string;
1095
+ message_type?: string;
1096
+ [key: string]: unknown;
1097
+ }
1098
+
1099
+ export type SDKStreamEventPayload =
1100
+ | SDKStreamEventDeltaPayload
1101
+ | SDKStreamEventMessagePayload
1102
+ | SDKUnknownStreamEventPayload;
1103
+
1104
+ export interface SDKStreamEventMessage {
1105
+ type: "stream_event";
1106
+ event: SDKStreamEventPayload;
1107
+ uuid: string;
1108
+ }
1109
+
1110
+ /**
1111
+ * Error message from the CLI — carries the actual error detail that
1112
+ * would otherwise be lost (the subsequent `type=result` only has
1113
+ * the opaque string "error" as its error field).
1114
+ */
1115
+ export interface SDKErrorMessage {
1116
+ type: "error";
1117
+ /** Human-readable error description from the CLI */
1118
+ message: string;
1119
+ /** Canonical typed error code for machine handling. */
1120
+ errorCode?: SDKErrorCode;
1121
+ /** True when the error detail indicates an approval conflict/deadlock. */
1122
+ approvalConflict?: boolean;
1123
+ /** Whether another recovery attempt could still succeed. */
1124
+ recoverable?: boolean;
1125
+ /** Parsed API error detail string when present. */
1126
+ errorDetail?: string;
1127
+ /** Why the run stopped (e.g. "error", "llm_api_error", "max_steps") */
1128
+ stopReason: string;
1129
+ /** Run that produced the error, if available */
1130
+ runId?: string;
1131
+ /** Nested Letta API error when the error originated server-side */
1132
+ apiError?: Record<string, unknown>;
1133
+ }
1134
+
1135
+ /**
1136
+ * Retry message — the CLI is retrying after a transient failure.
1137
+ * Emitted before each retry attempt so consumers can log / display progress.
1138
+ */
1139
+ export interface SDKRetryMessage {
1140
+ type: "retry";
1141
+ /** The stop reason that triggered the retry */
1142
+ reason: string;
1143
+ /** Current attempt number (1-based) */
1144
+ attempt: number;
1145
+ /** Maximum attempts before giving up */
1146
+ maxAttempts: number;
1147
+ /** Delay in ms before the next attempt */
1148
+ delayMs: number;
1149
+ /** Run that triggered the retry, if available */
1150
+ runId?: string;
1151
+ }
1152
+
1153
+ export interface SDKQueueItem {
1154
+ id: string;
1155
+ clientMessageId: string;
1156
+ kind: string;
1157
+ source: string;
1158
+ content: unknown;
1159
+ enqueuedAt: string;
1160
+ }
1161
+
1162
+ export interface SDKQueueUpdateMessage {
1163
+ type: "queue_update";
1164
+ queue: SDKQueueItem[];
1165
+ }
1166
+
1167
+ export interface SDKLoopStatusMessage {
1168
+ type: "loop_status";
1169
+ status: string;
1170
+ activeRunIds: string[];
1171
+ }
1172
+
1173
+ /** Union of all SDK message types */
1174
+ export type SDKMessage =
1175
+ | SDKInitMessage
1176
+ | SDKAssistantMessage
1177
+ | SDKToolCallMessage
1178
+ | SDKToolResultMessage
1179
+ | SDKReasoningMessage
1180
+ | SDKResultMessage
1181
+ | SDKStreamEventMessage
1182
+ | SDKErrorMessage
1183
+ | SDKRetryMessage
1184
+ | SDKQueueUpdateMessage
1185
+ | SDKLoopStatusMessage;
1186
+
1187
+ // ═══════════════════════════════════════════════════════════════
1188
+ // LIST MESSAGES API
1189
+ // ═══════════════════════════════════════════════════════════════
1190
+
1191
+ /**
1192
+ * Options for session.listMessages().
1193
+ */
1194
+ export interface ListMessagesOptions {
1195
+ /** Explicit conversation ID (e.g. "conv-123"). If omitted, uses agent default. */
1196
+ conversationId?: string;
1197
+ /** Return messages before this message ID (cursor for older pages). */
1198
+ before?: string;
1199
+ /** Return messages after this message ID (cursor for newer pages). */
1200
+ after?: string;
1201
+ /** Sort order. Defaults to "desc" (newest first). */
1202
+ order?: "asc" | "desc";
1203
+ /** Max messages per page. Defaults to 50. */
1204
+ limit?: number;
1205
+ }
1206
+
1207
+ /**
1208
+ * Result from session.listMessages().
1209
+ * `messages` are raw Letta API message objects in the requested order. Cursor
1210
+ * metadata is backend-supplied and omitted when the backend does not expose an
1211
+ * authoritative pagination answer.
1212
+ */
1213
+ export interface ListMessagesResult {
1214
+ messages: unknown[];
1215
+ /** ID of the oldest message in this page; use as `before` for the next page when present. */
1216
+ nextBefore?: string | null;
1217
+ /** Whether more pages exist in the requested direction, when known. */
1218
+ hasMore?: boolean;
1219
+ }
1220
+
1221
+ // ═══════════════════════════════════════════════════════════════
1222
+ // BOOTSTRAP SESSION STATE API
1223
+ // ═══════════════════════════════════════════════════════════════
1224
+
1225
+ /**
1226
+ * Options for session.bootstrapState().
1227
+ */
1228
+ export interface BootstrapStateOptions {
1229
+ /** Max messages to include in the initial history page. Defaults to 50. */
1230
+ limit?: number;
1231
+ /** Sort order for initial history page. Defaults to "desc" (newest first). */
1232
+ order?: "asc" | "desc";
1233
+ }
1234
+
1235
+ /**
1236
+ * Result from session.bootstrapState().
1237
+ *
1238
+ * Contains best-effort data needed to render the initial conversation view
1239
+ * without additional round-trips. Backend-derived booleans/cursors are omitted
1240
+ * when the remote/app-server backend does not expose an authoritative value.
1241
+ */
1242
+ export interface BootstrapStateResult {
1243
+ /** Resolved agent ID for this session. */
1244
+ agentId: string;
1245
+ /** Resolved conversation ID for this session. */
1246
+ conversationId: string;
1247
+ /** LLM model handle. */
1248
+ model: string | undefined;
1249
+ /** Backend-reported tool names, when the transport exposes an authoritative list. */
1250
+ tools?: string[];
1251
+ /** Whether memfs (git-backed memory) is enabled, when known. */
1252
+ memfsEnabled?: boolean;
1253
+ /** Initial history page (same shape as listMessages.messages). */
1254
+ messages: unknown[];
1255
+ /** Cursor to fetch older messages. Null when the backend knows there are no more pages. */
1256
+ nextBefore?: string | null;
1257
+ /** Whether more history pages exist, when known. */
1258
+ hasMore?: boolean;
1259
+ /** Whether there is a pending approval waiting for a response, when known. */
1260
+ hasPendingApproval?: boolean;
1261
+ /** Wall-clock timing breakdown in milliseconds (if provided by CLI). */
1262
+ timings?: {
1263
+ resolve_ms: number;
1264
+ list_messages_ms: number;
1265
+ total_ms: number;
1266
+ };
1267
+ }
1268
+
1269
+ // ═══════════════════════════════════════════════════════════════
1270
+ // EXTERNAL TOOL PROTOCOL TYPES
1271
+ // ═══════════════════════════════════════════════════════════════
1272
+
1273
+ /**
1274
+ * Request to execute an external tool (CLI → SDK)
1275
+ */
1276
+ export interface ExecuteExternalToolRequest {
1277
+ subtype: "execute_external_tool";
1278
+ tool_call_id: string;
1279
+ tool_name: string;
1280
+ input: Record<string, unknown>;
1281
+ }