@data-club/ai-hub-server 0.0.8 → 0.0.10

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 (83) hide show
  1. package/dist/auth/encryption.d.ts +5 -5
  2. package/dist/auth/encryption.js +5 -5
  3. package/dist/auth/userView.d.ts +8 -15
  4. package/dist/auth/userView.d.ts.map +1 -1
  5. package/dist/auth/userView.js +10 -23
  6. package/dist/auth/userView.js.map +1 -1
  7. package/dist/bootstrap.d.ts +2 -8
  8. package/dist/bootstrap.d.ts.map +1 -1
  9. package/dist/bootstrap.js +2 -35
  10. package/dist/bootstrap.js.map +1 -1
  11. package/dist/db/migrate.js +0 -17
  12. package/dist/db/migrate.js.map +1 -1
  13. package/dist/db/schema.d.ts +0 -263
  14. package/dist/db/schema.d.ts.map +1 -1
  15. package/dist/db/schema.js +0 -57
  16. package/dist/db/schema.js.map +1 -1
  17. package/dist/db/seed.d.ts +4 -19
  18. package/dist/db/seed.d.ts.map +1 -1
  19. package/dist/db/seed.js +6 -33
  20. package/dist/db/seed.js.map +1 -1
  21. package/dist/handlers/fetch.d.ts +6 -7
  22. package/dist/handlers/fetch.d.ts.map +1 -1
  23. package/dist/handlers/fetch.js +0 -2
  24. package/dist/handlers/fetch.js.map +1 -1
  25. package/dist/handlers/types.d.ts +5 -6
  26. package/dist/handlers/types.d.ts.map +1 -1
  27. package/dist/letta/client.d.ts +86 -263
  28. package/dist/letta/client.d.ts.map +1 -1
  29. package/dist/letta/client.js +99 -404
  30. package/dist/letta/client.js.map +1 -1
  31. package/dist/letta/index.d.ts +6 -8
  32. package/dist/letta/index.d.ts.map +1 -1
  33. package/dist/letta/index.js +5 -7
  34. package/dist/letta/index.js.map +1 -1
  35. package/dist/letta/sandbox.d.ts +45 -9
  36. package/dist/letta/sandbox.d.ts.map +1 -1
  37. package/dist/letta/sandbox.js +123 -11
  38. package/dist/letta/sandbox.js.map +1 -1
  39. package/dist/letta/types.d.ts +6 -49
  40. package/dist/letta/types.d.ts.map +1 -1
  41. package/dist/letta/types.js +5 -10
  42. package/dist/letta/types.js.map +1 -1
  43. package/dist/observability/logger.d.ts.map +1 -1
  44. package/dist/observability/logger.js +0 -2
  45. package/dist/observability/logger.js.map +1 -1
  46. package/dist/routes/admin/agents.d.ts.map +1 -1
  47. package/dist/routes/admin/agents.js +0 -40
  48. package/dist/routes/admin/agents.js.map +1 -1
  49. package/dist/routes/admin/settings.d.ts +6 -15
  50. package/dist/routes/admin/settings.d.ts.map +1 -1
  51. package/dist/routes/admin/settings.js +9 -107
  52. package/dist/routes/admin/settings.js.map +1 -1
  53. package/dist/routes/auth.d.ts +0 -4
  54. package/dist/routes/auth.d.ts.map +1 -1
  55. package/dist/routes/auth.js +1 -5
  56. package/dist/routes/auth.js.map +1 -1
  57. package/dist/routes/sessions.d.ts.map +1 -1
  58. package/dist/routes/sessions.js +9 -30
  59. package/dist/routes/sessions.js.map +1 -1
  60. package/dist/state/turnRunner.d.ts.map +1 -1
  61. package/dist/state/turnRunner.js +1 -75
  62. package/dist/state/turnRunner.js.map +1 -1
  63. package/package.json +4 -4
  64. package/src/auth/encryption.ts +5 -5
  65. package/src/auth/userView.ts +9 -22
  66. package/src/bootstrap.ts +4 -43
  67. package/src/db/migrate.ts +0 -17
  68. package/src/db/schema.ts +0 -68
  69. package/src/db/seed.ts +6 -47
  70. package/src/handlers/fetch.ts +6 -9
  71. package/src/handlers/types.ts +5 -6
  72. package/src/letta/client.ts +170 -634
  73. package/src/letta/index.ts +8 -21
  74. package/src/letta/sandbox.ts +151 -11
  75. package/src/letta/types.ts +9 -60
  76. package/src/observability/logger.ts +0 -2
  77. package/src/routes/admin/agents.ts +0 -49
  78. package/src/routes/admin/settings.ts +9 -113
  79. package/src/routes/auth.ts +1 -5
  80. package/src/routes/sessions.ts +11 -32
  81. package/src/state/turnRunner.ts +1 -77
  82. package/src/letta/lettaCliShim.mjs +0 -40
  83. package/src/letta/settingsFileSeed.ts +0 -254
