/** * SDK Types * * These are the public-facing types for SDK consumers. * Protocol types are defined locally to avoid relying on broken package subpath exports. */ import type { PersonalityId } from "@letta-ai/letta-code/agent-presets"; import type { DevicePermissionMode, DiffHunk, DiffHunkLine, DiffPreview, ListModelsResponseModelEntry, PermissionSuggestion, } from "@letta-ai/letta-code/app-server-protocol"; import type { Message as LettaMessage } from "@letta-ai/letta-client/resources/agents/messages"; import type { CreateBlock } from "@letta-ai/letta-client/resources/blocks/blocks"; import type { LettaCodeCloudSandboxOptions } from "./cloud-sandbox.js"; import type { ComputerSelector } from "./computers.js"; export type { CreateBlock } from "@letta-ai/letta-client/resources/blocks/blocks"; export type { GitHubRepositoryRef, LettaCodeCloudSandboxOptions, } from "./cloud-sandbox.js"; /** Letta Code personality preset used to seed a new agent. */ export type LettaCodePersonalityId = PersonalityId; export interface LettaCodeSocketLike { readyState: number; send(data: string): void; close(): void; addEventListener?(type: string, listener: (event: unknown) => void): void; removeEventListener?(type: string, listener: (event: unknown) => void): void; on?(type: string, listener: (event: unknown) => void): void; off?(type: string, listener: (event: unknown) => void): void; once?(type: string, listener: (event: unknown) => void): void; } export interface LettaCodeSocketOptions { headers?: Record; } export type LettaCodeSocketConstructor = new ( url: string, options?: LettaCodeSocketOptions, ) => LettaCodeSocketLike; /** * React Native's WebSocket constructor accepts request headers as its third * argument, unlike the Node-style constructor used by the SDK protocol layer. */ export type LettaCodeReactNativeSocketConstructor = new ( url: string, protocols?: string | string[] | null, options?: LettaCodeSocketOptions, ) => LettaCodeSocketLike; // ═══════════════════════════════════════════════════════════════ // MESSAGE CONTENT TYPES (for multimodal support) // ═══════════════════════════════════════════════════════════════ /** * Text content in a message */ export interface TextContent { type: "text"; text: string; } export interface RecoverPendingApprovalsOptions { /** * Timeout in milliseconds for the recovery control request. */ timeoutMs?: number; } export interface RecoverPendingApprovalsResult { recovered: boolean; /** * Whether a pending approval is known to remain after recovery. * Undefined means the SDK could not determine the state (for example, timeout). */ pendingApproval?: boolean; unsupported: boolean; detail?: string; } /** * Image content in a message (base64 encoded) */ export interface ImageContent { type: "image"; source: { type: "base64"; media_type: "image/png" | "image/jpeg" | "image/gif" | "image/webp"; data: string; }; } /** * A single content item (text or image) */ export type MessageContentItem = TextContent | ImageContent; /** * What send() accepts - either a simple string or multimodal content array */ export type SendMessage = string | MessageContentItem[]; /** * Per-turn options accepted by `send()`. */ export interface SendOptions { /** * Caller-supplied offline threading id (OTID) for this user message. * * The OTID is the canonical optimistic-input-matching key: stamp the row you * render optimistically with the same value and you can correlate it with the * persisted user message that comes back from the stream or from * `listMessages()`. It is also used as the turn's `clientMessageId`, so it * shows up on `SDKQueueItem.clientMessageId` while the message is queued. * * When omitted the SDK generates one. Must be a non-empty string; reuse the * same value when retrying a send so the runtime can deduplicate it. */ otid?: string; } // ═══════════════════════════════════════════════════════════════ // SKILLS / REMINDER / DREAMING TYPES // ═══════════════════════════════════════════════════════════════ export type SkillSource = "bundled" | "global" | "agent" | "project"; export type DreamingTrigger = "off" | "step-count" | "compaction-event"; export type DreamingBehavior = "reminder" | "auto-launch"; /** * Dreaming settings exposed through SDK options. * Any omitted fields preserve server/CLI defaults. */ export interface DreamingOptions { trigger?: DreamingTrigger; behavior?: DreamingBehavior; stepCount?: number; } /** Dreaming settings that can be changed when opening an existing agent session. */ export type SessionDreamingOptions = Omit; /** * Fully-resolved dreaming settings emitted by init messages. */ export interface EffectiveDreamingSettings { trigger: DreamingTrigger; behavior: DreamingBehavior; stepCount: number; } // ═══════════════════════════════════════════════════════════════ // SYSTEM PROMPT TYPES // ═══════════════════════════════════════════════════════════════ /** * Available system prompt presets. */ export type SystemPromptPreset = | "default" // Alias for letta-claude | "letta-claude" // Full Letta Code prompt (Claude-optimized) | "letta-codex" // Full Letta Code prompt (Codex-optimized) | "letta-gemini" // Full Letta Code prompt (Gemini-optimized) | "claude" // Basic Claude (no skills/memory instructions) | "codex" // Basic Codex | "gemini"; // Basic Gemini /** * System prompt preset configuration. */ export interface SystemPromptPresetConfigSDK { type: "preset"; preset: SystemPromptPreset; append?: string; } /** * System prompt configuration - either a raw string or preset config. */ export type SystemPromptConfig = string | SystemPromptPresetConfigSDK; // ═══════════════════════════════════════════════════════════════ // MEMORY TYPES // ═══════════════════════════════════════════════════════════════ /** * Reference to an existing shared block by ID. */ export interface BlockReference { blockId: string; } /** * Memory item - can be a preset name, custom block, or block reference. */ export type MemoryItem = | string // Preset name: "project", "persona", "human" | CreateBlock // Custom block: { label, value, description? } | BlockReference; // Shared block reference: { blockId } /** * Default memory block preset names. */ export type MemoryPreset = "persona" | "human" | "skills" | "loaded_skills"; // ═══════════════════════════════════════════════════════════════ // TOOL TYPES (matches pi-agent-core) // ═══════════════════════════════════════════════════════════════ /** * Tool result content block */ export interface AgentToolResultContent { type: "text" | "image"; text?: string; data?: string; // base64 for images mimeType?: string; } /** * Tool result (matches pi-agent-core) */ export interface AgentToolResult { content: AgentToolResultContent[]; /** Whether the tool completed with a model-visible error result. */ isError?: boolean; details?: T; } /** * Tool update callback (for streaming tool progress) */ export type AgentToolUpdateCallback = (update: Partial>) => void; /** * Agent tool definition (matches pi-agent-core) */ export interface AgentTool { /** Display label */ label: string; /** Tool name (used in API calls) */ name: string; /** Description shown to the model */ description: string; /** JSON Schema for parameters (TypeBox or plain object) */ parameters: TParams; /** Execution function */ execute: ( toolCallId: string, args: unknown, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback, ) => Promise>; } /** * Convenience type for tools with any params */ // eslint-disable-next-line @typescript-eslint/no-explicit-any export type AnyAgentTool = AgentTool; /** A local MCP process connected over stdin/stdout. */ export interface McpStdioServerConfig { type?: "stdio"; command: string; args?: string[]; env?: Record; /** Override the session cwd for this server process. */ cwd?: string; } /** A remote MCP server using Streamable HTTP. */ export interface McpHttpServerConfig { type: "http"; url: string; headers?: Record; } /** A remote MCP server using the legacy SSE transport. */ export interface McpSseServerConfig { type: "sse"; url: string; headers?: Record; } /** One MCP server definition. The key in {@link McpServers} supplies its name. */ export type McpServerConfig = | McpStdioServerConfig | McpHttpServerConfig | McpSseServerConfig; /** MCP servers keyed by the name used in `mcp____`. */ export type McpServers = Record; // ═══════════════════════════════════════════════════════════════ // TOP-LEVEL CLIENT TYPES // ═══════════════════════════════════════════════════════════════ /** * How the SDK reaches or runs the Letta Code harness. * * - local: spawn/manage a local Letta Code app-server over loopback websockets. * - remote: connect to a user-managed app-server over websockets. * - cloud: use agents hosted on Letta Cloud, with an explicit remote * environment or SDK-managed sandbox. */ export type LettaCodeBackend = "local" | "remote" | "cloud"; /** @deprecated Use `ComputerSelector` from the package root. */ export type LettaCodeEnvironment = ComputerSelector; export interface LettaCodeLocalAppServerOptions { /** * Optional URL for tests or advanced users with a pre-started local app-server. * Omit to let the SDK spawn and own a loopback app-server. */ url?: string; /** * Which Letta Code backend the spawned app-server runs against: * - "local": the in-process experimental backend (agents stored on this * machine, `agent-local-*` ids). The default. * - "api": Letta Cloud (real `agent-*` ids, cloud-side models such as * letta/auto-memory) with tools still executing on this machine. Requires * the harness to be authenticated (login or LETTA_API_KEY). */ harnessBackend?: "api" | "local"; /** Optional WebSocket constructor for tests/non-standard runtimes. */ WebSocket?: LettaCodeSocketConstructor; /** Timeout for websocket protocol request/turn correlation. */ requestTimeoutMs?: number; /** Whether agents created through this app-server are added to Letta Code's global pinned-agent list. */ pinGlobalAgent?: boolean; /** Local app-server listen URL when the SDK spawns it. Defaults to ws://127.0.0.1:0. */ listen?: string; /** Timeout waiting for the spawned app-server to print its listening URL. */ startupTimeoutMs?: number; } export interface LettaCodeLocalClientOptions { backend?: "local"; /** Advanced app-server overrides for local execution. */ appServer?: LettaCodeLocalAppServerOptions; } export interface LettaCodeRemoteClientOptions { backend: "remote"; /** URL of the user-managed app-server / websocket endpoint. */ url: string; /** Optional capability token sent as Authorization: Bearer during websocket upgrade. */ authToken?: string; /** Optional WebSocket constructor for non-browser runtimes and tests. */ WebSocket?: LettaCodeSocketConstructor; /** Timeout for websocket protocol request/turn correlation. */ requestTimeoutMs?: number; /** Whether agents created through this app-server are added to Letta Code's global pinned-agent list. */ pinGlobalAgent?: boolean; } export interface LettaCodeCloudClientOptions { backend: "cloud"; /** Optional API key override. Defaults to LETTA_API_KEY / existing auth. */ apiKey?: string; /** Optional API base URL override. Defaults to the Letta API. */ apiBaseUrl?: string; /** Optional extra HTTP headers for Cloud API requests. */ headers?: Record; /** Optional fetch implementation for tests/non-standard runtimes. */ fetch?: typeof fetch; /** Optional WebSocket constructor for non-browser runtimes and tests. */ WebSocket?: LettaCodeSocketConstructor; /** Timeout for websocket protocol request/turn correlation. */ requestTimeoutMs?: number; /** * WebSocket authentication style. Defaults to Authorization headers; set to * query for browser-style clients that cannot send WebSocket headers. */ webSocketAuth?: "header" | "query"; /** Heartbeat interval for the Cloud status websocket. Defaults to 30s. */ pingIntervalMs?: number; /** * Computer where Letta Cloud sessions run. If omitted, the SDK creates and * owns a managed sandbox for the session. */ computer?: ComputerSelector; /** @deprecated Use `computer`. */ environment?: LettaCodeEnvironment; /** Options for SDK-managed sandboxes when no computer is selected. */ sandbox?: LettaCodeCloudSandboxOptions; } export type LettaCodeClientOptions = | LettaCodeLocalClientOptions | LettaCodeRemoteClientOptions | LettaCodeCloudClientOptions; export interface Repository { id: string; name: string; createdAt: string; updatedAt: string; } export interface CreateRepositoryParams { name: string; } export interface ListRepositoriesParams { limit?: number; offset?: number; } export interface ListRepositoriesResult { repositories: Repository[]; hasNextPage: boolean; } export interface RepositoryResource { type: "repository"; repositoryId: string; /** * Whether to trigger a system-prompt recompile after attaching (and after * detaching on cleanup) so the session's conversation does not retain * stale repository projections. Defaults to `true`. */ recompile?: boolean; } export interface RepositoryFileEntry { path: string; type: "file" | "directory"; } export interface ListRepositoryFilesParams { pathPrefix?: string; depth?: number; ref?: string; } export interface ListRepositoryFilesResult { files: RepositoryFileEntry[]; ref: string; } export interface CreateRepositoryFileParams { path: string; content: string; } export interface RepositoryFile { path: string; content: string; contentSha256: string; ref?: string; } export interface UpdateRepositoryFileParams { path: string; content?: string; newPath?: string; precondition?: { contentSha256: string; }; } export interface RepositoryFileMutationResult { path: string; contentSha256: string; commitSha: string; } export interface DeleteRepositoryFileParams { path: string; } export interface DeleteRepositoryFileResult { success: boolean; commitSha: string; } export interface RepositoryVersion { sha: string; message: string; timestamp: string; author_name: string | null; } export interface ListRepositoryVersionsParams { path?: string; limit?: number; } export interface GetRepositoryVersionParams { path: string; } // ═══════════════════════════════════════════════════════════════ // SESSION OPTIONS // ═══════════════════════════════════════════════════════════════ /** * A suggested permission grant attached to a `can_use_tool` approval request. * Approval UIs can render these as selectable chips and echo the chosen ids * back via `CanUseToolResponseAllow.updatedPermissions`. */ export interface CanUseToolPermissionSuggestion { id: string; text: string; } export interface CanUseToolResponseAllow { behavior: "allow"; message?: string; updatedInput?: Record | null; updatedPermissions?: unknown[]; } export interface CanUseToolResponseDeny { behavior: "deny"; message: string; interrupt?: boolean; } export type CanUseToolResponse = | CanUseToolResponseAllow | CanUseToolResponseDeny; /** * Additional context for a `can_use_tool` approval request, passed as the * optional third argument to {@link CanUseToolCallback}. * * All fields are optional: transports pass through whatever subset the wire * protocol provides, leaving absent fields undefined. */ export interface CanUseToolContext { /** Id of the control request carrying this approval (for logging/correlation). */ requestId?: string; /** Tool call id — links the approval to its tool_call card in the message stream. */ toolCallId?: string; /** Suggested permission grants the user can select. */ permissionSuggestions?: CanUseToolPermissionSuggestion[]; /** Path that triggered the permission check, when the tool was blocked on a path rule. */ blockedPath?: string | null; /** * Diff previews for file-editing tools, passed through verbatim. * Shape matches letta-code's `DiffPreview` (mode: "advanced" | "fallback" | "unpreviewable"). */ diffs?: unknown[]; } /** * Callback for custom permission handling. * * The optional third argument carries approval context (tool call id, * permission suggestions, diff previews). Two-argument callbacks remain * fully supported. */ export type CanUseToolCallback = ( toolName: string, toolInput: Record, context?: CanUseToolContext, ) => Promise | CanUseToolResponse; export type PermissionMode = | "standard" | "acceptEdits" | "unrestricted" | "strict"; export type ReasoningEffort = | "none" | "minimal" | "low" | "medium" | "high" | "xhigh"; export type LettaCodeModelEntry = ListModelsResponseModelEntry; export interface ListModelsResult { entries: LettaCodeModelEntry[]; /** Handles available to this user. null means availability lookup failed. */ availableHandles?: string[] | null; /** BYOK provider name -> base provider name, e.g. lc-anthropic -> anthropic. */ byokProviderAliases?: Record; } export interface UpdateModelOptions { /** Model id from listModels() or direct model handle. Model ids usually omit '/'. */ model?: string; /** Explicit model id from listModels(). */ modelId?: string; /** Explicit direct model handle, including BYOK handles. */ modelHandle?: string; /** Select a reasoning tier for the target model handle. */ reasoningEffort?: ReasoningEffort; } export interface UpdateModelResult { /** The scope changed by the runtime. The default conversation uses the agent scope. */ appliedTo?: "agent" | "conversation"; modelId?: string; modelHandle?: string; modelSettings?: Record | null; } export type SDKProtocolMessage = Record & { type: TType; request_id?: string; }; export type SDKProtocolCommand = SDKProtocolMessage; export interface SendCommandOptions { /** Wait for a response with this protocol message type. Omit for fire-and-forget commands. */ responseType?: TResponseType; /** Override the websocket protocol request timeout for this command. */ timeoutMs?: number; /** Optional custom matcher for advanced protocol responses. */ predicate?: (message: SDKProtocolMessage) => boolean; } export type ClientToolsetBase = | "auto" | "codex" | "codex_snake" | "default" | "gemini" | "gemini_snake" | "none"; export interface ClientToolsetConfig { /** Request-scoped base toolset. Omitted preserves the harness preference. */ base?: ClientToolsetBase; /** Additional bundled client tools to load before applying allowedTools. */ include?: string[]; } /** * Options for createSession() and resumeSession() restricted to settings that * can be applied to existing agents. * For creating new agents with custom memory/persona, use createAgent(). */ export interface CreateSessionOptions { /** * Model for the session target. New and named conversations receive a * conversation override. The default conversation updates the agent default. */ model?: string; /** * Reasoning tier for the session target. This option uses the same scope as * `model` and is available on WebSocket protocol sessions. */ reasoningEffort?: ReasoningEffort; /** * Exact client-side tool allowlist for the session, including custom SDK * tools. When omitted, the harness default toolset and registered custom * tools apply. Interactive user-input tools (AskUserQuestion) are always * excluded for SDK sessions. */ allowedTools?: string[]; /** * Request-scoped built-in client toolset selection. The base chooses a * harness preset without changing persisted settings; include adds bundled * tools before allowedTools is applied. */ toolset?: ClientToolsetConfig; /** Permission mode */ permissionMode?: PermissionMode; /** Working directory for the CLI process */ cwd?: string; /** * Run without loading or changing the agent's MemFS. The agent and * conversation remain persistent; this only changes the session's local * memory, agent-skill, agent-mod, transcript, and reflection behavior. * Model, reasoning, dreaming, and repository options are unavailable because * they change persistent configuration. */ stateless?: boolean; /** * Restrict available skills by source. * Empty array disables all skills (`--no-skills`). */ skillSources?: SkillSource[]; /** * Configure dreaming settings. */ dreaming?: SessionDreamingOptions; /** Custom permission callback - called when tool needs approval */ canUseTool?: CanUseToolCallback; /** * Custom tools that execute locally in the SDK process. * These tools are registered with the CLI and executed when the LLM calls them. */ tools?: AnyAgentTool[]; /** * Session-scoped MCP servers keyed by server name. Stdio processes and * remote HTTP/SSE connections run in the Node SDK process and are exposed * through Letta Code's external-tool protocol. */ mcpServers?: McpServers; /** * Cloud repository resources to attach for the lifetime of the SDK session. * For relationships that should outlive the session, use * `client.agents.repositories.attach()` instead. */ resources?: RepositoryResource[]; } /** * Session options accepted by LettaAgentClient methods. * * `computer` is a Cloud execution-target override. It is deliberately * session-scoped rather than part of createAgent() options. */ export interface LettaCodeClientSessionOptions extends CreateSessionOptions { computer?: ComputerSelector; /** @deprecated Use `computer`. */ environment?: LettaCodeEnvironment; /** Per-session SDK-managed sandbox options when no computer is selected. */ sandbox?: LettaCodeCloudSandboxOptions; /** * Extra environment variables for the session's harness process. Each * SDK-owned local app-server session runs in its own process, so this * scopes cleanly per session — e.g. MEMORY_DIR / LETTA_MEMORY_DIR to point * the harness's memory scoping (and its guard) at a session-specific * memory copy. Ignored on remote and cloud transports. */ env?: Record; /** * Constrain an SDK-owned local session harness to memory-worker filesystem * access. Agent-ID sessions derive the standard root; set `MEMORY_DIR` or * `LETTA_MEMORY_DIR` for overrides and conversation-ID resumes. Fails closed * without a root or supported kernel sandbox. Excludes agent creation, * management calls, and remote/Cloud runtimes. */ filesystemConfinement?: "memory"; } export interface LettaCodeSession extends AsyncDisposable { /** * Send a user message. Pass `{ otid }` to supply your own correlation id for * optimistic reconciliation; the SDK generates one when omitted. */ send(message: SendMessage, options?: SendOptions): Promise; stream(): AsyncGenerator; abort(): Promise; sendCommand(command: SDKProtocolCommand): Promise; sendCommand( command: SDKProtocolCommand, options: SendCommandOptions, ): Promise; listMessages(options?: ListMessagesOptions): Promise; listModels(): Promise; /** * Update the model for this session target. Named conversations receive a * conversation override. The default conversation updates the agent default. * Read `appliedTo` from the result to confirm the changed scope. */ updateModel(update: string | UpdateModelOptions): Promise; /** * Fetch the initial conversation projection used to hydrate or reconcile a * resumed session. */ bootstrapState(options?: BootstrapStateOptions): Promise; /** * Ask the runtime to recover any approval that was pending across a * disconnect. */ recoverPendingApprovals( options?: RecoverPendingApprovalsOptions, ): Promise; /** * Update runtime controls for subsequent work in this conversation. * * The current app-server protocol does not acknowledge this command. The * promise confirms that the command was accepted for transport, not that the * runtime has applied it. */ changeDeviceState(updates: ChangeDeviceStateOptions): Promise; /** * Remove one queued user message and wait for the runtime acknowledgement. */ removeQueuedMessage(itemId: string): Promise; /** * Read the device execution context (online/processing flags, permission * mode, working directory, pending approvals). * * Sends a lightweight, request-correlated `sync` and resolves only after the * runtime acknowledges it and pushes a fresh `update_device_status` * snapshot for this runtime scope. */ getDeviceStatus(options?: GetDeviceStatusOptions): Promise; /** * Subscribe to every incoming device-status update for this session's * runtime scope. Returns an unsubscribe function. */ onDeviceStatus(listener: (status: SessionDeviceStatus) => void): () => void; close(): void; readonly agentId: string | null; readonly sessionId: string | null; readonly conversationId: string | null; } export interface ChangeDeviceStateOptions { cwd?: string; permissionMode?: PermissionMode; } export interface RemoveQueuedMessageResult { /** Queue item identifier echoed by the runtime. */ itemId: string; /** False when the item was no longer present in the authoritative queue. */ removed: boolean; } export interface GetDeviceStatusOptions { /** * Timeout in milliseconds for the authoritative sync and status replay. * Defaults to the session's request timeout. */ timeoutMs?: number; } /** A suggested permission grant attached to a pending approval. */ export type SessionPermissionSuggestion = PermissionSuggestion; export type SessionDiffHunkLine = DiffHunkLine; export type SessionDiffHunk = DiffHunk; /** Portable projection of a file-edit diff preview. */ export type SessionDiffPreview = DiffPreview; /** One tool approval the device is still waiting on. */ export interface SessionPendingControlRequest { /** * Control request id for correlation only. Approval decisions must still * resolve through `recoverPendingApprovals()` and `canUseTool`. */ requestId: string; /** Tool awaiting approval. */ toolName: string; /** Tool call id awaiting approval, when reported. */ toolCallId?: string; /** Tool input awaiting approval, when reported. */ toolInput?: Record; /** Permission grants offered by the runtime. */ permissionSuggestions: SessionPermissionSuggestion[]; /** Path that triggered the permission check, when reported. */ blockedPath: string | null; /** File-edit previews supplied with the approval, when reported. */ diffs?: SessionDiffPreview[]; } /** * Typed projection of the wire `update_device_status` payload. * * `raw` carries the full wire `device_status` object for fields that are not * projected (git context, toolsets, background processes, ...). */ export interface SessionDeviceStatus { /** Whether the executing device is connected. */ isOnline: boolean; /** Whether the device is currently processing a turn. */ isProcessing: boolean; /** Permission mode currently applied to this runtime scope. */ permissionMode: PermissionMode; /** Working directory currently applied to this runtime scope. */ workingDirectory: string | null; /** Agent memory checkout on the computer executing this session. */ memoryDirectory: string | null; /** Approvals the device is still waiting on (foreground-resume UI). */ pendingControlRequests: SessionPendingControlRequest[]; /** Full wire `device_status` payload as an escape hatch. */ raw: Record; } /** * Options for createAgent() - full control over agent creation. */ export interface CreateAgentOptions { /** * Optional Letta Code personality preset. Presets are explicit: when this is * omitted, createAgent() does not add personality-derived identity, name, or * description fields. */ personality?: LettaCodePersonalityId; /** Model to use (e.g., "claude-sonnet-4-20250514") */ model?: string; /** Embedding model to use (e.g., "text-embedding-ada-002") */ embedding?: string; /** * System prompt configuration. * - string: Use as the complete system prompt * - SystemPromptPreset: Use a preset * - { type: 'preset', preset, append? }: Use a preset with optional appended text */ systemPrompt?: string | SystemPromptPreset | SystemPromptPresetConfigSDK; /** * Legacy memory block configuration. New agents should use the git-backed * memory filesystem instead. Each item can be: * - string: Preset block name ("persona", "human", "skills", "loaded_skills") * - CreateBlock: Custom block definition (e.g., { label: "project", value: "..." }) * - { blockId: string }: Reference to existing shared block * @deprecated Prefer `memfs` and let the agent maintain memory files. */ memory?: MemoryItem[]; /** @deprecated Prefer a personality preset or a system memory file. */ persona?: string; /** @deprecated Prefer a focused memory file for user preferences. */ human?: string; /** * Whether to enable the git-backed memory filesystem on the new agent * (default true). Pass false for worker-style agents that should not carry * their own memory repo — enabling memfs is a slow backend round trip, and * concurrent sessions on a shared-memfs agent contend on its git state. */ memfs?: boolean; /** Display name for the agent. */ name?: string; /** Description of the agent's purpose. */ description?: string; /** Hide the agent from default listings (worker/subagent semantics). */ hidden?: boolean; /** * Server-side tools to attach at creation. When omitted, the harness * applies its created-agent defaults (web_search, fetch_webpage). Pass [] * for none or an explicit list to override. Client-side tools (Bash, * Edit, …) are provided by the harness at runtime and are unaffected. */ baseTools?: string[]; /** * Exact client-side tool allowlist for the session, including custom SDK * tools. When omitted, the harness default toolset and registered custom * tools apply. Interactive user-input tools (AskUserQuestion) are always * excluded for SDK sessions. */ allowedTools?: string[]; /** List of disallowed tool names */ disallowedTools?: string[]; /** Permission mode */ permissionMode?: PermissionMode; /** Working directory for the CLI process */ cwd?: string; /** Custom permission callback - called when tool needs approval */ canUseTool?: CanUseToolCallback; /** * Custom tools that execute locally in the SDK process. * These tools are registered with the CLI and executed when the LLM calls them. */ tools?: AnyAgentTool[]; /** Tags to organize and categorize the agent. */ tags?: string[]; /** * Restrict available skills by source. * Empty array disables all skills (`--no-skills`). */ skillSources?: SkillSource[]; /** * Toggle first-turn system info reminder (device/git/cwd context). * false -> `--no-system-info-reminder`. */ systemInfoReminder?: boolean; /** * Configure dreaming settings. */ dreaming?: DreamingOptions; } // ═══════════════════════════════════════════════════════════════ // SDK MESSAGE TYPES // ═══════════════════════════════════════════════════════════════ /** * SDK message types - clean wrappers around wire types */ export interface SDKInitMessage { type: "init"; agentId: string; sessionId: string; conversationId: string; model: string; /** Backend-reported tool names, when the transport exposes an authoritative list. */ tools?: string[]; memfsEnabled?: boolean; skillSources?: SkillSource[]; systemInfoReminderEnabled?: boolean; dreaming?: EffectiveDreamingSettings; } export interface SDKAssistantMessage { type: "assistant"; content: string; /** Top-level message ID when provided by the stream; otherwise an SDK-generated identifier. */ uuid: string; /** Stable lineage key for this typed message slice, when provided. */ otid?: string | null; /** Per-run replay cursor. Compare only within the same `runId`. */ seqId?: number; /** Run ID from the Letta API for this event (used for stale-run detection). */ runId?: string; } export interface SDKToolCallMessage { type: "tool_call"; toolCallId: string; toolName: string; toolInput: Record; /** Raw unparsed arguments string from the wire for consumer-side accumulation. */ rawArguments?: string; uuid: string; /** Run ID from the Letta API for this event (used for stale-run detection). */ runId?: string; } export interface SDKToolResultMessage { type: "tool_result"; toolCallId: string; content: string; isError: boolean; uuid: string; /** Run ID from the Letta API for this event (used for stale-run detection). */ runId?: string; } export interface SDKReasoningMessage { type: "reasoning"; content: string; /** Top-level message ID when provided by the stream; otherwise an SDK-generated identifier. */ uuid: string; /** Stable lineage key for this typed message slice, when provided. */ otid?: string | null; /** Per-run replay cursor. Compare only within the same `runId`. */ seqId?: number; /** Run ID from the Letta API for this event (used for stale-run detection). */ runId?: string; } /** Canonical SDK error codes recognized by the SDK. */ export type SDKErrorCode = | "approval_conflict" | "approval_conflict_terminal" | "protocol_error" | "error" | "llm_api_error" | "max_steps" | "interrupted" | "stream_closed"; export interface SDKResultMessage { type: "result"; success: boolean; result?: string; /** Legacy error string (kept for compatibility). Prefer errorCode. */ error?: string; /** Canonical typed error code for machine handling. */ errorCode?: SDKErrorCode; /** True when the failure corresponds to an approval conflict/deadlock. */ approvalConflict?: boolean; /** Whether another recovery attempt could still succeed. */ recoverable?: boolean; /** Number of SDK-managed recovery attempts executed for this turn. */ recoveryAttempts?: number; /** Best-effort human-readable approval-conflict detail (if available). */ errorDetail?: string; stopReason?: string; durationMs: number; totalCostUsd?: number; conversationId: string | null; /** Run IDs associated with this turn (if provided by the CLI). */ runIds?: string[]; } export interface SDKStreamEventDeltaPayload { type: string; index?: number; delta?: { type?: string; text?: string; reasoning?: string }; content_block?: { type?: string; text?: string }; [key: string]: unknown; } export interface SDKStreamEventMessagePayload { message_type: string; id?: string; otid?: string | null; seq_id?: number; run_id?: string; content?: unknown; reasoning?: string; name?: string; tool_call?: unknown; tool_calls?: unknown; tool_call_id?: string; tool_return?: string; status?: string; [key: string]: unknown; } export interface SDKUnknownStreamEventPayload { type?: string; message_type?: string; [key: string]: unknown; } export type SDKStreamEventPayload = | SDKStreamEventDeltaPayload | SDKStreamEventMessagePayload | SDKUnknownStreamEventPayload; export interface SDKStreamEventMessage { type: "stream_event"; event: SDKStreamEventPayload; uuid: string; } /** * Error message from the CLI — carries the actual error detail that * would otherwise be lost (the subsequent `type=result` only has * the opaque string "error" as its error field). */ export interface SDKErrorMessage { type: "error"; /** Human-readable error description from the CLI */ message: string; /** Canonical typed error code for machine handling. */ errorCode?: SDKErrorCode; /** True when the error detail indicates an approval conflict/deadlock. */ approvalConflict?: boolean; /** Whether another recovery attempt could still succeed. */ recoverable?: boolean; /** Parsed API error detail string when present. */ errorDetail?: string; /** Why the run stopped (e.g. "error", "llm_api_error", "max_steps") */ stopReason: string; /** Run that produced the error, if available */ runId?: string; /** Nested Letta API error when the error originated server-side */ apiError?: Record; } /** * Retry message — the CLI is retrying after a transient failure. * Emitted before each retry attempt so consumers can log / display progress. */ export interface SDKRetryMessage { type: "retry"; /** The stop reason that triggered the retry */ reason: string; /** Current attempt number (1-based) */ attempt: number; /** Maximum attempts before giving up */ maxAttempts: number; /** Delay in ms before the next attempt */ delayMs: number; /** Run that triggered the retry, if available */ runId?: string; } export interface SDKQueueItem { id: string; clientMessageId: string; kind: string; source: string; content: unknown; enqueuedAt: string; } export interface SDKQueueUpdateMessage { type: "queue_update"; queue: SDKQueueItem[]; } export interface SDKLoopStatusMessage { type: "loop_status"; status: string; activeRunIds: string[]; } /** Union of all SDK message types */ export type SDKMessage = | SDKInitMessage | SDKAssistantMessage | SDKToolCallMessage | SDKToolResultMessage | SDKReasoningMessage | SDKResultMessage | SDKStreamEventMessage | SDKErrorMessage | SDKRetryMessage | SDKQueueUpdateMessage | SDKLoopStatusMessage; // ═══════════════════════════════════════════════════════════════ // LIST MESSAGES API // ═══════════════════════════════════════════════════════════════ /** * Options for session.listMessages(). */ export interface ListMessagesOptions { /** Explicit conversation ID (e.g. "conv-123"). If omitted, uses agent default. */ conversationId?: string; /** Return messages before this message ID (cursor for older pages). */ before?: string; /** Return messages after this message ID (cursor for newer pages). */ after?: string; /** Sort order. Defaults to "desc" (newest first). */ order?: "asc" | "desc"; /** Max messages per page. Defaults to 50. */ limit?: number; } /** * Result from session.listMessages(). * `messages` are raw Letta API message objects in the requested order. Cursor * metadata is backend-supplied and omitted when the backend does not expose an * authoritative pagination answer. */ export interface ListMessagesResult { messages: LettaMessage[]; /** ID of the oldest message in this page; use as `before` for the next page when present. */ nextBefore?: string | null; /** Whether more pages exist in the requested direction, when known. */ hasMore?: boolean; } // ═══════════════════════════════════════════════════════════════ // BOOTSTRAP SESSION STATE API // ═══════════════════════════════════════════════════════════════ /** * Options for session.bootstrapState(). */ export interface BootstrapStateOptions { /** Max messages to include in the initial history page. Defaults to 50. */ limit?: number; /** Sort order for initial history page. Defaults to "desc" (newest first). */ order?: "asc" | "desc"; } /** * Result from session.bootstrapState(). * * Contains best-effort data needed to render the initial conversation view * without additional round-trips. Backend-derived booleans/cursors are omitted * when the remote/app-server backend does not expose an authoritative value. */ export interface BootstrapStateResult { /** Resolved agent ID for this session. */ agentId: string; /** Resolved conversation ID for this session. */ conversationId: string; /** LLM model handle. */ model: string | undefined; /** Backend-reported tool names, when the transport exposes an authoritative list. */ tools?: string[]; /** Whether memfs (git-backed memory) is enabled, when known. */ memfsEnabled?: boolean; /** Initial history page (same shape as listMessages.messages). */ messages: LettaMessage[]; /** Cursor to fetch older messages. Null when the backend knows there are no more pages. */ nextBefore?: string | null; /** Whether more history pages exist, when known. */ hasMore?: boolean; /** Whether there is a pending approval waiting for a response, when known. */ hasPendingApproval?: boolean; /** Wall-clock timing breakdown in milliseconds (if provided by CLI). */ timings?: { resolve_ms: number; list_messages_ms: number; total_ms: number; }; } // ═══════════════════════════════════════════════════════════════ // EXTERNAL TOOL PROTOCOL TYPES // ═══════════════════════════════════════════════════════════════ /** * Request to execute an external tool (CLI → SDK) */ export interface ExecuteExternalToolRequest { subtype: "execute_external_tool"; tool_call_id: string; tool_name: string; input: Record; }