@letta-ai/letta-code 0.25.4 → 0.25.5

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.
package/letta.js CHANGED
@@ -3143,7 +3143,7 @@ var package_default;
3143
3143
  var init_package = __esm(() => {
3144
3144
  package_default = {
3145
3145
  name: "@letta-ai/letta-code",
3146
- version: "0.25.4",
3146
+ version: "0.25.5",
3147
3147
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
3148
3148
  type: "module",
3149
3149
  bin: {
@@ -5756,13 +5756,16 @@ function isTruthyEnv(value) {
5756
5756
  function isLocalBackendEnvEnabled(env = process.env) {
5757
5757
  return isTruthyEnv(env[LOCAL_BACKEND_EXPERIMENTAL_ENV]);
5758
5758
  }
5759
+ function isLocalBackendNoMemfsEnvEnabled(env = process.env) {
5760
+ return isTruthyEnv(env[LOCAL_BACKEND_NO_MEMFS_ENV]);
5761
+ }
5759
5762
  function getLocalBackendStorageDir(homeDir = homedir3()) {
5760
5763
  return process.env[LOCAL_BACKEND_DIR_ENV] ?? join3(homeDir, ".letta", "lc-local-backend");
5761
5764
  }
5762
5765
  function getLocalBackendMemoryFilesystemRoot(agentId, storageDir = getLocalBackendStorageDir()) {
5763
5766
  return join3(storageDir, "memfs", agentId, "memory");
5764
5767
  }
5765
- var LOCAL_BACKEND_DIR_ENV = "LETTA_LOCAL_BACKEND_DIR", LOCAL_BACKEND_EXPERIMENTAL_ENV = "LETTA_LOCAL_BACKEND_EXPERIMENTAL";
5768
+ var LOCAL_BACKEND_DIR_ENV = "LETTA_LOCAL_BACKEND_DIR", LOCAL_BACKEND_EXPERIMENTAL_ENV = "LETTA_LOCAL_BACKEND_EXPERIMENTAL", LOCAL_BACKEND_NO_MEMFS_ENV = "LETTA_LOCAL_BACKEND_NO_MEMFS";
5766
5769
  var init_paths = () => {};
5767
5770
 
5768
5771
  // src/agent/memoryGit.ts
@@ -5918,6 +5921,11 @@ function getMemoryRemoteUrl(agentId) {
5918
5921
  return getGitRemoteUrl(agentId);
5919
5922
  }
5920
5923
  async function getAuthToken() {
5924
+ const { getBackend } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
5925
+ const backend = getBackend();
5926
+ if (backend.capabilities.localMemfs && !backend.capabilities.remoteMemfs) {
5927
+ return "";
5928
+ }
5921
5929
  const client = await getClient();
5922
5930
  return client._options?.apiKey ?? "";
5923
5931
  }
@@ -5969,7 +5977,7 @@ async function runGit(cwd, args, token) {
5969
5977
  const result = await execFile("git", allArgs, {
5970
5978
  cwd,
5971
5979
  env: buildNonInteractiveGitEnv(),
5972
- maxBuffer: 10 * 1024 * 1024,
5980
+ maxBuffer: 10485760,
5973
5981
  timeout: 60000
5974
5982
  });
5975
5983
  return {
@@ -6101,9 +6109,9 @@ async function unsetLocalGitConfig(dir, key) {
6101
6109
  async function fetchAgentDisplayName(agentId) {
6102
6110
  let timeout;
6103
6111
  try {
6104
- const client = await getClient();
6112
+ const { getBackend } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
6105
6113
  const agent = await Promise.race([
6106
- client.agents.retrieve(agentId),
6114
+ getBackend().retrieveAgent(agentId),
6107
6115
  new Promise((resolve2) => {
6108
6116
  timeout = setTimeout(() => resolve2(null), AGENT_DISPLAY_NAME_TIMEOUT_MS);
6109
6117
  })
@@ -6714,12 +6722,13 @@ async function getMemoryGitStatus(agentId) {
6714
6722
  };
6715
6723
  }
6716
6724
  async function addGitMemoryTag(agentId, prefetchedAgent) {
6717
- const client = await getClient();
6718
6725
  try {
6719
- const agent = prefetchedAgent ?? await client.agents.retrieve(agentId);
6726
+ const { getBackend } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
6727
+ const backend = getBackend();
6728
+ const agent = prefetchedAgent ?? await backend.retrieveAgent(agentId);
6720
6729
  const tags = agent.tags || [];
6721
6730
  if (!tags.includes(GIT_MEMORY_ENABLED_TAG)) {
6722
- await client.agents.update(agentId, {
6731
+ await backend.updateAgent(agentId, {
6723
6732
  tags: [...tags, GIT_MEMORY_ENABLED_TAG]
6724
6733
  });
6725
6734
  debugLog("memfs-git", `Added ${GIT_MEMORY_ENABLED_TAG} tag`);
@@ -6729,12 +6738,13 @@ async function addGitMemoryTag(agentId, prefetchedAgent) {
6729
6738
  }
6730
6739
  }
6731
6740
  async function removeGitMemoryTag(agentId) {
6732
- const client = await getClient();
6733
6741
  try {
6734
- const agent = await client.agents.retrieve(agentId);
6742
+ const { getBackend } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
6743
+ const backend = getBackend();
6744
+ const agent = await backend.retrieveAgent(agentId);
6735
6745
  const tags = agent.tags || [];
6736
6746
  if (tags.includes(GIT_MEMORY_ENABLED_TAG)) {
6737
- await client.agents.update(agentId, {
6747
+ await backend.updateAgent(agentId, {
6738
6748
  tags: tags.filter((t) => t !== GIT_MEMORY_ENABLED_TAG)
6739
6749
  });
6740
6750
  debugLog("memfs-git", `Removed ${GIT_MEMORY_ENABLED_TAG} tag`);
@@ -69921,10 +69931,135 @@ function shouldKeepReasoningPart(part, provider) {
69921
69931
  return hasAnthropicReasoningMetadata(part);
69922
69932
  return true;
69923
69933
  }
69924
- function sanitizeUIMessagesForProvider(messages, provider) {
69934
+ function stringArray(value) {
69935
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string") ? value : undefined;
69936
+ }
69937
+ function mimeToModality(mime) {
69938
+ if (mime.startsWith("image/"))
69939
+ return "image";
69940
+ if (mime.startsWith("audio/"))
69941
+ return "audio";
69942
+ if (mime.startsWith("video/"))
69943
+ return "video";
69944
+ if (mime === "application/pdf")
69945
+ return "pdf";
69946
+ return;
69947
+ }
69948
+ function modalitiesFromModelSettings(modelSettings) {
69949
+ const modalities = isRecord2(modelSettings.modalities) ? modelSettings.modalities : undefined;
69950
+ const input = stringArray(modalities?.input);
69951
+ if (!input)
69952
+ return;
69953
+ return new Set(input.filter((entry) => ["text", "image", "audio", "video", "pdf"].includes(entry)));
69954
+ }
69955
+ function capabilitiesFromModelSettings(modelSettings) {
69956
+ const capabilities = isRecord2(modelSettings.capabilities) ? modelSettings.capabilities : undefined;
69957
+ const input = isRecord2(capabilities?.input) ? capabilities.input : undefined;
69958
+ if (!input)
69959
+ return;
69960
+ const supported = new Set(["text"]);
69961
+ for (const modality of ["image", "audio", "video", "pdf"]) {
69962
+ if (input[modality] === true)
69963
+ supported.add(modality);
69964
+ }
69965
+ return supported;
69966
+ }
69967
+ function knownModelInputModalities(modelHandle, modelSettings) {
69968
+ const explicitModalities = modalitiesFromModelSettings(modelSettings);
69969
+ if (explicitModalities)
69970
+ return explicitModalities;
69971
+ const explicitCapabilities = capabilitiesFromModelSettings(modelSettings);
69972
+ if (explicitCapabilities)
69973
+ return explicitCapabilities;
69974
+ const handle = modelHandle.toLowerCase();
69975
+ const supported = new Set(["text"]);
69976
+ if (handle.startsWith("anthropic/") || handle.startsWith("claude-pro-max/") || handle.startsWith("bedrock/") || handle.startsWith("google_ai/") || handle.startsWith("google_vertex/") || handle.includes("gemini") || handle.includes("claude") || handle.includes("gpt-4o") || handle.includes("gpt-4.1") || handle.includes("gpt-5") || handle.includes("o3") || handle.includes("o4") || handle.includes("vision") || handle.includes("qwen-vl") || handle.includes("qwen2-vl") || handle.includes("qwen2.5-vl") || handle.includes("qwen3-vl") || handle.includes("llava") || handle.includes("bakllava") || handle.includes("moondream")) {
69977
+ supported.add("image");
69978
+ }
69979
+ return supported;
69980
+ }
69981
+ function modelSupportsInputModality(modelHandle, modelSettings, modality) {
69982
+ if (modality === "text")
69983
+ return true;
69984
+ return knownModelInputModalities(modelHandle, modelSettings).has(modality);
69985
+ }
69986
+ function isEmptyBase64DataUrl(data) {
69987
+ if (typeof data !== "string" || !data.startsWith("data:"))
69988
+ return false;
69989
+ const match = data.match(/^data:([^;]+);base64,(.*)$/);
69990
+ return Boolean(match && (!match[2] || match[2].length === 0));
69991
+ }
69992
+ function filePartMediaType(part) {
69993
+ if (typeof part.mediaType === "string")
69994
+ return part.mediaType;
69995
+ if (typeof part.mime === "string")
69996
+ return part.mime;
69997
+ return;
69998
+ }
69999
+ function imagePartMediaType(part) {
70000
+ if (typeof part.image === "string" && part.image.startsWith("data:")) {
70001
+ return part.image.split(";")[0]?.replace("data:", "");
70002
+ }
70003
+ if (isRecord2(part.source) && typeof part.source.media_type === "string") {
70004
+ return part.source.media_type;
70005
+ }
70006
+ return;
70007
+ }
70008
+ function partFilename(part) {
70009
+ return stringValue(part.filename) ?? stringValue(part.name);
70010
+ }
70011
+ function replaceUnsupportedInputPart(part, agent) {
70012
+ if (!isRecord2(part))
70013
+ return part;
70014
+ const record2 = part;
70015
+ const partType = typeof record2.type === "string" ? record2.type : undefined;
70016
+ if (partType !== "file" && partType !== "image") {
70017
+ return part;
70018
+ }
70019
+ if (partType === "image" && isEmptyBase64DataUrl(record2.image)) {
70020
+ return {
70021
+ type: "text",
70022
+ text: "ERROR: Image file is empty or corrupted. Please provide a valid image."
70023
+ };
70024
+ }
70025
+ const mime = partType === "image" ? imagePartMediaType(record2) : filePartMediaType(record2);
70026
+ if (!mime)
70027
+ return part;
70028
+ const modality = mimeToModality(mime);
70029
+ if (!modality)
70030
+ return part;
70031
+ if (modelSupportsInputModality(agent.model, agent.model_settings, modality)) {
70032
+ return part;
70033
+ }
70034
+ const name25 = partFilename(record2);
70035
+ return {
70036
+ type: "text",
70037
+ text: `ERROR: Cannot read ${name25 ? `"${name25}"` : modality} (this model does not support ${modality} input). Inform the user.`
70038
+ };
70039
+ }
70040
+ function replaceUnsupportedInputParts(messages, agent) {
70041
+ let didChange = false;
70042
+ const transformed = messages.map((message) => {
70043
+ if (message.role !== "user")
70044
+ return message;
70045
+ let messageDidChange = false;
70046
+ const parts = message.parts.map((part) => {
70047
+ const replacement = replaceUnsupportedInputPart(part, agent);
70048
+ if (replacement !== part) {
70049
+ didChange = true;
70050
+ messageDidChange = true;
70051
+ }
70052
+ return replacement;
70053
+ });
70054
+ return messageDidChange ? { ...message, parts } : message;
70055
+ });
70056
+ return didChange ? transformed : messages;
70057
+ }
70058
+ function sanitizeUIMessagesForProvider(messages, provider, agent) {
70059
+ const capabilitySanitizedMessages = replaceUnsupportedInputParts(messages, agent);
69925
70060
  if (provider === "unknown")
69926
- return messages;
69927
- return messages.map((message) => {
70061
+ return capabilitySanitizedMessages;
70062
+ return capabilitySanitizedMessages.map((message) => {
69928
70063
  const parts = message.parts.filter((part) => shouldKeepReasoningPart(part, provider));
69929
70064
  return parts.length === message.parts.length ? message : { ...message, parts };
69930
70065
  }).filter((message) => message.role !== "assistant" || message.parts.length > 0);
@@ -70022,7 +70157,7 @@ class AISDKStreamAdapter {
70022
70157
  const tools = toToolSet(input.clientTools);
70023
70158
  const provider = aiSDKProviderKind(input.agent.model, input.agent.model_settings);
70024
70159
  const uiMessages = await validateUIMessages({
70025
- messages: sanitizeUIMessagesForProvider(input.uiMessages, provider),
70160
+ messages: sanitizeUIMessagesForProvider(input.uiMessages, provider, input.agent),
70026
70161
  tools
70027
70162
  });
70028
70163
  const result = this.runStreamText({
@@ -70432,6 +70567,7 @@ function normalizeAgentRecord(value, defaultAgentModel) {
70432
70567
  if (modelSettings.max_tokens === undefined && (typeof legacyLlmConfig.max_tokens === "number" || legacyLlmConfig.max_tokens === null)) {
70433
70568
  modelSettings.max_tokens = legacyLlmConfig.max_tokens;
70434
70569
  }
70570
+ const compactionSettings = optionalRecordOrNull(value.compaction_settings);
70435
70571
  return {
70436
70572
  id: value.id,
70437
70573
  name: optionalString(value.name) ?? "Letta Code",
@@ -70439,7 +70575,8 @@ function normalizeAgentRecord(value, defaultAgentModel) {
70439
70575
  system: optionalString(value.system) ?? "",
70440
70576
  tags: isStringArray(value.tags) ? value.tags : [],
70441
70577
  model: optionalString(value.model) ?? optionalString(legacyLlmConfig.model) ?? defaultAgentModel,
70442
- model_settings: modelSettings
70578
+ model_settings: modelSettings,
70579
+ ...compactionSettings !== undefined ? { compaction_settings: compactionSettings } : {}
70443
70580
  };
70444
70581
  }
70445
70582
  function projectAgentState(record2, messageIds = [], inContextMessageIds = messageIds, lastRunCompletion) {
@@ -70455,6 +70592,7 @@ function projectAgentState(record2, messageIds = [], inContextMessageIds = messa
70455
70592
  tags: record2.tags,
70456
70593
  model: record2.model,
70457
70594
  model_settings: record2.model_settings,
70595
+ ...record2.compaction_settings !== undefined ? { compaction_settings: record2.compaction_settings } : {},
70458
70596
  message_ids: messageIds,
70459
70597
  in_context_message_ids: inContextMessageIds,
70460
70598
  ...lastRunCompletion ? { last_run_completion: lastRunCompletion } : {},
@@ -70483,6 +70621,39 @@ function normalizeContent(content) {
70483
70621
  function isRecord3(value) {
70484
70622
  return typeof value === "object" && value !== null && !Array.isArray(value);
70485
70623
  }
70624
+ function localFilePartFromLegacyImage(part) {
70625
+ if (part.type !== "image" || !isRecord3(part.source)) {
70626
+ return null;
70627
+ }
70628
+ const source = part.source;
70629
+ if (source.type !== "base64") {
70630
+ return null;
70631
+ }
70632
+ const mediaType = source.media_type;
70633
+ const data = source.data;
70634
+ if (typeof mediaType !== "string" || typeof data !== "string") {
70635
+ return null;
70636
+ }
70637
+ return {
70638
+ type: "file",
70639
+ mediaType,
70640
+ url: `data:${mediaType};base64,${data}`
70641
+ };
70642
+ }
70643
+ function normalizeLocalMessageForAISDK(message) {
70644
+ let didChange = false;
70645
+ const parts = message.parts.map((part) => {
70646
+ if (isRecord3(part)) {
70647
+ const filePart = localFilePartFromLegacyImage(part);
70648
+ if (filePart) {
70649
+ didChange = true;
70650
+ return filePart;
70651
+ }
70652
+ }
70653
+ return part;
70654
+ });
70655
+ return didChange ? { ...message, parts } : message;
70656
+ }
70486
70657
  function textFromContent(content) {
70487
70658
  if (typeof content === "string")
70488
70659
  return content;
@@ -70714,6 +70885,19 @@ class LocalStore {
70714
70885
  }
70715
70886
  return this.projectAgent(updated);
70716
70887
  }
70888
+ setAgentCompactionSettings(agentId, settings) {
70889
+ const existing = this.agents.get(agentId);
70890
+ if (!existing) {
70891
+ throw new LocalBackendNotFoundError("Agent", agentId);
70892
+ }
70893
+ const updated = {
70894
+ ...existing,
70895
+ compaction_settings: settings === null ? null : { ...settings }
70896
+ };
70897
+ this.agents.set(agentId, updated);
70898
+ this.persistAgent(agentId);
70899
+ return this.projectAgent(updated);
70900
+ }
70717
70901
  createAgent(body) {
70718
70902
  const agent = this.createAgentRecord(body);
70719
70903
  const agentId = agent.id;
@@ -70951,8 +71135,12 @@ class LocalStore {
70951
71135
  },
70952
71136
  parts: [{ type: "text", text: input.packedSummary }]
70953
71137
  };
70954
- this.localMessagesByConversationKey.set(key, [summaryMessage]);
70955
- conversation.in_context_message_ids = [summaryMessage.id];
71138
+ const compactedMessages = [
71139
+ summaryMessage,
71140
+ ...(input.remainingMessages ?? []).map(cloneLocalMessage)
71141
+ ];
71142
+ this.localMessagesByConversationKey.set(key, compactedMessages);
71143
+ conversation.in_context_message_ids = compactedMessages.map((message) => message.id);
70956
71144
  conversation.last_message_at = date5;
70957
71145
  conversation.updated_at = date5;
70958
71146
  this.conversations.set(key, conversation);
@@ -70960,7 +71148,7 @@ class LocalStore {
70960
71148
  this.rebuildMessageIndex();
70961
71149
  return {
70962
71150
  numMessagesBefore: previousMessages.length,
70963
- numMessagesAfter: 1,
71151
+ numMessagesAfter: compactedMessages.length,
70964
71152
  summaryMessage: cloneLocalMessage(summaryMessage)
70965
71153
  };
70966
71154
  }
@@ -71316,6 +71504,11 @@ class LocalStore {
71316
71504
  parts.push({ type: "text", text: part.text });
71317
71505
  continue;
71318
71506
  }
71507
+ const filePart = localFilePartFromLegacyImage(part);
71508
+ if (filePart) {
71509
+ parts.push(filePart);
71510
+ continue;
71511
+ }
71319
71512
  parts.push(part);
71320
71513
  }
71321
71514
  return parts.length > 0 ? parts : textContent(textFromContent(content));
@@ -71352,7 +71545,7 @@ class LocalStore {
71352
71545
  if (!conversation?.id || !conversation.agent_id)
71353
71546
  continue;
71354
71547
  const key = this.conversationKey(conversation.id, conversation.agent_id);
71355
- const localMessages = readJsonlFile(join7(conversationDir, "messages.jsonl"));
71548
+ const localMessages = readJsonlFile(join7(conversationDir, "messages.jsonl")).map(normalizeLocalMessageForAISDK);
71356
71549
  const compiledSystemPrompt = readJsonFile(join7(conversationDir, "system-prompt.json"));
71357
71550
  const messages = projectLocalMessagesToStoredMessages(localMessages, conversation.agent_id, conversation.id);
71358
71551
  this.conversations.set(key, conversation);
@@ -71903,6 +72096,9 @@ var init_HeadlessBackend = __esm(() => {
71903
72096
  });
71904
72097
 
71905
72098
  // src/backend/local/compaction.ts
72099
+ function isLocalSlidingWindowCompactionPlanningError(error51) {
72100
+ return error51 instanceof LocalSlidingWindowCompactionPlanningError;
72101
+ }
71906
72102
  function isRecord4(value) {
71907
72103
  return typeof value === "object" && value !== null && !Array.isArray(value);
71908
72104
  }
@@ -71961,24 +72157,24 @@ ${body}
71961
72157
  }
71962
72158
  return transcript;
71963
72159
  }
71964
- async function runGenerateText(input, transcript) {
72160
+ async function runGenerateText(input, transcript, defaultPrompt) {
71965
72161
  const run = input.generateText ?? generateText;
71966
72162
  return run({
71967
72163
  model: input.createModel?.() ?? createAISDKModelFactoryFromAgent(input.agent.model, input.agent.model_settings, { localProviderAuthStorageDir: input.localProviderAuthStorageDir })(),
71968
- system: input.prompt ?? LOCAL_ALL_COMPACTION_PROMPT,
72164
+ system: input.prompt ?? defaultPrompt,
71969
72165
  prompt: transcript,
71970
72166
  providerOptions: buildAISDKProviderOptions(input.agent.model, input.agent.model_settings),
71971
72167
  maxRetries: 0,
71972
72168
  abortSignal: input.abortSignal
71973
72169
  });
71974
72170
  }
71975
- async function summarizeLocalMessagesAll(input) {
72171
+ async function summarizeLocalMessagesWithPrompt(input, defaultPrompt) {
71976
72172
  if (input.messages.length === 0)
71977
72173
  return "No prior conversation messages.";
71978
72174
  const primaryTranscript = formatLocalMessagesForSummary(input.messages);
71979
72175
  let result;
71980
72176
  try {
71981
- result = await runGenerateText(input, primaryTranscript);
72177
+ result = await runGenerateText(input, primaryTranscript, defaultPrompt);
71982
72178
  } catch (error51) {
71983
72179
  if (!isContextWindowOverflowError(error51))
71984
72180
  throw error51;
@@ -71986,7 +72182,7 @@ async function summarizeLocalMessagesAll(input) {
71986
72182
  truncationChars: TOOL_TRANSCRIPT_TRUNCATION_CHARS,
71987
72183
  maxChars: TRANSCRIPT_FALLBACK_MAX_CHARS
71988
72184
  });
71989
- result = await runGenerateText(input, fallbackTranscript);
72185
+ result = await runGenerateText(input, fallbackTranscript, defaultPrompt);
71990
72186
  }
71991
72187
  let summary = result.text.trim();
71992
72188
  const clipChars = input.clipChars === undefined ? 50000 : input.clipChars;
@@ -71995,6 +72191,62 @@ async function summarizeLocalMessagesAll(input) {
71995
72191
  }
71996
72192
  return summary;
71997
72193
  }
72194
+ async function summarizeLocalMessagesAll(input) {
72195
+ return summarizeLocalMessagesWithPrompt(input, LOCAL_ALL_COMPACTION_PROMPT);
72196
+ }
72197
+ function isSettledLocalToolState2(state) {
72198
+ return state === "output-available" || state === "output-error" || state === "output-denied";
72199
+ }
72200
+ function hasPendingLocalToolPart(message) {
72201
+ return message.parts.some((part) => {
72202
+ if (!isRecord4(part))
72203
+ return false;
72204
+ const partRecord = part;
72205
+ return typeof partRecord.type === "string" && partRecord.type.startsWith("tool-") && !isSettledLocalToolState2(partRecord.state);
72206
+ });
72207
+ }
72208
+ function normalizedSlidingWindowPercentage(value) {
72209
+ if (typeof value !== "number" || !Number.isFinite(value)) {
72210
+ return LOCAL_DEFAULT_SLIDING_WINDOW_PERCENTAGE;
72211
+ }
72212
+ if (value <= 0)
72213
+ return 0.1;
72214
+ if (value > 1)
72215
+ return 1;
72216
+ return value;
72217
+ }
72218
+ function isValidSlidingWindowCutoff(messages, index, maximumCutoffIndex) {
72219
+ const message = messages[index];
72220
+ return message?.role === "assistant" && index > 1 && index < maximumCutoffIndex;
72221
+ }
72222
+ function planLocalSlidingWindowCompaction(messages, options = {}) {
72223
+ if (messages.length < 4) {
72224
+ throw new LocalSlidingWindowCompactionPlanningError("Not enough messages for sliding window compaction.");
72225
+ }
72226
+ const percentage = normalizedSlidingWindowPercentage(options.slidingWindowPercentage);
72227
+ const lastMessage = messages.at(-1);
72228
+ const maximumCutoffIndex = lastMessage && hasPendingLocalToolPart(lastMessage) ? messages.length - 2 : messages.length - 1;
72229
+ const goalTokens = typeof options.contextWindow === "number" && Number.isFinite(options.contextWindow) ? (1 - percentage) * options.contextWindow : undefined;
72230
+ for (let evictionPercentage = percentage;evictionPercentage < 1; evictionPercentage += 0.1) {
72231
+ const messageCutoffIndex = Math.min(Math.round(evictionPercentage * messages.length), messages.length - 1);
72232
+ const cutoffIndex = [...Array(messageCutoffIndex + 1).keys()].reverse().find((index) => isValidSlidingWindowCutoff(messages, index, maximumCutoffIndex));
72233
+ if (cutoffIndex === undefined)
72234
+ continue;
72235
+ const messagesToKeep = messages.slice(cutoffIndex);
72236
+ if (goalTokens !== undefined && estimateLocalMessageTokens(messagesToKeep) >= goalTokens) {
72237
+ continue;
72238
+ }
72239
+ return {
72240
+ messagesToSummarize: messages.slice(0, cutoffIndex),
72241
+ messagesToKeep,
72242
+ cutoffIndex
72243
+ };
72244
+ }
72245
+ throw new LocalSlidingWindowCompactionPlanningError("No assistant message found for sliding window compaction.");
72246
+ }
72247
+ async function summarizeLocalMessagesSlidingWindow(input) {
72248
+ return summarizeLocalMessagesWithPrompt(input, LOCAL_SLIDING_WINDOW_COMPACTION_PROMPT);
72249
+ }
71998
72250
  function estimateLocalMessageTokens(messages) {
71999
72251
  const chars = messages.reduce((total, message) => total + JSON.stringify(message).length, 0);
72000
72252
  return Math.ceil(chars / 4);
@@ -72009,12 +72261,18 @@ The following is an in-context recursive summary of the prior messages: ${summar
72009
72261
  ...stats ? { compaction_stats: stats } : {}
72010
72262
  });
72011
72263
  }
72012
- var ALL_WORD_LIMIT = 500, SUMMARY_TRUNCATION_SUFFIX = "... [summary truncated to fit]", TOOL_TRANSCRIPT_TRUNCATION_CHARS = 4000, TRANSCRIPT_FALLBACK_MAX_CHARS = 120000, LOCAL_ALL_COMPACTION_PROMPT;
72264
+ var ALL_WORD_LIMIT = 500, SLIDING_WORD_LIMIT = 300, SUMMARY_TRUNCATION_SUFFIX = "... [summary truncated to fit]", TOOL_TRANSCRIPT_TRUNCATION_CHARS = 4000, TRANSCRIPT_FALLBACK_MAX_CHARS = 120000, LOCAL_DEFAULT_COMPACTION_MODE = "sliding_window", LOCAL_DEFAULT_SLIDING_WINDOW_PERCENTAGE = 0.3, LocalSlidingWindowCompactionPlanningError, LOCAL_ALL_COMPACTION_PROMPT, LOCAL_SLIDING_WINDOW_COMPACTION_PROMPT;
72013
72265
  var init_compaction = __esm(() => {
72014
72266
  init_dist6();
72015
72267
  init_AISDKModelFactory();
72016
72268
  init_AISDKStreamAdapter();
72017
72269
  init_contextWindowOverflow();
72270
+ LocalSlidingWindowCompactionPlanningError = class LocalSlidingWindowCompactionPlanningError extends Error {
72271
+ constructor(message) {
72272
+ super(message);
72273
+ this.name = "LocalSlidingWindowCompactionPlanningError";
72274
+ }
72275
+ };
72018
72276
  LOCAL_ALL_COMPACTION_PROMPT = `Your task is to create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions.
72019
72277
  This summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing development work without losing context. Your summary should include the following sections:
72020
72278
 
@@ -72038,6 +72296,24 @@ This summary should be thorough in capturing technical details, code patterns, a
72038
72296
  Write in first person as a factual record of what occurred. Be concise but thorough - the goal is to preserve enough context that the recent messages make sense and important information isn't lost to prevent duplicate work or repeated mistakes.
72039
72297
 
72040
72298
  Keep your summary under ${ALL_WORD_LIMIT} words. Only output the summary.`;
72299
+ LOCAL_SLIDING_WINDOW_COMPACTION_PROMPT = `The following messages are being evicted from the BEGINNING of your context window. Write a detailed summary that captures what happened in these messages to appear BEFORE the remaining recent messages in context, providing background for what comes after. Include the following sections:
72300
+
72301
+ 1.**High level goals**: What is the high level goal and ongoing task? Capture the user's explicit requests and intent in detail. If there is an existing summary in the transcript, make sure to take it into consideration to continue tracking the higher level goals and long-term progress.
72302
+
72303
+ 2. **What happened**: The conversations, tasks, and exchanges that took place. What did the user ask for? What did you do? How did things progress? If there is a previous summary being evicted, please extract a concise version of the critical info from it.
72304
+
72305
+ 3. **Important details**: Enumerate specific files and code sections examined, modified, or created, as well as important plan files, GitHub issues/PR links, and Linear ticket IDs. For each item, include why it matters and any relevant names, data, configs, or facts discussed.
72306
+ - **Preserve identifiers verbatim** (plan filename/path, exact URL, issue/PR number, ticket ID); do not paraphrase or truncate.
72307
+ - **Preserve referenced identifiers unless explicitly resolved**: Keep exact URLs/IDs from the conversation unless there is clear evidence they are no longer relevant.
72308
+ - Do not omit details likely to be referenced later.
72309
+
72310
+ 4. **Errors and fixes**: List all errors that you ran into, and how you fixed them. Pay special attention to specific user feedback that you received and record verbatim if useful.
72311
+
72312
+ 5. **Lookup hints**: For any detailed content (long lists, extensive data, specific conversations) that couldn't fit in the summary, note the topic and key terms that could be used to find it in message history later.
72313
+
72314
+ Write in first person as a factual record of what occurred. Be thorough and detailed - the goal is to preserve enough context that the recent messages make sense and important information isn't lost to prevent duplicate work or repeated mistakes.
72315
+
72316
+ Keep your summary under ${SLIDING_WORD_LIMIT} words. Only output the summary.`;
72041
72317
  });
72042
72318
 
72043
72319
  // src/backend/local/LocalModelConfig.ts
@@ -76285,6 +76561,9 @@ __export(exports_modify, {
76285
76561
  function supportsDistinctAnthropicXHighEffort(modelHandle) {
76286
76562
  return modelHandle.includes("claude-opus-4-7");
76287
76563
  }
76564
+ function isRecord5(value) {
76565
+ return typeof value === "object" && value !== null && !Array.isArray(value);
76566
+ }
76288
76567
  function buildModelSettings(modelHandle, updateArgs) {
76289
76568
  const isOpenAI = modelHandle.startsWith("openai/") || modelHandle.startsWith(`${OPENAI_CODEX_PROVIDER_NAME}/`);
76290
76569
  const isAnthropic = modelHandle.startsWith("anthropic/") || modelHandle.startsWith("claude-pro-max/") || modelHandle.startsWith("minimax/");
@@ -76407,6 +76686,12 @@ function buildModelSettings(modelHandle, updateArgs) {
76407
76686
  if (typeof updateArgs?.max_output_tokens === "number" && "provider_type" in settings) {
76408
76687
  settings.max_output_tokens = updateArgs.max_output_tokens;
76409
76688
  }
76689
+ if (isRecord5(updateArgs?.modalities)) {
76690
+ settings.modalities = updateArgs.modalities;
76691
+ }
76692
+ if (isRecord5(updateArgs?.capabilities)) {
76693
+ settings.capabilities = updateArgs.capabilities;
76694
+ }
76410
76695
  return settings;
76411
76696
  }
76412
76697
  async function updateAgentLLMConfig(agentId, modelHandle, updateArgs, options) {
@@ -78117,6 +78402,95 @@ function createTelegramAdapter(config2) {
78117
78402
  let botModule = null;
78118
78403
  let running = false;
78119
78404
  const bufferedMediaGroups = new Map;
78405
+ const typingByChatId = new Map;
78406
+ async function sendTypingAction(chatId) {
78407
+ if (!running)
78408
+ return;
78409
+ try {
78410
+ const telegramBot = await ensureBot();
78411
+ await telegramBot.api.sendChatAction(chatId, "typing");
78412
+ } catch (error51) {
78413
+ console.warn(`[Telegram] Failed to send typing action for chat ${chatId}:`, error51 instanceof Error ? error51.message : error51);
78414
+ }
78415
+ }
78416
+ function getTypingSourceKey(source) {
78417
+ const chatId = getTypingChatId(source);
78418
+ if (!chatId)
78419
+ return null;
78420
+ return [
78421
+ source.accountId ?? "",
78422
+ chatId,
78423
+ source.threadId ?? "",
78424
+ source.messageId ?? "",
78425
+ source.agentId,
78426
+ source.conversationId
78427
+ ].join(":");
78428
+ }
78429
+ function startTypingForSource(source) {
78430
+ const chatId = getTypingChatId(source);
78431
+ const sourceKey = getTypingSourceKey(source);
78432
+ if (!chatId || !sourceKey)
78433
+ return;
78434
+ const existing = typingByChatId.get(chatId);
78435
+ if (existing) {
78436
+ existing.sourceKeys.add(sourceKey);
78437
+ return;
78438
+ }
78439
+ sendTypingAction(chatId);
78440
+ const timer = setInterval(() => {
78441
+ sendTypingAction(chatId);
78442
+ }, TELEGRAM_TYPING_REFRESH_MS);
78443
+ const timeout = setTimeout(() => {
78444
+ clearTypingForChat(chatId);
78445
+ }, TELEGRAM_TYPING_MAX_MS);
78446
+ if (typeof timer.unref === "function") {
78447
+ timer.unref?.();
78448
+ }
78449
+ if (typeof timeout.unref === "function") {
78450
+ timeout.unref?.();
78451
+ }
78452
+ typingByChatId.set(chatId, {
78453
+ sourceKeys: new Set([sourceKey]),
78454
+ timer,
78455
+ timeout
78456
+ });
78457
+ }
78458
+ function stopTypingForSource(source) {
78459
+ const chatId = getTypingChatId(source);
78460
+ const sourceKey = getTypingSourceKey(source);
78461
+ if (!chatId || !sourceKey)
78462
+ return;
78463
+ const entry = typingByChatId.get(chatId);
78464
+ if (!entry)
78465
+ return;
78466
+ entry.sourceKeys.delete(sourceKey);
78467
+ if (entry.sourceKeys.size === 0) {
78468
+ clearTypingForChat(chatId);
78469
+ }
78470
+ }
78471
+ function clearTypingForChat(chatId) {
78472
+ const entry = typingByChatId.get(chatId);
78473
+ if (!entry)
78474
+ return;
78475
+ clearInterval(entry.timer);
78476
+ clearTimeout(entry.timeout);
78477
+ typingByChatId.delete(chatId);
78478
+ }
78479
+ function clearAllTyping() {
78480
+ for (const entry of typingByChatId.values()) {
78481
+ clearInterval(entry.timer);
78482
+ clearTimeout(entry.timeout);
78483
+ }
78484
+ typingByChatId.clear();
78485
+ }
78486
+ function getTypingChatId(source) {
78487
+ if (source.channel !== "telegram")
78488
+ return null;
78489
+ const chatId = source.chatId;
78490
+ if (typeof chatId !== "string" || chatId.length === 0)
78491
+ return null;
78492
+ return chatId;
78493
+ }
78120
78494
  async function ensureModule() {
78121
78495
  if (!botModule) {
78122
78496
  botModule = await loadGrammyModule();
@@ -78310,6 +78684,7 @@ function createTelegramAdapter(config2) {
78310
78684
  clearTimeout(entry.timer);
78311
78685
  }
78312
78686
  bufferedMediaGroups.clear();
78687
+ clearAllTyping();
78313
78688
  if (!running || !bot)
78314
78689
  return;
78315
78690
  await bot.stop();
@@ -78335,6 +78710,7 @@ function createTelegramAdapter(config2) {
78335
78710
  } else {
78336
78711
  await telegramBot.api.setMessageReaction(msg.chatId, Number(targetMessageId), []);
78337
78712
  }
78713
+ clearTypingForChat(msg.chatId);
78338
78714
  return { messageId: targetMessageId };
78339
78715
  }
78340
78716
  if (msg.mediaPath) {
@@ -78361,6 +78737,7 @@ function createTelegramAdapter(config2) {
78361
78737
  return await telegramBot.api.sendDocument(msg.chatId, inputFile, options);
78362
78738
  }
78363
78739
  })();
78740
+ clearTypingForChat(msg.chatId);
78364
78741
  return { messageId: String(result2.message_id) };
78365
78742
  }
78366
78743
  const opts = {};
@@ -78373,6 +78750,7 @@ function createTelegramAdapter(config2) {
78373
78750
  opts.parse_mode = msg.parseMode;
78374
78751
  }
78375
78752
  const result = await telegramBot.api.sendMessage(msg.chatId, msg.text, opts);
78753
+ clearTypingForChat(msg.chatId);
78376
78754
  return { messageId: String(result.message_id) };
78377
78755
  },
78378
78756
  async sendDirectReply(chatId, text2, options) {
@@ -78382,12 +78760,29 @@ function createTelegramAdapter(config2) {
78382
78760
  } : undefined;
78383
78761
  await telegramBot.api.sendMessage(chatId, text2, reply_parameters ? { reply_parameters } : {});
78384
78762
  },
78763
+ async handleTurnLifecycleEvent(event) {
78764
+ if (!running)
78765
+ return;
78766
+ if (event.type === "queued") {
78767
+ return;
78768
+ }
78769
+ if (event.type === "processing") {
78770
+ for (const source of event.sources) {
78771
+ startTypingForSource(source);
78772
+ }
78773
+ return;
78774
+ }
78775
+ for (const source of event.sources) {
78776
+ stopTypingForSource(source);
78777
+ }
78778
+ },
78385
78779
  async handleControlRequestEvent(event) {
78386
78780
  const telegramBot = await ensureBot();
78387
78781
  const reply_parameters = event.source.messageId || event.source.threadId ? {
78388
78782
  message_id: Number(event.source.threadId ?? event.source.messageId)
78389
78783
  } : undefined;
78390
78784
  await telegramBot.api.sendMessage(event.source.chatId, formatChannelControlRequestPrompt(event), reply_parameters ? { reply_parameters } : {});
78785
+ clearTypingForChat(event.source.chatId);
78391
78786
  },
78392
78787
  onMessage: undefined
78393
78788
  };
@@ -78404,9 +78799,11 @@ async function validateTelegramToken(token) {
78404
78799
  id: info.id
78405
78800
  };
78406
78801
  }
78802
+ var TELEGRAM_TYPING_REFRESH_MS = 4000, TELEGRAM_TYPING_MAX_MS;
78407
78803
  var init_adapter = __esm(() => {
78408
78804
  init_media();
78409
78805
  init_runtime();
78806
+ TELEGRAM_TYPING_MAX_MS = 5 * 60 * 1000;
78410
78807
  });
78411
78808
 
78412
78809
  // src/channels/telegram/messageActions.ts
@@ -78499,13 +78896,13 @@ function cloneAccount(account) {
78499
78896
  }
78500
78897
  return cloned;
78501
78898
  }
78502
- function isRecord5(value) {
78899
+ function isRecord6(value) {
78503
78900
  return !!value && typeof value === "object" && !Array.isArray(value);
78504
78901
  }
78505
78902
  function normalizeLoadedAccount(account) {
78506
78903
  const next = cloneAccount(account);
78507
78904
  if (!isFirstPartyChannelId(next.channel)) {
78508
- next.config = isRecord5(next.config) ? { ...next.config } : {};
78905
+ next.config = isRecord6(next.config) ? { ...next.config } : {};
78509
78906
  }
78510
78907
  if (isTelegramChannelAccount(next) && (next.displayName === "Telegram bot" || next.displayName === "Migrated Telegram bot") || isSlackChannelAccount(next) && (next.displayName === "Slack app" || next.displayName === "Migrated Slack app") || isDiscordChannelAccount(next) && (next.displayName === "Discord bot" || next.displayName === "Migrated Discord bot")) {
78511
78908
  next.displayName = undefined;
@@ -81006,6 +81403,12 @@ function resolveDiscordReactionEmoji(value) {
81006
81403
  };
81007
81404
  return nameMap[normalized] ?? normalized;
81008
81405
  }
81406
+ function buildDiscordIngressMessageKey(accountId, messageId) {
81407
+ if (!isNonEmptyString3(accountId) || !isNonEmptyString3(messageId)) {
81408
+ return null;
81409
+ }
81410
+ return `${accountId}:${messageId}`;
81411
+ }
81009
81412
  function buildDiscordReplyOptions(replyToMessageId, channelId) {
81010
81413
  const trimmed = replyToMessageId?.trim();
81011
81414
  if (!trimmed || trimmed === channelId) {
@@ -81013,7 +81416,8 @@ function buildDiscordReplyOptions(replyToMessageId, channelId) {
81013
81416
  }
81014
81417
  return {
81015
81418
  reply: {
81016
- messageReference: trimmed
81419
+ messageReference: trimmed,
81420
+ failIfNotExists: false
81017
81421
  }
81018
81422
  };
81019
81423
  }
@@ -81055,12 +81459,6 @@ function createDiscordAdapter(config2) {
81055
81459
  const seenIngressMessageKeys = new Map;
81056
81460
  const lifecycleStateByMessageKey = new Map;
81057
81461
  const lifecycleOperationByMessageKey = new Map;
81058
- function buildIngressMessageKey(channelId, messageId) {
81059
- if (!isNonEmptyString3(channelId) || !isNonEmptyString3(messageId)) {
81060
- return null;
81061
- }
81062
- return `${channelId}:${messageId}`;
81063
- }
81064
81462
  function pruneSeenIngressMessageKeys(now2 = Date.now()) {
81065
81463
  for (const [key, expiresAt] of seenIngressMessageKeys) {
81066
81464
  if (expiresAt <= now2) {
@@ -81079,8 +81477,8 @@ function createDiscordAdapter(config2) {
81079
81477
  }
81080
81478
  }
81081
81479
  }
81082
- function markIngressMessageSeen(channelId, messageId) {
81083
- const key = buildIngressMessageKey(channelId, messageId);
81480
+ function markIngressMessageSeen(messageId) {
81481
+ const key = buildDiscordIngressMessageKey(config2.accountId, messageId);
81084
81482
  if (!key)
81085
81483
  return false;
81086
81484
  const now2 = Date.now();
@@ -81270,7 +81668,7 @@ function createDiscordAdapter(config2) {
81270
81668
  const isThread = isThreadMessage(message);
81271
81669
  const wasMentioned = chatType === "channel" && hasBotMention(message);
81272
81670
  if (chatType === "direct") {
81273
- if (markIngressMessageSeen(message.channelId, message.id))
81671
+ if (markIngressMessageSeen(message.id))
81274
81672
  return;
81275
81673
  const attachments2 = await collectAttachments(message.attachments, message.channelId);
81276
81674
  if (!content && (!attachments2 || attachments2.length === 0))
@@ -81307,7 +81705,7 @@ function createDiscordAdapter(config2) {
81307
81705
  allowedChannels: config2.allowedChannels
81308
81706
  }))
81309
81707
  return;
81310
- if (markIngressMessageSeen(message.channelId, message.id))
81708
+ if (markIngressMessageSeen(message.id))
81311
81709
  return;
81312
81710
  let effectiveChatId = message.channelId;
81313
81711
  let effectiveThreadId = isThread ? message.channelId : null;
@@ -81778,7 +82176,7 @@ __export(exports_pluginRegistry, {
81778
82176
  import { existsSync as existsSync11, readdirSync as readdirSync3, readFileSync as readFileSync9 } from "node:fs";
81779
82177
  import { resolve as resolve6, sep } from "node:path";
81780
82178
  import { pathToFileURL as pathToFileURL2 } from "node:url";
81781
- function isRecord6(value) {
82179
+ function isRecord7(value) {
81782
82180
  return !!value && typeof value === "object" && !Array.isArray(value);
81783
82181
  }
81784
82182
  function isValidChannelId(value) {
@@ -81794,7 +82192,7 @@ function readChannelManifest(channelDir) {
81794
82192
  }
81795
82193
  try {
81796
82194
  const parsed = JSON.parse(readFileSync9(manifestPath, "utf-8"));
81797
- if (!isRecord6(parsed)) {
82195
+ if (!isRecord7(parsed)) {
81798
82196
  return null;
81799
82197
  }
81800
82198
  const id = typeof parsed.id === "string" ? parsed.id.trim() : "";
@@ -81838,8 +82236,8 @@ function createUserChannelRegistration(manifest) {
81838
82236
  throw new Error(`Channel plugin "${manifest.id}" entry escapes its directory.`);
81839
82237
  }
81840
82238
  const loadPromise = import(pathToFileURL2(entryPath).href).then((loaded) => {
81841
- const exported = (isRecord6(loaded) ? loaded.channelPlugin : undefined) ?? (isRecord6(loaded) ? loaded.default : undefined);
81842
- if (!isRecord6(exported)) {
82239
+ const exported = (isRecord7(loaded) ? loaded.channelPlugin : undefined) ?? (isRecord7(loaded) ? loaded.default : undefined);
82240
+ if (!isRecord7(exported)) {
81843
82241
  throw new Error(`Channel plugin "${manifest.id}" must export channelPlugin or default.`);
81844
82242
  }
81845
82243
  const plugin = exported;
@@ -82786,6 +83184,9 @@ function buildChannelNotificationXml(msg) {
82786
83184
  `chat_id="${escapeXmlAttribute(msg.chatId)}"`,
82787
83185
  `sender_id="${escapeXmlAttribute(msg.senderId)}"`
82788
83186
  ];
83187
+ if (msg.accountId) {
83188
+ attrs.push(`account_id="${escapeXmlAttribute(msg.accountId)}"`);
83189
+ }
82789
83190
  if (msg.senderName) {
82790
83191
  attrs.push(`sender_name="${escapeXmlAttribute(msg.senderName)}"`);
82791
83192
  }
@@ -83146,8 +83547,9 @@ class ChannelRegistry {
83146
83547
  }
83147
83548
  return matches[0] ?? null;
83148
83549
  }
83149
- getRouteForScope(channel, chatId, agentId, conversationId) {
83150
- const matches = getRoutesForChannel(channel).filter((route) => route.chatId === chatId && route.agentId === agentId && route.conversationId === conversationId && route.enabled);
83550
+ getRouteForScope(channel, chatId, agentId, conversationId, accountId) {
83551
+ const normalizedAccountId = accountId?.trim();
83552
+ const matches = getRoutesForChannel(channel).filter((route) => route.chatId === chatId && route.agentId === agentId && route.conversationId === conversationId && (!normalizedAccountId || (route.accountId ?? LEGACY_CHANNEL_ACCOUNT_ID) === normalizedAccountId) && route.enabled);
83151
83553
  if (matches.length !== 1) {
83152
83554
  return null;
83153
83555
  }
@@ -83741,6 +84143,7 @@ async function executeSingleDecision(decision, onChunk, options) {
83741
84143
  toolCallId: decision.approval.toolCallId,
83742
84144
  toolContextId: options?.toolContextId,
83743
84145
  parentScope: options?.parentScope,
84146
+ channelTurnSources: options?.channelTurnSources,
83744
84147
  onOutput: options?.onStreamingOutput ? (chunk, stream) => options.onStreamingOutput?.(decision.approval.toolCallId, chunk, stream === "stderr") : undefined,
83745
84148
  onFileWrite: options?.onFileWrite
83746
84149
  });
@@ -90350,8 +90753,7 @@ var init_readOnlyShell = __esm(() => {
90350
90753
  memory: new Set(["status", "help", "backups", "export", "tokens"]),
90351
90754
  memfs: new Set(["status", "help", "backups", "export", "tokens"]),
90352
90755
  agents: new Set(["list", "help"]),
90353
- messages: new Set(["search", "list", "help"]),
90354
- blocks: new Set(["list", "help"])
90756
+ messages: new Set(["search", "list", "help"])
90355
90757
  };
90356
90758
  SAFE_GH_COMMANDS = {
90357
90759
  pr: new Set(["list", "status", "checks", "diff", "view"]),
@@ -90828,7 +91230,7 @@ async function initSecretsFromServer(agentId, cachedAgent) {
90828
91230
  setCache(agentId, {});
90829
91231
  return;
90830
91232
  }
90831
- const agent = cachedAgent ?? await (await getClient()).agents.retrieve(agentId, {
91233
+ const agent = cachedAgent ?? await getBackend().retrieveAgent(agentId, {
90832
91234
  include: ["agent.secrets"]
90833
91235
  });
90834
91236
  const secrets2 = {};
@@ -90861,6 +91263,9 @@ async function refreshAndListSecrets(agentIdArg) {
90861
91263
  return Object.keys(cache3).sort().map((key) => ({ key, value: cache3[key] ?? "" }));
90862
91264
  }
90863
91265
  async function applySecretBatch(options, agentIdArg) {
91266
+ if (!getBackend().capabilities.serverSecrets) {
91267
+ throw new Error("Agent secrets are not supported by this backend yet");
91268
+ }
90864
91269
  const agentId = resolveSecretsAgentId(agentIdArg);
90865
91270
  if (!agentId) {
90866
91271
  throw new Error("No agent context set. Agent ID is required.");
@@ -90872,8 +91277,7 @@ async function applySecretBatch(options, agentIdArg) {
90872
91277
  for (const rawKey of options.unset ?? []) {
90873
91278
  delete next[rawKey.toUpperCase()];
90874
91279
  }
90875
- const client = await getClient();
90876
- await client.agents.update(agentId, { secrets: next });
91280
+ await getBackend().updateAgent(agentId, { secrets: next });
90877
91281
  setCache(agentId, next);
90878
91282
  return Object.keys(next).sort();
90879
91283
  }
@@ -90881,14 +91285,13 @@ async function setSecretOnServer(key, value, agentIdArg) {
90881
91285
  if (!getBackend().capabilities.serverSecrets) {
90882
91286
  throw new Error("Agent secrets are not supported by this backend yet");
90883
91287
  }
90884
- const client = await getClient();
90885
91288
  const agentId = resolveSecretsAgentId(agentIdArg);
90886
91289
  if (!agentId) {
90887
91290
  throw new Error("No agent context set. Agent ID is required.");
90888
91291
  }
90889
91292
  const secrets2 = { ...loadSecrets(agentId) };
90890
91293
  secrets2[key] = value;
90891
- await client.agents.update(agentId, { secrets: secrets2 });
91294
+ await getBackend().updateAgent(agentId, { secrets: secrets2 });
90892
91295
  setCache(agentId, secrets2);
90893
91296
  }
90894
91297
  async function deleteSecretOnServer(key, agentIdArg) {
@@ -90904,8 +91307,7 @@ async function deleteSecretOnServer(key, agentIdArg) {
90904
91307
  return false;
90905
91308
  }
90906
91309
  delete secrets2[key];
90907
- const client = await getClient();
90908
- await client.agents.update(agentId, { secrets: secrets2 });
91310
+ await getBackend().updateAgent(agentId, { secrets: secrets2 });
90909
91311
  setCache(agentId, secrets2);
90910
91312
  return true;
90911
91313
  }
@@ -90921,7 +91323,6 @@ var SECRETS_CACHE_KEY;
90921
91323
  var init_secretsStore = __esm(() => {
90922
91324
  init_context();
90923
91325
  init_backend2();
90924
- init_client2();
90925
91326
  SECRETS_CACHE_KEY = Symbol.for("@letta/secretsCache");
90926
91327
  });
90927
91328
 
@@ -93695,7 +94096,9 @@ function getShellEnv() {
93695
94096
  env.LETTA_AGENT_ID = agentId;
93696
94097
  env.AGENT_ID = agentId;
93697
94098
  try {
93698
- if (settingsManager.isMemfsEnabled(agentId) || process.env.LETTA_LOCAL_BACKEND_EXPERIMENTAL === "1" || process.env.LETTA_LOCAL_BACKEND_EXPERIMENTAL?.toLowerCase() === "true") {
94099
+ const localBackendNoMemfs = isLocalBackendNoMemfsEnvEnabled();
94100
+ const localBackendEnabled = process.env.LETTA_LOCAL_BACKEND_EXPERIMENTAL === "1" || process.env.LETTA_LOCAL_BACKEND_EXPERIMENTAL?.toLowerCase() === "true";
94101
+ if (!localBackendNoMemfs && (settingsManager.isMemfsEnabled(agentId) || localBackendEnabled)) {
93699
94102
  const memoryDir = resolveScopedMemoryDir({ agentId });
93700
94103
  if (!memoryDir) {
93701
94104
  throw new Error("Unable to resolve memory directory");
@@ -93763,6 +94166,7 @@ var init_shellEnv = __esm(() => {
93763
94166
  init_context();
93764
94167
  init_memoryFilesystem();
93765
94168
  init_client2();
94169
+ init_paths();
93766
94170
  init_runtime_context();
93767
94171
  init_settings_manager();
93768
94172
  });
@@ -96883,6 +97287,25 @@ function buildSyntheticChannelRoute(params) {
96883
97287
  updatedAt: now2
96884
97288
  };
96885
97289
  }
97290
+ function inferAccountIdFromChannelTurnSources(params) {
97291
+ const chatId = params.input.chatId;
97292
+ if (!chatId) {
97293
+ return;
97294
+ }
97295
+ const accountIds = new Set;
97296
+ for (const source of params.channelTurnSources ?? []) {
97297
+ if (source.channel !== params.input.channel || source.chatId !== chatId || source.agentId !== params.scope.agentId || source.conversationId !== params.scope.conversationId) {
97298
+ continue;
97299
+ }
97300
+ if (params.input.threadId !== undefined && (source.threadId ?? null) !== (params.input.threadId ?? null)) {
97301
+ continue;
97302
+ }
97303
+ if (source.accountId?.trim()) {
97304
+ accountIds.add(source.accountId.trim());
97305
+ }
97306
+ }
97307
+ return accountIds.size === 1 ? [...accountIds][0] : undefined;
97308
+ }
96886
97309
  async function resolveExplicitMessageChannelContext(params) {
96887
97310
  if (params.input.channel !== "slack") {
96888
97311
  return `Error: Explicit MessageChannel targets are not supported on ${params.input.channel}.`;
@@ -96933,9 +97356,14 @@ async function message_channel(args) {
96933
97356
  try {
96934
97357
  let executionContext;
96935
97358
  if (input.chatId) {
96936
- const route2 = registry2.getRouteForScope(input.channel, input.chatId, scope.agentId, scope.conversationId);
97359
+ const resolvedAccountId = input.accountId ?? inferAccountIdFromChannelTurnSources({
97360
+ input,
97361
+ scope,
97362
+ channelTurnSources: args.channelTurnSources
97363
+ });
97364
+ const route2 = registry2.getRouteForScope(input.channel, input.chatId, scope.agentId, scope.conversationId, resolvedAccountId);
96937
97365
  if (!route2) {
96938
- return `Error: No route for chat_id "${input.chatId}" on "${input.channel}" for this agent/conversation.`;
97366
+ return resolvedAccountId ? `Error: No route for chat_id "${input.chatId}" on "${input.channel}" account "${resolvedAccountId}" for this agent/conversation.` : `Error: No route for chat_id "${input.chatId}" on "${input.channel}" for this agent/conversation. If multiple channel accounts can receive this chat, pass accountId (from the channel notification's account_id) to disambiguate.`;
96939
97367
  }
96940
97368
  const adapter2 = registry2.getAdapter(input.channel, route2.accountId);
96941
97369
  if (!adapter2) {
@@ -110723,6 +111151,12 @@ var init_SearchFileContentGemini2 = __esm(() => {
110723
111151
  // src/agent/skills.ts
110724
111152
  var exports_skills = {};
110725
111153
  __export(exports_skills, {
111154
+ isUserInvocableSkill: () => isUserInvocableSkill,
111155
+ isModelInvocableSkill: () => isModelInvocableSkill,
111156
+ getLegacyAgentSkillsDir: () => getLegacyAgentSkillsDir,
111157
+ getFrontmatterStringList: () => getFrontmatterStringList,
111158
+ getFrontmatterString: () => getFrontmatterString,
111159
+ getFrontmatterBoolean: () => getFrontmatterBoolean,
110726
111160
  getBundledSkills: () => getBundledSkills,
110727
111161
  getAgentSkillsDir: () => getAgentSkillsDir,
110728
111162
  formatSkillsAsSystemReminder: () => formatSkillsAsSystemReminder,
@@ -110745,7 +111179,45 @@ function getBundledSkillsPath() {
110745
111179
  function compareSkills(a, b) {
110746
111180
  return a.id.localeCompare(b.id) || a.source.localeCompare(b.source) || a.path.localeCompare(b.path);
110747
111181
  }
111182
+ function stripSurroundingQuotes(value) {
111183
+ const trimmed = value.trim();
111184
+ if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
111185
+ return trimmed.slice(1, -1);
111186
+ }
111187
+ return trimmed;
111188
+ }
111189
+ function getFrontmatterString(frontmatter, key) {
111190
+ const value = frontmatter[key];
111191
+ return typeof value === "string" ? stripSurroundingQuotes(value) : undefined;
111192
+ }
111193
+ function getFrontmatterStringList(frontmatter, key) {
111194
+ const value = frontmatter[key];
111195
+ if (Array.isArray(value)) {
111196
+ return value.map(stripSurroundingQuotes).filter((item) => item.length > 0);
111197
+ }
111198
+ if (typeof value === "string") {
111199
+ return stripSurroundingQuotes(value).split(/\s+/).map((item) => item.trim()).filter((item) => item.length > 0);
111200
+ }
111201
+ return;
111202
+ }
111203
+ function getFrontmatterBoolean(frontmatter, key) {
111204
+ const value = getFrontmatterString(frontmatter, key)?.toLowerCase();
111205
+ if (value === "true")
111206
+ return true;
111207
+ if (value === "false")
111208
+ return false;
111209
+ return;
111210
+ }
111211
+ function isModelInvocableSkill(skill) {
111212
+ return skill.disableModelInvocation !== true;
111213
+ }
111214
+ function isUserInvocableSkill(skill) {
111215
+ return skill.userInvocable !== false;
111216
+ }
110748
111217
  function getAgentSkillsDir(agentId) {
111218
+ return join25(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "memory/skills");
111219
+ }
111220
+ function getLegacyAgentSkillsDir(agentId) {
110749
111221
  return join25(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "skills");
110750
111222
  }
110751
111223
  async function getBundledSkills() {
@@ -110788,6 +111260,12 @@ async function discoverSkills(projectSkillsPath = join25(process.cwd(), SKILLS_D
110788
111260
  }
110789
111261
  }
110790
111262
  if (agentId && includeSource("agent")) {
111263
+ const legacyDir = getLegacyAgentSkillsDir(agentId);
111264
+ const legacyResult = await discoverSkillsFromDir(legacyDir, "agent");
111265
+ allErrors.push(...legacyResult.errors);
111266
+ for (const skill of legacyResult.skills) {
111267
+ skillsById.set(skill.id, skill);
111268
+ }
110791
111269
  const agentSkillsDir = getAgentSkillsDir(agentId);
110792
111270
  const agentResult = await discoverSkillsFromDir(agentSkillsDir, "agent");
110793
111271
  allErrors.push(...agentResult.errors);
@@ -110871,7 +111349,7 @@ async function parseSkillFile(filePath, rootPath, source) {
110871
111349
  const defaultId = dirPath || "root";
110872
111350
  const id = (typeof frontmatter.id === "string" ? frontmatter.id : null) || defaultId;
110873
111351
  const name25 = (typeof frontmatter.name === "string" ? frontmatter.name : null) || (typeof frontmatter.title === "string" ? frontmatter.title : null) || (id.split("/").pop() ?? "").replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase());
110874
- let description = typeof frontmatter.description === "string" ? frontmatter.description : null;
111352
+ let description = getFrontmatterString(frontmatter, "description") ?? null;
110875
111353
  if (!description) {
110876
111354
  const firstParagraph = body.trim().split(`
110877
111355
 
@@ -110879,30 +111357,31 @@ async function parseSkillFile(filePath, rootPath, source) {
110879
111357
  description = firstParagraph || "No description available";
110880
111358
  }
110881
111359
  description = description.trim();
110882
- if (description.startsWith('"') && description.endsWith('"') || description.startsWith("'") && description.endsWith("'")) {
110883
- description = description.slice(1, -1);
110884
- }
110885
- let tags;
110886
- if (Array.isArray(frontmatter.tags)) {
110887
- tags = frontmatter.tags;
110888
- } else if (typeof frontmatter.tags === "string") {
110889
- tags = [frontmatter.tags];
110890
- }
111360
+ const whenToUse = getFrontmatterString(frontmatter, "when_to_use")?.trim();
111361
+ const modelDescription = whenToUse ? `${description}
111362
+
111363
+ When to use: ${whenToUse}` : description;
111364
+ const tags = getFrontmatterStringList(frontmatter, "tags");
110891
111365
  return {
110892
111366
  id,
110893
111367
  name: name25,
110894
- description,
110895
- category: typeof frontmatter.category === "string" ? frontmatter.category : undefined,
111368
+ description: modelDescription,
111369
+ whenToUse,
111370
+ argumentHint: getFrontmatterString(frontmatter, "argument-hint"),
111371
+ arguments: getFrontmatterStringList(frontmatter, "arguments"),
111372
+ disableModelInvocation: getFrontmatterBoolean(frontmatter, "disable-model-invocation") ?? false,
111373
+ userInvocable: getFrontmatterBoolean(frontmatter, "user-invocable") ?? true,
111374
+ category: getFrontmatterString(frontmatter, "category"),
110896
111375
  tags,
110897
111376
  path: filePath,
110898
111377
  source
110899
111378
  };
110900
111379
  }
110901
111380
  function formatSkillsAsSystemReminder(skills) {
110902
- if (skills.length === 0) {
111381
+ const lines = skills.filter(isModelInvocableSkill).sort(compareSkills).map((s) => `- ${s.id} (${s.source}): ${s.description}`);
111382
+ if (lines.length === 0) {
110903
111383
  return "";
110904
111384
  }
110905
- const lines = [...skills].sort(compareSkills).map((s) => `- ${s.id} (${s.source}): ${s.description}`);
110906
111385
  return `<system-reminder>
110907
111386
  The following skills are available for use with the Skill tool:
110908
111387
 
@@ -110936,6 +111415,15 @@ var init_skillContentRegistry = __esm(() => {
110936
111415
  });
110937
111416
 
110938
111417
  // src/tools/impl/Skill.ts
111418
+ var exports_Skill = {};
111419
+ __export(exports_Skill, {
111420
+ wrapSkillContent: () => wrapSkillContent,
111421
+ skill: () => skill,
111422
+ renderSkillContent: () => renderSkillContent,
111423
+ readSkillContent: () => readSkillContent,
111424
+ loadRenderedSkillContent: () => loadRenderedSkillContent,
111425
+ getResolvedSkillsDir: () => getResolvedSkillsDir
111426
+ });
110939
111427
  import { existsSync as existsSync23, readdirSync as readdirSync7 } from "node:fs";
110940
111428
  import { readFile as readFile10 } from "node:fs/promises";
110941
111429
  import { dirname as dirname12, join as join26 } from "node:path";
@@ -111020,6 +111508,83 @@ function getResolvedAgentId(args) {
111020
111508
  return;
111021
111509
  }
111022
111510
  }
111511
+ function splitSkillArguments(args) {
111512
+ const parts = [];
111513
+ const pattern = /"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|\S+/g;
111514
+ for (const match2 of args.matchAll(pattern)) {
111515
+ const raw = match2[1] ?? match2[2] ?? match2[0];
111516
+ parts.push(raw.replace(/\\(["'\\])/g, "$1"));
111517
+ }
111518
+ return parts;
111519
+ }
111520
+ function substituteSkillArguments(content, args, argumentNames) {
111521
+ const rawArgs = args?.trim() ?? "";
111522
+ if (!rawArgs) {
111523
+ return content;
111524
+ }
111525
+ const argParts = splitSkillArguments(rawArgs);
111526
+ let result = content;
111527
+ let substituted = false;
111528
+ result = result.replace(/\$ARGUMENTS\[(\d+)\]/g, (_match, index) => {
111529
+ substituted = true;
111530
+ return argParts[Number(index)] ?? "";
111531
+ });
111532
+ result = result.replace(/\$ARGUMENTS/g, () => {
111533
+ substituted = true;
111534
+ return rawArgs;
111535
+ });
111536
+ result = result.replace(/\$(\d+)\b/g, (_match, index) => {
111537
+ substituted = true;
111538
+ return argParts[Number(index)] ?? "";
111539
+ });
111540
+ for (const [index, name25] of (argumentNames ?? []).entries()) {
111541
+ const escapedName = name25.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
111542
+ const namePattern = new RegExp(`\\$${escapedName}\\b`, "g");
111543
+ result = result.replace(namePattern, () => {
111544
+ substituted = true;
111545
+ return argParts[index] ?? "";
111546
+ });
111547
+ }
111548
+ if (!substituted) {
111549
+ result = `${result.trimEnd()}
111550
+
111551
+ ARGUMENTS: ${rawArgs}`;
111552
+ }
111553
+ return result;
111554
+ }
111555
+ function renderSkillContent(skillName, skillContent, skillPath, options = {}) {
111556
+ const { frontmatter } = parseFrontmatter(skillContent);
111557
+ if (!options.allowDisabledModelInvocation && getFrontmatterBoolean(frontmatter, "disable-model-invocation") === true) {
111558
+ throw new Error(`Skill "${skillName}" is marked disable-model-invocation and can only be invoked directly by the user.`);
111559
+ }
111560
+ const skillDir = dirname12(skillPath);
111561
+ const hasExtras = hasAdditionalFiles(skillPath);
111562
+ const argumentNames = getFrontmatterStringList(frontmatter, "arguments");
111563
+ const withSkillDir = skillContent.replace(/<SKILL_DIR>/g, skillDir).replace(/\$\{CLAUDE_SKILL_DIR\}/g, skillDir);
111564
+ const withArguments = substituteSkillArguments(withSkillDir, options.args, argumentNames);
111565
+ const dirHeader = hasExtras ? `# Skill Directory: ${skillDir}
111566
+
111567
+ ` : "";
111568
+ return `${dirHeader}${withArguments}`;
111569
+ }
111570
+ async function loadRenderedSkillContent(skillName, options = {}) {
111571
+ const skillsDir = options.skillsDir ?? await getResolvedSkillsDir();
111572
+ const { content: skillContent, path: skillPath } = await readSkillContent(skillName, skillsDir, options.agentId);
111573
+ return renderSkillContent(skillName, skillContent, skillPath, options);
111574
+ }
111575
+ function escapeXmlAttribute2(value) {
111576
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
111577
+ }
111578
+ function wrapSkillContent(skillName, content) {
111579
+ if (/^[A-Za-z_][A-Za-z0-9_.-]*$/.test(skillName)) {
111580
+ return `<${skillName}>
111581
+ ${content}
111582
+ </${skillName}>`;
111583
+ }
111584
+ return `<skill name="${escapeXmlAttribute2(skillName)}">
111585
+ ${content}
111586
+ </skill>`;
111587
+ }
111023
111588
  async function skill(args) {
111024
111589
  validateRequiredParams(args, ["skill"], "Skill");
111025
111590
  const { skill: skillName, toolCallId } = args;
@@ -111029,18 +111594,13 @@ async function skill(args) {
111029
111594
  try {
111030
111595
  const agentId = getResolvedAgentId(args);
111031
111596
  const skillsDir = await getResolvedSkillsDir();
111032
- const { content: skillContent, path: skillPath } = await readSkillContent(skillName, skillsDir, agentId);
111033
- const skillDir = dirname12(skillPath);
111034
- const hasExtras = hasAdditionalFiles(skillPath);
111035
- const processedContent = hasExtras ? skillContent.replace(/<SKILL_DIR>/g, skillDir) : skillContent;
111036
- const dirHeader = hasExtras ? `# Skill Directory: ${skillDir}
111037
-
111038
- ` : "";
111039
- const fullContent = `${dirHeader}${processedContent}`;
111597
+ const fullContent = await loadRenderedSkillContent(skillName, {
111598
+ agentId,
111599
+ skillsDir,
111600
+ args: args.args
111601
+ });
111040
111602
  if (toolCallId) {
111041
- queueSkillContent(toolCallId, `<${skillName}>
111042
- ${fullContent}
111043
- </${skillName}>`);
111603
+ queueSkillContent(toolCallId, wrapSkillContent(skillName, fullContent));
111044
111604
  }
111045
111605
  return { message: `Launching skill: ${skillName}` };
111046
111606
  } catch (error51) {
@@ -111426,18 +111986,21 @@ var init_contextBudget = __esm(() => {
111426
111986
  // src/agent/subagents/manager.ts
111427
111987
  import { spawn as spawn5 } from "node:child_process";
111428
111988
  function getModelHandleFromAgent(agent) {
111989
+ const directModel = agent.model;
111990
+ if (directModel?.includes("/")) {
111991
+ return directModel;
111992
+ }
111429
111993
  const endpoint = agent.llm_config?.model_endpoint_type;
111430
111994
  const model = agent.llm_config?.model;
111431
111995
  if (endpoint && model) {
111432
111996
  return `${endpoint}/${model}`;
111433
111997
  }
111434
- return model || null;
111998
+ return directModel || model || null;
111435
111999
  }
111436
112000
  async function getPrimaryAgentModelHandle() {
111437
112001
  try {
111438
112002
  const agentId = getCurrentAgentId();
111439
- const client = await getClient();
111440
- const agent = await client.agents.retrieve(agentId);
112003
+ const agent = await getBackend().retrieveAgent(agentId);
111441
112004
  return { handle: getModelHandleFromAgent(agent), agent };
111442
112005
  } catch {
111443
112006
  return { handle: null, agent: null };
@@ -111707,6 +112270,8 @@ function resolveSubagentLauncher(cliArgs, options = {}) {
111707
112270
  function composeSubagentChildEnv(options) {
111708
112271
  const {
111709
112272
  parentProcessEnv,
112273
+ backendMode,
112274
+ localBackendStorageDir,
111710
112275
  parentAgentId,
111711
112276
  permissionMode: permissionMode2,
111712
112277
  inheritedPrimaryRoot,
@@ -111720,6 +112285,14 @@ function composeSubagentChildEnv(options) {
111720
112285
  LETTA_CODE_AGENT_ROLE: "subagent",
111721
112286
  ...parentAgentId && { LETTA_PARENT_AGENT_ID: parentAgentId }
111722
112287
  };
112288
+ if (backendMode === "local") {
112289
+ childEnv.LETTA_LOCAL_BACKEND_EXPERIMENTAL = "1";
112290
+ if (localBackendStorageDir) {
112291
+ childEnv.LETTA_LOCAL_BACKEND_DIR = localBackendStorageDir;
112292
+ }
112293
+ } else if (backendMode === "api") {
112294
+ childEnv.LETTA_LOCAL_BACKEND_EXPERIMENTAL = "0";
112295
+ }
111723
112296
  const nextScope = new Set([
111724
112297
  ...parseScopeList(parentProcessEnv.LETTA_MEMORY_SCOPE),
111725
112298
  ...cliPermissions.getMemoryScope()
@@ -111743,6 +112316,12 @@ function composeSubagentChildEnv(options) {
111743
112316
  }
111744
112317
  return childEnv;
111745
112318
  }
112319
+ function resolveSubagentInheritedPrimaryRoot(options) {
112320
+ if (options.backendMode === "local" && options.parentAgentId) {
112321
+ return getLocalBackendMemoryFilesystemRoot(options.parentAgentId, options.localBackendStorageDir ?? getLocalBackendStorageDir2());
112322
+ }
112323
+ return options.inheritedPrimaryRoot;
112324
+ }
111746
112325
  function getReflectionStartupNotice() {
111747
112326
  return `[Reflection startup context truncated: system prompt + initial message are capped at ~${REFLECTION_STARTUP_CONTEXT_TOKEN_LIMIT.toLocaleString()} estimated tokens. Some parent memory preview content was omitted; read files directly from MEMORY_DIR if needed.]`;
111748
112327
  }
@@ -111805,9 +112384,12 @@ ${userPrompt}`);
111805
112384
  }
111806
112385
  return hardTruncateReflectionPrompt(userPrompt, allowedPromptChars);
111807
112386
  }
111808
- function buildSubagentArgs(type, config2, model, userPrompt, existingAgentId, existingConversationId, maxTurns) {
112387
+ function buildSubagentArgs(type, config2, model, userPrompt, existingAgentId, existingConversationId, maxTurns, options = {}) {
111809
112388
  const args = [];
111810
112389
  const isDeployingExisting = Boolean(existingAgentId || existingConversationId);
112390
+ if (options.backendMode) {
112391
+ args.push("--backend", options.backendMode);
112392
+ }
111811
112393
  if (isDeployingExisting) {
111812
112394
  if (existingConversationId) {
111813
112395
  args.push("--conv", existingConversationId);
@@ -111879,7 +112461,9 @@ async function executeSubagent(type, config2, model, userPrompt, baseURL, subage
111879
112461
  updateSubagent(subagentId, { model });
111880
112462
  }
111881
112463
  try {
111882
- const cliArgs = buildSubagentArgs(type, config2, model, userPrompt, existingAgentId, existingConversationId, maxTurns);
112464
+ const activeBackend = getBackend();
112465
+ const backendMode = activeBackend.capabilities.localMemfs ? "local" : "api";
112466
+ const cliArgs = buildSubagentArgs(type, config2, model, userPrompt, existingAgentId, existingConversationId, maxTurns, { backendMode });
111883
112467
  const launcher = resolveSubagentLauncher(cliArgs);
111884
112468
  let parentAgentId = parentAgentIdOverride;
111885
112469
  if (!parentAgentId) {
@@ -111893,19 +112477,28 @@ async function executeSubagent(type, config2, model, userPrompt, baseURL, subage
111893
112477
  const inheritedMemoryRoots = resolveAllowedMemoryRoots({
111894
112478
  currentAgentId: parentAgentId ?? null
111895
112479
  });
112480
+ const localBackendStorageDir = backendMode === "local" ? getLocalBackendStorageDir2() : null;
112481
+ const inheritedPrimaryRoot = resolveSubagentInheritedPrimaryRoot({
112482
+ backendMode,
112483
+ parentAgentId,
112484
+ inheritedPrimaryRoot: inheritedMemoryRoots.primaryRoot,
112485
+ localBackendStorageDir
112486
+ });
111896
112487
  const subagentWorkingDirectory = resolveSubagentWorkingDirectory(process.env, getCurrentWorkingDirectory(), {
111897
112488
  subagentType: type,
111898
112489
  permissionMode: config2.permissionMode,
111899
- inheritedPrimaryRoot: inheritedMemoryRoots.primaryRoot
112490
+ inheritedPrimaryRoot
111900
112491
  });
111901
112492
  const childEnv = composeSubagentChildEnv({
111902
112493
  parentProcessEnv: {
111903
112494
  ...process.env,
111904
112495
  USER_CWD: subagentWorkingDirectory
111905
112496
  },
112497
+ backendMode,
112498
+ localBackendStorageDir,
111906
112499
  parentAgentId,
111907
112500
  permissionMode: config2.permissionMode,
111908
- inheritedPrimaryRoot: inheritedMemoryRoots.primaryRoot,
112501
+ inheritedPrimaryRoot,
111909
112502
  inheritedApiKey,
111910
112503
  inheritedBaseUrl
111911
112504
  });
@@ -112091,7 +112684,7 @@ async function spawnSubagent(type, prompt, userModel, subagentId, signal, existi
112091
112684
  let finalPrompt = prompt;
112092
112685
  if (isDeployingExisting && resolvedParentAgentId) {
112093
112686
  try {
112094
- const cachedParent = parentAgent ?? await (await getClient()).agents.retrieve(resolvedParentAgentId);
112687
+ const cachedParent = parentAgent ?? await getBackend().retrieveAgent(resolvedParentAgentId);
112095
112688
  if (forkedContext) {
112096
112689
  const systemReminder = buildForkSystemReminder(type);
112097
112690
  finalPrompt = systemReminder + prompt;
@@ -112106,8 +112699,9 @@ async function spawnSubagent(type, prompt, userModel, subagentId, signal, existi
112106
112699
  }
112107
112700
  var BYOK_PROVIDER_TO_BASE;
112108
112701
  var init_manager3 = __esm(() => {
112109
- init_client2();
112702
+ init_backend2();
112110
112703
  init_metadata();
112704
+ init_paths();
112111
112705
  init_subagentState();
112112
112706
  init_constants();
112113
112707
  init_cli();
@@ -112135,22 +112729,6 @@ var init_manager3 = __esm(() => {
112135
112729
  };
112136
112730
  });
112137
112731
 
112138
- // src/backend/api/conversations.ts
112139
- var exports_conversations = {};
112140
- __export(exports_conversations, {
112141
- forkConversation: () => forkConversation
112142
- });
112143
- async function forkConversation(conversationId, options = {}) {
112144
- const query = {
112145
- ...options.agentId ? { agent_id: options.agentId } : {},
112146
- ...options.hidden !== undefined ? { hidden: options.hidden } : {}
112147
- };
112148
- return apiRequest("POST", `/v1/conversations/${encodeURIComponent(conversationId)}/fork`, undefined, { query });
112149
- }
112150
- var init_conversations2 = __esm(() => {
112151
- init_request();
112152
- });
112153
-
112154
112732
  // src/cli/helpers/messageQueueBridge.ts
112155
112733
  function setMessageQueueAdder(fn) {
112156
112734
  queueAdder = fn;
@@ -112568,7 +113146,7 @@ async function task(args) {
112568
113146
  try {
112569
113147
  const parentAgentId = getCurrentAgentId();
112570
113148
  const parentConvId = getConversationId() ?? "default";
112571
- const forkedConv = await forkConversation(parentConvId, {
113149
+ const forkedConv = await getBackend().forkConversation(parentConvId, {
112572
113150
  ...parentConvId === "default" ? { agentId: parentAgentId } : {},
112573
113151
  hidden: true
112574
113152
  });
@@ -112666,7 +113244,7 @@ var init_Task2 = __esm(() => {
112666
113244
  init_context();
112667
113245
  init_subagents();
112668
113246
  init_manager3();
112669
- init_conversations2();
113247
+ init_backend2();
112670
113248
  init_messageQueueBridge();
112671
113249
  init_subagentState();
112672
113250
  init_hooks();
@@ -116911,7 +117489,7 @@ function detectSkillScript(command, workingDir) {
116911
117489
  if (projectSkill) {
116912
117490
  return projectSkill;
116913
117491
  }
116914
- const agentRegex = new RegExp(`^${escapeRegex4(normalizedHomeDir)}/\\.letta/agents/[^/]+/skills/(.+?)/scripts/`);
117492
+ const agentRegex = new RegExp(`^${escapeRegex4(normalizedHomeDir)}/\\.letta/agents/[^/]+/(?:memory/)?skills/(.+?)/scripts/`);
116915
117493
  const agentSkill = detect("agent-scoped", agentRegex);
116916
117494
  if (agentSkill) {
116917
117495
  return agentSkill;
@@ -117784,14 +118362,14 @@ function clipToolReturn(text2, maxLines = 3, maxChars = 300) {
117784
118362
  }
117785
118363
  return clipped;
117786
118364
  }
117787
- function isRecord7(value) {
118365
+ function isRecord8(value) {
117788
118366
  return typeof value === "object" && value !== null;
117789
118367
  }
117790
118368
  function isStringArray2(value) {
117791
118369
  return Array.isArray(value) && value.every((item) => typeof item === "string");
117792
118370
  }
117793
118371
  function isMultimodalContent(arr) {
117794
- return arr.every((item) => isRecord7(item) && (item.type === "text" || item.type === "image"));
118372
+ return arr.every((item) => isRecord8(item) && (item.type === "text" || item.type === "image"));
117795
118373
  }
117796
118374
  function flattenToolResponse(result) {
117797
118375
  if (result === null || result === undefined) {
@@ -117800,7 +118378,7 @@ function flattenToolResponse(result) {
117800
118378
  if (typeof result === "string") {
117801
118379
  return result;
117802
118380
  }
117803
- if (!isRecord7(result)) {
118381
+ if (!isRecord8(result)) {
117804
118382
  return JSON.stringify(result);
117805
118383
  }
117806
118384
  if (typeof result.message === "string") {
@@ -117817,7 +118395,7 @@ function flattenToolResponse(result) {
117817
118395
  return result.content;
117818
118396
  }
117819
118397
  if (Array.isArray(result.content)) {
117820
- const textContent2 = result.content.filter((item) => isRecord7(item) && item.type === "text" && typeof item.text === "string").map((item) => item.text).join(`
118398
+ const textContent2 = result.content.filter((item) => isRecord8(item) && item.type === "text" && typeof item.text === "string").map((item) => item.text).join(`
117821
118399
  `);
117822
118400
  if (textContent2) {
117823
118401
  return textContent2;
@@ -117932,8 +118510,16 @@ async function executeTool2(name25, args, options) {
117932
118510
  if (internalName === "Skill" && options?.parentScope) {
117933
118511
  enhancedArgs = { ...enhancedArgs, parentScope: options.parentScope };
117934
118512
  }
117935
- if (internalName === "MessageChannel" && options?.parentScope) {
117936
- enhancedArgs = { ...enhancedArgs, parentScope: options.parentScope };
118513
+ if (internalName === "MessageChannel") {
118514
+ if (options?.parentScope) {
118515
+ enhancedArgs = { ...enhancedArgs, parentScope: options.parentScope };
118516
+ }
118517
+ if (options?.channelTurnSources?.length) {
118518
+ enhancedArgs = {
118519
+ ...enhancedArgs,
118520
+ channelTurnSources: options.channelTurnSources
118521
+ };
118522
+ }
117937
118523
  }
117938
118524
  const PLAN_MODE_TOOL_NAMES = new Set([
117939
118525
  "EnterPlanMode",
@@ -117960,7 +118546,7 @@ async function executeTool2(name25, args, options) {
117960
118546
  } catch {}
117961
118547
  }
117962
118548
  }
117963
- const recordResult = isRecord7(result) ? result : undefined;
118549
+ const recordResult = isRecord8(result) ? result : undefined;
117964
118550
  const stdoutValue = recordResult?.stdout;
117965
118551
  const stderrValue = recordResult?.stderr;
117966
118552
  const stdout = isStringArray2(stdoutValue) ? stdoutValue : undefined;
@@ -118694,9 +119280,8 @@ async function hydrateMemfsSettingFromAgent(agent) {
118694
119280
  return enabled;
118695
119281
  }
118696
119282
  async function isMemfsEnabledOnServer(agentId) {
118697
- const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
118698
- const client = await getClient2();
118699
- const agent = await client.agents.retrieve(agentId, {
119283
+ const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
119284
+ const agent = await getBackend2().retrieveAgent(agentId, {
118700
119285
  include: ["agent.tags"]
118701
119286
  });
118702
119287
  const { GIT_MEMORY_ENABLED_TAG: GIT_MEMORY_ENABLED_TAG2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
@@ -118829,7 +119414,8 @@ async function applyMemfsFlags(agentId, memfsFlag, noMemfsFlag, options) {
118829
119414
  const backend = getBackend2();
118830
119415
  if (backend.capabilities.localMemfs) {
118831
119416
  if (noMemfsFlag) {
118832
- throw new Error("Disabling MemFS is not supported by the local backend.");
119417
+ settingsManager2.setMemfsEnabled(agentId, false);
119418
+ return { action: "disabled" };
118833
119419
  }
118834
119420
  const memoryDir = getScopedMemoryFilesystemRoot(agentId);
118835
119421
  const { initializeLocalMemoryRepo: initializeLocalMemoryRepo2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
@@ -119285,7 +119871,7 @@ ${skillsBlock.trimStart()}`;
119285
119871
  function compileLocalSystemPrompt(options) {
119286
119872
  const compiledAt = options.now ?? new Date;
119287
119873
  const memoryDir = options.memoryDir ?? getMemoryFilesystemRoot(options.agent.id);
119288
- const memfs = renderMemfsProjection(memoryDir);
119874
+ const memfs = options.includeMemfs === false ? { content: "", revision: undefined } : renderMemfsProjection(memoryDir);
119289
119875
  const metadata = compileMemoryMetadata({
119290
119876
  agentId: options.agent.id,
119291
119877
  conversationId: options.conversationId,
@@ -119357,6 +119943,37 @@ function initialMemoryFilesFromCreateBody(body) {
119357
119943
  }
119358
119944
  return [...files.values()].sort((a, b) => a.relativePath.localeCompare(b.relativePath));
119359
119945
  }
119946
+ function isRecord9(value) {
119947
+ return typeof value === "object" && value !== null && !Array.isArray(value);
119948
+ }
119949
+ function compactionSettingsRecord(value) {
119950
+ if (value === null)
119951
+ return null;
119952
+ return isRecord9(value) ? { ...value } : undefined;
119953
+ }
119954
+ function hasOwn2(record2, key) {
119955
+ return Object.hasOwn(record2, key);
119956
+ }
119957
+ function localCompactionMode(value) {
119958
+ if (value === "all" || value === "sliding_window")
119959
+ return value;
119960
+ return;
119961
+ }
119962
+ function validateLocalCompactionSettingsRecord(settings) {
119963
+ if (settings.mode === undefined || settings.mode === null)
119964
+ return;
119965
+ if (!localCompactionMode(settings.mode)) {
119966
+ throw new Error(`Local backend compaction currently supports only modes "all" and "sliding_window" (received "${String(settings.mode)}").`);
119967
+ }
119968
+ }
119969
+ function localCompactionSettingsForStorage(settings) {
119970
+ if (settings === undefined || settings === null)
119971
+ return settings;
119972
+ const hasLocalSetting = hasOwn2(settings, "mode") || hasOwn2(settings, "prompt") || hasOwn2(settings, "clip_chars") || hasOwn2(settings, "sliding_window_percentage");
119973
+ if (!hasLocalSetting)
119974
+ return;
119975
+ return { ...settings };
119976
+ }
119360
119977
  function createLocalExecutor(options, onContextWindowOverflow, onContextUsage) {
119361
119978
  if (options.executor)
119362
119979
  return options.executor;
@@ -119396,6 +120013,7 @@ var init_LocalBackend = __esm(() => {
119396
120013
  storageDir;
119397
120014
  createModel;
119398
120015
  generateText;
120016
+ memfsEnabledOverride;
119399
120017
  constructor(options) {
119400
120018
  const localBackendRef = {};
119401
120019
  const modelConfig = resolveLocalModelConfig(options.storageDir);
@@ -119421,19 +120039,46 @@ var init_LocalBackend = __esm(() => {
119421
120039
  this.memoryDir = options.memoryDir;
119422
120040
  this.createModel = options.createModel;
119423
120041
  this.generateText = options.generateText;
120042
+ this.memfsEnabledOverride = options.memfsEnabled;
119424
120043
  }
119425
120044
  async listModels() {
119426
120045
  return listLocalModels(this.storageDir);
119427
120046
  }
119428
120047
  async createAgent(...args) {
119429
120048
  const [body] = args;
119430
- const agent = await super.createAgent(...args);
119431
- await this.ensureLocalMemoryRepo(agent.id, initialMemoryFilesFromCreateBody(body), agent.name ?? undefined);
120049
+ const requestedCompactionSettings = compactionSettingsRecord(body.compaction_settings);
120050
+ if (requestedCompactionSettings !== undefined && requestedCompactionSettings !== null) {
120051
+ validateLocalCompactionSettingsRecord(requestedCompactionSettings);
120052
+ }
120053
+ const compactionSettingsForStorage = localCompactionSettingsForStorage(requestedCompactionSettings);
120054
+ let agent = await super.createAgent(...args);
120055
+ if (compactionSettingsForStorage !== undefined) {
120056
+ agent = this.store.setAgentCompactionSettings(agent.id, compactionSettingsForStorage);
120057
+ }
120058
+ if (this.isLocalMemfsEnabled()) {
120059
+ await this.ensureLocalMemoryRepo(agent.id, initialMemoryFilesFromCreateBody(body), agent.name ?? undefined);
120060
+ }
119432
120061
  await this.compileAndMaybePersistSystemPrompt("default", agent.id, {
119433
120062
  dryRun: false
119434
120063
  });
119435
120064
  return agent;
119436
120065
  }
120066
+ async updateAgent(...args) {
120067
+ const [agentId, body] = args;
120068
+ const bodyRecord = body;
120069
+ const settings = hasOwn2(bodyRecord, "compaction_settings") ? compactionSettingsRecord(bodyRecord.compaction_settings) : undefined;
120070
+ if (settings !== undefined && settings !== null) {
120071
+ validateLocalCompactionSettingsRecord(settings);
120072
+ }
120073
+ const compactionSettingsForStorage = localCompactionSettingsForStorage(settings);
120074
+ let agent = await super.updateAgent(...args);
120075
+ if (hasOwn2(bodyRecord, "compaction_settings")) {
120076
+ if (compactionSettingsForStorage !== undefined) {
120077
+ agent = this.store.setAgentCompactionSettings(agentId, compactionSettingsForStorage);
120078
+ }
120079
+ }
120080
+ return agent;
120081
+ }
119437
120082
  async createConversation(body) {
119438
120083
  const conversation = await super.createConversation(body);
119439
120084
  await this.compileAndMaybePersistSystemPrompt(conversation.id, conversation.agent_id, { dryRun: false });
@@ -119448,7 +120093,7 @@ var init_LocalBackend = __esm(() => {
119448
120093
  async compactConversationMessages(conversationId, body) {
119449
120094
  const bodyRecord = body ?? {};
119450
120095
  const agentId = typeof bodyRecord.agent_id === "string" && bodyRecord.agent_id.length > 0 ? bodyRecord.agent_id : this.store.resolveAgentIdForConversation(conversationId);
119451
- const result = await this.compactLocalConversationAll(conversationId, agentId, "manual", body);
120096
+ const result = await this.compactLocalConversation(conversationId, agentId, "manual", body);
119452
120097
  return {
119453
120098
  num_messages_before: result.numMessagesBefore,
119454
120099
  num_messages_after: result.numMessagesAfter,
@@ -119463,6 +120108,9 @@ var init_LocalBackend = __esm(() => {
119463
120108
  memoryDirForAgent(agentId) {
119464
120109
  return this.memoryDir ?? getLocalBackendMemoryFilesystemRoot(agentId, this.storageDir);
119465
120110
  }
120111
+ isLocalMemfsEnabled() {
120112
+ return this.memfsEnabledOverride ?? !isLocalBackendNoMemfsEnvEnabled();
120113
+ }
119466
120114
  async ensureLocalMemoryRepo(agentId, files = [], authorName) {
119467
120115
  await initializeLocalMemoryRepo({
119468
120116
  memoryDir: this.memoryDirForAgent(agentId),
@@ -119472,9 +120120,7 @@ var init_LocalBackend = __esm(() => {
119472
120120
  });
119473
120121
  }
119474
120122
  async compactAfterContextOverflow(input, _error) {
119475
- const result = await this.compactLocalConversationAll(input.conversationId, input.agentId, "context_window_overflow", {
119476
- compaction_settings: { mode: "all" }
119477
- });
120123
+ const result = await this.compactLocalConversation(input.conversationId, input.agentId, "context_window_overflow");
119478
120124
  return {
119479
120125
  uiMessages: this.store.listLocalMessages(input.conversationId, input.agentId),
119480
120126
  summary: result.summary,
@@ -119487,9 +120133,7 @@ var init_LocalBackend = __esm(() => {
119487
120133
  if (contextTokens === undefined || contextWindow === undefined || contextTokens <= contextWindow) {
119488
120134
  return null;
119489
120135
  }
119490
- const result = await this.compactLocalConversationAll(input.conversationId, input.agentId, "context_window_limit", {
119491
- compaction_settings: { mode: "all" }
119492
- });
120136
+ const result = await this.compactLocalConversation(input.conversationId, input.agentId, "context_window_limit");
119493
120137
  return {
119494
120138
  uiMessages: this.store.listLocalMessages(input.conversationId, input.agentId),
119495
120139
  summary: result.summary,
@@ -119508,24 +120152,55 @@ var init_LocalBackend = __esm(() => {
119508
120152
  const agent = this.store.retrieveAgentRecord(agentId);
119509
120153
  return typeof agent.model_settings.context_window_limit === "number" ? agent.model_settings.context_window_limit : undefined;
119510
120154
  }
119511
- async compactLocalConversationAll(conversationId, agentId, trigger, body) {
119512
- const settings = (body ?? {}).compaction_settings;
119513
- const mode = typeof settings?.mode === "string" ? settings.mode : "all";
119514
- if (mode !== "all") {
119515
- throw new Error(`Local backend compaction currently supports only mode "all" (received "${mode}").`);
119516
- }
120155
+ resolveCompactionSettings(agent, body) {
120156
+ const bodyRecord = body ?? {};
120157
+ const requestSettings = compactionSettingsRecord(bodyRecord.compaction_settings);
120158
+ if (requestSettings !== undefined && requestSettings !== null) {
120159
+ validateLocalCompactionSettingsRecord(requestSettings);
120160
+ }
120161
+ const agentSettings = compactionSettingsRecord(agent.compaction_settings);
120162
+ const baseSettings = agentSettings && agentSettings !== null ? agentSettings : {};
120163
+ const mergedSettings = requestSettings && requestSettings !== null ? { ...baseSettings, ...requestSettings } : baseSettings;
120164
+ const requestChangedMode = requestSettings !== undefined && requestSettings !== null && hasOwn2(requestSettings, "mode");
120165
+ const requestChangedPrompt = requestSettings !== undefined && requestSettings !== null && hasOwn2(requestSettings, "prompt");
120166
+ if (requestChangedMode && !requestChangedPrompt && agentSettings && agentSettings !== null && agentSettings.mode !== requestSettings.mode) {
120167
+ delete mergedSettings.prompt;
120168
+ }
120169
+ const mode = localCompactionMode(mergedSettings.mode) ?? LOCAL_DEFAULT_COMPACTION_MODE;
120170
+ return {
120171
+ mode,
120172
+ prompt: typeof mergedSettings.prompt === "string" || mergedSettings.prompt === null ? mergedSettings.prompt : undefined,
120173
+ clipChars: typeof mergedSettings.clip_chars === "number" || mergedSettings.clip_chars === null ? mergedSettings.clip_chars : undefined,
120174
+ slidingWindowPercentage: typeof mergedSettings.sliding_window_percentage === "number" ? mergedSettings.sliding_window_percentage : LOCAL_DEFAULT_SLIDING_WINDOW_PERCENTAGE
120175
+ };
120176
+ }
120177
+ async compactLocalConversation(conversationId, agentId, trigger, body) {
119517
120178
  const agent = this.store.retrieveAgentRecord(agentId);
120179
+ const settings = this.resolveCompactionSettings(agent, body);
120180
+ if (settings.mode === "sliding_window") {
120181
+ try {
120182
+ return await this.compactLocalConversationSlidingWindow(conversationId, agentId, agent, trigger, settings);
120183
+ } catch (error51) {
120184
+ if (!isLocalSlidingWindowCompactionPlanningError(error51))
120185
+ throw error51;
120186
+ }
120187
+ }
120188
+ return this.compactLocalConversationAll(conversationId, agentId, agent, trigger, {
120189
+ ...settings,
120190
+ mode: "all",
120191
+ prompt: settings.mode === "all" ? settings.prompt : undefined
120192
+ });
120193
+ }
120194
+ async compactLocalConversationAll(conversationId, agentId, agent, trigger, settings) {
119518
120195
  const messages = this.store.listLocalMessages(conversationId, agentId);
119519
120196
  const contextTokensBefore = estimateLocalMessageTokens(messages);
119520
- const prompt = typeof settings?.prompt === "string" ? settings.prompt : null;
119521
- const clipChars = typeof settings?.clip_chars === "number" || settings?.clip_chars === null ? settings.clip_chars : undefined;
119522
120197
  const summary = await summarizeLocalMessagesAll({
119523
120198
  agent,
119524
120199
  messages,
119525
120200
  createModel: this.createModel,
119526
120201
  generateText: this.generateText,
119527
- prompt,
119528
- clipChars,
120202
+ prompt: settings.prompt,
120203
+ clipChars: settings.clipChars,
119529
120204
  localProviderAuthStorageDir: this.storageDir
119530
120205
  });
119531
120206
  const stats = {
@@ -119550,10 +120225,51 @@ var init_LocalBackend = __esm(() => {
119550
120225
  stats
119551
120226
  };
119552
120227
  }
120228
+ async compactLocalConversationSlidingWindow(conversationId, agentId, agent, trigger, settings) {
120229
+ const messages = this.store.listLocalMessages(conversationId, agentId);
120230
+ const contextWindow = this.effectiveContextWindow(conversationId, agentId);
120231
+ const plan = planLocalSlidingWindowCompaction(messages, {
120232
+ slidingWindowPercentage: settings.slidingWindowPercentage,
120233
+ contextWindow
120234
+ });
120235
+ const summary = await summarizeLocalMessagesSlidingWindow({
120236
+ agent,
120237
+ messages: plan.messagesToSummarize,
120238
+ createModel: this.createModel,
120239
+ generateText: this.generateText,
120240
+ prompt: settings.prompt,
120241
+ clipChars: settings.clipChars,
120242
+ localProviderAuthStorageDir: this.storageDir
120243
+ });
120244
+ const contextTokensAfter = Math.ceil(summary.length / 4) + estimateLocalMessageTokens(plan.messagesToKeep);
120245
+ const stats = {
120246
+ trigger,
120247
+ context_tokens_before: estimateLocalMessageTokens(messages),
120248
+ context_tokens_after: contextTokensAfter,
120249
+ context_window: contextWindow,
120250
+ messages_count_before: messages.length,
120251
+ messages_count_after: 1 + plan.messagesToKeep.length
120252
+ };
120253
+ const storeResult = this.store.compactConversationAll({
120254
+ conversationId,
120255
+ agentId,
120256
+ summary,
120257
+ packedSummary: packageLocalSummaryMessage(summary, stats),
120258
+ stats,
120259
+ remainingMessages: plan.messagesToKeep
120260
+ });
120261
+ return {
120262
+ numMessagesBefore: storeResult.numMessagesBefore,
120263
+ numMessagesAfter: storeResult.numMessagesAfter,
120264
+ summary,
120265
+ stats
120266
+ };
120267
+ }
119553
120268
  async getOrCompileSystemPrompt(conversationId, agentId, agent = this.store.retrieveAgentRecord(agentId), previousMessageCount = 0) {
119554
120269
  const existing = this.store.getCompiledSystemPrompt(conversationId, agentId);
119555
- const memfsRevision = await getMemoryHeadRevision(this.memoryDirForAgent(agentId));
119556
- if (existing?.rawSystemHash === hashRawSystemPrompt(agent.system) && memfsRevision !== null && existing.memfsRevision === memfsRevision) {
120270
+ const memfsEnabled = this.isLocalMemfsEnabled();
120271
+ const memfsRevision = memfsEnabled ? await getMemoryHeadRevision(this.memoryDirForAgent(agentId)) : undefined;
120272
+ if (existing?.rawSystemHash === hashRawSystemPrompt(agent.system) && (memfsEnabled ? memfsRevision !== null && existing.memfsRevision === memfsRevision : existing.memfsRevision === undefined)) {
119557
120273
  return existing;
119558
120274
  }
119559
120275
  return this.compileAndMaybePersistSystemPrompt(conversationId, agentId, {
@@ -119563,7 +120279,10 @@ var init_LocalBackend = __esm(() => {
119563
120279
  }
119564
120280
  async compileAndMaybePersistSystemPrompt(conversationId, agentId, options) {
119565
120281
  const agent = this.store.retrieveAgentRecord(agentId);
119566
- await this.ensureLocalMemoryRepo(agentId, [], agent.name);
120282
+ const memfsEnabled = this.isLocalMemfsEnabled();
120283
+ if (memfsEnabled) {
120284
+ await this.ensureLocalMemoryRepo(agentId, [], agent.name);
120285
+ }
119567
120286
  const previousMessageCount = options.previousMessageCount ?? this.store.listConversationMessages(conversationId, {
119568
120287
  agent_id: agentId,
119569
120288
  order: "asc"
@@ -119572,7 +120291,8 @@ var init_LocalBackend = __esm(() => {
119572
120291
  agent,
119573
120292
  conversationId,
119574
120293
  previousMessageCount,
119575
- memoryDir: this.memoryDirForAgent(agentId)
120294
+ memoryDir: memfsEnabled ? this.memoryDirForAgent(agentId) : undefined,
120295
+ includeMemfs: memfsEnabled
119576
120296
  });
119577
120297
  if (!options.dryRun) {
119578
120298
  this.store.setCompiledSystemPrompt(conversationId, agentId, compiled);
@@ -119582,6 +120302,22 @@ var init_LocalBackend = __esm(() => {
119582
120302
  };
119583
120303
  });
119584
120304
 
120305
+ // src/backend/api/conversations.ts
120306
+ var exports_conversations = {};
120307
+ __export(exports_conversations, {
120308
+ forkConversation: () => forkConversation
120309
+ });
120310
+ async function forkConversation(conversationId, options = {}) {
120311
+ const query = {
120312
+ ...options.agentId ? { agent_id: options.agentId } : {},
120313
+ ...options.hidden !== undefined ? { hidden: options.hidden } : {}
120314
+ };
120315
+ return apiRequest("POST", `/v1/conversations/${encodeURIComponent(conversationId)}/fork`, undefined, { query });
120316
+ }
120317
+ var init_conversations2 = __esm(() => {
120318
+ init_request();
120319
+ });
120320
+
119585
120321
  // src/backend/backend.ts
119586
120322
  import { homedir as homedir19 } from "node:os";
119587
120323
 
@@ -119728,6 +120464,7 @@ function getBackend() {
119728
120464
  }
119729
120465
  function configureBackendMode(mode) {
119730
120466
  configuredBackendMode = mode;
120467
+ process.env[LOCAL_BACKEND_EXPERIMENTAL_ENV] = mode === "local" ? "1" : "0";
119731
120468
  backend = createBackendForMode(mode);
119732
120469
  }
119733
120470
  function isLocalBackendEnabled() {
@@ -143963,7 +144700,10 @@ function getTerminalTheme() {
143963
144700
  cachedTheme = detectTerminalThemeSync();
143964
144701
  return cachedTheme;
143965
144702
  }
143966
- var cachedTheme = null;
144703
+ function getTerminalBackgroundColor() {
144704
+ return cachedBackground;
144705
+ }
144706
+ var cachedTheme = null, cachedBackground = null;
143967
144707
 
143968
144708
  // src/cli/components/colors.ts
143969
144709
  function parseHex(hex3) {
@@ -143974,6 +144714,26 @@ function parseHex(hex3) {
143974
144714
  b: parseInt(h.slice(4, 6), 16)
143975
144715
  };
143976
144716
  }
144717
+ function rgbToHex({ r, g, b }) {
144718
+ const toHex = (value) => value.toString(16).padStart(2, "0");
144719
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
144720
+ }
144721
+ function isLightRgb({ r, g, b }) {
144722
+ return 0.299 * r + 0.587 * g + 0.114 * b > 128;
144723
+ }
144724
+ function blendRgb(fg, bg, alpha) {
144725
+ return {
144726
+ r: Math.floor(fg.r * alpha + bg.r * (1 - alpha)),
144727
+ g: Math.floor(fg.g * alpha + bg.g * (1 - alpha)),
144728
+ b: Math.floor(fg.b * alpha + bg.b * (1 - alpha))
144729
+ };
144730
+ }
144731
+ function getCodexUserMessageBackground() {
144732
+ const theme = getTerminalTheme();
144733
+ const terminalBg = getTerminalBackgroundColor() ?? (theme === "light" ? { r: 255, g: 255, b: 255 } : { r: 0, g: 0, b: 0 });
144734
+ const overlay = isLightRgb(terminalBg) ? { color: { r: 0, g: 0, b: 0 }, alpha: 0.04 } : { color: { r: 255, g: 255, b: 255 }, alpha: 0.12 };
144735
+ return rgbToHex(blendRgb(overlay.color, terminalBg, overlay.alpha));
144736
+ }
143977
144737
  function hexToBgAnsi(hex3) {
143978
144738
  const { r, g, b } = parseHex(hex3);
143979
144739
  return `\x1B[48;2;${r};${g};${b}m`;
@@ -144146,9 +144906,8 @@ var init_colors = __esm(() => {
144146
144906
  return getTerminalTheme() === "light" ? _colors.shellSyntaxLight : _colors.shellSyntaxDark;
144147
144907
  },
144148
144908
  get userMessage() {
144149
- const theme = getTerminalTheme();
144150
144909
  return {
144151
- background: theme === "light" ? "#dcddf2" : "#2d2d2d",
144910
+ background: getCodexUserMessageBackground(),
144152
144911
  text: undefined
144153
144912
  };
144154
144913
  }
@@ -146702,7 +147461,7 @@ var init_accountConfig3 = __esm(() => {
146702
147461
  });
146703
147462
 
146704
147463
  // src/channels/accountConfig.ts
146705
- function isRecord8(value) {
147464
+ function isRecord11(value) {
146706
147465
  return !!value && typeof value === "object" && !Array.isArray(value);
146707
147466
  }
146708
147467
  function getChannelAccountConfigAdapter(channelId) {
@@ -146713,7 +147472,7 @@ function getChannelPluginConfig(input, key = "config") {
146713
147472
  if (value === undefined) {
146714
147473
  return {};
146715
147474
  }
146716
- return isRecord8(value) ? value : null;
147475
+ return isRecord11(value) ? value : null;
146717
147476
  }
146718
147477
  function isValidChannelPluginConfigPayload(channelId, input, key = "config") {
146719
147478
  const config2 = getChannelPluginConfig(input, key);
@@ -152919,6 +153678,13 @@ var init_approval_result_normalization = __esm(() => {
152919
153678
  });
152920
153679
 
152921
153680
  // src/agent/clientSkills.ts
153681
+ var exports_clientSkills = {};
153682
+ __export(exports_clientSkills, {
153683
+ invalidateClientSkillsPayloadCacheForAgent: () => invalidateClientSkillsPayloadCacheForAgent,
153684
+ invalidateClientSkillsPayloadCache: () => invalidateClientSkillsPayloadCache,
153685
+ discoverClientSideSkills: () => discoverClientSideSkills,
153686
+ buildClientSkillsPayload: () => buildClientSkillsPayload
153687
+ });
152922
153688
  import { existsSync as existsSync32, readdirSync as readdirSync11, realpathSync as realpathSync3, statSync as statSync8 } from "node:fs";
152923
153689
  import { join as join34 } from "node:path";
152924
153690
  function getCache2() {
@@ -153013,6 +153779,17 @@ function cloneResult(result) {
153013
153779
  errors: result.errors.map((e) => ({ ...e }))
153014
153780
  };
153015
153781
  }
153782
+ function invalidateClientSkillsPayloadCache() {
153783
+ getCache2().clear();
153784
+ }
153785
+ function invalidateClientSkillsPayloadCacheForAgent(agentId) {
153786
+ const cache5 = getCache2();
153787
+ for (const [k, entry] of cache5) {
153788
+ if (entry.key.startsWith(`${agentId}|`) || k.startsWith(`${agentId}|`)) {
153789
+ cache5.delete(k);
153790
+ }
153791
+ }
153792
+ }
153016
153793
  function getMemorySkillsDirs2(agentId) {
153017
153794
  const dirs = new Set;
153018
153795
  const scopedMemoryDir = resolveScopedMemoryDir({ agentId });
@@ -153068,56 +153845,28 @@ function resolveSkillDiscoveryContext(options) {
153068
153845
  function getPrimaryProjectSkillsDirectory() {
153069
153846
  return join34(process.cwd(), ".agents", "skills");
153070
153847
  }
153071
- async function buildClientSkillsPayload(options = {}) {
153072
- const { legacySkillsDirectory, skillSources } = resolveSkillDiscoveryContext(options);
153848
+ async function collectClientSideSkills(options) {
153073
153849
  const discoverSkillsFn = options.discoverSkillsFn ?? discoverSkills;
153074
- const useCache = !options.discoverSkillsFn;
153075
- const cwd2 = process.cwd();
153076
- const primaryProjectSkillsDirectory = getPrimaryProjectSkillsDirectory();
153077
- const memorySkillsDirs = getMemorySkillsDirs2(options.agentId);
153078
- const cacheComponents = {
153079
- agentId: options.agentId,
153080
- skillSources,
153081
- cwd: cwd2,
153082
- legacySkillsDirectory,
153083
- primaryProjectSkillsDirectory,
153084
- memorySkillsDirs,
153085
- skillRootRevisions: getSkillRootRevisions({
153086
- agentId: options.agentId,
153087
- skillSources,
153088
- legacySkillsDirectory,
153089
- primaryProjectSkillsDirectory,
153090
- memorySkillsDirs
153091
- })
153092
- };
153093
- const cacheKey = computeCacheKey(cacheComponents);
153094
- if (useCache) {
153095
- const cache5 = getCache2();
153096
- const cached2 = cache5.get(cacheKey);
153097
- if (cached2) {
153098
- return cloneResult(cached2.result);
153099
- }
153100
- }
153101
153850
  const skillsById = new Map;
153102
153851
  const errors4 = [];
153103
- const nonProjectSources = skillSources.filter((source) => source !== "project");
153852
+ const nonProjectSources = options.skillSources?.filter((source) => source !== "project") ?? [];
153104
153853
  const discoveryRuns = [];
153105
153854
  if (nonProjectSources.length > 0) {
153106
153855
  discoveryRuns.push({
153107
- path: primaryProjectSkillsDirectory,
153856
+ path: options.primaryProjectSkillsDirectory,
153108
153857
  sources: nonProjectSources
153109
153858
  });
153110
153859
  }
153111
- const includeProjectSource = skillSources.includes("project");
153112
- if (includeProjectSource && legacySkillsDirectory !== primaryProjectSkillsDirectory) {
153860
+ const includeProjectSource = options.skillSources?.includes("project") ?? false;
153861
+ if (includeProjectSource && options.legacySkillsDirectory !== options.primaryProjectSkillsDirectory) {
153113
153862
  discoveryRuns.push({
153114
- path: legacySkillsDirectory,
153863
+ path: options.legacySkillsDirectory,
153115
153864
  sources: ["project"]
153116
153865
  });
153117
153866
  }
153118
153867
  if (includeProjectSource) {
153119
153868
  discoveryRuns.push({
153120
- path: primaryProjectSkillsDirectory,
153869
+ path: options.primaryProjectSkillsDirectory,
153121
153870
  sources: ["project"]
153122
153871
  });
153123
153872
  }
@@ -153135,7 +153884,7 @@ async function buildClientSkillsPayload(options = {}) {
153135
153884
  errors4.push({ path: run.path, message });
153136
153885
  }
153137
153886
  }
153138
- if (skillSources.length > 0) {
153887
+ if ((options.skillSources?.length ?? 0) > 0) {
153139
153888
  const memoryDiscovery = await discoverMemorySkills(options.agentId);
153140
153889
  errors4.push(...memoryDiscovery.errors);
153141
153890
  for (const skill2 of memoryDiscovery.skills) {
@@ -153146,7 +153895,59 @@ async function buildClientSkillsPayload(options = {}) {
153146
153895
  skillsById.set(skill2.id, skill2);
153147
153896
  }
153148
153897
  }
153149
- const sortedSkills = [...skillsById.values()].sort(compareSkills);
153898
+ return {
153899
+ skills: [...skillsById.values()].sort(compareSkills),
153900
+ errors: errors4
153901
+ };
153902
+ }
153903
+ async function discoverClientSideSkills(options = {}) {
153904
+ const { legacySkillsDirectory, skillSources } = resolveSkillDiscoveryContext(options);
153905
+ return collectClientSideSkills({
153906
+ ...options,
153907
+ legacySkillsDirectory,
153908
+ skillSources,
153909
+ primaryProjectSkillsDirectory: getPrimaryProjectSkillsDirectory()
153910
+ });
153911
+ }
153912
+ async function buildClientSkillsPayload(options = {}) {
153913
+ const { legacySkillsDirectory, skillSources } = resolveSkillDiscoveryContext(options);
153914
+ const discoverSkillsFn = options.discoverSkillsFn ?? discoverSkills;
153915
+ const useCache = !options.discoverSkillsFn;
153916
+ const cwd2 = process.cwd();
153917
+ const primaryProjectSkillsDirectory = getPrimaryProjectSkillsDirectory();
153918
+ const memorySkillsDirs = getMemorySkillsDirs2(options.agentId);
153919
+ const cacheComponents = {
153920
+ agentId: options.agentId,
153921
+ skillSources,
153922
+ cwd: cwd2,
153923
+ legacySkillsDirectory,
153924
+ primaryProjectSkillsDirectory,
153925
+ memorySkillsDirs,
153926
+ skillRootRevisions: getSkillRootRevisions({
153927
+ agentId: options.agentId,
153928
+ skillSources,
153929
+ legacySkillsDirectory,
153930
+ primaryProjectSkillsDirectory,
153931
+ memorySkillsDirs
153932
+ })
153933
+ };
153934
+ const cacheKey = computeCacheKey(cacheComponents);
153935
+ if (useCache) {
153936
+ const cache5 = getCache2();
153937
+ const cached2 = cache5.get(cacheKey);
153938
+ if (cached2) {
153939
+ return cloneResult(cached2.result);
153940
+ }
153941
+ }
153942
+ const discovery = await collectClientSideSkills({
153943
+ ...options,
153944
+ legacySkillsDirectory,
153945
+ skillSources,
153946
+ primaryProjectSkillsDirectory,
153947
+ discoverSkillsFn
153948
+ });
153949
+ const errors4 = discovery.errors;
153950
+ const sortedSkills = discovery.skills.filter(isModelInvocableSkill);
153150
153951
  if (errors4.length > 0) {
153151
153952
  const summarizedErrors = errors4.map((error51) => `${error51.path}: ${error51.message}`);
153152
153953
  options.logger?.(`Failed to build some client_skills entries: ${summarizedErrors.join("; ")}`);
@@ -154033,7 +154834,7 @@ function markIncompleteToolsAsCancelled(b, setInterruptedFlag = true, reason = "
154033
154834
  }
154034
154835
  return anyToolsCancelled;
154035
154836
  }
154036
- function isRecord9(v) {
154837
+ function isRecord12(v) {
154037
154838
  return v !== null && typeof v === "object";
154038
154839
  }
154039
154840
  function getStringProp(obj, key) {
@@ -154044,9 +154845,9 @@ function extractTextPart(v) {
154044
154845
  if (typeof v === "string")
154045
154846
  return v;
154046
154847
  if (Array.isArray(v)) {
154047
- return v.map((p) => isRecord9(p) ? getStringProp(p, "text") ?? "" : "").join("");
154848
+ return v.map((p) => isRecord12(p) ? getStringProp(p, "text") ?? "" : "").join("");
154048
154849
  }
154049
- if (isRecord9(v)) {
154850
+ if (isRecord12(v)) {
154050
154851
  return getStringProp(v, "text") ?? getStringProp(v, "delta") ?? "";
154051
154852
  }
154052
154853
  return "";
@@ -155966,13 +156767,13 @@ function buildAgentInfo(options) {
155966
156767
  }
155967
156768
  const showMemoryDir = (() => {
155968
156769
  try {
155969
- return settingsManager.isMemfsEnabled(agentInfo.id);
156770
+ return isLocalBackendEnvEnabled() || settingsManager.isMemfsEnabled(agentInfo.id);
155970
156771
  } catch {
155971
156772
  return false;
155972
156773
  }
155973
156774
  })();
155974
156775
  const memoryDirLine = showMemoryDir ? `
155975
- - **Memory directory (also stored in \`MEMORY_DIR\` env var)**: \`${getMemoryFilesystemRoot(agentInfo.id)}\`` : "";
156776
+ - **Memory directory (also stored in \`MEMORY_DIR\` env var)**: \`${getScopedMemoryFilesystemRoot(agentInfo.id)}\`` : "";
155976
156777
  const convLine = conversationId ? `
155977
156778
  - **Conversation ID (also stored in \`CONVERSATION_ID\` env var)**: ${conversationId}` : "";
155978
156779
  return `${SYSTEM_REMINDER_OPEN} This is an automated message providing information about you.
@@ -155987,6 +156788,7 @@ ${SYSTEM_REMINDER_CLOSE}`;
155987
156788
  }
155988
156789
  var init_agentInfo = __esm(() => {
155989
156790
  init_memoryFilesystem();
156791
+ init_paths();
155990
156792
  init_constants();
155991
156793
  init_settings_manager();
155992
156794
  });
@@ -158169,6 +158971,9 @@ function getApprovalToolCallDesyncErrorText(errorInfo) {
158169
158971
  }
158170
158972
  return null;
158171
158973
  }
158974
+ function isBackendNotFoundError(error51) {
158975
+ return error51 instanceof APIError2 && (error51.status === 404 || error51.status === 422) || error51 instanceof Error && error51.name === "LocalBackendNotFoundError";
158976
+ }
158172
158977
  function shouldAttemptPostStopApprovalRecovery(params) {
158173
158978
  const approvalDesyncDetected = isApprovalToolCallDesyncError(params.runErrorDetail) || isApprovalToolCallDesyncError(params.latestErrorText) || isApprovalToolCallDesyncError(params.fallbackError);
158174
158979
  return shouldAttemptApprovalRecovery({
@@ -158300,12 +159105,12 @@ async function debugLogApprovalResumeState(runtime, params) {
158300
159105
  return;
158301
159106
  }
158302
159107
  try {
158303
- const client = await getClient();
158304
- const agent = await client.agents.retrieve(params.agentId);
159108
+ const backend4 = getBackend();
159109
+ const agent = await backend4.retrieveAgent(params.agentId);
158305
159110
  const isExplicitConversation = params.conversationId.length > 0 && params.conversationId !== "default";
158306
- const lastInContextId = isExplicitConversation ? (await client.conversations.retrieve(params.conversationId)).in_context_message_ids?.at(-1) ?? null : agent.message_ids?.at(-1) ?? null;
158307
- const lastInContextMessages = lastInContextId ? await client.messages.retrieve(lastInContextId) : [];
158308
- const resumeData = await getResumeData(client, agent, params.conversationId, {
159111
+ const lastInContextId = isExplicitConversation ? (await backend4.retrieveConversation(params.conversationId)).in_context_message_ids?.at(-1) ?? null : agent.message_ids?.at(-1) ?? null;
159112
+ const lastInContextMessages = lastInContextId ? await backend4.retrieveMessage(lastInContextId) : [];
159113
+ const resumeData = await getResumeDataFromBackend2(agent, params.conversationId, {
158309
159114
  includeMessageHistory: false
158310
159115
  });
158311
159116
  console.log("[Listen][DEBUG] Post-approval continuation resume snapshot", JSON.stringify({
@@ -158348,12 +159153,12 @@ async function recoverApprovalStateForSync(runtime, scope) {
158348
159153
  clearRecoveredApprovalState(runtime);
158349
159154
  return;
158350
159155
  }
158351
- const client = await getClient();
159156
+ const backend4 = getBackend();
158352
159157
  let agent;
158353
159158
  try {
158354
- agent = await client.agents.retrieve(scope.agent_id);
159159
+ agent = await backend4.retrieveAgent(scope.agent_id);
158355
159160
  } catch (error51) {
158356
- if (error51 instanceof APIError2 && (error51.status === 404 || error51.status === 422)) {
159161
+ if (isBackendNotFoundError(error51)) {
158357
159162
  clearRecoveredApprovalState(runtime);
158358
159163
  return;
158359
159164
  }
@@ -158361,11 +159166,11 @@ async function recoverApprovalStateForSync(runtime, scope) {
158361
159166
  }
158362
159167
  let resumeData;
158363
159168
  try {
158364
- resumeData = await getResumeData(client, agent, scope.conversation_id, {
159169
+ resumeData = await getResumeDataFromBackend2(agent, scope.conversation_id, {
158365
159170
  includeMessageHistory: false
158366
159171
  });
158367
159172
  } catch (error51) {
158368
- if (error51 instanceof APIError2 && (error51.status === 404 || error51.status === 422)) {
159173
+ if (isBackendNotFoundError(error51)) {
158369
159174
  clearRecoveredApprovalState(runtime);
158370
159175
  return;
158371
159176
  }
@@ -158521,7 +159326,8 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
158521
159326
  parentScope: recovered.agentId && recovered.conversationId ? {
158522
159327
  agentId: recovered.agentId,
158523
159328
  conversationId: recovered.conversationId
158524
- } : undefined
159329
+ } : undefined,
159330
+ channelTurnSources: runtime.activeChannelTurnSources ?? undefined
158525
159331
  });
158526
159332
  } finally {
158527
159333
  emitToolExecutionOutput.flush();
@@ -158579,7 +159385,6 @@ var init_recovery = __esm(async () => {
158579
159385
  init_check_approval();
158580
159386
  init_turn_recovery_policy();
158581
159387
  init_backend2();
158582
- init_client2();
158583
159388
  init_formatDenial();
158584
159389
  init_interactivePolicy();
158585
159390
  init_constants2();
@@ -158631,16 +159436,19 @@ function markAwaitingAcceptedApprovalContinuationRunId(runtime, input) {
158631
159436
  runtime.activeRunId = null;
158632
159437
  }
158633
159438
  }
159439
+ function isBackendNotFoundError2(err) {
159440
+ return err instanceof APIError2 && (err.status === 404 || err.status === 422) || err instanceof Error && err.name === "LocalBackendNotFoundError";
159441
+ }
158634
159442
  async function resolveStaleApprovals(runtime, socket, abortSignal, deps = {}) {
158635
159443
  if (!runtime.agentId)
158636
159444
  return null;
158637
- const getResumeDataImpl = deps.getResumeData ?? getResumeData;
158638
- const client = await getClient();
159445
+ const getResumeDataImpl = deps.getResumeData ?? getResumeDataFromBackend2;
159446
+ const backend4 = getBackend();
158639
159447
  let agent;
158640
159448
  try {
158641
- agent = await client.agents.retrieve(runtime.agentId);
159449
+ agent = await backend4.retrieveAgent(runtime.agentId);
158642
159450
  } catch (err) {
158643
- if (err instanceof APIError2 && (err.status === 404 || err.status === 422)) {
159451
+ if (isBackendNotFoundError2(err)) {
158644
159452
  return null;
158645
159453
  }
158646
159454
  throw err;
@@ -158648,11 +159456,11 @@ async function resolveStaleApprovals(runtime, socket, abortSignal, deps = {}) {
158648
159456
  const requestedConversationId = runtime.conversationId !== "default" ? runtime.conversationId : undefined;
158649
159457
  let resumeData;
158650
159458
  try {
158651
- resumeData = await getResumeDataImpl(client, agent, requestedConversationId, {
159459
+ resumeData = await getResumeDataImpl(agent, requestedConversationId, {
158652
159460
  includeMessageHistory: false
158653
159461
  });
158654
159462
  } catch (err) {
158655
- if (err instanceof APIError2 && (err.status === 404 || err.status === 422)) {
159463
+ if (isBackendNotFoundError2(err)) {
158656
159464
  return null;
158657
159465
  }
158658
159466
  throw err;
@@ -159018,7 +159826,6 @@ var init_send = __esm(async () => {
159018
159826
  init_check_approval();
159019
159827
  init_turn_recovery_policy();
159020
159828
  init_backend2();
159021
- init_client2();
159022
159829
  init_errorFormatter();
159023
159830
  init_streamAbortRelay();
159024
159831
  init_constants2();
@@ -160773,7 +161580,7 @@ function formatArgsDisplay(argsJson, toolName) {
160773
161580
  try {
160774
161581
  if (argsJson?.trim()) {
160775
161582
  const p = JSON.parse(argsJson);
160776
- if (isRecord10(p)) {
161583
+ if (isRecord13(p)) {
160777
161584
  const clone2 = { ...p };
160778
161585
  if ("request_heartbeat" in clone2)
160779
161586
  delete clone2.request_heartbeat;
@@ -160894,7 +161701,7 @@ function formatArgsDisplay(argsJson, toolName) {
160894
161701
  }
160895
161702
  return { display, parsed, shellSemantic };
160896
161703
  }
160897
- var isRecord10 = (v) => typeof v === "object" && v !== null;
161704
+ var isRecord13 = (v) => typeof v === "object" && v !== null;
160898
161705
  var init_formatArgsDisplay = __esm(async () => {
160899
161706
  init_shellSemanticDisplay();
160900
161707
  await init_toolNameMapping();
@@ -161391,6 +162198,7 @@ async function handleApprovalStop(params) {
161391
162198
  onStreamingOutput: emitToolExecutionOutput,
161392
162199
  workingDirectory: turnWorkingDirectory,
161393
162200
  parentScope: agentId && conversationId ? { agentId, conversationId } : undefined,
162201
+ channelTurnSources: runtime.activeChannelTurnSources ?? undefined,
161394
162202
  onFileWrite
161395
162203
  });
161396
162204
  } finally {
@@ -161516,9 +162324,8 @@ var init_turn_approval = __esm(async () => {
161516
162324
 
161517
162325
  // src/websocket/listener/memfs-sync.ts
161518
162326
  async function syncMemfsForAgent(agentId) {
161519
- const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
161520
- const client = await getClient2();
161521
- const agent = await client.agents.retrieve(agentId);
162327
+ const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
162328
+ const agent = await getBackend2().retrieveAgent(agentId);
161522
162329
  const { GIT_MEMORY_ENABLED_TAG: GIT_MEMORY_ENABLED_TAG2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
161523
162330
  if (!agent.tags?.includes(GIT_MEMORY_ENABLED_TAG2)) {
161524
162331
  debugLog("memfs-sync", `Agent ${agentId} does not have memfs tag, skipping`);
@@ -161555,8 +162362,7 @@ function getAgentMetadataPromise(listener, agentId) {
161555
162362
  return listener.agentMetadataByAgent.get(agentId) ?? null;
161556
162363
  }
161557
162364
  async function fetchListenerAgentMetadata(agentId) {
161558
- const client = await getClient();
161559
- const agent = await client.agents.retrieve(agentId);
162365
+ const agent = await getBackend().retrieveAgent(agentId);
161560
162366
  return {
161561
162367
  name: agent.name ?? null,
161562
162368
  description: agent.description ?? null,
@@ -161609,7 +162415,7 @@ function clearListenerWarmState(listener) {
161609
162415
  }
161610
162416
  var defaultWarmupDeps, warmupDeps;
161611
162417
  var init_warmup = __esm(() => {
161612
- init_client2();
162418
+ init_backend2();
161613
162419
  init_debug();
161614
162420
  init_memfs_sync();
161615
162421
  init_secrets_sync();
@@ -161666,8 +162472,7 @@ function buildMaybeLaunchReflectionSubagent(params) {
161666
162472
  let systemPrompt = cachedAgent?.system ?? undefined;
161667
162473
  if (!systemPrompt) {
161668
162474
  try {
161669
- const client = await getClient();
161670
- const agent = await client.agents.retrieve(agentId);
162475
+ const agent = await getBackend().retrieveAgent(agentId);
161671
162476
  systemPrompt = agent.system ?? undefined;
161672
162477
  } catch {
161673
162478
  debugLog("memory", "Failed to fetch agent system prompt for reflection payload");
@@ -161844,8 +162649,7 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
161844
162649
  syncReminderStateFromContextTracker(runtime.reminderState, runtime.contextTracker);
161845
162650
  if (agentId) {
161846
162651
  try {
161847
- const client = await getClient();
161848
- cachedAgent = await client.agents.retrieve(agentId);
162652
+ cachedAgent = await getBackend().retrieveAgent(agentId);
161849
162653
  } catch {}
161850
162654
  }
161851
162655
  if (!runtime.reminderState.hasSentAgentInfo && cachedAgent) {
@@ -162059,9 +162863,8 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
162059
162863
  conversationId
162060
162864
  });
162061
162865
  try {
162062
- const client = await getClient();
162063
- const agent = await client.agents.retrieve(agentId || "");
162064
- const { pendingApprovals: existingApprovals } = await getResumeData(client, agent, requestedConversationId);
162866
+ const agent = await getBackend().retrieveAgent(agentId || "");
162867
+ const { pendingApprovals: existingApprovals } = await getResumeDataFromBackend2(agent, requestedConversationId);
162065
162868
  currentInput = rebuildInputWithFreshDenials(currentInput, existingApprovals ?? [], "Auto-denied: stale approval from interrupted session");
162066
162869
  } catch {
162067
162870
  currentInput = rebuildInputWithFreshDenials(currentInput, [], "");
@@ -162345,7 +163148,7 @@ var init_turn = __esm(async () => {
162345
163148
  init_context();
162346
163149
  init_memoryFilesystem();
162347
163150
  init_turn_recovery_policy();
162348
- init_client2();
163151
+ init_backend2();
162349
163152
  init_errorFormatter();
162350
163153
  init_memoryReminder();
162351
163154
  init_memorySubagentCompletion();
@@ -162452,17 +163255,19 @@ function emitSlashCommandEnd(socket, runtime, scope, fields) {
162452
163255
  emitCanonicalMessageDelta(socket, runtime, endDelta, scope);
162453
163256
  }
162454
163257
  async function handleClearCommand(_socket, conversationRuntime, opts) {
162455
- const client = await getClient();
163258
+ const backend4 = getBackend();
162456
163259
  const agentId = conversationRuntime.agentId;
162457
163260
  if (!agentId) {
162458
163261
  throw new Error("No agent ID available for /clear command");
162459
163262
  }
162460
- if (conversationRuntime.conversationId === "default") {
163263
+ if (conversationRuntime.conversationId === "default" && !backend4.capabilities.localModelCatalog) {
163264
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
163265
+ const client = await getClient2();
162461
163266
  await client.agents.messages.reset(agentId, {
162462
163267
  add_default_initial_messages: false
162463
163268
  });
162464
163269
  }
162465
- const conversation = await client.conversations.create({
163270
+ const conversation = await backend4.createConversation({
162466
163271
  agent_id: agentId,
162467
163272
  isolated_block_labels: [...ISOLATED_BLOCK_LABELS]
162468
163273
  });
@@ -162660,7 +163465,7 @@ var init_commands = __esm(async () => {
162660
163465
  init_memory();
162661
163466
  init_memoryFilesystem();
162662
163467
  init_promptAssets();
162663
- init_client2();
163468
+ init_backend2();
162664
163469
  init_initCommand();
162665
163470
  init_constants();
162666
163471
  init_settings_manager();
@@ -164043,6 +164848,16 @@ function isExecuteCommandCommand(value) {
164043
164848
  const hasValidArgs = c.args === undefined || typeof c.args === "string";
164044
164849
  return c.type === "execute_command" && typeof c.command_id === "string" && typeof c.request_id === "string" && isRuntimeScope(c.runtime) && hasValidArgs;
164045
164850
  }
164851
+ function parseServerLifecycleMessage(data) {
164852
+ try {
164853
+ const raw = typeof data === "string" ? data : data.toString();
164854
+ const parsed = JSON.parse(raw);
164855
+ if (parsed && typeof parsed === "object" && parsed.type === "pong") {
164856
+ return { type: "pong" };
164857
+ }
164858
+ } catch {}
164859
+ return null;
164860
+ }
164046
164861
  function parseServerMessage(data) {
164047
164862
  try {
164048
164863
  const raw = typeof data === "string" ? data : data.toString();
@@ -165538,11 +166353,12 @@ function handleMemoryProtocolCommand(parsed, context4) {
165538
166353
  const buffer = encoding === "base64" ? Buffer.from(parsed.content, "base64") : Buffer.from(parsed.content, "utf-8");
165539
166354
  await mkdir9(dirname20(absolutePath), { recursive: true });
165540
166355
  await writeFile11(absolutePath, buffer);
166356
+ const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
166357
+ const backend4 = getBackend2();
166358
+ const memorySyncMode = backend4.capabilities.localMemfs && !backend4.capabilities.remoteMemfs ? "local" : undefined;
165541
166359
  let agentName = parsed.agent_id;
165542
166360
  try {
165543
- const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
165544
- const client = await getClient2();
165545
- const agent = await client.agents.retrieve(parsed.agent_id);
166361
+ const agent = await backend4.retrieveAgent(parsed.agent_id);
165546
166362
  if (agent.name && agent.name.trim().length > 0) {
165547
166363
  agentName = agent.name.trim();
165548
166364
  }
@@ -165558,6 +166374,7 @@ function handleMemoryProtocolCommand(parsed, context4) {
165558
166374
  authorName: agentName,
165559
166375
  authorEmail: `${parsed.agent_id}@letta.com`
165560
166376
  },
166377
+ ...memorySyncMode ? { syncMode: memorySyncMode } : {},
165561
166378
  replay: async () => {
165562
166379
  await mkdir9(dirname20(absolutePath), { recursive: true });
165563
166380
  await writeFile11(absolutePath, buffer);
@@ -165652,11 +166469,12 @@ function handleMemoryProtocolCommand(parsed, context4) {
165652
166469
  }, "listener_delete_memory_file_send_failed", "listener_delete_memory_file");
165653
166470
  return;
165654
166471
  }
166472
+ const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
166473
+ const backend4 = getBackend2();
166474
+ const memorySyncMode = backend4.capabilities.localMemfs && !backend4.capabilities.remoteMemfs ? "local" : undefined;
165655
166475
  let agentName = parsed.agent_id;
165656
166476
  try {
165657
- const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
165658
- const client = await getClient2();
165659
- const agent = await client.agents.retrieve(parsed.agent_id);
166477
+ const agent = await backend4.retrieveAgent(parsed.agent_id);
165660
166478
  if (agent.name && agent.name.trim().length > 0) {
165661
166479
  agentName = agent.name.trim();
165662
166480
  }
@@ -165671,6 +166489,7 @@ function handleMemoryProtocolCommand(parsed, context4) {
165671
166489
  authorName: agentName,
165672
166490
  authorEmail: `${parsed.agent_id}@letta.com`
165673
166491
  },
166492
+ ...memorySyncMode ? { syncMode: memorySyncMode } : {},
165674
166493
  replay: async () => {
165675
166494
  await removeIfPresent();
165676
166495
  return [pathspec];
@@ -168200,6 +169019,11 @@ function createListenerMessageHandler(params) {
168200
169019
  const raw = data.toString();
168201
169020
  let parsedScope = null;
168202
169021
  try {
169022
+ const lifecycleMessage = parseServerLifecycleMessage(data);
169023
+ if (lifecycleMessage) {
169024
+ safeEmitWsEvent("recv", "lifecycle", lifecycleMessage);
169025
+ return;
169026
+ }
168203
169027
  const parsed = parseServerMessage(data);
168204
169028
  parsedScope = getParsedRuntimeScope(parsed);
168205
169029
  if (parsed) {
@@ -169521,6 +170345,178 @@ var init_listen_client = __esm(async () => {
169521
170345
  await init_client4();
169522
170346
  });
169523
170347
 
170348
+ // src/backend/api/search.ts
170349
+ async function warmSearchCache(body) {
170350
+ return apiRequest("POST", "/v1/_internal_search/cache-warm", body);
170351
+ }
170352
+ async function searchMessages(body) {
170353
+ return apiRequest("POST", "/v1/messages/search", body);
170354
+ }
170355
+ var init_search = __esm(() => {
170356
+ init_request();
170357
+ });
170358
+
170359
+ // src/backend/messageSearch.ts
170360
+ function pageItems(page) {
170361
+ if (Array.isArray(page))
170362
+ return page;
170363
+ if (page && typeof page === "object") {
170364
+ const maybePage = page;
170365
+ if (typeof maybePage.getPaginatedItems === "function") {
170366
+ return maybePage.getPaginatedItems();
170367
+ }
170368
+ if (Array.isArray(maybePage.items)) {
170369
+ return maybePage.items;
170370
+ }
170371
+ }
170372
+ return [];
170373
+ }
170374
+ function textFromContent2(content) {
170375
+ if (typeof content === "string")
170376
+ return content;
170377
+ if (!Array.isArray(content))
170378
+ return "";
170379
+ return content.map((part) => {
170380
+ if (part && typeof part === "object" && "text" in part && typeof part.text === "string") {
170381
+ return part.text;
170382
+ }
170383
+ return "";
170384
+ }).filter(Boolean).join(`
170385
+ `);
170386
+ }
170387
+ function stringifySearchValue(value) {
170388
+ if (typeof value === "string")
170389
+ return value;
170390
+ if (value === null || value === undefined)
170391
+ return "";
170392
+ try {
170393
+ return JSON.stringify(value);
170394
+ } catch {
170395
+ return String(value);
170396
+ }
170397
+ }
170398
+ function searchableText(message) {
170399
+ const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : message.tool_call ? [message.tool_call] : [];
170400
+ return [
170401
+ message.message_type,
170402
+ textFromContent2(message.content),
170403
+ message.reasoning,
170404
+ message.summary,
170405
+ ...toolCalls.flatMap((call) => [call.name, call.arguments]),
170406
+ stringifySearchValue(message.tool_return),
170407
+ stringifySearchValue(message.func_response)
170408
+ ].filter((part) => typeof part === "string" && part.length > 0).join(`
170409
+ `);
170410
+ }
170411
+ function matchesQuery(message, query) {
170412
+ const terms = query.toLowerCase().split(/\s+/).map((term) => term.trim()).filter(Boolean);
170413
+ if (terms.length === 0)
170414
+ return false;
170415
+ const haystack = searchableText(message).toLowerCase();
170416
+ return terms.every((term) => haystack.includes(term));
170417
+ }
170418
+ function withinDateRange(message, startDate, endDate) {
170419
+ if (!startDate && !endDate)
170420
+ return true;
170421
+ if (!message.date)
170422
+ return true;
170423
+ const time3 = new Date(message.date).getTime();
170424
+ if (Number.isNaN(time3))
170425
+ return true;
170426
+ const startTime = startDate ? new Date(startDate).getTime() : 0;
170427
+ const endTime = endDate ? new Date(endDate).getTime() : Number.POSITIVE_INFINITY;
170428
+ return time3 >= startTime && time3 <= endTime;
170429
+ }
170430
+ function toSearchResult(message) {
170431
+ const createdAt = message.date ?? new Date(0).toISOString();
170432
+ return {
170433
+ ...message,
170434
+ message_id: message.id ?? `${message.agent_id ?? "local"}:${createdAt}`,
170435
+ created_at: createdAt,
170436
+ agent_id: message.agent_id ?? null,
170437
+ conversation_id: message.conversation_id ?? null
170438
+ };
170439
+ }
170440
+ async function localConversationMessages(backend4, conversationId, agentId) {
170441
+ try {
170442
+ const page = await backend4.listConversationMessages(conversationId, {
170443
+ limit: LOCAL_SEARCH_SCAN_LIMIT,
170444
+ order: "desc",
170445
+ ...agentId ? { agent_id: agentId } : {}
170446
+ });
170447
+ return pageItems(page);
170448
+ } catch {
170449
+ return [];
170450
+ }
170451
+ }
170452
+ async function localAgentMessages(backend4, agentId) {
170453
+ const messages = [
170454
+ ...await localConversationMessages(backend4, "default", agentId)
170455
+ ];
170456
+ try {
170457
+ const conversationsPage = await backend4.listConversations({
170458
+ agent_id: agentId,
170459
+ limit: LOCAL_SEARCH_SCAN_LIMIT
170460
+ });
170461
+ const conversations = pageItems(conversationsPage);
170462
+ for (const conversation of conversations) {
170463
+ if (!conversation.id || conversation.id === "default")
170464
+ continue;
170465
+ messages.push(...await localConversationMessages(backend4, conversation.id, agentId));
170466
+ }
170467
+ } catch {}
170468
+ return messages;
170469
+ }
170470
+ async function localSearchMessages(backend4, body) {
170471
+ const query = typeof body.query === "string" ? body.query.trim() : "";
170472
+ if (!query)
170473
+ return [];
170474
+ const limit2 = typeof body.limit === "number" ? body.limit : 100;
170475
+ const agentId = typeof body.agent_id === "string" ? body.agent_id : undefined;
170476
+ const conversationId = typeof body.conversation_id === "string" ? body.conversation_id : undefined;
170477
+ const startDate = typeof body.start_date === "string" ? body.start_date : undefined;
170478
+ const endDate = typeof body.end_date === "string" ? body.end_date : undefined;
170479
+ let messages = [];
170480
+ if (conversationId) {
170481
+ messages = await localConversationMessages(backend4, conversationId, agentId);
170482
+ } else if (agentId) {
170483
+ messages = await localAgentMessages(backend4, agentId);
170484
+ } else {
170485
+ const agentsPage = await backend4.listAgents({
170486
+ limit: LOCAL_SEARCH_SCAN_LIMIT
170487
+ });
170488
+ const agents = pageItems(agentsPage);
170489
+ for (const agent of agents) {
170490
+ messages.push(...await localAgentMessages(backend4, agent.id));
170491
+ }
170492
+ }
170493
+ return messages.filter((message) => matchesQuery(message, query)).filter((message) => withinDateRange(message, startDate, endDate)).sort((a, b) => (b.date ?? "").localeCompare(a.date ?? "")).slice(0, limit2).map(toSearchResult);
170494
+ }
170495
+ async function searchMessagesForBackend(body, backend4 = getBackend()) {
170496
+ if (backend4.capabilities.localModelCatalog) {
170497
+ return await localSearchMessages(backend4, body);
170498
+ }
170499
+ return searchMessages({
170500
+ ...body,
170501
+ search_mode: body.search_mode === "vector" || body.search_mode === "fts" || body.search_mode === "hybrid" ? body.search_mode : body.search_mode
170502
+ });
170503
+ }
170504
+ async function warmMessageSearchCacheForBackend(body, backend4 = getBackend()) {
170505
+ if (backend4.capabilities.localModelCatalog) {
170506
+ return {
170507
+ collection: body.collection ?? "messages",
170508
+ status: "local-backend-noop",
170509
+ warmed: false
170510
+ };
170511
+ }
170512
+ return warmSearchCache(body);
170513
+ }
170514
+ var LOCAL_SEARCH_SCAN_LIMIT = 1000;
170515
+ var init_messageSearch = __esm(() => {
170516
+ init_search();
170517
+ init_backend();
170518
+ });
170519
+
169524
170520
  // src/utils/debug.ts
169525
170521
  var exports_debug2 = {};
169526
170522
  __export(exports_debug2, {
@@ -169662,6 +170658,12 @@ var init_version2 = __esm(() => {
169662
170658
  // src/agent/skills.ts
169663
170659
  var exports_skills2 = {};
169664
170660
  __export(exports_skills2, {
170661
+ isUserInvocableSkill: () => isUserInvocableSkill2,
170662
+ isModelInvocableSkill: () => isModelInvocableSkill2,
170663
+ getLegacyAgentSkillsDir: () => getLegacyAgentSkillsDir2,
170664
+ getFrontmatterStringList: () => getFrontmatterStringList2,
170665
+ getFrontmatterString: () => getFrontmatterString2,
170666
+ getFrontmatterBoolean: () => getFrontmatterBoolean2,
169665
170667
  getBundledSkills: () => getBundledSkills2,
169666
170668
  getAgentSkillsDir: () => getAgentSkillsDir2,
169667
170669
  formatSkillsAsSystemReminder: () => formatSkillsAsSystemReminder2,
@@ -169684,7 +170686,45 @@ function getBundledSkillsPath2() {
169684
170686
  function compareSkills2(a, b) {
169685
170687
  return a.id.localeCompare(b.id) || a.source.localeCompare(b.source) || a.path.localeCompare(b.path);
169686
170688
  }
170689
+ function stripSurroundingQuotes2(value) {
170690
+ const trimmed = value.trim();
170691
+ if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
170692
+ return trimmed.slice(1, -1);
170693
+ }
170694
+ return trimmed;
170695
+ }
170696
+ function getFrontmatterString2(frontmatter, key) {
170697
+ const value = frontmatter[key];
170698
+ return typeof value === "string" ? stripSurroundingQuotes2(value) : undefined;
170699
+ }
170700
+ function getFrontmatterStringList2(frontmatter, key) {
170701
+ const value = frontmatter[key];
170702
+ if (Array.isArray(value)) {
170703
+ return value.map(stripSurroundingQuotes2).filter((item) => item.length > 0);
170704
+ }
170705
+ if (typeof value === "string") {
170706
+ return stripSurroundingQuotes2(value).split(/\s+/).map((item) => item.trim()).filter((item) => item.length > 0);
170707
+ }
170708
+ return;
170709
+ }
170710
+ function getFrontmatterBoolean2(frontmatter, key) {
170711
+ const value = getFrontmatterString2(frontmatter, key)?.toLowerCase();
170712
+ if (value === "true")
170713
+ return true;
170714
+ if (value === "false")
170715
+ return false;
170716
+ return;
170717
+ }
170718
+ function isModelInvocableSkill2(skill2) {
170719
+ return skill2.disableModelInvocation !== true;
170720
+ }
170721
+ function isUserInvocableSkill2(skill2) {
170722
+ return skill2.userInvocable !== false;
170723
+ }
169687
170724
  function getAgentSkillsDir2(agentId) {
170725
+ return join42(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "memory/skills");
170726
+ }
170727
+ function getLegacyAgentSkillsDir2(agentId) {
169688
170728
  return join42(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "skills");
169689
170729
  }
169690
170730
  async function getBundledSkills2() {
@@ -169727,6 +170767,12 @@ async function discoverSkills2(projectSkillsPath = join42(process.cwd(), SKILLS_
169727
170767
  }
169728
170768
  }
169729
170769
  if (agentId && includeSource("agent")) {
170770
+ const legacyDir = getLegacyAgentSkillsDir2(agentId);
170771
+ const legacyResult = await discoverSkillsFromDir2(legacyDir, "agent");
170772
+ allErrors.push(...legacyResult.errors);
170773
+ for (const skill2 of legacyResult.skills) {
170774
+ skillsById.set(skill2.id, skill2);
170775
+ }
169730
170776
  const agentSkillsDir = getAgentSkillsDir2(agentId);
169731
170777
  const agentResult = await discoverSkillsFromDir2(agentSkillsDir, "agent");
169732
170778
  allErrors.push(...agentResult.errors);
@@ -169810,7 +170856,7 @@ async function parseSkillFile2(filePath, rootPath, source) {
169810
170856
  const defaultId = dirPath || "root";
169811
170857
  const id = (typeof frontmatter.id === "string" ? frontmatter.id : null) || defaultId;
169812
170858
  const name25 = (typeof frontmatter.name === "string" ? frontmatter.name : null) || (typeof frontmatter.title === "string" ? frontmatter.title : null) || (id.split("/").pop() ?? "").replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase());
169813
- let description = typeof frontmatter.description === "string" ? frontmatter.description : null;
170859
+ let description = getFrontmatterString2(frontmatter, "description") ?? null;
169814
170860
  if (!description) {
169815
170861
  const firstParagraph = body.trim().split(`
169816
170862
 
@@ -169818,30 +170864,31 @@ async function parseSkillFile2(filePath, rootPath, source) {
169818
170864
  description = firstParagraph || "No description available";
169819
170865
  }
169820
170866
  description = description.trim();
169821
- if (description.startsWith('"') && description.endsWith('"') || description.startsWith("'") && description.endsWith("'")) {
169822
- description = description.slice(1, -1);
169823
- }
169824
- let tags;
169825
- if (Array.isArray(frontmatter.tags)) {
169826
- tags = frontmatter.tags;
169827
- } else if (typeof frontmatter.tags === "string") {
169828
- tags = [frontmatter.tags];
169829
- }
170867
+ const whenToUse = getFrontmatterString2(frontmatter, "when_to_use")?.trim();
170868
+ const modelDescription = whenToUse ? `${description}
170869
+
170870
+ When to use: ${whenToUse}` : description;
170871
+ const tags = getFrontmatterStringList2(frontmatter, "tags");
169830
170872
  return {
169831
170873
  id,
169832
170874
  name: name25,
169833
- description,
169834
- category: typeof frontmatter.category === "string" ? frontmatter.category : undefined,
170875
+ description: modelDescription,
170876
+ whenToUse,
170877
+ argumentHint: getFrontmatterString2(frontmatter, "argument-hint"),
170878
+ arguments: getFrontmatterStringList2(frontmatter, "arguments"),
170879
+ disableModelInvocation: getFrontmatterBoolean2(frontmatter, "disable-model-invocation") ?? false,
170880
+ userInvocable: getFrontmatterBoolean2(frontmatter, "user-invocable") ?? true,
170881
+ category: getFrontmatterString2(frontmatter, "category"),
169835
170882
  tags,
169836
170883
  path: filePath,
169837
170884
  source
169838
170885
  };
169839
170886
  }
169840
170887
  function formatSkillsAsSystemReminder2(skills) {
169841
- if (skills.length === 0) {
170888
+ const lines = skills.filter(isModelInvocableSkill2).sort(compareSkills2).map((s) => `- ${s.id} (${s.source}): ${s.description}`);
170889
+ if (lines.length === 0) {
169842
170890
  return "";
169843
170891
  }
169844
- const lines = [...skills].sort(compareSkills2).map((s) => `- ${s.id} (${s.source}): ${s.description}`);
169845
170892
  return `<system-reminder>
169846
170893
  The following skills are available for use with the Skill tool:
169847
170894
 
@@ -169906,6 +170953,7 @@ __export(exports_terminalTheme, {
169906
170953
  parseHexComponent: () => parseHexComponent,
169907
170954
  initTerminalTheme: () => initTerminalTheme,
169908
170955
  getTerminalTheme: () => getTerminalTheme2,
170956
+ getTerminalBackgroundColor: () => getTerminalBackgroundColor2,
169909
170957
  detectTerminalThemeSync: () => detectTerminalThemeSync2,
169910
170958
  detectTerminalThemeAsync: () => detectTerminalThemeAsync,
169911
170959
  calculateLuminance: () => calculateLuminance
@@ -169980,6 +171028,7 @@ function calculateLuminance(r, g, b) {
169980
171028
  async function detectTerminalThemeAsync() {
169981
171029
  const bg = await queryTerminalBackground(100);
169982
171030
  if (bg) {
171031
+ cachedBackground2 = bg;
169983
171032
  const luminance = calculateLuminance(bg.r, bg.g, bg.b);
169984
171033
  return luminance > 0.4 ? "light" : "dark";
169985
171034
  }
@@ -170008,11 +171057,14 @@ function getTerminalTheme2() {
170008
171057
  cachedTheme2 = detectTerminalThemeSync2();
170009
171058
  return cachedTheme2;
170010
171059
  }
171060
+ function getTerminalBackgroundColor2() {
171061
+ return cachedBackground2;
171062
+ }
170011
171063
  async function initTerminalTheme() {
170012
171064
  cachedTheme2 = await detectTerminalThemeAsync();
170013
171065
  return cachedTheme2;
170014
171066
  }
170015
- var cachedTheme2 = null;
171067
+ var cachedTheme2 = null, cachedBackground2 = null;
170016
171068
 
170017
171069
  // src/agent/bootstrap-tools.ts
170018
171070
  var exports_bootstrap_tools = {};
@@ -172207,15 +173259,19 @@ In headless mode, use:
172207
173259
  const skillSourcesRaw = values["skill-sources"];
172208
173260
  const memfsFlag = values.memfs;
172209
173261
  const noMemfsFlag = values["no-memfs"];
173262
+ const localNoMemfsRequested = Boolean(backend4.capabilities.localMemfs && (noMemfsFlag || isLocalBackendNoMemfsEnvEnabled()));
173263
+ if (localNoMemfsRequested) {
173264
+ process.env[LOCAL_BACKEND_NO_MEMFS_ENV] = "1";
173265
+ }
172210
173266
  const memfsStartupRaw = values["memfs-startup"];
172211
173267
  const memfsStartupPolicy = memfsStartupRaw === "background" || memfsStartupRaw === "skip" ? memfsStartupRaw : "blocking";
172212
- const requestedMemoryPromptMode = memfsFlag ? "memfs" : noMemfsFlag ? "standard" : undefined;
173268
+ const requestedMemoryPromptMode = memfsFlag ? "memfs" : noMemfsFlag || localNoMemfsRequested ? "standard" : undefined;
172213
173269
  if (memfsFlag && !backend4.capabilities.remoteMemfs) {
172214
173270
  trackHeadlessBoundaryError("headless_memfs_unsupported_backend", "MemFS requires a backend with remote MemFS support", "headless_startup_memfs_flags");
172215
173271
  console.error("Error: --memfs is not supported by this backend yet");
172216
173272
  process.exit(1);
172217
173273
  }
172218
- const shouldAutoEnableMemfsForNewAgent = !memfsFlag && !noMemfsFlag;
173274
+ const shouldAutoEnableMemfsForNewAgent = !memfsFlag && !noMemfsFlag && !localNoMemfsRequested;
172219
173275
  const fromAfFile = resolveImportFlagAlias2({
172220
173276
  importFlagValue: values.import,
172221
173277
  fromAfFlagValue: values["from-af"]
@@ -172495,7 +173551,7 @@ In headless mode, use:
172495
173551
  if (!agent && forceNew) {
172496
173552
  const { isLettaCloud: isLettaCloud2 } = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
172497
173553
  const willAutoEnableMemfs = backend4.capabilities.remoteMemfs && shouldAutoEnableMemfsForNewAgent && await isLettaCloud2();
172498
- const effectiveMemoryMode = backend4.capabilities.localMemfs ? "local-memfs" : requestedMemoryPromptMode ?? (willAutoEnableMemfs ? "memfs" : undefined);
173554
+ const effectiveMemoryMode = backend4.capabilities.localMemfs ? localNoMemfsRequested ? "standard" : "local-memfs" : requestedMemoryPromptMode ?? (willAutoEnableMemfs ? "memfs" : undefined);
172499
173555
  const personalityOptions = personality ? await buildCreateAgentOptionsForPersonality2({
172500
173556
  personalityId: personality,
172501
173557
  model,
@@ -172597,12 +173653,8 @@ In headless mode, use:
172597
173653
  const secretsInitPromise = secretsAgentId ? Promise.resolve().then(() => (init_secretsStore(), exports_secretsStore)).then(({ initSecretsFromServer: initSecretsFromServer2 }) => initSecretsFromServer2(secretsAgentId, agent ?? undefined)) : Promise.resolve();
172598
173654
  if (!backend4.capabilities.remoteMemfs) {
172599
173655
  if (backend4.capabilities.localMemfs) {
172600
- if (noMemfsFlag) {
172601
- console.error("Disabling MemFS is not supported by the local backend.");
172602
- process.exit(1);
172603
- }
172604
- settingsManager.setMemfsEnabled(agent.id, true);
172605
- } else if (noMemfsFlag) {
173656
+ settingsManager.setMemfsEnabled(agent.id, !localNoMemfsRequested);
173657
+ } else if (noMemfsFlag || localNoMemfsRequested) {
172606
173658
  settingsManager.setMemfsEnabled(agent.id, false);
172607
173659
  }
172608
173660
  } else if (memfsStartupPolicy === "skip") {
@@ -174578,6 +175630,7 @@ var init_headless = __esm(async () => {
174578
175630
  init_personality();
174579
175631
  init_skillSources();
174580
175632
  init_backend2();
175633
+ init_paths();
174581
175634
  init_errorFormatter();
174582
175635
  init_memoryReminder();
174583
175636
  init_messageQueueBridge();
@@ -175420,8 +176473,7 @@ async function handleProfileSave(ctx, msg, profileName) {
175420
176473
  const cmdId = addCommandResult2(ctx.buffersRef, ctx.refreshDerived, msg, `Saving profile "${profileName}"...`, false, "running");
175421
176474
  ctx.setCommandRunning(true);
175422
176475
  try {
175423
- const client = await getClient();
175424
- await client.agents.update(ctx.agentId, { name: profileName });
176476
+ await getBackend().updateAgent(ctx.agentId, { name: profileName });
175425
176477
  ctx.updateAgentName(profileName);
175426
176478
  settingsManager.saveProfile(profileName, ctx.agentId);
175427
176479
  updateCommandResult2(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Pinned "${profileName}" locally and globally.`, true);
@@ -175503,9 +176555,7 @@ async function handlePin(ctx, msg, argsStr) {
175503
176555
  const globalPinned = settingsManager.getGlobalPinnedAgents();
175504
176556
  if (name25 && name25 !== ctx.agentName) {
175505
176557
  try {
175506
- const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
175507
- const client = await getClient2();
175508
- await client.agents.update(ctx.agentId, { name: name25 });
176558
+ await getBackend().updateAgent(ctx.agentId, { name: name25 });
175509
176559
  ctx.updateAgentName(name25);
175510
176560
  } catch (error51) {
175511
176561
  addCommandResult2(ctx.buffersRef, ctx.refreshDerived, msg, `Failed to rename agent: ${error51}`, false);
@@ -175552,7 +176602,7 @@ function handleUnpin(ctx, msg, argsStr) {
175552
176602
  }
175553
176603
  var activeCommandId2 = null;
175554
176604
  var init_profile = __esm(() => {
175555
- init_client2();
176605
+ init_backend2();
175556
176606
  init_settings_manager();
175557
176607
  init_errorFormatter();
175558
176608
  });
@@ -190710,7 +191760,7 @@ function highlightCode(code, language) {
190710
191760
  }
190711
191761
  return lines;
190712
191762
  }
190713
- var import_react34, jsx_dev_runtime12, lowlight, BASH_LANGUAGE = "bash", FIRST_LINE_PREFIX = "$ ", EXT_TO_LANG, HEREDOC_RE, REDIRECT_FILE_RE, SyntaxHighlightedCommand;
191763
+ var import_react34, jsx_dev_runtime12, lowlight, BASH_LANGUAGE = "bash", FIRST_LINE_PROMPT = "$", PROMPT_COLUMN_WIDTH = 2, EXT_TO_LANG, HEREDOC_RE, REDIRECT_FILE_RE, SyntaxHighlightedCommand;
190714
191764
  var init_SyntaxHighlightedCommand = __esm(async () => {
190715
191765
  init_lowlight();
190716
191766
  init_colors();
@@ -190811,9 +191861,13 @@ var init_SyntaxHighlightedCommand = __esm(async () => {
190811
191861
  const lineKey = spans.map((s) => s.text).join("");
190812
191862
  return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
190813
191863
  children: [
190814
- showPrompt ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
190815
- color: palette.prompt,
190816
- children: lineIdx === 0 ? FIRST_LINE_PREFIX : " "
191864
+ showPrompt ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
191865
+ width: PROMPT_COLUMN_WIDTH,
191866
+ flexShrink: 0,
191867
+ children: lineIdx === 0 ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
191868
+ color: palette.prompt,
191869
+ children: FIRST_LINE_PROMPT
191870
+ }, undefined, false, undefined, this) : null
190817
191871
  }, undefined, false, undefined, this) : null,
190818
191872
  /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
190819
191873
  color: palette.text,
@@ -199525,6 +200579,7 @@ function boxBottom(width) {
199525
200579
  }
199526
200580
  var import_react67, jsx_dev_runtime44, BOX_TOP_LEFT = "╭", BOX_TOP_RIGHT = "╮", BOX_BOTTOM_LEFT = "╰", BOX_BOTTOM_RIGHT = "╯", BOX_HORIZONTAL = "─", BOX_VERTICAL = "│", HOOK_EVENTS, FALLBACK_TOOL_NAMES, SAVE_LOCATIONS, HooksManager;
199527
200581
  var init_HooksManager = __esm(async () => {
200582
+ init_backend2();
199528
200583
  init_types3();
199529
200584
  init_writer();
199530
200585
  init_settings_manager();
@@ -199597,6 +200652,9 @@ var init_HooksManager = __esm(async () => {
199597
200652
  return;
199598
200653
  const fetchAgentTools = async () => {
199599
200654
  try {
200655
+ if (!getBackend().capabilities.serverSideToolManagement) {
200656
+ return;
200657
+ }
199600
200658
  const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
199601
200659
  const client = await getClient2();
199602
200660
  const toolsPage = await client.agents.tools.list(agentId, {
@@ -202384,6 +203442,7 @@ function SlashCommandAutocomplete({
202384
203442
  }) {
202385
203443
  const columns = useTerminalWidth();
202386
203444
  const [customCommands, setCustomCommands] = import_react72.useState([]);
203445
+ const [skillCommands, setSkillCommands] = import_react72.useState([]);
202387
203446
  import_react72.useEffect(() => {
202388
203447
  Promise.resolve().then(() => (init_custom(), exports_custom)).then(({ getCustomCommands: getCustomCommands2 }) => {
202389
203448
  getCustomCommands2().then((customs) => {
@@ -202396,6 +203455,35 @@ function SlashCommandAutocomplete({
202396
203455
  });
202397
203456
  });
202398
203457
  }, []);
203458
+ import_react72.useEffect(() => {
203459
+ let cancelled = false;
203460
+ (async () => {
203461
+ try {
203462
+ const { discoverClientSideSkills: discoverClientSideSkills2 } = await Promise.resolve().then(() => (init_clientSkills(), exports_clientSkills));
203463
+ const { getSkillSources: getSkillSources2 } = await Promise.resolve().then(() => (init_context(), exports_context));
203464
+ const { isUserInvocableSkill: isUserInvocableSkill3 } = await Promise.resolve().then(() => (init_skills(), exports_skills));
203465
+ const discovery = await discoverClientSideSkills2({
203466
+ agentId,
203467
+ skillSources: getSkillSources2()
203468
+ });
203469
+ if (cancelled)
203470
+ return;
203471
+ const matches2 = discovery.skills.filter(isUserInvocableSkill3).map((skill2) => ({
203472
+ cmd: `/${skill2.id}`,
203473
+ desc: `${skill2.description}${skill2.argumentHint ? ` ${skill2.argumentHint}` : ""} (${skill2.source} skill)`,
203474
+ order: 300
203475
+ }));
203476
+ setSkillCommands(matches2);
203477
+ } catch {
203478
+ if (!cancelled) {
203479
+ setSkillCommands([]);
203480
+ }
203481
+ }
203482
+ })();
203483
+ return () => {
203484
+ cancelled = true;
203485
+ };
203486
+ }, [agentId]);
202399
203487
  const allCommands = import_react72.useMemo(() => {
202400
203488
  let builtins = _allCommands;
202401
203489
  if (agentId) {
@@ -202419,8 +203507,13 @@ function SlashCommandAutocomplete({
202419
203507
  builtins = _allCommands;
202420
203508
  }
202421
203509
  }
202422
- return [...builtins, ...customCommands].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
202423
- }, [agentId, workingDirectory, customCommands]);
203510
+ const reservedCommands = new Set([
203511
+ ...builtins.map((cmd) => cmd.cmd),
203512
+ ...customCommands.map((cmd) => cmd.cmd)
203513
+ ]);
203514
+ const visibleSkillCommands = skillCommands.filter((cmd) => !reservedCommands.has(cmd.cmd));
203515
+ return [...builtins, ...customCommands, ...visibleSkillCommands].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
203516
+ }, [agentId, workingDirectory, customCommands, skillCommands]);
202424
203517
  const queryInfo = import_react72.useMemo(() => extractSearchQuery2(currentInput, cursorPosition), [currentInput, cursorPosition]);
202425
203518
  const { matches, showNoMatches, hideAutocomplete } = import_react72.useMemo(() => {
202426
203519
  if (!queryInfo) {
@@ -209433,8 +210526,7 @@ function MemoryTabViewer({
209433
210526
  import_react81.useEffect(() => {
209434
210527
  const fetchBlocks = async () => {
209435
210528
  try {
209436
- const client = await getClient();
209437
- const agent = await client.agents.retrieve(agentId, {
210529
+ const agent = await getBackend().retrieveAgent(agentId, {
209438
210530
  include: ["agent.blocks"]
209439
210531
  });
209440
210532
  setFreshBlocks(agent.memory?.blocks || []);
@@ -209711,7 +210803,7 @@ function MemoryTabViewer({
209711
210803
  }
209712
210804
  var import_react81, jsx_dev_runtime58, SOLID_LINE21 = "─", VISIBLE_LINES = 12;
209713
210805
  var init_MemoryTabViewer = __esm(async () => {
209714
- init_client2();
210806
+ init_backend2();
209715
210807
  init_debug();
209716
210808
  init_useTerminalWidth();
209717
210809
  init_colors();
@@ -209725,24 +210817,13 @@ var init_MemoryTabViewer = __esm(async () => {
209725
210817
  jsx_dev_runtime58 = __toESM(require_jsx_dev_runtime(), 1);
209726
210818
  });
209727
210819
 
209728
- // src/backend/api/search.ts
209729
- async function warmSearchCache(body) {
209730
- return apiRequest("POST", "/v1/_internal_search/cache-warm", body);
209731
- }
209732
- async function searchMessages(body) {
209733
- return apiRequest("POST", "/v1/messages/search", body);
209734
- }
209735
- var init_search = __esm(() => {
209736
- init_request();
209737
- });
209738
-
209739
210820
  // src/cli/components/MessageSearch.tsx
209740
210821
  async function warmMessageSearchCache() {
209741
210822
  const body = {
209742
210823
  collection: "messages",
209743
210824
  scope: {}
209744
210825
  };
209745
- return warmSearchCache(body);
210826
+ return warmMessageSearchCacheForBackend(body);
209746
210827
  }
209747
210828
  function isSearchRangeAvailable(range2, options) {
209748
210829
  if (range2 === "agent")
@@ -209881,7 +210962,7 @@ function MessageSearch({
209881
210962
  } else if (range2 === "conv" && conversationId) {
209882
210963
  body.conversation_id = conversationId;
209883
210964
  }
209884
- return searchMessages(body);
210965
+ return searchMessagesForBackend(body);
209885
210966
  }, [agentId, conversationId]);
209886
210967
  const fetchAndCacheSearchResults = import_react82.useCallback(async (query, mode, range2) => {
209887
210968
  const cacheKey = getCacheKey(query, mode, range2);
@@ -210354,7 +211435,7 @@ function MessageSearch({
210354
211435
  }
210355
211436
  var import_react82, jsx_dev_runtime59, SOLID_LINE22 = "─", VISIBLE_ITEMS = 5, SEARCH_LIMIT = 100, SEARCH_MODES, SEARCH_RANGES;
210356
211437
  var init_MessageSearch = __esm(async () => {
210357
- init_search();
211438
+ init_messageSearch();
210358
211439
  init_useTerminalWidth();
210359
211440
  init_colors();
210360
211441
  await __promiseAll([
@@ -212682,7 +213763,7 @@ function getTabDescription(tab2, agentId) {
212682
213763
  case "project":
212683
213764
  return ".skills/";
212684
213765
  case "agent":
212685
- return `~/.letta/agents/${shortId}/skills/`;
213766
+ return `~/.letta/agents/${shortId}/memory/skills/`;
212686
213767
  case "global":
212687
213768
  return "~/.letta/skills/";
212688
213769
  case "bundled":
@@ -212722,7 +213803,7 @@ function SkillsDialog({ onClose, agentId }) {
212722
213803
  }
212723
213804
  return grouped;
212724
213805
  }, [skills]);
212725
- const availableTabs = import_react91.useMemo(() => TAB_ORDER.filter((tab2) => (skillsBySource.get(tab2)?.length ?? 0) > 0), [skillsBySource]);
213806
+ const availableTabs = import_react91.useMemo(() => [...TAB_ORDER], []);
212726
213807
  const [activeTab, setActiveTab] = import_react91.useState(null);
212727
213808
  import_react91.useEffect(() => {
212728
213809
  if (!loading && availableTabs.length > 0 && activeTab === null) {
@@ -212876,13 +213957,20 @@ function SkillsDialog({ onClose, agentId }) {
212876
213957
  }, undefined, false, undefined, this) : null
212877
213958
  ]
212878
213959
  }, undefined, true, undefined, this),
213960
+ !loading && activeTab && currentSkills.length === 0 && /* @__PURE__ */ jsx_dev_runtime68.jsxDEV(Box_default, {
213961
+ paddingLeft: 2,
213962
+ children: /* @__PURE__ */ jsx_dev_runtime68.jsxDEV(Text2, {
213963
+ dimColor: true,
213964
+ children: "No skills in this location"
213965
+ }, undefined, false, undefined, this)
213966
+ }, undefined, false, undefined, this),
212879
213967
  /* @__PURE__ */ jsx_dev_runtime68.jsxDEV(Box_default, {
212880
213968
  marginTop: 1,
212881
213969
  children: /* @__PURE__ */ jsx_dev_runtime68.jsxDEV(Text2, {
212882
213970
  dimColor: true,
212883
213971
  children: [
212884
213972
  " ",
212885
- availableTabs.length > 1 ? "↑↓ scroll · ←→/Tab switch · Esc to close" : "Esc to close"
213973
+ "↑↓ scroll · ←→/Tab switch · Esc to close"
212886
213974
  ]
212887
213975
  }, undefined, true, undefined, this)
212888
213976
  }, undefined, false, undefined, this)
@@ -215187,7 +216275,7 @@ var init_ToolCallMessageRich = __esm(async () => {
215187
216275
  let shellCommand = null;
215188
216276
  let shellSemanticKind = null;
215189
216277
  if (!isQuestionTool(rawName)) {
215190
- const parseArgs10 = () => {
216278
+ const parseArgs9 = () => {
215191
216279
  if (!argsText.trim()) {
215192
216280
  return { formatted: null, parseable: true };
215193
216281
  }
@@ -215198,7 +216286,7 @@ var init_ToolCallMessageRich = __esm(async () => {
215198
216286
  return { formatted: null, parseable: false };
215199
216287
  }
215200
216288
  };
215201
- const { formatted, parseable } = parseArgs10();
216289
+ const { formatted, parseable } = parseArgs9();
215202
216290
  const argsComplete = parseable || line.phase === "running" || line.phase === "finished" || !isStreaming;
215203
216291
  if (!argsComplete) {
215204
216292
  args = "(…)";
@@ -215311,13 +216399,13 @@ var init_ToolCallMessageRich = __esm(async () => {
215311
216399
  }, undefined, true, undefined, this);
215312
216400
  }
215313
216401
  const displayResultText = clipToolReturn(extractedText).replace(/\n+$/, "");
215314
- const isRecord11 = (v) => typeof v === "object" && v !== null;
216402
+ const isRecord14 = (v) => typeof v === "object" && v !== null;
215315
216403
  if (isTodoTool(rawName, displayName) && line.resultOk !== false && line.argsText) {
215316
216404
  try {
215317
216405
  const parsedArgs = JSON.parse(line.argsText);
215318
216406
  if (parsedArgs.todos && Array.isArray(parsedArgs.todos)) {
215319
216407
  const safeTodos = parsedArgs.todos.map((t, i) => {
215320
- const rec = isRecord11(t) ? t : {};
216408
+ const rec = isRecord14(t) ? t : {};
215321
216409
  const status = rec.status === "completed" ? "completed" : rec.status === "in_progress" ? "in_progress" : "pending";
215322
216410
  const id = typeof rec.id === "string" ? rec.id : String(i);
215323
216411
  const content = typeof rec.content === "string" ? rec.content : typeof rec.description === "string" ? rec.description : JSON.stringify(t);
@@ -215335,7 +216423,7 @@ var init_ToolCallMessageRich = __esm(async () => {
215335
216423
  const parsedArgs = JSON.parse(line.argsText);
215336
216424
  if (parsedArgs.plan && Array.isArray(parsedArgs.plan)) {
215337
216425
  const safePlan = parsedArgs.plan.map((item) => {
215338
- const rec = isRecord11(item) ? item : {};
216426
+ const rec = isRecord14(item) ? item : {};
215339
216427
  const status = rec.status === "completed" ? "completed" : rec.status === "in_progress" ? "in_progress" : "pending";
215340
216428
  const step = typeof rec.step === "string" ? rec.step : JSON.stringify(item);
215341
216429
  return { step, status };
@@ -216152,6 +217240,27 @@ var init_TrajectorySummary = __esm(async () => {
216152
217240
  });
216153
217241
 
216154
217242
  // src/cli/components/UserMessageRich.tsx
217243
+ function getCurrentStdoutColumns() {
217244
+ if (typeof process === "undefined")
217245
+ return null;
217246
+ const columns = process.stdout?.columns;
217247
+ return typeof columns === "number" && columns > 0 ? columns : null;
217248
+ }
217249
+ function isInkFullWidthCodePoint(codePoint) {
217250
+ return codePoint >= 4352 && (codePoint <= 4447 || codePoint === 9001 || codePoint === 9002 || 11904 <= codePoint && codePoint <= 12871 && codePoint !== 12351 || 12880 <= codePoint && codePoint <= 19903 || 19968 <= codePoint && codePoint <= 42182 || 43360 <= codePoint && codePoint <= 43388 || 44032 <= codePoint && codePoint <= 55203 || 63744 <= codePoint && codePoint <= 64255 || 65040 <= codePoint && codePoint <= 65049 || 65072 <= codePoint && codePoint <= 65131 || 65281 <= codePoint && codePoint <= 65376 || 65504 <= codePoint && codePoint <= 65510 || 110592 <= codePoint && codePoint <= 110593 || 127488 <= codePoint && codePoint <= 127569 || 131072 <= codePoint && codePoint <= 262141);
217251
+ }
217252
+ function inkStringWidth(text2) {
217253
+ let width = 0;
217254
+ for (let index = 0;index < text2.length; ) {
217255
+ const codePoint = text2.codePointAt(index);
217256
+ if (codePoint === undefined)
217257
+ break;
217258
+ const character = String.fromCodePoint(codePoint);
217259
+ width += isInkFullWidthCodePoint(codePoint) || character.length > 1 ? 2 : 1;
217260
+ index += character.length;
217261
+ }
217262
+ return width;
217263
+ }
216155
217264
  function wordWrap(text2, width) {
216156
217265
  if (width <= 0)
216157
217266
  return [text2];
@@ -216163,7 +217272,7 @@ function wordWrap(text2, width) {
216163
217272
  current = word;
216164
217273
  } else {
216165
217274
  const candidate = `${current} ${word}`;
216166
- if (stringWidth(candidate) <= width) {
217275
+ if (inkStringWidth(candidate) <= width) {
216167
217276
  current = candidate;
216168
217277
  } else {
216169
217278
  lines.push(current);
@@ -216211,7 +217320,11 @@ function splitSystemReminderBlocks(text2) {
216211
217320
  }
216212
217321
  return blocks;
216213
217322
  }
216214
- function renderBlock(text2, contentWidth, columns, highlighted, colorAnsi, promptPrefix, continuationPrefix) {
217323
+ function padToColumns(text2, columns) {
217324
+ const pad = Math.max(0, columns - inkStringWidth(text2));
217325
+ return `${text2}${" ".repeat(pad)}`;
217326
+ }
217327
+ function renderBlock(text2, contentWidth, columns, highlighted, promptPrefix, continuationPrefix) {
216215
217328
  const inputLines = text2.split(`
216216
217329
  `);
216217
217330
  const outputLines = [];
@@ -216227,34 +217340,39 @@ function renderBlock(text2, contentWidth, columns, highlighted, colorAnsi, promp
216227
217340
  }
216228
217341
  if (outputLines.length === 0)
216229
217342
  return [];
216230
- const isSingleLine = outputLines.length === 1;
216231
- return outputLines.map((ol, i) => {
217343
+ const renderedLines = outputLines.map((ol, i) => {
216232
217344
  const prefix = i === 0 ? promptPrefix : continuationPrefix;
217345
+ const content = `${prefix}${ol}`;
216233
217346
  if (!highlighted) {
216234
- return prefix + ol;
216235
- }
216236
- const content = i === 0 ? `${promptPrefix.slice(0, -1)}${colorAnsi} ${ol}` : `${prefix}${ol}`;
216237
- const visWidth = stringWidth(content);
216238
- if (isSingleLine) {
216239
- return `${colorAnsi}${content}${" ".repeat(COMPACT_PAD)}\x1B[0m`;
217347
+ return { text: content, highlighted: false };
216240
217348
  }
216241
- const pad = Math.max(0, columns - visWidth);
216242
- return `${colorAnsi}${content}${" ".repeat(pad)}\x1B[0m`;
217349
+ return { text: padToColumns(content, columns), highlighted: true };
216243
217350
  });
217351
+ if (!highlighted) {
217352
+ return renderedLines;
217353
+ }
217354
+ const blankLine = {
217355
+ text: " ".repeat(Math.max(0, columns)),
217356
+ highlighted: true
217357
+ };
217358
+ return [blankLine, ...renderedLines, blankLine];
216244
217359
  }
216245
- var import_react101, jsx_dev_runtime81, COMPACT_PAD = 1, UserMessage;
217360
+ var import_react101, jsx_dev_runtime81, UserMessage;
216246
217361
  var init_UserMessageRich = __esm(async () => {
216247
- init_string_width();
216248
217362
  init_constants();
216249
217363
  init_useTerminalWidth();
216250
217364
  init_colors();
216251
- await init_Text2();
217365
+ await __promiseAll([
217366
+ init_build2(),
217367
+ init_Text2()
217368
+ ]);
216252
217369
  import_react101 = __toESM(require_react(), 1);
216253
217370
  jsx_dev_runtime81 = __toESM(require_jsx_dev_runtime(), 1);
216254
217371
  UserMessage = import_react101.memo(({ line, prompt }) => {
216255
- const columns = useTerminalWidth();
217372
+ const trackedColumns2 = useTerminalWidth();
217373
+ const columns = getCurrentStdoutColumns() ?? trackedColumns2;
216256
217374
  const promptPrefix = `${prompt || ">"} `;
216257
- const prefixWidth = stringWidth(promptPrefix);
217375
+ const prefixWidth = inkStringWidth(promptPrefix);
216258
217376
  const continuationPrefix = " ".repeat(prefixWidth);
216259
217377
  const contentWidth = Math.max(1, columns - prefixWidth);
216260
217378
  const cleanedText = extractTaskNotificationsForDisplay(line.text).cleanedText;
@@ -216263,23 +217381,25 @@ var init_UserMessageRich = __esm(async () => {
216263
217381
  return null;
216264
217382
  }
216265
217383
  const { background, text: textColor } = colors.userMessage;
216266
- const bgAnsi = hexToBgAnsi(background);
216267
- const fgAnsi = textColor ? hexToFgAnsi(textColor) : "";
216268
- const colorAnsi = bgAnsi + fgAnsi;
216269
217384
  const blocks = splitSystemReminderBlocks(displayText);
216270
217385
  const allLines = [];
216271
217386
  for (const block of blocks) {
216272
217387
  if (!block.text.trim())
216273
217388
  continue;
216274
217389
  if (allLines.length > 0) {
216275
- allLines.push("");
217390
+ allLines.push({ text: "", highlighted: false });
216276
217391
  }
216277
- const blockLines = renderBlock(block.text, contentWidth, columns, !block.isSystemReminder, colorAnsi, promptPrefix, continuationPrefix);
217392
+ const blockLines = renderBlock(block.text, contentWidth, columns, !block.isSystemReminder, promptPrefix, continuationPrefix);
216278
217393
  allLines.push(...blockLines);
216279
217394
  }
216280
- return /* @__PURE__ */ jsx_dev_runtime81.jsxDEV(Text2, {
216281
- children: allLines.join(`
216282
- `)
217395
+ return /* @__PURE__ */ jsx_dev_runtime81.jsxDEV(Box_default, {
217396
+ flexDirection: "column",
217397
+ children: allLines.map((line2, index) => /* @__PURE__ */ jsx_dev_runtime81.jsxDEV(Text2, {
217398
+ backgroundColor: line2.highlighted ? background : undefined,
217399
+ color: line2.highlighted ? textColor : undefined,
217400
+ wrap: line2.highlighted ? "end" : "wrap",
217401
+ children: line2.text
217402
+ }, index, false, undefined, this))
216283
217403
  }, undefined, false, undefined, this);
216284
217404
  });
216285
217405
  UserMessage.displayName = "UserMessage";
@@ -217761,7 +218881,7 @@ function updateCommandResult3(buffersRef, refreshDerived, cmdId, input, output,
217761
218881
  buffersRef.current.byId.set(cmdId, line);
217762
218882
  refreshDerived();
217763
218883
  }
217764
- function parseArgs10(msg) {
218884
+ function parseArgs9(msg) {
217765
218885
  return msg.trim().split(/\s+/).filter(Boolean);
217766
218886
  }
217767
218887
  function formatConnectUsage() {
@@ -217961,7 +219081,7 @@ ${formatBedrockUsage2()}`, false);
217961
219081
  }
217962
219082
  }
217963
219083
  async function handleConnect(ctx, msg) {
217964
- const parts = parseArgs10(msg);
219084
+ const parts = parseArgs9(msg);
217965
219085
  const providerToken = parts[1];
217966
219086
  if (!providerToken) {
217967
219087
  addCommandResult3(ctx.buffersRef, ctx.refreshDerived, msg, formatConnectUsage(), false);
@@ -218077,7 +219197,7 @@ The '${CLAUDE_PROVIDER_NAME}' provider does not exist in your Letta account.`, f
218077
219197
  }
218078
219198
  }
218079
219199
  async function handleDisconnect(ctx, msg) {
218080
- const parts = parseArgs10(msg);
219200
+ const parts = parseArgs9(msg);
218081
219201
  const providerToken = parts[1]?.toLowerCase();
218082
219202
  if (providerToken === "help") {
218083
219203
  addCommandResult3(ctx.buffersRef, ctx.refreshDerived, msg, formatDisconnectHelp(), true);
@@ -220379,9 +221499,8 @@ function App2({
220379
221499
  return;
220380
221500
  }
220381
221501
  try {
220382
- const client = await getClient();
220383
221502
  debugLog("conversations", `retrieve(${conversationId}) [syncConversationModel]`);
220384
- const conversation = await client.conversations.retrieve(conversationId);
221503
+ const conversation = await getBackend().retrieveConversation(conversationId);
220385
221504
  if (cancelled)
220386
221505
  return;
220387
221506
  const conversationModel = conversation.model;
@@ -220813,9 +221932,8 @@ ${newState.originalPrompt}`,
220813
221932
  })) {
220814
221933
  llmApiErrorRetriesRef.current += 1;
220815
221934
  try {
220816
- const client = await getClient();
220817
- const agent = await client.agents.retrieve(agentIdRef.current);
220818
- const { pendingApprovals: existingApprovals } = await getResumeData(client, agent, conversationIdRef.current);
221935
+ const agent = await getBackend().retrieveAgent(agentIdRef.current);
221936
+ const { pendingApprovals: existingApprovals } = await getResumeDataFromBackend2(agent, conversationIdRef.current);
220819
221937
  currentInput = rebuildInputWithFreshDenials(currentInput, existingApprovals ?? [], "Auto-denied: stale approval from interrupted session");
220820
221938
  } catch {
220821
221939
  currentInput = rebuildInputWithFreshDenials(currentInput, [], "");
@@ -220964,9 +222082,8 @@ ${newState.originalPrompt}`,
220964
222082
  if (hasApprovalInPayload2) {
220965
222083
  if (isInvalidToolCallIdsError(errorDetail)) {
220966
222084
  try {
220967
- const client = await getClient();
220968
- const agent = await client.agents.retrieve(agentIdRef.current);
220969
- const { pendingApprovals: serverApprovals } = await getResumeData(client, agent, conversationIdRef.current);
222085
+ const agent = await getBackend().retrieveAgent(agentIdRef.current);
222086
+ const { pendingApprovals: serverApprovals } = await getResumeDataFromBackend2(agent, conversationIdRef.current);
220970
222087
  if (serverApprovals && serverApprovals.length > 0) {
220971
222088
  const userMessage = currentInput.find((item) => item?.type === "message");
220972
222089
  if (userMessage && "content" in userMessage) {
@@ -221013,7 +222130,7 @@ ${newState.originalPrompt}`,
221013
222130
  }
221014
222131
  const syncAgentState = async () => {
221015
222132
  try {
221016
- const agent = prefetchedAgent ?? await (await getClient()).agents.retrieve(agentIdRef.current);
222133
+ const agent = prefetchedAgent ?? await getBackend().retrieveAgent(agentIdRef.current);
221017
222134
  const currentModel = llmConfigRef.current?.model;
221018
222135
  const currentEndpoint = llmConfigRef.current?.model_endpoint_type;
221019
222136
  const currentEffort = llmConfigRef.current?.reasoning_effort;
@@ -221174,8 +222291,7 @@ ${feedback}
221174
222291
  if (!conversationTitle) {
221175
222292
  isAutoConversationTitleInFlightRef.current = false;
221176
222293
  } else {
221177
- const client = await getClient();
221178
- client.conversations.update(conversationIdRef.current, {
222294
+ getBackend().updateConversation(conversationIdRef.current, {
221179
222295
  summary: conversationTitle
221180
222296
  }).then(() => {
221181
222297
  shouldAutoGenerateConversationTitleRef.current = false;
@@ -221593,9 +222709,8 @@ ${feedback}
221593
222709
  const invalidIdsDetected = isInvalidToolCallIdsError(detailFromRun) || isInvalidToolCallIdsError(latestErrorText);
221594
222710
  if (hasApprovalInPayload && invalidIdsDetected) {
221595
222711
  try {
221596
- const client = await getClient();
221597
- const agent = await client.agents.retrieve(agentIdRef.current);
221598
- const { pendingApprovals: serverApprovals } = await getResumeData(client, agent, conversationIdRef.current);
222712
+ const agent = await getBackend().retrieveAgent(agentIdRef.current);
222713
+ const { pendingApprovals: serverApprovals } = await getResumeDataFromBackend2(agent, conversationIdRef.current);
221599
222714
  if (serverApprovals && serverApprovals.length > 0) {
221600
222715
  const userMessage = currentInput.find((item) => item?.type === "message");
221601
222716
  if (userMessage && "content" in userMessage) {
@@ -221638,9 +222753,8 @@ ${feedback}
221638
222753
  })) {
221639
222754
  llmApiErrorRetriesRef.current += 1;
221640
222755
  try {
221641
- const client = await getClient();
221642
- const agent = await client.agents.retrieve(agentIdRef.current);
221643
- const { pendingApprovals: existingApprovals } = await getResumeData(client, agent, conversationIdRef.current);
222756
+ const agent = await getBackend().retrieveAgent(agentIdRef.current);
222757
+ const { pendingApprovals: existingApprovals } = await getResumeDataFromBackend2(agent, conversationIdRef.current);
221644
222758
  currentInput = rebuildInputWithFreshDenials(currentInput, existingApprovals ?? [], "Auto-denied: stale approval from interrupted session");
221645
222759
  } catch {
221646
222760
  currentInput = rebuildInputWithFreshDenials(currentInput, [], "");
@@ -222273,7 +223387,7 @@ ${feedback}
222273
223387
  setBtwState({ status: "forking", question });
222274
223388
  try {
222275
223389
  const isDefault = conversationIdRef.current === "default";
222276
- const forked = await forkConversation(conversationIdRef.current, {
223390
+ const forked = await getBackend().forkConversation(conversationIdRef.current, {
222277
223391
  ...isDefault ? { agentId } : {}
222278
223392
  });
222279
223393
  debugLog("btw", "forked conversationId=%s", forked.id);
@@ -222314,14 +223428,13 @@ ${feedback}
222314
223428
  })) {
222315
223429
  approvalRecoveryRetries += 1;
222316
223430
  try {
222317
- const client = await getClient();
222318
223431
  const currentAgentId = agentIdRef.current ?? agentId;
222319
223432
  if (!currentAgentId) {
222320
223433
  currentInput = rebuildInputWithFreshDenials(currentInput, [], "");
222321
223434
  continue;
222322
223435
  }
222323
- const agent = await client.agents.retrieve(currentAgentId);
222324
- const { pendingApprovals: existingApprovals } = await getResumeData(client, agent, forked.id);
223436
+ const agent = await getBackend().retrieveAgent(currentAgentId);
223437
+ const { pendingApprovals: existingApprovals } = await getResumeDataFromBackend2(agent, forked.id);
222325
223438
  currentInput = rebuildInputWithFreshDenials(currentInput, existingApprovals ?? [], STALE_APPROVAL_RECOVERY_DENIAL_REASON);
222326
223439
  } catch {
222327
223440
  currentInput = rebuildInputWithFreshDenials(currentInput, [], "");
@@ -222378,8 +223491,7 @@ ${feedback}
222378
223491
  if (!agentState) {
222379
223492
  throw new Error("Agent state not available");
222380
223493
  }
222381
- const client = await getClient();
222382
- const resumeData = await getResumeData(client, agentState, conversationId2);
223494
+ const resumeData = await getResumeDataFromBackend2(agentState, conversationId2);
222383
223495
  await maybeCarryOverActiveConversationModel(conversationId2);
222384
223496
  setConversationIdAndRef(conversationId2);
222385
223497
  setConversationAutoTitleEligibility(false);
@@ -222482,8 +223594,7 @@ ${feedback}
222482
223594
  const cmd = overlayCommand ?? commandRunner.start("/agents", "Switching agent...");
222483
223595
  cmd.update({ output: "Switching agent...", phase: "running" });
222484
223596
  try {
222485
- const client = await getClient();
222486
- const agent = await client.agents.retrieve(targetAgentId);
223597
+ const agent = await getBackend().retrieveAgent(targetAgentId);
222487
223598
  const targetConversationId = opts?.conversationId ?? "default";
222488
223599
  await updateProjectSettings({ lastAgent: targetAgentId });
222489
223600
  settingsManager.persistSession(targetAgentId, targetConversationId);
@@ -222572,8 +223683,7 @@ ${feedback}
222572
223683
  const isSelfHosted = !getServerUrl().includes("api.letta.com");
222573
223684
  if (isSelfHosted) {
222574
223685
  try {
222575
- const client = await getClient();
222576
- const availableHandles = (await client.models.list()).map((model) => model.handle).filter((handle) => typeof handle === "string");
223686
+ const availableHandles = (await backend4.listModels()).map((model) => model.handle).filter((handle) => typeof handle === "string");
222577
223687
  effectiveModel = selectDefaultAgentModel({
222578
223688
  preferredModel: effectiveModel,
222579
223689
  isSelfHosted: true,
@@ -222769,9 +223879,8 @@ ${expanded.command}` : expanded.command;
222769
223879
  return { blocked: false };
222770
223880
  }
222771
223881
  try {
222772
- const client = await getClient();
222773
- const agent = await client.agents.retrieve(agentId);
222774
- const { pendingApprovals: existingApprovals } = await getResumeData(client, agent, conversationIdRef.current);
223882
+ const agent = await getBackend().retrieveAgent(agentId);
223883
+ const { pendingApprovals: existingApprovals } = await getResumeDataFromBackend2(agent, conversationIdRef.current);
222775
223884
  if (!existingApprovals || existingApprovals.length === 0) {
222776
223885
  setNeedsEagerApprovalCheck(false);
222777
223886
  return { blocked: false };
@@ -222935,6 +224044,11 @@ ${SYSTEM_REMINDER_CLOSE}` : "";
222935
224044
  return { submitted: true };
222936
224045
  }
222937
224046
  if (trimmed === "/install-github-app") {
224047
+ if (getBackend().capabilities.localModelCatalog) {
224048
+ const cmd = commandRunner.start(trimmed, "Checking GitHub App installer support...");
224049
+ cmd.fail("GitHub App installation is not supported by the local backend.");
224050
+ return { submitted: true };
224051
+ }
222938
224052
  startOverlayCommand("install-github-app", "/install-github-app", "Opening GitHub App installer...", "GitHub App installer dismissed");
222939
224053
  setActiveOverlay("install-github-app");
222940
224054
  return { submitted: true };
@@ -223038,6 +224152,11 @@ ${SYSTEM_REMINDER_CLOSE}` : "";
223038
224152
  };
223039
224153
  const afterMcp = msg.trim().slice(4).trim();
223040
224154
  const firstWord = afterMcp.split(/\s+/)[0]?.toLowerCase();
224155
+ if (firstWord !== "help" && !getBackend().capabilities.serverSideToolManagement) {
224156
+ const cmd = commandRunner.start(msg, "Checking MCP support...");
224157
+ cmd.fail("MCP server management is not supported by the local backend yet.");
224158
+ return { submitted: true };
224159
+ }
223041
224160
  if (!firstWord) {
223042
224161
  startOverlayCommand("mcp", "/mcp", "Opening MCP server manager...", "MCP dialog dismissed");
223043
224162
  setActiveOverlay("mcp");
@@ -223552,8 +224671,8 @@ Type your task to begin the loop.`, true);
223552
224671
  setCommandRunning(true);
223553
224672
  await runEndHooks();
223554
224673
  try {
223555
- const client = await getClient();
223556
- const conversation = await client.conversations.create({
224674
+ const backend4 = getBackend();
224675
+ const conversation = await backend4.createConversation({
223557
224676
  agent_id: agentId,
223558
224677
  isolated_block_labels: [...ISOLATED_BLOCK_LABELS],
223559
224678
  ...conversationName && { summary: conversationName }
@@ -223593,13 +224712,13 @@ Type your task to begin the loop.`, true);
223593
224712
  setCommandRunning(true);
223594
224713
  await runEndHooks();
223595
224714
  try {
223596
- const client = await getClient();
223597
224715
  const isDefault = conversationIdRef.current === "default";
223598
- const forked = await forkConversation(conversationIdRef.current, {
224716
+ const backend4 = getBackend();
224717
+ const forked = await backend4.forkConversation(conversationIdRef.current, {
223599
224718
  ...isDefault ? { agentId } : {}
223600
224719
  });
223601
224720
  if (conversationSummary) {
223602
- await client.conversations.update(forked.id, {
224721
+ await backend4.updateConversation(forked.id, {
223603
224722
  summary: conversationSummary
223604
224723
  });
223605
224724
  }
@@ -223648,13 +224767,14 @@ Type your task to begin the loop.`, true);
223648
224767
  setCommandRunning(true);
223649
224768
  await runEndHooks();
223650
224769
  try {
223651
- const client = await getClient();
223652
- if (conversationIdRef.current === "default") {
224770
+ const backend4 = getBackend();
224771
+ if (conversationIdRef.current === "default" && !backend4.capabilities.localModelCatalog) {
224772
+ const client = await getClient();
223653
224773
  await client.agents.messages.reset(agentId, {
223654
224774
  add_default_initial_messages: false
223655
224775
  });
223656
224776
  }
223657
- const conversation = await client.conversations.create({
224777
+ const conversation = await backend4.createConversation({
223658
224778
  agent_id: agentId,
223659
224779
  isolated_block_labels: [...ISOLATED_BLOCK_LABELS]
223660
224780
  });
@@ -223801,20 +224921,20 @@ Type your task to begin the loop.`, true);
223801
224921
  });
223802
224922
  setCommandRunning(true);
223803
224923
  try {
223804
- const client = await getClient();
224924
+ const backend4 = getBackend();
223805
224925
  if (shouldAutoGenerate) {
223806
224926
  const conversationTitle = await generateConversationTitle();
223807
224927
  if (!conversationTitle) {
223808
224928
  cmd.fail("No conversation content available to generate a title");
223809
224929
  return { submitted: true };
223810
224930
  }
223811
- await client.conversations.update(conversationId, {
224931
+ await backend4.updateConversation(conversationId, {
223812
224932
  summary: conversationTitle
223813
224933
  });
223814
224934
  setConversationAutoTitleEligibility(false);
223815
224935
  cmd.finish(`Conversation title set to "${conversationTitle}"`, true);
223816
224936
  } else {
223817
- await client.conversations.update(conversationId, {
224937
+ await backend4.updateConversation(conversationId, {
223818
224938
  summary: newValue
223819
224939
  });
223820
224940
  setConversationAutoTitleEligibility(false);
@@ -223839,8 +224959,9 @@ Type your task to begin the loop.`, true);
223839
224959
  });
223840
224960
  setCommandRunning(true);
223841
224961
  try {
223842
- const client = await getClient();
223843
- await client.agents.update(agentId, { name: newValue });
224962
+ await getBackend().updateAgent(agentId, {
224963
+ name: newValue
224964
+ });
223844
224965
  updateAgentName(newValue);
223845
224966
  cmd.agentHint = `Your name is now "${newValue}" — acknowledge this and save your new name to memory.`;
223846
224967
  cmd.finish(`Agent renamed to "${newValue}"`, true);
@@ -223877,10 +224998,11 @@ Type your task to begin the loop.`, true);
223877
224998
  cmd.update({ output: "Updating description...", phase: "running" });
223878
224999
  setCommandRunning(true);
223879
225000
  try {
223880
- const client = await getClient();
223881
- await client.agents.update(agentId, {
225001
+ await getBackend().updateAgent(agentId, {
223882
225002
  description: newDescription
223883
225003
  });
225004
+ setAgentState((prev) => prev ? { ...prev, description: newDescription } : prev);
225005
+ setAgentDescription(newDescription);
223884
225006
  cmd.finish(`Description updated to "${newDescription}"`, true);
223885
225007
  } catch (error51) {
223886
225008
  const errorDetails = formatErrorDetails2(error51, agentId);
@@ -223923,8 +225045,7 @@ Type your task to begin the loop.`, true);
223923
225045
  setCommandRunning(true);
223924
225046
  try {
223925
225047
  if (agentState) {
223926
- const client = await getClient();
223927
- const resumeData = await getResumeData(client, agentState, targetConvId);
225048
+ const resumeData = await getResumeDataFromBackend2(agentState, targetConvId);
223928
225049
  setConversationIdAndRef(targetConvId);
223929
225050
  setConversationAutoTitleEligibility(false);
223930
225051
  pendingConversationSwitchRef.current = {
@@ -224198,6 +225319,10 @@ Press Enter to continue, or type anything to cancel.`, false, "running");
224198
225319
  }
224199
225320
  if (msg.trim() === "/export" || msg.trim() === "/download") {
224200
225321
  const cmd = commandRunner.start(msg.trim(), "Exporting agent file...");
225322
+ if (!getBackend().capabilities.agentFileImportExport) {
225323
+ cmd.fail("AgentFile export is not supported by the local backend yet.");
225324
+ return { submitted: true };
225325
+ }
224201
225326
  setCommandRunning(true);
224202
225327
  try {
224203
225328
  const client = await getClient();
@@ -224484,8 +225609,7 @@ ${SYSTEM_REMINDER_CLOSE}`;
224484
225609
  const reflectionConversationId = conversationIdRef.current;
224485
225610
  let systemPrompt;
224486
225611
  try {
224487
- const client = await getClient();
224488
- const agent = await client.agents.retrieve(agentId);
225612
+ const agent = await getBackend().retrieveAgent(agentId);
224489
225613
  systemPrompt = agent.system ?? undefined;
224490
225614
  } catch {}
224491
225615
  const autoPayload = await buildAutoReflectionPayload(agentId, reflectionConversationId, systemPrompt);
@@ -224752,6 +225876,48 @@ ${SYSTEM_REMINDER_CLOSE}`),
224752
225876
  if (registryCmd) {
224753
225877
  registryCmd.fail(`Unknown command: ${registryCommandName}`);
224754
225878
  }
225879
+ const skillCommandName = registryCommandName.slice(1);
225880
+ const { discoverClientSideSkills: discoverClientSideSkills2 } = await Promise.resolve().then(() => (init_clientSkills(), exports_clientSkills));
225881
+ const { getSkillSources: getSkillSources3 } = await Promise.resolve().then(() => (init_context(), exports_context));
225882
+ const { isUserInvocableSkill: isUserInvocableSkill3 } = await Promise.resolve().then(() => (init_skills(), exports_skills));
225883
+ const skillDiscovery = await discoverClientSideSkills2({
225884
+ agentId,
225885
+ skillSources: getSkillSources3()
225886
+ });
225887
+ const matchedSkill = skillDiscovery.skills.find((skill2) => skill2.id === skillCommandName && isUserInvocableSkill3(skill2));
225888
+ if (matchedSkill) {
225889
+ const cmd = commandRunner.start(trimmed, `Running /${matchedSkill.id}...`);
225890
+ const approvalCheck = await checkPendingApprovalsForSlashCommand();
225891
+ if (approvalCheck.blocked) {
225892
+ cmd.fail(`Pending approval(s). Resolve approvals before running /${matchedSkill.id}.`);
225893
+ return { submitted: false };
225894
+ }
225895
+ const args = trimmed.slice(`/${matchedSkill.id}`.length).trim();
225896
+ setCommandRunning(true);
225897
+ try {
225898
+ const { loadRenderedSkillContent: loadRenderedSkillContent2, wrapSkillContent: wrapSkillContent2 } = await Promise.resolve().then(() => (init_Skill2(), exports_Skill));
225899
+ const skillContent = await loadRenderedSkillContent2(matchedSkill.id, {
225900
+ agentId,
225901
+ args,
225902
+ allowDisabledModelInvocation: true
225903
+ });
225904
+ cmd.finish("Running skill...", true);
225905
+ await processConversationWithQueuedApprovals([
225906
+ {
225907
+ type: "message",
225908
+ role: "user",
225909
+ content: buildTextParts(wrapSkillContent2(matchedSkill.id, skillContent)),
225910
+ otid: randomUUID18()
225911
+ }
225912
+ ]);
225913
+ } catch (error51) {
225914
+ const errorDetails = formatErrorDetails2(error51, agentId);
225915
+ cmd.fail(`Failed to run skill: ${errorDetails}`);
225916
+ } finally {
225917
+ setCommandRunning(false);
225918
+ }
225919
+ return { submitted: true };
225920
+ }
224755
225921
  } else {
224756
225922
  if (registryCmd) {
224757
225923
  registryCmd.finish(result.output, result.success);
@@ -224842,8 +226008,7 @@ ${SYSTEM_REMINDER_CLOSE}
224842
226008
  const reflectionConversationId = conversationIdRef.current;
224843
226009
  let systemPrompt;
224844
226010
  try {
224845
- const client = await getClient();
224846
- const agent = await client.agents.retrieve(agentId);
226011
+ const agent = await getBackend().retrieveAgent(agentId);
224847
226012
  systemPrompt = agent.system ?? undefined;
224848
226013
  } catch {}
224849
226014
  const autoPayload = await buildAutoReflectionPayload(agentId, reflectionConversationId, systemPrompt);
@@ -224972,9 +226137,8 @@ ${SYSTEM_REMINDER_CLOSE}
224972
226137
  buffersRef.current.order.push(eagerStatusId);
224973
226138
  refreshDerived();
224974
226139
  try {
224975
- const client = await getClient();
224976
- const agent = await client.agents.retrieve(agentId);
224977
- const { pendingApprovals: existingApprovals } = await getResumeData(client, agent, conversationIdRef.current);
226140
+ const agent = await getBackend().retrieveAgent(agentId);
226141
+ const { pendingApprovals: existingApprovals } = await getResumeDataFromBackend2(agent, conversationIdRef.current);
224978
226142
  buffersRef.current.byId.delete(eagerStatusId);
224979
226143
  buffersRef.current.order = buffersRef.current.order.filter((id) => id !== eagerStatusId);
224980
226144
  if (userCancelledRef.current || abortControllerRef.current?.signal.aborted) {
@@ -225933,16 +227097,17 @@ ${guidance}`);
225933
227097
  phase: "running"
225934
227098
  });
225935
227099
  try {
225936
- const client = await getClient();
225937
227100
  const existing = agentState?.compaction_settings;
225938
227101
  const existingModel = existing?.model?.trim();
225939
- await client.agents.update(agentId, {
225940
- compaction_settings: {
225941
- ...existing,
225942
- model: existingModel || DEFAULT_SUMMARIZATION_MODEL,
225943
- mode
225944
- }
227102
+ const nextCompactionSettings = {
227103
+ ...existing,
227104
+ model: existingModel || DEFAULT_SUMMARIZATION_MODEL,
227105
+ mode
227106
+ };
227107
+ await getBackend().updateAgent(agentId, {
227108
+ compaction_settings: nextCompactionSettings
225945
227109
  });
227110
+ setAgentState((prev) => prev ? { ...prev, compaction_settings: nextCompactionSettings } : prev);
225946
227111
  cmd.finish(`Updated compaction mode to: ${mode}`, true);
225947
227112
  } catch (error51) {
225948
227113
  const errorDetails = formatErrorDetails2(error51, agentId);
@@ -226094,9 +227259,8 @@ ${guidance}`);
226094
227259
  if (action.conversationId === conversationId) {
226095
227260
  cmd.finish("Already on this conversation", true);
226096
227261
  } else {
226097
- const client = await getClient();
226098
227262
  if (agentState) {
226099
- const resumeData = await getResumeData(client, agentState, action.conversationId);
227263
+ const resumeData = await getResumeDataFromBackend2(agentState, action.conversationId);
226100
227264
  setConversationIdAndRef(action.conversationId);
226101
227265
  setConversationAutoTitleEligibility(false);
226102
227266
  pendingConversationSwitchRef.current = {
@@ -227407,8 +228571,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
227407
228571
  });
227408
228572
  try {
227409
228573
  if (agentState) {
227410
- const client = await getClient();
227411
- const resumeData = await getResumeData(client, agentState, convId);
228574
+ const resumeData = await getResumeDataFromBackend2(agentState, convId);
227412
228575
  setConversationIdAndRef(convId);
227413
228576
  setConversationAutoTitleEligibility(false);
227414
228577
  pendingConversationSwitchRef.current = {
@@ -227513,8 +228676,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
227513
228676
  phase: "running"
227514
228677
  });
227515
228678
  try {
227516
- const client = await getClient();
227517
- const conversation = await client.conversations.create({
228679
+ const conversation = await getBackend().createConversation({
227518
228680
  agent_id: agentId,
227519
228681
  isolated_block_labels: [...ISOLATED_BLOCK_LABELS]
227520
228682
  });
@@ -227602,8 +228764,7 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
227602
228764
  });
227603
228765
  try {
227604
228766
  if (agentState) {
227605
- const client = await getClient();
227606
- const resumeData = await getResumeData(client, agentState, actualTargetConv);
228767
+ const resumeData = await getResumeDataFromBackend2(agentState, actualTargetConv);
227607
228768
  setConversationIdAndRef(actualTargetConv);
227608
228769
  setConversationAutoTitleEligibility(false);
227609
228770
  pendingConversationSwitchRef.current = {
@@ -227759,9 +228920,10 @@ Open /mcp to attach or detach tools for this server.`, true);
227759
228920
  phase: "running"
227760
228921
  });
227761
228922
  try {
227762
- const client = await getClient();
227763
228923
  if (newName && newName !== agentName) {
227764
- await client.agents.update(agentId, { name: newName });
228924
+ await getBackend().updateAgent(agentId, {
228925
+ name: newName
228926
+ });
227765
228927
  updateAgentName(newName);
227766
228928
  }
227767
228929
  if (pinDialogLocal) {
@@ -227809,7 +228971,6 @@ var init_App2 = __esm(async () => {
227809
228971
  init_backend2();
227810
228972
  init_agents5();
227811
228973
  init_client2();
227812
- init_conversations2();
227813
228974
  init_metadata();
227814
228975
  init_constants();
227815
228976
  init_manager();
@@ -229146,9 +230307,8 @@ async function hydrateMemfsSettingFromAgent2(agent) {
229146
230307
  return enabled;
229147
230308
  }
229148
230309
  async function isMemfsEnabledOnServer2(agentId) {
229149
- const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
229150
- const client = await getClient2();
229151
- const agent = await client.agents.retrieve(agentId, {
230310
+ const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
230311
+ const agent = await getBackend2().retrieveAgent(agentId, {
229152
230312
  include: ["agent.tags"]
229153
230313
  });
229154
230314
  const { GIT_MEMORY_ENABLED_TAG: GIT_MEMORY_ENABLED_TAG2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
@@ -229281,7 +230441,8 @@ async function applyMemfsFlags2(agentId, memfsFlag, noMemfsFlag, options) {
229281
230441
  const backend4 = getBackend2();
229282
230442
  if (backend4.capabilities.localMemfs) {
229283
230443
  if (noMemfsFlag) {
229284
- throw new Error("Disabling MemFS is not supported by the local backend.");
230444
+ settingsManager3.setMemfsEnabled(agentId, false);
230445
+ return { action: "disabled" };
229285
230446
  }
229286
230447
  const memoryDir = getScopedMemoryFilesystemRoot2(agentId);
229287
230448
  const { initializeLocalMemoryRepo: initializeLocalMemoryRepo2 } = await Promise.resolve().then(() => (init_memoryGit(), exports_memoryGit));
@@ -229458,7 +230619,7 @@ async function initSecretsFromServer2(agentId, cachedAgent) {
229458
230619
  setCache2(agentId, {});
229459
230620
  return;
229460
230621
  }
229461
- const agent = cachedAgent ?? await (await getClient()).agents.retrieve(agentId, {
230622
+ const agent = cachedAgent ?? await getBackend().retrieveAgent(agentId, {
229462
230623
  include: ["agent.secrets"]
229463
230624
  });
229464
230625
  const secrets2 = {};
@@ -229491,6 +230652,9 @@ async function refreshAndListSecrets2(agentIdArg) {
229491
230652
  return Object.keys(cache5).sort().map((key) => ({ key, value: cache5[key] ?? "" }));
229492
230653
  }
229493
230654
  async function applySecretBatch2(options, agentIdArg) {
230655
+ if (!getBackend().capabilities.serverSecrets) {
230656
+ throw new Error("Agent secrets are not supported by this backend yet");
230657
+ }
229494
230658
  const agentId = resolveSecretsAgentId2(agentIdArg);
229495
230659
  if (!agentId) {
229496
230660
  throw new Error("No agent context set. Agent ID is required.");
@@ -229502,8 +230666,7 @@ async function applySecretBatch2(options, agentIdArg) {
229502
230666
  for (const rawKey of options.unset ?? []) {
229503
230667
  delete next[rawKey.toUpperCase()];
229504
230668
  }
229505
- const client = await getClient();
229506
- await client.agents.update(agentId, { secrets: next });
230669
+ await getBackend().updateAgent(agentId, { secrets: next });
229507
230670
  setCache2(agentId, next);
229508
230671
  return Object.keys(next).sort();
229509
230672
  }
@@ -229511,14 +230674,13 @@ async function setSecretOnServer2(key, value, agentIdArg) {
229511
230674
  if (!getBackend().capabilities.serverSecrets) {
229512
230675
  throw new Error("Agent secrets are not supported by this backend yet");
229513
230676
  }
229514
- const client = await getClient();
229515
230677
  const agentId = resolveSecretsAgentId2(agentIdArg);
229516
230678
  if (!agentId) {
229517
230679
  throw new Error("No agent context set. Agent ID is required.");
229518
230680
  }
229519
230681
  const secrets2 = { ...loadSecrets2(agentId) };
229520
230682
  secrets2[key] = value;
229521
- await client.agents.update(agentId, { secrets: secrets2 });
230683
+ await getBackend().updateAgent(agentId, { secrets: secrets2 });
229522
230684
  setCache2(agentId, secrets2);
229523
230685
  }
229524
230686
  async function deleteSecretOnServer2(key, agentIdArg) {
@@ -229534,8 +230696,7 @@ async function deleteSecretOnServer2(key, agentIdArg) {
229534
230696
  return false;
229535
230697
  }
229536
230698
  delete secrets2[key];
229537
- const client = await getClient();
229538
- await client.agents.update(agentId, { secrets: secrets2 });
230699
+ await getBackend().updateAgent(agentId, { secrets: secrets2 });
229539
230700
  setCache2(agentId, secrets2);
229540
230701
  return true;
229541
230702
  }
@@ -229551,7 +230712,6 @@ var SECRETS_CACHE_KEY2;
229551
230712
  var init_secretsStore2 = __esm(() => {
229552
230713
  init_context();
229553
230714
  init_backend2();
229554
- init_client2();
229555
230715
  SECRETS_CACHE_KEY2 = Symbol.for("@letta/secretsCache");
229556
230716
  });
229557
230717
 
@@ -230084,6 +231244,9 @@ init_available_models();
230084
231244
  function supportsDistinctAnthropicXHighEffort2(modelHandle) {
230085
231245
  return modelHandle.includes("claude-opus-4-7");
230086
231246
  }
231247
+ function isRecord10(value) {
231248
+ return typeof value === "object" && value !== null && !Array.isArray(value);
231249
+ }
230087
231250
  function buildModelSettings2(modelHandle, updateArgs) {
230088
231251
  const isOpenAI = modelHandle.startsWith("openai/") || modelHandle.startsWith(`${OPENAI_CODEX_PROVIDER_NAME}/`);
230089
231252
  const isAnthropic = modelHandle.startsWith("anthropic/") || modelHandle.startsWith("claude-pro-max/") || modelHandle.startsWith("minimax/");
@@ -230206,6 +231369,12 @@ function buildModelSettings2(modelHandle, updateArgs) {
230206
231369
  if (typeof updateArgs?.max_output_tokens === "number" && "provider_type" in settings) {
230207
231370
  settings.max_output_tokens = updateArgs.max_output_tokens;
230208
231371
  }
231372
+ if (isRecord10(updateArgs?.modalities)) {
231373
+ settings.modalities = updateArgs.modalities;
231374
+ }
231375
+ if (isRecord10(updateArgs?.capabilities)) {
231376
+ settings.capabilities = updateArgs.capabilities;
231377
+ }
230209
231378
  return settings;
230210
231379
  }
230211
231380
  async function updateAgentLLMConfig2(agentId, modelHandle, updateArgs, options) {
@@ -230529,6 +231698,15 @@ async function getBillingTier2() {
230529
231698
  }
230530
231699
  }
230531
231700
 
231701
+ // src/backend/local/paths.ts
231702
+ var LOCAL_BACKEND_NO_MEMFS_ENV2 = "LETTA_LOCAL_BACKEND_NO_MEMFS";
231703
+ function isTruthyEnv3(value) {
231704
+ return value === "1" || value?.toLowerCase() === "true";
231705
+ }
231706
+ function isLocalBackendNoMemfsEnvEnabled2(env = process.env) {
231707
+ return isTruthyEnv3(env[LOCAL_BACKEND_NO_MEMFS_ENV2]);
231708
+ }
231709
+
230532
231710
  // src/cli/args.ts
230533
231711
  import { parseArgs } from "node:util";
230534
231712
  var CLI_FLAG_CATALOG = {
@@ -232866,7 +234044,7 @@ function validateRegistryHandleOrThrow(handle) {
232866
234044
  // src/cli/subcommands/agents.ts
232867
234045
  init_create();
232868
234046
  init_personality();
232869
- init_client2();
234047
+ init_backend2();
232870
234048
  init_settings_manager();
232871
234049
  import { parseArgs as parseArgs2 } from "node:util";
232872
234050
  function printUsage() {
@@ -233000,8 +234178,7 @@ async function runCreateAction(values) {
233000
234178
  if (values.pinned) {
233001
234179
  settingsManager.pinGlobal(agentId);
233002
234180
  }
233003
- const client = await getClient();
233004
- const updatedAgent = await client.agents.retrieve(agentId);
234181
+ const updatedAgent = await getBackend().retrieveAgent(agentId);
233005
234182
  console.log(JSON.stringify(updatedAgent, null, 2));
233006
234183
  return 0;
233007
234184
  } catch (error51) {
@@ -233031,8 +234208,7 @@ async function runListAction(values) {
233031
234208
  params.include = ["agent.blocks"];
233032
234209
  }
233033
234210
  try {
233034
- const client = await getClient();
233035
- const result = await client.agents.list(params);
234211
+ const result = await getBackend().listAgents(params);
233036
234212
  console.log(JSON.stringify(result, null, 2));
233037
234213
  return 0;
233038
234214
  } catch (error51) {
@@ -233041,234 +234217,6 @@ async function runListAction(values) {
233041
234217
  }
233042
234218
  }
233043
234219
 
233044
- // src/cli/subcommands/blocks.ts
233045
- init_client2();
233046
- init_settings_manager();
233047
- import { parseArgs as parseArgs3 } from "node:util";
233048
- function printUsage2() {
233049
- console.log(`
233050
- Usage:
233051
- letta blocks list --agent <id> [--limit <n>]
233052
- letta blocks copy --block-id <id> [--label <new-label>] [--agent <id>] [--override]
233053
- letta blocks attach --block-id <id> [--agent <id>] [--read-only] [--override]
233054
-
233055
- Notes:
233056
- - Output is JSON only.
233057
- - Uses CLI auth; override with LETTA_API_KEY/LETTA_BASE_URL if needed.
233058
- - Default target agent for copy/attach is LETTA_AGENT_ID.
233059
- `.trim());
233060
- }
233061
- function parseLimit2(value, fallback) {
233062
- if (typeof value !== "string" || value.length === 0)
233063
- return fallback;
233064
- const parsed = Number.parseInt(value, 10);
233065
- return Number.isNaN(parsed) ? fallback : parsed;
233066
- }
233067
- function getAgentId2(agentFromArgs, agentIdFromArgs) {
233068
- return agentFromArgs || agentIdFromArgs || process.env.LETTA_AGENT_ID || "";
233069
- }
233070
- var BLOCKS_OPTIONS = {
233071
- help: { type: "boolean", short: "h" },
233072
- agent: { type: "string" },
233073
- "agent-id": { type: "string" },
233074
- limit: { type: "string" },
233075
- "block-id": { type: "string" },
233076
- label: { type: "string" },
233077
- override: { type: "boolean" },
233078
- "read-only": { type: "boolean" }
233079
- };
233080
- function parseBlocksArgs(argv) {
233081
- return parseArgs3({
233082
- args: argv,
233083
- options: BLOCKS_OPTIONS,
233084
- strict: true,
233085
- allowPositionals: true
233086
- });
233087
- }
233088
- async function copyBlock(client, blockId, options) {
233089
- const currentAgentId = getAgentId2(options?.targetAgentId);
233090
- if (!currentAgentId) {
233091
- throw new Error("Missing agent id. Set LETTA_AGENT_ID or pass --agent/--agent-id.");
233092
- }
233093
- let detachedBlock;
233094
- const sourceBlock = await client.blocks.retrieve(blockId);
233095
- const targetLabel = options?.labelOverride || sourceBlock.label || "migrated-block";
233096
- if (options?.override) {
233097
- const currentBlocksResponse = await client.agents.blocks.list(currentAgentId);
233098
- const currentBlocks = Array.isArray(currentBlocksResponse) ? currentBlocksResponse : currentBlocksResponse.items || [];
233099
- const conflictingBlock = currentBlocks.find((b) => b.label === targetLabel);
233100
- if (conflictingBlock) {
233101
- console.error(`Detaching existing block with label "${targetLabel}" (${conflictingBlock.id})...`);
233102
- detachedBlock = conflictingBlock;
233103
- try {
233104
- await client.agents.blocks.detach(conflictingBlock.id, {
233105
- agent_id: currentAgentId
233106
- });
233107
- } catch (detachError) {
233108
- throw new Error(`Failed to detach existing block "${targetLabel}": ${detachError instanceof Error ? detachError.message : String(detachError)}`);
233109
- }
233110
- }
233111
- }
233112
- let newBlock;
233113
- try {
233114
- newBlock = await client.blocks.create({
233115
- label: targetLabel,
233116
- value: sourceBlock.value,
233117
- description: sourceBlock.description || undefined,
233118
- limit: sourceBlock.limit
233119
- });
233120
- } catch (createError) {
233121
- if (detachedBlock) {
233122
- console.error(`Create failed, reattaching original block "${detachedBlock.label}"...`);
233123
- try {
233124
- await client.agents.blocks.attach(detachedBlock.id, {
233125
- agent_id: currentAgentId
233126
- });
233127
- console.error("Original block reattached successfully.");
233128
- } catch {
233129
- console.error(`WARNING: Failed to reattach original block! Block ID: ${detachedBlock.id}`);
233130
- }
233131
- }
233132
- throw createError;
233133
- }
233134
- let attachResult;
233135
- try {
233136
- attachResult = await client.agents.blocks.attach(newBlock.id, {
233137
- agent_id: currentAgentId
233138
- });
233139
- } catch (attachError) {
233140
- if (detachedBlock) {
233141
- console.error(`Attach failed, reattaching original block "${detachedBlock.label}"...`);
233142
- try {
233143
- await client.agents.blocks.attach(detachedBlock.id, {
233144
- agent_id: currentAgentId
233145
- });
233146
- console.error("Original block reattached successfully.");
233147
- } catch {
233148
- console.error(`WARNING: Failed to reattach original block! Block ID: ${detachedBlock.id}`);
233149
- }
233150
- }
233151
- throw attachError;
233152
- }
233153
- return { sourceBlock, newBlock, attachResult, detachedBlock };
233154
- }
233155
- async function attachBlock(client, blockId, options) {
233156
- const currentAgentId = getAgentId2(options?.targetAgentId);
233157
- if (!currentAgentId) {
233158
- throw new Error("Missing agent id. Set LETTA_AGENT_ID or pass --agent/--agent-id.");
233159
- }
233160
- let detachedBlock;
233161
- if (options?.override) {
233162
- const sourceBlock = await client.blocks.retrieve(blockId);
233163
- const sourceLabel = sourceBlock.label;
233164
- const currentBlocksResponse = await client.agents.blocks.list(currentAgentId);
233165
- const currentBlocks = Array.isArray(currentBlocksResponse) ? currentBlocksResponse : currentBlocksResponse.items || [];
233166
- const conflictingBlock = currentBlocks.find((b) => b.label === sourceLabel);
233167
- if (conflictingBlock) {
233168
- console.error(`Detaching existing block with label "${sourceLabel}" (${conflictingBlock.id})...`);
233169
- detachedBlock = conflictingBlock;
233170
- try {
233171
- await client.agents.blocks.detach(conflictingBlock.id, {
233172
- agent_id: currentAgentId
233173
- });
233174
- } catch (detachError) {
233175
- throw new Error(`Failed to detach existing block "${sourceLabel}": ${detachError instanceof Error ? detachError.message : String(detachError)}`);
233176
- }
233177
- }
233178
- }
233179
- let attachResult;
233180
- try {
233181
- attachResult = await client.agents.blocks.attach(blockId, {
233182
- agent_id: currentAgentId
233183
- });
233184
- } catch (attachError) {
233185
- if (detachedBlock) {
233186
- console.error(`Attach failed, reattaching original block "${detachedBlock.label}"...`);
233187
- try {
233188
- await client.agents.blocks.attach(detachedBlock.id, {
233189
- agent_id: currentAgentId
233190
- });
233191
- console.error("Original block reattached successfully.");
233192
- } catch {
233193
- console.error(`WARNING: Failed to reattach original block! Block ID: ${detachedBlock.id}`);
233194
- }
233195
- }
233196
- throw attachError;
233197
- }
233198
- if (options?.readOnly) {
233199
- console.warn("Note: read_only flag is set on the block itself, not per-agent. " + "Use the block update API to set read_only if needed.");
233200
- }
233201
- return { attachResult, detachedBlock };
233202
- }
233203
- async function runBlocksSubcommand(argv) {
233204
- let parsed;
233205
- try {
233206
- parsed = parseBlocksArgs(argv);
233207
- } catch (error51) {
233208
- const message = error51 instanceof Error ? error51.message : String(error51);
233209
- console.error(`Error: ${message}`);
233210
- printUsage2();
233211
- return 1;
233212
- }
233213
- const [action] = parsed.positionals;
233214
- if (parsed.values.help || !action || action === "help") {
233215
- printUsage2();
233216
- return 0;
233217
- }
233218
- try {
233219
- await settingsManager.initialize();
233220
- const client = await getClient();
233221
- if (action === "list") {
233222
- const agentId = parsed.values.agent || parsed.values["agent-id"] || "";
233223
- if (!agentId || typeof agentId !== "string") {
233224
- console.error("Missing required --agent <id>.");
233225
- return 1;
233226
- }
233227
- const result = await client.agents.blocks.list(agentId, {
233228
- limit: parseLimit2(parsed.values.limit, 1000)
233229
- });
233230
- console.log(JSON.stringify(result, null, 2));
233231
- return 0;
233232
- }
233233
- if (action === "copy") {
233234
- const blockId = parsed.values["block-id"];
233235
- if (!blockId || typeof blockId !== "string") {
233236
- console.error("Missing required --block-id <id>.");
233237
- return 1;
233238
- }
233239
- const agentId = getAgentId2(parsed.values.agent, parsed.values["agent-id"]);
233240
- const result = await copyBlock(client, blockId, {
233241
- labelOverride: typeof parsed.values.label === "string" ? parsed.values.label : undefined,
233242
- targetAgentId: agentId,
233243
- override: parsed.values.override === true
233244
- });
233245
- console.log(JSON.stringify(result, null, 2));
233246
- return 0;
233247
- }
233248
- if (action === "attach") {
233249
- const blockId = parsed.values["block-id"];
233250
- if (!blockId || typeof blockId !== "string") {
233251
- console.error("Missing required --block-id <id>.");
233252
- return 1;
233253
- }
233254
- const agentId = getAgentId2(parsed.values.agent, parsed.values["agent-id"]);
233255
- const result = await attachBlock(client, blockId, {
233256
- readOnly: parsed.values["read-only"] === true,
233257
- override: parsed.values.override === true,
233258
- targetAgentId: agentId
233259
- });
233260
- console.log(JSON.stringify(result, null, 2));
233261
- return 0;
233262
- }
233263
- } catch (error51) {
233264
- console.error(error51 instanceof Error ? error51.message : String(error51));
233265
- return 1;
233266
- }
233267
- console.error(`Unknown action: ${action}`);
233268
- printUsage2();
233269
- return 1;
233270
- }
233271
-
233272
234220
  // src/cli/subcommands/channels.ts
233273
234221
  init_accounts();
233274
234222
  init_pairing();
@@ -233277,8 +234225,8 @@ init_registry();
233277
234225
  init_routing();
233278
234226
  init_runtimeDeps();
233279
234227
  await init_service();
233280
- import { parseArgs as parseArgs4 } from "node:util";
233281
- function printUsage3() {
234228
+ import { parseArgs as parseArgs3 } from "node:util";
234229
+ function printUsage2() {
233282
234230
  console.log(`
233283
234231
  Usage:
233284
234232
  letta channels install <channel> Install channel runtime dependencies
@@ -233342,14 +234290,14 @@ var CHANNELS_OPTIONS = {
233342
234290
  code: { type: "string" }
233343
234291
  };
233344
234292
  function parseChannelsArgs(argv) {
233345
- return parseArgs4({
234293
+ return parseArgs3({
233346
234294
  args: argv,
233347
234295
  options: CHANNELS_OPTIONS,
233348
234296
  strict: true,
233349
234297
  allowPositionals: true
233350
234298
  });
233351
234299
  }
233352
- function getAgentId3(fromArgs) {
234300
+ function getAgentId2(fromArgs) {
233353
234301
  return fromArgs || process.env.LETTA_AGENT_ID || "";
233354
234302
  }
233355
234303
  function getConversationId2(fromArgs) {
@@ -233486,7 +234434,7 @@ function handleRouteAdd(values) {
233486
234434
  const channelId = values.channel;
233487
234435
  const accountId = values["account-id"];
233488
234436
  const chatId = values["chat-id"];
233489
- const agentId = getAgentId3(values.agent);
234437
+ const agentId = getAgentId2(values.agent);
233490
234438
  const conversationId = getConversationId2(values.conversation);
233491
234439
  if (!channelId) {
233492
234440
  console.error("Error: --channel is required.");
@@ -233574,7 +234522,7 @@ async function handlePair(values) {
233574
234522
  const channelId = values.channel;
233575
234523
  const accountId = values["account-id"];
233576
234524
  const code = values.code;
233577
- const agentId = getAgentId3(values.agent);
234525
+ const agentId = getAgentId2(values.agent);
233578
234526
  const conversationId = getConversationId2(values.conversation);
233579
234527
  if (!channelId) {
233580
234528
  console.error("Error: --channel is required.");
@@ -233605,7 +234553,7 @@ async function handlePair(values) {
233605
234553
  function handleBind(values) {
233606
234554
  const channelId = values.channel;
233607
234555
  const accountId = values["account-id"];
233608
- const agentId = getAgentId3(values.agent);
234556
+ const agentId = getAgentId2(values.agent);
233609
234557
  if (!channelId) {
233610
234558
  console.error("Error: --channel is required.");
233611
234559
  return 1;
@@ -233645,7 +234593,7 @@ function handleBind(values) {
233645
234593
  async function runChannelsSubcommand(argv) {
233646
234594
  const { values, positionals } = parseChannelsArgs(argv);
233647
234595
  if (values.help) {
233648
- printUsage3();
234596
+ printUsage2();
233649
234597
  return 0;
233650
234598
  }
233651
234599
  const [action, ...rest] = positionals;
@@ -233688,7 +234636,7 @@ async function runChannelsSubcommand(argv) {
233688
234636
  return await handlePair(values);
233689
234637
  default:
233690
234638
  if (!action) {
233691
- printUsage3();
234639
+ printUsage2();
233692
234640
  return 0;
233693
234641
  }
233694
234642
  console.error(`Unknown channels action: "${action}". Use: install, configure, status, route, bind, pair`);
@@ -233703,7 +234651,7 @@ init_connect_normalize();
233703
234651
  init_connect_oauth_core();
233704
234652
  import { createInterface as createInterface4 } from "node:readline/promises";
233705
234653
  import { Writable } from "node:stream";
233706
- import { parseArgs as parseArgs5 } from "node:util";
234654
+ import { parseArgs as parseArgs4 } from "node:util";
233707
234655
  var CONNECT_OPTIONS = {
233708
234656
  help: { type: "boolean", short: "h" },
233709
234657
  "api-key": { type: "string" },
@@ -233794,7 +234742,7 @@ async function runConnectSubcommand(argv, deps = {}) {
233794
234742
  const io = { ...DEFAULT_DEPS2, ...deps };
233795
234743
  let parsed;
233796
234744
  try {
233797
- parsed = parseArgs5({
234745
+ parsed = parseArgs4({
233798
234746
  args: argv,
233799
234747
  options: CONNECT_OPTIONS,
233800
234748
  strict: true,
@@ -233903,8 +234851,8 @@ async function runConnectSubcommand(argv, deps = {}) {
233903
234851
 
233904
234852
  // src/cli/subcommands/cron.ts
233905
234853
  init_cron();
233906
- import { parseArgs as parseArgs6 } from "node:util";
233907
- function printUsage4() {
234854
+ import { parseArgs as parseArgs5 } from "node:util";
234855
+ function printUsage3() {
233908
234856
  console.log(`
233909
234857
  Usage:
233910
234858
  letta cron add --prompt <text> --every <interval> [options]
@@ -233948,14 +234896,14 @@ var CRON_OPTIONS = {
233948
234896
  all: { type: "boolean" }
233949
234897
  };
233950
234898
  function parseCronArgs(argv) {
233951
- return parseArgs6({
234899
+ return parseArgs5({
233952
234900
  args: argv,
233953
234901
  options: CRON_OPTIONS,
233954
234902
  strict: true,
233955
234903
  allowPositionals: true
233956
234904
  });
233957
234905
  }
233958
- function getAgentId4(fromArgs) {
234906
+ function getAgentId3(fromArgs) {
233959
234907
  return fromArgs || process.env.LETTA_AGENT_ID || "";
233960
234908
  }
233961
234909
  function getConversationId3(fromArgs) {
@@ -233977,7 +234925,7 @@ function handleAdd(values) {
233977
234925
  console.error("Error: --prompt is required.");
233978
234926
  return 1;
233979
234927
  }
233980
- const agentId = getAgentId4(values.agent);
234928
+ const agentId = getAgentId3(values.agent);
233981
234929
  if (!agentId) {
233982
234930
  console.error("Error: --agent or LETTA_AGENT_ID required.");
233983
234931
  return 1;
@@ -234098,7 +235046,7 @@ function handleGet(positionals) {
234098
235046
  }
234099
235047
  function handleDelete(values, positionals) {
234100
235048
  if (values.all) {
234101
- const agentId = getAgentId4(values.agent);
235049
+ const agentId = getAgentId3(values.agent);
234102
235050
  if (!agentId) {
234103
235051
  console.error("Error: --agent or LETTA_AGENT_ID required with --all.");
234104
235052
  return 1;
@@ -234126,12 +235074,12 @@ async function runCronSubcommand(argv) {
234126
235074
  parsed = parseCronArgs(argv);
234127
235075
  } catch (err) {
234128
235076
  console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
234129
- printUsage4();
235077
+ printUsage3();
234130
235078
  return 1;
234131
235079
  }
234132
235080
  const [action] = parsed.positionals;
234133
235081
  if (parsed.values.help || !action || action === "help") {
234134
- printUsage4();
235082
+ printUsage3();
234135
235083
  return 0;
234136
235084
  }
234137
235085
  switch (action) {
@@ -234145,7 +235093,7 @@ async function runCronSubcommand(argv) {
234145
235093
  return handleDelete(parsed.values, parsed.positionals);
234146
235094
  default:
234147
235095
  console.error(`Unknown action: ${action}`);
234148
- printUsage4();
235096
+ printUsage3();
234149
235097
  return 1;
234150
235098
  }
234151
235099
  }
@@ -234160,7 +235108,7 @@ await __promiseAll([
234160
235108
  ]);
234161
235109
  var import_react30 = __toESM(require_react(), 1);
234162
235110
  import { hostname as hostname4 } from "node:os";
234163
- import { parseArgs as parseArgs7 } from "node:util";
235111
+ import { parseArgs as parseArgs6 } from "node:util";
234164
235112
 
234165
235113
  // src/websocket/listen-log.ts
234166
235114
  import {
@@ -234479,7 +235427,7 @@ async function resolveListenerRegistrationOptions(deviceId, connectionName) {
234479
235427
  };
234480
235428
  }
234481
235429
  async function runListenSubcommand(argv) {
234482
- const { values } = parseArgs7({
235430
+ const { values } = parseArgs6({
234483
235431
  args: argv,
234484
235432
  options: {
234485
235433
  "env-name": { type: "string" },
@@ -234815,7 +235763,7 @@ import { cpSync, existsSync as existsSync35, mkdirSync as mkdirSync25, rmSync as
234815
235763
  import { readdir as readdir7 } from "node:fs/promises";
234816
235764
  import { homedir as homedir26 } from "node:os";
234817
235765
  import { join as join38 } from "node:path";
234818
- import { parseArgs as parseArgs8 } from "node:util";
235766
+ import { parseArgs as parseArgs7 } from "node:util";
234819
235767
 
234820
235768
  // src/cli/subcommands/memoryTokens.ts
234821
235769
  init_systemPromptSize();
@@ -234896,7 +235844,7 @@ async function runMemoryTokensAction(options) {
234896
235844
  }
234897
235845
 
234898
235846
  // src/cli/subcommands/memory.ts
234899
- function printUsage5() {
235847
+ function printUsage4() {
234900
235848
  console.log(`
234901
235849
  Usage:
234902
235850
  letta memory status [--agent <id>]
@@ -234925,7 +235873,7 @@ Examples:
234925
235873
  letta memory tokens --memory-dir ~/.letta/agents/agent-123/memory --format json
234926
235874
  `.trim());
234927
235875
  }
234928
- function getAgentId5(agentFromArgs, agentIdFromArgs) {
235876
+ function getAgentId4(agentFromArgs, agentIdFromArgs) {
234929
235877
  return agentFromArgs || agentIdFromArgs || process.env.LETTA_AGENT_ID || "";
234930
235878
  }
234931
235879
  var MEMORY_OPTIONS = {
@@ -234941,7 +235889,7 @@ var MEMORY_OPTIONS = {
234941
235889
  quiet: { type: "boolean" }
234942
235890
  };
234943
235891
  function parseMemoryArgs(argv) {
234944
- return parseArgs8({
235892
+ return parseArgs7({
234945
235893
  args: argv,
234946
235894
  options: MEMORY_OPTIONS,
234947
235895
  strict: true,
@@ -235002,15 +235950,15 @@ async function runMemorySubcommand(argv) {
235002
235950
  } catch (error51) {
235003
235951
  const message = error51 instanceof Error ? error51.message : String(error51);
235004
235952
  console.error(`Error: ${message}`);
235005
- printUsage5();
235953
+ printUsage4();
235006
235954
  return 1;
235007
235955
  }
235008
235956
  const [action] = parsed.positionals;
235009
235957
  if (parsed.values.help || !action || action === "help") {
235010
- printUsage5();
235958
+ printUsage4();
235011
235959
  return 0;
235012
235960
  }
235013
- const agentId = getAgentId5(parsed.values.agent, parsed.values["agent-id"]);
235961
+ const agentId = getAgentId4(parsed.values.agent, parsed.values["agent-id"]);
235014
235962
  if (action === "tokens") {
235015
235963
  return runMemoryTokensAction({
235016
235964
  memoryDir: parsed.values["memory-dir"],
@@ -235143,17 +236091,18 @@ async function runMemorySubcommand(argv) {
235143
236091
  return 1;
235144
236092
  }
235145
236093
  console.error(`Unknown action: ${action}`);
235146
- printUsage5();
236094
+ printUsage4();
235147
236095
  return 1;
235148
236096
  }
235149
236097
 
235150
236098
  // src/cli/subcommands/messages.ts
235151
- init_client2();
236099
+ init_backend2();
236100
+ init_messageSearch();
235152
236101
  init_settings_manager();
235153
236102
  import { writeFile as writeFile11 } from "node:fs/promises";
235154
236103
  import { resolve as resolve33 } from "node:path";
235155
- import { parseArgs as parseArgs9 } from "node:util";
235156
- function printUsage6() {
236104
+ import { parseArgs as parseArgs8 } from "node:util";
236105
+ function printUsage5() {
235157
236106
  console.log(`
235158
236107
  Usage:
235159
236108
  letta messages search --query <text> [options]
@@ -235196,7 +236145,7 @@ Notes:
235196
236145
  - For agent-to-agent messaging, use: letta -p --from-agent <sender-id> --agent <target-id> "message"
235197
236146
  `.trim());
235198
236147
  }
235199
- function parseLimit3(value, fallback) {
236148
+ function parseLimit2(value, fallback) {
235200
236149
  if (typeof value !== "string" || value.length === 0)
235201
236150
  return fallback;
235202
236151
  const parsed = Number.parseInt(value, 10);
@@ -235216,9 +236165,23 @@ function parseOrder(value) {
235216
236165
  }
235217
236166
  return;
235218
236167
  }
235219
- function getAgentId6(agentFromArgs, agentIdFromArgs) {
236168
+ function getAgentId5(agentFromArgs, agentIdFromArgs) {
235220
236169
  return agentFromArgs || agentIdFromArgs || process.env.LETTA_AGENT_ID || "";
235221
236170
  }
236171
+ function pageItems2(page) {
236172
+ if (Array.isArray(page))
236173
+ return page;
236174
+ if (page && typeof page === "object") {
236175
+ const maybePage = page;
236176
+ if (typeof maybePage.getPaginatedItems === "function") {
236177
+ return maybePage.getPaginatedItems();
236178
+ }
236179
+ if (Array.isArray(maybePage.items)) {
236180
+ return maybePage.items;
236181
+ }
236182
+ }
236183
+ return [];
236184
+ }
235222
236185
  var MESSAGES_OPTIONS = {
235223
236186
  help: { type: "boolean", short: "h" },
235224
236187
  query: { type: "string" },
@@ -235239,7 +236202,7 @@ var MESSAGES_OPTIONS = {
235239
236202
  output: { type: "string" }
235240
236203
  };
235241
236204
  function parseMessagesArgs(argv) {
235242
- return parseArgs9({
236205
+ return parseArgs8({
235243
236206
  args: argv,
235244
236207
  options: MESSAGES_OPTIONS,
235245
236208
  strict: true,
@@ -235253,17 +236216,17 @@ async function runMessagesSubcommand(argv) {
235253
236216
  } catch (error51) {
235254
236217
  const message = error51 instanceof Error ? error51.message : String(error51);
235255
236218
  console.error(`Error: ${message}`);
235256
- printUsage6();
236219
+ printUsage5();
235257
236220
  return 1;
235258
236221
  }
235259
236222
  const [action] = parsed.positionals;
235260
236223
  if (parsed.values.help || !action || action === "help") {
235261
- printUsage6();
236224
+ printUsage5();
235262
236225
  return 0;
235263
236226
  }
235264
236227
  try {
235265
236228
  await settingsManager.initialize();
235266
- const client = await getClient();
236229
+ const backend4 = getBackend();
235267
236230
  const renderText = (value) => {
235268
236231
  if (typeof value === "string")
235269
236232
  return value;
@@ -235347,13 +236310,13 @@ async function runMessagesSubcommand(argv) {
235347
236310
  const seenIds = new Set;
235348
236311
  let cursorBefore;
235349
236312
  for (let pageIndex = 0;pageIndex < maxPages; pageIndex += 1) {
235350
- const page = await client.conversations.messages.list(conversationId, {
236313
+ const page = await backend4.listConversationMessages(conversationId, {
235351
236314
  limit: pageLimit,
235352
236315
  order: "desc",
235353
236316
  ...conversationId === "default" && agentIdForDefault ? { agent_id: agentIdForDefault } : {},
235354
236317
  ...cursorBefore ? { before: cursorBefore } : {}
235355
236318
  });
235356
- const items = page.getPaginatedItems();
236319
+ const items = pageItems2(page);
235357
236320
  if (items.length === 0) {
235358
236321
  break;
235359
236322
  }
@@ -235380,24 +236343,24 @@ async function runMessagesSubcommand(argv) {
235380
236343
  return 1;
235381
236344
  }
235382
236345
  const allAgents = parsed.values["all-agents"] ?? false;
235383
- const agentId = getAgentId6(parsed.values.agent, parsed.values["agent-id"]);
236346
+ const agentId = getAgentId5(parsed.values.agent, parsed.values["agent-id"]);
235384
236347
  if (!allAgents && !agentId) {
235385
236348
  console.error("Missing agent id. Set LETTA_AGENT_ID or pass --agent/--agent-id.");
235386
236349
  return 1;
235387
236350
  }
235388
- const result = await client.messages.search({
236351
+ const result = await searchMessagesForBackend({
235389
236352
  query,
235390
236353
  agent_id: allAgents ? undefined : agentId,
235391
236354
  search_mode: parseMode(parsed.values.mode) ?? "hybrid",
235392
236355
  start_date: parsed.values["start-date"],
235393
236356
  end_date: parsed.values["end-date"],
235394
- limit: parseLimit3(parsed.values.limit, 10)
236357
+ limit: parseLimit2(parsed.values.limit, 10)
235395
236358
  });
235396
236359
  console.log(JSON.stringify(result, null, 2));
235397
236360
  return 0;
235398
236361
  }
235399
236362
  if (action === "list") {
235400
- const agentId = getAgentId6(parsed.values.agent, parsed.values["agent-id"]);
236363
+ const agentId = getAgentId5(parsed.values.agent, parsed.values["agent-id"]);
235401
236364
  if (!agentId) {
235402
236365
  console.error("Missing agent id. Set LETTA_AGENT_ID or pass --agent/--agent-id.");
235403
236366
  return 1;
@@ -235408,14 +236371,14 @@ async function runMessagesSubcommand(argv) {
235408
236371
  console.error(`Invalid --order "${orderRaw}". Use "asc" or "desc".`);
235409
236372
  return 1;
235410
236373
  }
235411
- const response = await client.agents.messages.list(agentId, {
236374
+ const response = await backend4.listAgentMessages(agentId, {
235412
236375
  conversation_id: "default",
235413
- limit: parseLimit3(parsed.values.limit, 20),
236376
+ limit: parseLimit2(parsed.values.limit, 20),
235414
236377
  after: parsed.values.after,
235415
236378
  before: parsed.values.before,
235416
236379
  order
235417
236380
  });
235418
- const messages = response.getPaginatedItems() ?? [];
236381
+ const messages = pageItems2(response);
235419
236382
  const startDate = parsed.values["start-date"];
235420
236383
  const endDate = parsed.values["end-date"];
235421
236384
  let filtered = messages;
@@ -235443,13 +236406,13 @@ async function runMessagesSubcommand(argv) {
235443
236406
  console.error("Missing conversation id. Pass --conversation <id> or --conversation-id <id>.");
235444
236407
  return 1;
235445
236408
  }
235446
- const agentId = getAgentId6(parsed.values.agent, parsed.values["agent-id"]);
236409
+ const agentId = getAgentId5(parsed.values.agent, parsed.values["agent-id"]);
235447
236410
  if (conversationId === "default" && !agentId) {
235448
236411
  console.error('Conversation "default" requires an agent id. Set LETTA_AGENT_ID or pass --agent/--agent-id.');
235449
236412
  return 1;
235450
236413
  }
235451
- const pageLimit = Math.max(1, parseLimit3(parsed.values.limit, 100));
235452
- const maxPages = Math.max(1, parseLimit3(parsed.values["max-pages"], 200));
236414
+ const pageLimit = Math.max(1, parseLimit2(parsed.values.limit, 100));
236415
+ const maxPages = Math.max(1, parseLimit2(parsed.values["max-pages"], 200));
235453
236416
  const outputPathRaw = parsed.values.out || parsed.values.output;
235454
236417
  const messages = await fetchConversationMessages(conversationId, agentId || undefined, pageLimit, maxPages);
235455
236418
  const transcript = messages.flatMap((msg) => formatEntry(msg)).join(`
@@ -235480,7 +236443,7 @@ async function runMessagesSubcommand(argv) {
235480
236443
  return 1;
235481
236444
  }
235482
236445
  console.error(`Unknown action: ${action}`);
235483
- printUsage6();
236446
+ printUsage5();
235484
236447
  return 1;
235485
236448
  }
235486
236449
 
@@ -235498,8 +236461,6 @@ async function runSubcommand(argv) {
235498
236461
  return runAgentsSubcommand(rest);
235499
236462
  case "messages":
235500
236463
  return runMessagesSubcommand(rest);
235501
- case "blocks":
235502
- return runBlocksSubcommand(rest);
235503
236464
  case "server":
235504
236465
  case "remote":
235505
236466
  return runListenSubcommand(rest);
@@ -237720,7 +238681,6 @@ USAGE
237720
238681
  letta memory ... Memory filesystem subcommands
237721
238682
  letta agents ... Agents subcommands (JSON-only)
237722
238683
  letta messages ... Messages subcommands (JSON-only)
237723
- letta blocks ... Blocks subcommands (JSON-only)
237724
238684
  letta connect ... Connect providers from terminal
237725
238685
 
237726
238686
  OPTIONS
@@ -237740,9 +238700,6 @@ SUBCOMMANDS
237740
238700
  letta messages search --query <text> [--all-agents]
237741
238701
  letta messages list [--agent <id>]
237742
238702
  letta messages transcript --conversation <id> [--out <path>]
237743
- letta blocks list --agent <id>
237744
- letta blocks copy --block-id <id> [--label <label>] [--agent <id>] [--override]
237745
- letta blocks attach --block-id <id> [--agent <id>] [--read-only] [--override]
237746
238703
  letta connect <provider> [options]
237747
238704
 
237748
238705
  BEHAVIOR
@@ -238031,8 +238988,13 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
238031
238988
  const skillsDirectory = values.skills ?? undefined;
238032
238989
  const memfsFlag = values.memfs;
238033
238990
  const noMemfsFlag = values["no-memfs"];
238034
- const requestedMemoryPromptMode = memfsFlag ? "memfs" : noMemfsFlag ? "standard" : undefined;
238035
- const shouldAutoEnableMemfsForNewAgent = !memfsFlag && !noMemfsFlag;
238991
+ const startupBackend = getBackend();
238992
+ const localNoMemfsRequested = Boolean(startupBackend.capabilities.localMemfs && (noMemfsFlag || isLocalBackendNoMemfsEnvEnabled2()));
238993
+ if (localNoMemfsRequested) {
238994
+ process.env[LOCAL_BACKEND_NO_MEMFS_ENV2] = "1";
238995
+ }
238996
+ const requestedMemoryPromptMode = memfsFlag ? "memfs" : noMemfsFlag || localNoMemfsRequested ? "standard" : undefined;
238997
+ const shouldAutoEnableMemfsForNewAgent = !memfsFlag && !noMemfsFlag && !localNoMemfsRequested;
238036
238998
  const noSkillsFlag = values["no-skills"];
238037
238999
  const noBundledSkillsFlag = values["no-bundled-skills"];
238038
239000
  const skillSourcesRaw = values["skill-sources"];
@@ -238783,7 +239745,7 @@ Error: ${message}`);
238783
239745
  }
238784
239746
  const { isLettaCloud: isLettaCloud3 } = await Promise.resolve().then(() => (init_memoryFilesystem2(), exports_memoryFilesystem2));
238785
239747
  const willAutoEnableMemfs = shouldAutoEnableMemfsForNewAgent && await isLettaCloud3();
238786
- const effectiveMemoryMode = backend4.capabilities.localMemfs ? "local-memfs" : requestedMemoryPromptMode ?? (willAutoEnableMemfs ? "memfs" : undefined);
239748
+ const effectiveMemoryMode = backend4.capabilities.localMemfs ? localNoMemfsRequested ? "standard" : "local-memfs" : requestedMemoryPromptMode ?? (willAutoEnableMemfs ? "memfs" : undefined);
238787
239749
  const personalityOptions = personality ? await buildCreateAgentOptionsForPersonality({
238788
239750
  personalityId: personality,
238789
239751
  model: effectiveModel
@@ -238845,16 +239807,15 @@ Error: ${message}`);
238845
239807
  skipPromptUpdate: shouldCreateNew
238846
239808
  })) : Promise.resolve().then(() => {
238847
239809
  if (backend4.capabilities.localMemfs) {
238848
- if (noMemfsFlag) {
238849
- throw new Error("Disabling MemFS is not supported by the local backend.");
238850
- }
238851
- settingsManager2.setMemfsEnabled(agentId2, true);
238852
- return { action: "enabled" };
239810
+ settingsManager2.setMemfsEnabled(agentId2, !localNoMemfsRequested);
239811
+ return {
239812
+ action: localNoMemfsRequested ? "disabled" : "enabled"
239813
+ };
238853
239814
  }
238854
239815
  if (memfsFlag) {
238855
239816
  throw new Error("MemFS is not supported by the active backend.");
238856
239817
  }
238857
- if (noMemfsFlag) {
239818
+ if (noMemfsFlag || localNoMemfsRequested) {
238858
239819
  settingsManager2.setMemfsEnabled(agentId2, false);
238859
239820
  }
238860
239821
  return null;
@@ -239146,4 +240107,4 @@ Error during initialization: ${message}`);
239146
240107
  }
239147
240108
  main();
239148
240109
 
239149
- //# debugId=A8E6490E4F5F858164756E2164756E21
240110
+ //# debugId=3EDFF39471E7DC8264756E2164756E21