@@ -1,47 +1,40 @@
1
1
  /**
2
- * Hybrid Letta access layer.
2
+ * Letta access layer — server-less local backend.
3
3
  *
4
- * **Two SDKs, two roles:**
4
+ * AI Hub drives **Letta Code's local backend** through
5
+ * `@data-club/letta-runtime`: agent/conversation state lives on the local
6
+ * filesystem (`AI_HUB_LETTA_STORE_DIR`), chat turns run in an SDK-spawned
7
+ * Letta Code CLI subprocess, and inference is client-side (Letta Code's Pi
8
+ * provider layer calling Anthropic / AWS Bedrock directly). There is no
9
+ * Letta server and no `@letta-ai/letta-client` anywhere in this path — the
10
+ * server-backed implementation was removed in the local-backend migration
11
+ * (see docs/investigations/2026-07-01-letta-code-local-backend-migration.md).
5
12
  *
6
- * - **`@letta-ai/letta-client`** owns *direct REST operations*
7
- * `retrieveAgent`, `createConversation`, `listMessages`. These are
8
- * stable agent / conversation / message CRUD against the Letta
9
- * server's REST surface; they don't involve model routing or
10
- * provider shape.
11
- * - **`@letta-ai/letta-code-sdk`** owns the *chat-streaming path* —
12
- * `streamUserMessage`. Spawns a Letta Code CLI subprocess per turn;
13
- * the CLI's internal Pi (Provider Interface) + bundled `models.json`
14
- * handle model selection, reasoning-tier presets, and provider
15
- * fallback routing (e.g. Anthropic → Bedrock Opus 4.7). This is what
16
- * keeps ai-hub current with model releases without code changes.
13
+ * **MCP tools.** Letta Code is not an MCP client; with no Letta server, AI
14
+ * Hub is the MCP host. On the first chat turn this module connects to the
15
+ * servers configured in `AI_HUB_MCP_SERVERS` (`name=url,name2=url2`,
16
+ * Streamable HTTP) and injects their tools into every session via the
17
+ * runtime's `tools` option; tool executions round-trip through the SDK's
18
+ * `execute_external_tool` control channel in this process.
17
19
  *
18
- * **The hard rule from §6.4 is preserved** every Letta interaction
19
- * goes through one of these two SDKs; no raw HTTP, no parallel fetch.
20
+ * **Tool suppression.** Letta Code's bundled tools are hidden from the
21
+ * model via `disallowedTools` (the headless-mode equivalent of the TUI's
22
+ * `/toolset none`). The old `--tools ""` CLI shim is gone — emptying the
23
+ * CLI's tool registry also strips SDK-injected MCP tools (verified
24
+ * empirically), so the disallow list is the only suppression mechanism.
20
25
  *
21
- * Configuration source: `admin_setting.letta_base_url` +
22
- * `admin_setting.letta_api_key_encrypted` (decrypted with
23
- * `AI_HUB_ENCRYPTION_KEY`). The Letta-Client wrapper memoizes one SDK
24
- * instance per `(apiKey, baseURL)` pair so super-admin connection
25
- * edits propagate without restart. The Letta-Code subprocess inherits
26
- * `process.env` (which must carry `LETTA_BASE_URL` + `LETTA_API_KEY` —
27
- * the boot script sets these from the same decrypted DB row).
28
- *
29
- * @see SPECIFICATIONS.md §6.4 — Letta integration
30
- * @see SPECIFICATIONS.md §6.4.1 — first-class SDK surfaces
26
+ * This module composes AI-Hub policy (subprocess throttle, tool
27
+ * disallow-lists, sandbox cwd) around the runtime; everything Letta-shaped
28
+ * lives in `@data-club/letta-runtime`.
31
29
  */
32
- import LettaSdkDefault from "@letta-ai/letta-client";
33
- import { resumeSession, type SDKMessage } from "@letta-ai/letta-code-sdk";
34
- import type { DrizzleDB } from "../db/connection.js";
30
+ import { type LettaMessageRecord, type LettaRuntime, type SDKMessage } from "@data-club/letta-runtime";
35
31
  import { type SubprocessThrottle } from "./subprocessThrottle.js";
36
- import type { LettaMessage } from "./types.js";
37
32
  export { ServerOverloadedError, SubprocessThrottle } from "./subprocessThrottle.js";
38
33
  /**
39
- * Thrown when `forkConversation(sourceId)` or `retrieveConversation(id)`
40
- * resolves to "no such conversation" (Letta 404). The admin agents
41
- * validator catches this and returns `400 fork_source_not_found` inline
42
- * on the field; the chat route surfaces it as a 500 (admin-side
43
- * validation should have caught it before any user-facing session
44
- * create reached the fork path).
34
+ * Thrown when `forkConversation(sourceId)` resolves to "no such
35
+ * conversation". The admin agents validator catches this and returns
36
+ * `400 fork_source_not_found` inline on the field; the chat route surfaces
37
+ * it as a 500 (admin-side validation should have caught it earlier).
45
38
  *
46
39
  * @see docs/server/session-sandboxes.md
47
40
  */
@@ -49,307 +42,137 @@ export declare class ForkSourceNotFoundError extends Error {
49
42
  readonly conversationId: string;
50
43
  constructor(conversationId: string);
51
44
  }
52
- /**
53
- * Provider-reported token usage for a single Letta run + the run's
54
- * last assistant-message id (so callers can stamp the badge on the
55
- * visible bubble). All token fields are nullable because the
56
- * producing provider may not report every dimension — Anthropic
57
- * reports `cache_write_tokens`, others don't; reasoning tokens come
58
- * back only when the model produced any; etc.
59
- *
60
- * Sourced via a single `GET /v1/runs/{run_id}/messages` call.
61
- */
62
- export interface RunUsageStats {
63
- /**
64
- * Id of the LAST `assistant_message`-typed entry in the run. `null`
65
- * when the run had no assistant messages (rare — error-only runs).
66
- * Callers stamp `message_usage` against this id.
67
- */
68
- lastAssistantMessageId: string | null;
69
- promptTokens: number | null;
70
- completionTokens: number | null;
71
- totalTokens: number | null;
72
- cachedInputTokens: number | null;
73
- cacheWriteTokens: number | null;
74
- reasoningTokens: number | null;
75
- contextTokens: number | null;
76
- }
77
45
  /** Parameters for `streamUserMessage`. */
78
46
  export interface StreamUserMessageOpts {
79
47
  /** The Letta conversation id (`session.letta_conversation_id`). */
80
48
  conversationId: string;
81
49
  /**
82
- * The Letta agent id the session is against. Required so we can
83
- * re-seed `~/.letta/settings.json` on every spawn concurrent CLI
84
- * subprocesses race on writes and can wipe the entry, so the
85
- * agent-registration-time seed isn't reliable on its own. The
86
- * seed-on-spawn call below is idempotent (no-op when the entry
87
- * is already present with the same value).
50
+ * The Letta agent id the session is against. Not needed to spawn a turn
51
+ * on the local backend (the conversation record carries its agent), but
52
+ * kept on the opts shape for logging and interface stability.
88
53
  */
89
54
  lettaAgentId: string;
90
55
  /**
91
- * Plain-text user message body. Sent verbatim to Letta. The admin's
92
- * system prompt is delivered through Letta's normal channel (the
93
- * agent's persisted `system` field), so we don't re-inject it here.
56
+ * Plain-text user message body. Sent verbatim. The admin's system prompt
57
+ * is delivered through the agent record's persisted `system` field.
94
58
  */
95
59
  userMessage: string;
96
60
  /**
97
61
  * Step-12.5 — optional working directory for the spawned Letta Code
98
- * subprocess. When set, threaded into the SDK's `resumeSession({ cwd })`
99
- * option (maps to the CLI's `--cwd` flag). Used to confine the agent's
100
- * filesystem-tool access to a per-session sandbox folder; when
101
- * provided, the spawn ALSO drops the `FILESYSTEM_TOOLS` group from
102
- * the `disallowedTools` list so the agent can actually read / write
103
- * inside that folder.
104
- *
105
- * When `undefined`, no `cwd` is passed (the CLI inherits the
106
- * ai-hub-server process's working directory, as it always has) AND
107
- * the filesystem tools remain disallowed — today's stateless agent
108
- * shape.
62
+ * subprocess (per-session sandbox folder). When set, the filesystem
63
+ * tools are re-enabled so the agent can use the seeded files; when
64
+ * `undefined`, they stay disallowed.
109
65
  *
110
66
  * @see docs/server/session-sandboxes.md
111
67
  */
112
68
  cwd?: string;
113
69
  }
114
70
  /**
115
- * Handle returned by `streamUserMessage`. Wraps the Letta Code SDK
116
- * `Session` + the subprocess-throttle lease so the caller owns one
117
- * resource bundle to drain, cancel, and clean up.
118
- *
119
- * Lifecycle expectations:
71
+ * Handle returned by `streamUserMessage`. Wraps the runtime's turn handle +
72
+ * the subprocess-throttle lease so the caller owns one resource bundle to
73
+ * drain, cancel, and clean up.
120
74
  *
121
- * 1. Caller iterates `events` to consume `SDKMessage`s in real time.
122
- * 2. At any point, calling `abort()` sends an `interrupt` control to
123
- * the spawned CLI. Behavior depends on what the CLI is doing —
124
- * during model generation interrupts work cleanly; during a
125
- * long-running tool call the interrupt is currently queued (see
126
- * migration plan §7 open question 5).
127
- * 3. Caller MUST call `close()` in a `finally` regardless of how the
128
- * iteration ended (done, cancelled, error). `close()` terminates
129
- * the CLI subprocess + releases the throttle lease. Idempotent.
75
+ * Lifecycle: iterate `events`; `abort()` to interrupt; ALWAYS `close()` in
76
+ * a `finally` (terminates the CLI subprocess + releases the throttle lease;
77
+ * idempotent).
130
78
  */
131
79
  export interface ChatTurnHandle {
132
80
  /** Async iterable of Letta Code SDK messages — caller drains this. */
133
81
  events: AsyncIterable<SDKMessage>;
134
- /**
135
- * Sends an `interrupt` control to the spawned CLI. Best-effort; if
136
- * the CLI is mid-tool the interrupt may be queued. The caller still
137
- * needs to call `close()` to release subprocess + lease.
138
- */
82
+ /** Sends an `interrupt` control to the spawned CLI. Best-effort. */
139
83
  abort(): Promise<void>;
140
- /**
141
- * Tears down the Letta Code subprocess + releases the throttle slot.
142
- * Idempotent — safe to call twice. Caller MUST invoke this in a
143
- * `finally`. Sync because the SDK's `session.close()` is sync.
144
- */
84
+ /** Tears down the subprocess + releases the throttle slot. Idempotent. */
145
85
  close(): void;
146
86
  }
147
87
  /**
148
- * Project-shaped Letta client. The handlers depend on this interface,
149
- * not on the underlying SDKs, so tests can plug a mock implementation
150
- * in via `getLettaClient` on the server context.
151
- *
152
- * @see SPECIFICATIONS.md §6.4
88
+ * Project-shaped Letta client. The handlers depend on this interface, not
89
+ * on the underlying runtime, so tests can plug a mock implementation in via
90
+ * `getLettaClient` on the server context.
153
91
  */
154
92
  export interface LettaClient {
155
93
  /**
156
- * Retrieves a Letta agent by id (via `@letta-ai/letta-client`).
157
- * Returns `null` (not throws) on miss so the agent-validation flow
158
- * on `POST/PATCH /admin/agents` can return a 400
159
- * `letta_agent_not_found` without try/catch noise. Any non-404 SDK
160
- * error rethrows — the admin handler returns 500.
161
- *
162
- * @param lettaAgentId - candidate Letta-side agent id.
163
- * @returns the agent state or `null` if not found.
94
+ * Retrieves a Letta agent by id from the local store. Returns `null`
95
+ * (not throws) on miss so the agent-validation flow on
96
+ * `POST/PATCH /admin/agents` can return a 400 `letta_agent_not_found`
97
+ * without try/catch noise.
164
98
  */
165
99
  retrieveAgent(lettaAgentId: string): Promise<{
166
100
  id: string;
167
101
  name: string;
168
- /** Provider-prefixed model handle (e.g. `"anthropic/claude-opus-4-7"`). */
102
+ /** Provider-prefixed model handle (e.g. `"bedrock/eu.anthropic.claude-opus-4-6-v1"`). */
169
103
  model: string;
170
104
  } | null>;
171
- /**
172
- * Creates a fresh conversation against the given Letta agent (via
173
- * `@letta-ai/letta-client`). Returns the conversation id we store
174
- * on the new session row.
175
- *
176
- * @param lettaAgentId - the Letta-side agent id.
177
- * @returns the new conversation's id.
178
- */
105
+ /** Creates a fresh conversation against the given agent. */
179
106
  createConversation(lettaAgentId: string): Promise<{
180
107
  id: string;
181
108
  }>;
182
109
  /**
183
- * Step-12.5 — retrieves a Letta conversation by id (via
184
- * `client.conversations.retrieve`). Used by the admin agents
185
- * validator to verify `fork_source_conversation_id` resolves to a
186
- * real conversation AND that its `agent_id` matches the agent's
187
- * `letta_agent_id` (Letta's fork API requires same-agent forking).
188
- *
189
- * Returns `null` on Letta 404 so the handler can surface
190
- * `400 fork_source_not_found` without try/catch noise; non-404
191
- * SDK errors propagate.
192
- *
193
- * @param conversationId - the candidate Letta conversation id.
194
- * @returns `{ id, agentId }` or `null` if not found.
110
+ * Retrieves a conversation by id (admin fork-source validation). Returns
111
+ * `null` on miss.
195
112
  */
196
113
  retrieveConversation(conversationId: string): Promise<{
197
114
  id: string;
198
115
  agentId: string;
199
116
  } | null>;
200
117
  /**
201
- * Step-12.5 — forks an existing Letta conversation into a new
202
- * conversation belonging to the same agent (via
203
- * `client.conversations.fork`). The new conversation shares the
204
- * source's in-context messages and gets a freshly compiled system
205
- * message reflecting the agent's current memory-block values.
118
+ * Clones an existing conversation (transcript included) into a new one
119
+ * on the same agent. Powers session creation from a rotating message's
120
+ * prepared conversation.
206
121
  *
207
- * Used by `POST /sessions` when the parent agent's
208
- * `fork_source_conversation_id` is set. The admin endpoint validates
209
- * source existence + agent match at write time, so this call is
210
- * expected to succeed in the happy path; a 404 here is treated as
211
- * "operator deleted the source conversation between admin-validate
212
- * and user-session-create" and surfaced as `ForkSourceNotFoundError`.
213
- *
214
- * @param sourceConversationId - the Letta conversation id to fork.
215
- * @returns the new conversation's `{ id, agentId }`.
216
- * @throws ForkSourceNotFoundError on Letta 404.
122
+ * @throws ForkSourceNotFoundError when the source no longer exists.
217
123
  */
218
124
  forkConversation(sourceConversationId: string): Promise<{
219
125
  id: string;
220
126
  agentId: string;
221
127
  }>;
222
- /**
223
- * Lists every message in a conversation, oldest first (via
224
- * `@letta-ai/letta-client`). Used for `GET /sessions/{id}/messages`
225
- * history rendering.
226
- *
227
- * @param conversationId - the Letta conversation id.
228
- * @returns the (oldest-first) array of messages.
229
- */
128
+ /** Lists every message in a conversation, oldest first. */
230
129
  listMessages(conversationId: string): Promise<ReadonlyArray<LettaMessage>>;
231
130
  /**
232
- * Deletes a single message from an agent's history by id.
233
- *
234
- * The typed SDK only exposes `create` / `list` on conversation messages,
235
- * so this reaches the Letta server's `DELETE /v1/agents/{agent_id}/messages/{message_id}`
236
- * endpoint via the SDK's raw HTTP escape hatch (`sdk.delete(...)`) — the
237
- * same pattern `getRunUsageStats` uses for `sdk.get(...)`. A 404 is treated
238
- * as "already gone" and swallowed; other errors propagate.
239
- *
240
- * Used by the rotation runner to remove the prompt's `user_message` so a
241
- * rotating starting message's prepared conversation opens with the agent's
242
- * reply.
243
- *
244
- * @param lettaAgentId - the agent the message belongs to.
245
- * @param messageId - the message id (from `listMessages`).
131
+ * NO-OP on the local backend. Message deletion was a Letta-server REST
132
+ * capability; per the migration decision, rotating messages now keep
133
+ * their initial prompt message instead of deleting it. The method stays
134
+ * on the interface so the rotation runner's flow is unchanged.
246
135
  */
247
136
  deleteMessage(lettaAgentId: string, messageId: string): Promise<void>;
248
137
  /**
249
- * Deletes an entire Letta conversation (via `client.conversations.delete`).
250
- * Best-effort cleanup of a rotating message's previous prepared
251
- * conversation after a successful rotation produces a fresh one — a 404 is
252
- * swallowed; other errors propagate to the caller (which logs + continues).
253
- *
254
- * @param conversationId - the Letta conversation id to delete.
138
+ * NO-OP on the local backend. Old prepared conversations are left in the
139
+ * local store (orphans are harmless files); a cleanup pass can come later.
255
140
  */
256
141
  deleteConversation(conversationId: string): Promise<void>;
257
142
  /**
258
- * Fetches provider-reported token usage for a Letta run, including
259
- * prompt-cache hit / write counts. The SDK's `session.stream()`
260
- * drops `usage_statistics` messages, so we re-fetch via REST after
261
- * the turn lands; the runner uses this to stamp a usage badge on
262
- * the last assistant message.
143
+ * Spawns a Letta Code CLI subprocess and streams a chat turn.
263
144
  *
264
- * Returns `null` when:
265
- * - the run id is unknown to Letta (404),
266
- * - the run hasn't emitted a usage_statistics message yet,
267
- * - the network call fails (best-effort the badge is a nicety,
268
- * not load-bearing).
269
- *
270
- * @param runId - Letta run id captured from `SDKAssistantMessage.runId`.
271
- */
272
- getRunUsageStats(runId: string): Promise<RunUsageStats | null>;
273
- /**
274
- * Spawns a Letta Code CLI subprocess and streams a chat turn against
275
- * the given conversation. Returns a `ChatTurnHandle` the caller
276
- * drains + cancels + closes.
277
- *
278
- * Pre-flight checks (in order, all may throw):
279
- * 1. **Subprocess throttle.** `SubprocessThrottle.acquire()` runs
280
- * first — throws `ServerOverloadedError` if RAM is under the
281
- * threshold or the hard-cap is reached. The chat route catches
282
- * this and returns HTTP 503 `server_overloaded`.
283
- * 2. **Session initialization.** `session.initialize()` may throw if
284
- * the CLI subprocess fails to spawn or can't reach Letta. The
285
- * lease is released before the throw so the throttle counter
286
- * doesn't leak.
287
- *
288
- * The Letta Code session is configured for the ai-hub use case:
289
- * - `permissionMode: "bypassPermissions"` — no interactive approvals
290
- * (we don't expose them to end-users in v1).
291
- * - `skillSources: []` — no auto-loaded skills (challenge 2 in the
292
- * migration brief).
293
- * - `systemInfoReminder: false` — no first-turn environment dump.
294
- * - `memfsStartup: "skip"` — no git-backed memory filesystem.
295
- * - `disallowedTools: ["AskUserQuestion", "EnterPlanMode",
296
- * "ExitPlanMode"]` — tools that require runtime user input.
297
- *
298
- * Toolset suppression is handled out-of-band by the
299
- * `seedAgentToolsetNone` upsert into `~/.letta/settings.json` at
300
- * agent-registration time.
301
- *
302
- * @param opts - see `StreamUserMessageOpts`.
303
- * @returns a `ChatTurnHandle` the caller drains and closes.
304
- * @throws `ServerOverloadedError` when the throttle rejects.
145
+ * Pre-flight (in order, both may throw):
146
+ * 1. `SubprocessThrottle.acquire()` `ServerOverloadedError` HTTP 503.
147
+ * 2. MCP bridge connect (first turn only, cached after) — a configured
148
+ * MCP server that can't be reached fails the turn rather than
149
+ * presenting a differently-capable agent.
305
150
  */
306
151
  streamUserMessage(opts: StreamUserMessageOpts): Promise<ChatTurnHandle>;
307
152
  }
153
+ /** One Letta-format message as consumed by history renderers. */
154
+ export type LettaMessage = LettaMessageRecord;
308
155
  /** Dependency bundle for `createDefaultLettaClient`. */
309
156
  export interface CreateLettaClientDeps {
310
- /** Drizzle handle. */
311
- db: DrizzleDB;
312
- /** Parsed encryption key for decrypting the Letta API key at rest. */
313
- encryptionKey: Buffer;
314
157
  /** Subprocess-spawn throttle (shared across the server instance). */
315
158
  subprocessThrottle: SubprocessThrottle;
316
159
  /**
317
- * Env source — used as the fallback when the DB column is empty or
318
- * whitespace. Production passes `process.env`; tests pass a synthesized
319
- * record so the env precedence behaviour is exercisable without
320
- * touching the real environment. Re-read on every `getSdk()` call so a
321
- * server restart with a different `.env` reflects immediately.
160
+ * Env source. Reads:
161
+ * - `AI_HUB_LETTA_STORE_DIR` local-backend store (default
162
+ * `~/.letta/lc-local-backend`; on deployments point this at the
163
+ * persistent encrypted volume, shared with operator SSH sessions).
164
+ * - `AI_HUB_LETTA_CLI_PATH` Letta Code CLI entry override (default:
165
+ * the installed `@data-club/letta-code` package).
166
+ * - `AI_HUB_MCP_SERVERS` — MCP servers to host (`name=url,...`); empty
167
+ * or unset → no MCP tools.
322
168
  */
323
169
  envSource?: Record<string, string | undefined>;
324
- /**
325
- * Override the Letta Client SDK constructor — only used by tests.
326
- * Production passes the SDK's `Letta` class (or omits to use the
327
- * default).
328
- */
329
- sdkConstructor?: typeof LettaSdkDefault;
330
- /**
331
- * Override `resumeSession` from `@letta-ai/letta-code-sdk` — only
332
- * used by tests, which inject a fake session factory.
333
- */
334
- resumeSessionFn?: typeof resumeSession;
170
+ /** Override the runtime — only used by tests. */
171
+ runtime?: LettaRuntime;
335
172
  }
336
173
  /**
337
- * Constructs the default `LettaClient` implementation.
338
- *
339
- * Reads `admin_setting.letta_base_url` + `letta_api_key_encrypted` on
340
- * each Letta-Client call (no in-flight polling — fresh-on-demand) and
341
- * memoizes the underlying SDK instance against `(apiKey, baseURL)` so
342
- * super-admin connection-settings edits propagate without restart.
343
- *
344
- * Throws on the first Letta-Client call if `admin_setting` has no
345
- * `letta_base_url` or no decryptable API key.
346
- *
347
- * @param deps - see `CreateLettaClientDeps`.
348
- * @returns the project-shaped Letta client.
349
- *
350
- * @see SPECIFICATIONS.md §6.4
351
- * @see SPECIFICATIONS.md §11 — `admin_setting` schema
174
+ * Constructs the default `LettaClient` implementation over the local
175
+ * backend. See the module doc for the architecture.
352
176
  */
353
177
  export declare function createDefaultLettaClient(deps: CreateLettaClientDeps): LettaClient;
354
- export type { LettaMessage, LettaSdk } from "./types.js";
355
178
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/letta/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/letta/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAMH,OAAO,EAML,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,UAAU,EAEhB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,KAAK,kBAAkB,EAExB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAEpF;;;;;;;GAOG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;aACpB,cAAc,EAAE,MAAM;gBAAtB,cAAc,EAAE,MAAM;CAInD;AAsED,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC,mEAAmE;IACnE,cAAc,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,MAAM,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAClC,oEAAoE;IACpE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,0EAA0E;IAC1E,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;;OAKG;IACH,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAC3C,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,yFAAyF;QACzF,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,IAAI,CAAC,CAAC;IACV,4DAA4D;IAC5D,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClE;;;OAGG;IACH,oBAAoB,CAClB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACnD;;;;;;OAMG;IACH,gBAAgB,CACd,oBAAoB,EAAE,MAAM,GAC3B,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5C,2DAA2D;IAC3D,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;IAC3E;;;;;OAKG;IACH,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE;;;OAGG;IACH,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D;;;;;;;;OAQG;IACH,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACzE;AAED,iEAAiE;AACjE,MAAM,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAM9C,wDAAwD;AACxD,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,kBAAkB,EAAE,kBAAkB,CAAC;IACvC;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/C,iDAAiD;IACjD,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAQD;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,qBAAqB,GAC1B,WAAW,CAiHb"}