@letta-ai/letta-code 0.15.2 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/letta.js +1503 -1008
  2. package/package.json +3 -1
package/letta.js CHANGED
@@ -3122,7 +3122,7 @@ var package_default;
3122
3122
  var init_package = __esm(() => {
3123
3123
  package_default = {
3124
3124
  name: "@letta-ai/letta-code",
3125
- version: "0.15.2",
3125
+ version: "0.15.3",
3126
3126
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
3127
3127
  type: "module",
3128
3128
  bin: {
@@ -3184,6 +3184,8 @@ var init_package = __esm(() => {
3184
3184
  check: "bun run scripts/check.js",
3185
3185
  dev: "bun --loader:.md=text --loader:.mdx=text --loader:.txt=text run src/index.ts",
3186
3186
  build: "node scripts/postinstall-patches.js && bun run build.js",
3187
+ "test:update-chain:manual": "bun run src/tests/update-chain-smoke.ts --mode manual",
3188
+ "test:update-chain:startup": "bun run src/tests/update-chain-smoke.ts --mode startup",
3187
3189
  prepublishOnly: "bun run build",
3188
3190
  postinstall: "node scripts/postinstall-patches.js"
3189
3191
  },
@@ -5635,13 +5637,15 @@ If the user asks for help or wants to give feedback inform them of the following
5635
5637
 
5636
5638
  When the user directly asks about Letta Code (eg 'can Letta Code do...', 'does Letta Code have...') or asks in second person (eg 'are you able...', 'can you do...'), first use the WebFetch tool to gather information to answer the question from the Letta Code repository at https://github.com/letta-ai/letta-code.
5637
5639
 
5640
+ When running in Letta Code, shell tools provide \`AGENT_ID\`: your current agent ID.
5641
+
5638
5642
  # Skills
5639
5643
  - /<skill-name> (e.g., /commit) is shorthand for users to invoke a skill. When executed, the skill gets expanded to a full prompt. Use the Skill tool to execute them. IMPORTANT: Only use Skill for skills listed in system-reminder messages in the conversation - do not guess or use built-in CLI commands.
5640
5644
  `;
5641
5645
  var init_system_prompt = () => {};
5642
5646
 
5643
5647
  // src/agent/prompts/system_prompt_memfs.txt
5644
- var system_prompt_memfs_default = "\n# Memory\n\nYou have an advanced memory system that enables you to remember past interactions and continuously improve your own capabilities.\n\n## Memory Filesystem\nYour memory is stored in a git repository at `~/.letta/agents/<agent-id>/memory/`. This provides full version control, sync with the server, and create worktrees for parallel edits.\nEach file contains metadata frontmatter include a `description` (the description of the file's contents), `limit` (the character limit), and optional `metadata`.\nThe filesystem tree is always available in your system prompt, along with the contents of files in the `system/` folder.\nYou also have additional external memory (e.g. your message history) that is accessible and that you can bring into context with tools when needed.\n\n## How It Works\n1. Each `.md` file in `memory/system/` is pinned to your system prompt with tags <system/context/{name}.md></system/context/{name}.md>\n2. The `memory_filesystem` block renders the current tree view of all available memory files\n2. Changes pushed to git sync to the API server within seconds\n3. API server changes sync to git automatically\n4. The system prompt is only recompiled with the latest memory on the API on compactions or message resets: your local copy may diverge\n\n## Syncing\n```bash\ncd ~/.letta/agents/<agent-id>/memory\n\n# See what changed\ngit status\n\n# Commit and push your changes\ngit add system/\ngit commit -m \"<type>: <what changed>\" # e.g. \"fix: update user prefs\", \"refactor: reorganize persona blocks\"\ngit push\n\n# Get latest from server\ngit pull\n```\nThe system will remind you when your memory has uncommitted changes. Sync when convenient.\n\n## History\n```bash\ngit -C ~/.letta/agents/<agent-id>/memory log --oneline\n```\n";
5648
+ var system_prompt_memfs_default = "\n# Memory\n\nYou have an advanced memory system that enables you to remember past interactions and continuously improve your own capabilities.\n\n## Memory Filesystem\nYour memory is stored in a git repository at `$MEMORY_DIR` (absolute path provided by Letta Code shell tools; usually `~/.letta/agents/$AGENT_ID/memory/`). This provides full version control, sync with the server, and create worktrees for parallel edits.\nEach file contains metadata frontmatter include a `description` (the description of the file's contents), `limit` (the character limit), and optional `metadata`.\nThe filesystem tree is always available in your system prompt, along with the contents of files in the `system/` folder.\nYou also have additional external memory (e.g. your message history) that is accessible and that you can bring into context with tools when needed.\n\n## How It Works\n1. Each `.md` file in `memory/system/` is pinned to your system prompt with tags <system/context/{name}.md></system/context/{name}.md>\n2. The `memory_filesystem` block renders the current tree view of all available memory files\n2. Changes pushed to git sync to the API server within seconds\n3. API server changes sync to git automatically\n4. The system prompt is only recompiled with the latest memory on the API on compactions or message resets: your local copy may diverge\n\n## Syncing\n```bash\ncd \"$MEMORY_DIR\"\n\n# See what changed\ngit status\n\n# Commit and push your changes\ngit add system/\ngit commit -m \"<type>: <what changed>\" # e.g. \"fix: update user prefs\", \"refactor: reorganize persona blocks\"\ngit push\n\n# Get latest from server\ngit pull\n```\nThe system will remind you when your memory has uncommitted changes. Sync when convenient.\n\n## History\n```bash\ngit -C \"$MEMORY_DIR\" log --oneline\n```\n";
5645
5649
  var init_system_prompt_memfs = () => {};
5646
5650
 
5647
5651
  // src/agent/prompts/system_prompt_memory.txt
@@ -37549,6 +37553,926 @@ var init_process_manager = __esm(() => {
37549
37553
  backgroundTasks = new Map;
37550
37554
  });
37551
37555
 
37556
+ // src/providers/openai-codex-provider.ts
37557
+ var exports_openai_codex_provider = {};
37558
+ __export(exports_openai_codex_provider, {
37559
+ updateOpenAICodexProvider: () => updateOpenAICodexProvider,
37560
+ removeOpenAICodexProvider: () => removeOpenAICodexProvider,
37561
+ listProviders: () => listProviders,
37562
+ getOpenAICodexProvider: () => getOpenAICodexProvider,
37563
+ deleteOpenAICodexProvider: () => deleteOpenAICodexProvider,
37564
+ createOrUpdateOpenAICodexProvider: () => createOrUpdateOpenAICodexProvider,
37565
+ createOpenAICodexProvider: () => createOpenAICodexProvider,
37566
+ checkOpenAICodexEligibility: () => checkOpenAICodexEligibility,
37567
+ OPENAI_CODEX_PROVIDER_NAME: () => OPENAI_CODEX_PROVIDER_NAME,
37568
+ CHATGPT_OAUTH_PROVIDER_TYPE: () => CHATGPT_OAUTH_PROVIDER_TYPE
37569
+ });
37570
+ async function getLettaConfig() {
37571
+ const settings = await settingsManager.getSettingsWithSecureTokens();
37572
+ const baseUrl = process.env.LETTA_BASE_URL || settings.env?.LETTA_BASE_URL || LETTA_CLOUD_API_URL;
37573
+ const apiKey = process.env.LETTA_API_KEY || settings.env?.LETTA_API_KEY || "";
37574
+ return { baseUrl, apiKey };
37575
+ }
37576
+ async function providersRequest(method, path3, body) {
37577
+ const { baseUrl, apiKey } = await getLettaConfig();
37578
+ const url = `${baseUrl}${path3}`;
37579
+ const response = await fetch(url, {
37580
+ method,
37581
+ headers: getLettaCodeHeaders2(apiKey),
37582
+ ...body && { body: JSON.stringify(body) }
37583
+ });
37584
+ if (!response.ok) {
37585
+ const errorText = await response.text();
37586
+ if (response.status === 403) {
37587
+ try {
37588
+ const errorData = JSON.parse(errorText);
37589
+ if (errorData.error && typeof errorData.error === "string" && errorData.error.includes("only available for pro or enterprise")) {
37590
+ throw new Error("PLAN_UPGRADE_REQUIRED");
37591
+ }
37592
+ } catch (parseError) {
37593
+ if (parseError instanceof Error && parseError.message === "PLAN_UPGRADE_REQUIRED") {
37594
+ throw parseError;
37595
+ }
37596
+ }
37597
+ }
37598
+ throw new Error(`Provider API error (${response.status}): ${errorText}`);
37599
+ }
37600
+ const text = await response.text();
37601
+ if (!text) {
37602
+ return {};
37603
+ }
37604
+ return JSON.parse(text);
37605
+ }
37606
+ async function listProviders() {
37607
+ try {
37608
+ const response = await providersRequest("GET", "/v1/providers");
37609
+ return response;
37610
+ } catch {
37611
+ return [];
37612
+ }
37613
+ }
37614
+ async function getOpenAICodexProvider() {
37615
+ const providers = await listProviders();
37616
+ return providers.find((p) => p.name === OPENAI_CODEX_PROVIDER_NAME) || null;
37617
+ }
37618
+ async function createOpenAICodexProvider(config) {
37619
+ const apiKeyJson = JSON.stringify({
37620
+ access_token: config.access_token,
37621
+ id_token: config.id_token,
37622
+ refresh_token: config.refresh_token,
37623
+ account_id: config.account_id,
37624
+ expires_at: config.expires_at
37625
+ });
37626
+ return providersRequest("POST", "/v1/providers", {
37627
+ name: OPENAI_CODEX_PROVIDER_NAME,
37628
+ provider_type: CHATGPT_OAUTH_PROVIDER_TYPE,
37629
+ api_key: apiKeyJson
37630
+ });
37631
+ }
37632
+ async function updateOpenAICodexProvider(providerId, config) {
37633
+ const apiKeyJson = JSON.stringify({
37634
+ access_token: config.access_token,
37635
+ id_token: config.id_token,
37636
+ refresh_token: config.refresh_token,
37637
+ account_id: config.account_id,
37638
+ expires_at: config.expires_at
37639
+ });
37640
+ return providersRequest("PATCH", `/v1/providers/${providerId}`, {
37641
+ api_key: apiKeyJson
37642
+ });
37643
+ }
37644
+ async function deleteOpenAICodexProvider(providerId) {
37645
+ await providersRequest("DELETE", `/v1/providers/${providerId}`);
37646
+ }
37647
+ async function createOrUpdateOpenAICodexProvider(config) {
37648
+ const existing = await getOpenAICodexProvider();
37649
+ if (existing) {
37650
+ return updateOpenAICodexProvider(existing.id, config);
37651
+ } else {
37652
+ return createOpenAICodexProvider(config);
37653
+ }
37654
+ }
37655
+ async function removeOpenAICodexProvider() {
37656
+ const existing = await getOpenAICodexProvider();
37657
+ if (existing) {
37658
+ await deleteOpenAICodexProvider(existing.id);
37659
+ }
37660
+ }
37661
+ async function checkOpenAICodexEligibility() {
37662
+ try {
37663
+ const balance = await providersRequest("GET", "/v1/metadata/balance");
37664
+ const billingTier = balance.billing_tier.toLowerCase();
37665
+ if (billingTier === "pro" || billingTier === "enterprise") {
37666
+ return {
37667
+ eligible: true,
37668
+ billing_tier: balance.billing_tier
37669
+ };
37670
+ }
37671
+ return {
37672
+ eligible: false,
37673
+ billing_tier: balance.billing_tier,
37674
+ reason: `ChatGPT OAuth requires a Pro or Enterprise plan. Current plan: ${balance.billing_tier}`
37675
+ };
37676
+ } catch (error) {
37677
+ console.warn("Failed to check ChatGPT OAuth eligibility:", error);
37678
+ return {
37679
+ eligible: true,
37680
+ billing_tier: "unknown"
37681
+ };
37682
+ }
37683
+ }
37684
+ var OPENAI_CODEX_PROVIDER_NAME = "chatgpt-plus-pro", CHATGPT_OAUTH_PROVIDER_TYPE = "chatgpt_oauth";
37685
+ var init_openai_codex_provider = __esm(async () => {
37686
+ init_http_headers();
37687
+ init_oauth();
37688
+ await init_settings_manager();
37689
+ });
37690
+
37691
+ // src/agent/available-models.ts
37692
+ var exports_available_models = {};
37693
+ __export(exports_available_models, {
37694
+ prefetchAvailableModelHandles: () => prefetchAvailableModelHandles,
37695
+ getModelContextWindow: () => getModelContextWindow,
37696
+ getAvailableModelsCacheInfo: () => getAvailableModelsCacheInfo,
37697
+ getAvailableModelHandles: () => getAvailableModelHandles,
37698
+ clearAvailableModelsCache: () => clearAvailableModelsCache
37699
+ });
37700
+ function isFresh(now = Date.now()) {
37701
+ return cache4 !== null && now - cache4.fetchedAt < CACHE_TTL_MS;
37702
+ }
37703
+ function clearAvailableModelsCache() {
37704
+ cache4 = null;
37705
+ }
37706
+ function getAvailableModelsCacheInfo() {
37707
+ const now = Date.now();
37708
+ return {
37709
+ hasCache: cache4 !== null,
37710
+ isFresh: isFresh(now),
37711
+ fetchedAt: cache4?.fetchedAt ?? null,
37712
+ ageMs: cache4 ? now - cache4.fetchedAt : null,
37713
+ ttlMs: CACHE_TTL_MS
37714
+ };
37715
+ }
37716
+ async function refreshByokProviders() {
37717
+ const client = await getClient2();
37718
+ try {
37719
+ const providers = await client.get("/v1/providers/");
37720
+ const byokProviders = providers.filter((p) => p.provider_category === "byok");
37721
+ await Promise.allSettled(byokProviders.map(async (provider) => {
37722
+ try {
37723
+ await client.patch(`/v1/providers/${provider.id}/refresh`);
37724
+ } catch (error) {
37725
+ debugWarn("available-models", `Failed to refresh provider ${provider.name} (${provider.id}):`, error);
37726
+ }
37727
+ }));
37728
+ } catch (error) {
37729
+ debugWarn("available-models", "Failed to list providers for refresh:", error);
37730
+ }
37731
+ }
37732
+ async function fetchFromNetwork() {
37733
+ const client = await getClient2();
37734
+ const modelsList = await client.models.list();
37735
+ const handles = new Set(modelsList.map((m) => m.handle).filter((h) => !!h));
37736
+ const contextWindows = new Map;
37737
+ for (const model of modelsList) {
37738
+ if (model.handle && model.max_context_window) {
37739
+ contextWindows.set(model.handle, model.max_context_window);
37740
+ }
37741
+ }
37742
+ return { handles, contextWindows, fetchedAt: Date.now() };
37743
+ }
37744
+ async function getAvailableModelHandles(options) {
37745
+ const forceRefresh = options?.forceRefresh === true;
37746
+ const now = Date.now();
37747
+ if (!forceRefresh && isFresh(now) && cache4) {
37748
+ return {
37749
+ handles: cache4.handles,
37750
+ source: "cache",
37751
+ fetchedAt: cache4.fetchedAt
37752
+ };
37753
+ }
37754
+ if (!forceRefresh && inflight) {
37755
+ const entry2 = await inflight;
37756
+ return {
37757
+ handles: entry2.handles,
37758
+ source: "network",
37759
+ fetchedAt: entry2.fetchedAt
37760
+ };
37761
+ }
37762
+ if (forceRefresh) {
37763
+ await refreshByokProviders();
37764
+ }
37765
+ inflight = fetchFromNetwork().then((entry2) => {
37766
+ cache4 = entry2;
37767
+ return entry2;
37768
+ }).finally(() => {
37769
+ inflight = null;
37770
+ });
37771
+ const entry = await inflight;
37772
+ return {
37773
+ handles: entry.handles,
37774
+ source: "network",
37775
+ fetchedAt: entry.fetchedAt
37776
+ };
37777
+ }
37778
+ function prefetchAvailableModelHandles() {
37779
+ getAvailableModelHandles().catch(() => {});
37780
+ }
37781
+ async function getModelContextWindow(handle) {
37782
+ if (!cache4) {
37783
+ await getAvailableModelHandles();
37784
+ }
37785
+ return cache4?.contextWindows.get(handle);
37786
+ }
37787
+ var CACHE_TTL_MS, cache4 = null, inflight = null;
37788
+ var init_available_models = __esm(async () => {
37789
+ init_debug();
37790
+ await init_client2();
37791
+ CACHE_TTL_MS = 5 * 60 * 1000;
37792
+ });
37793
+
37794
+ // src/agent/memoryPrompt.ts
37795
+ var exports_memoryPrompt = {};
37796
+ __export(exports_memoryPrompt, {
37797
+ stripManagedMemorySections: () => stripManagedMemorySections,
37798
+ reconcileMemoryPrompt: () => reconcileMemoryPrompt,
37799
+ detectMemoryPromptDrift: () => detectMemoryPromptDrift
37800
+ });
37801
+ function normalizeNewlines(text) {
37802
+ return text.replace(/\r\n/g, `
37803
+ `);
37804
+ }
37805
+ function scanHeadingsOutsideFences(text) {
37806
+ const lines = text.split(`
37807
+ `);
37808
+ const headings = [];
37809
+ let inFence = false;
37810
+ let fenceToken = "";
37811
+ let offset = 0;
37812
+ for (const line of lines) {
37813
+ const trimmed = line.trimStart();
37814
+ const fenceMatch = trimmed.match(/^(```+|~~~+)/);
37815
+ if (fenceMatch) {
37816
+ const token = fenceMatch[1] ?? fenceMatch[0] ?? "";
37817
+ const tokenChar = token.startsWith("`") ? "`" : "~";
37818
+ if (!inFence) {
37819
+ inFence = true;
37820
+ fenceToken = tokenChar;
37821
+ } else if (fenceToken === tokenChar) {
37822
+ inFence = false;
37823
+ fenceToken = "";
37824
+ }
37825
+ }
37826
+ if (!inFence) {
37827
+ const headingMatch = line.match(/^\s*(#{1,6})\s+(.+?)\s*$/);
37828
+ if (headingMatch) {
37829
+ const hashes = headingMatch[1] ?? "";
37830
+ const rawTitle = headingMatch[2] ?? "";
37831
+ if (hashes && rawTitle) {
37832
+ const level = hashes.length;
37833
+ const title = rawTitle.replace(/\s+#*$/, "").trim();
37834
+ headings.push({
37835
+ level,
37836
+ title,
37837
+ startOffset: offset
37838
+ });
37839
+ }
37840
+ }
37841
+ }
37842
+ offset += line.length + 1;
37843
+ }
37844
+ return headings;
37845
+ }
37846
+ function stripHeadingSections(text, shouldStrip) {
37847
+ let current = text;
37848
+ while (true) {
37849
+ const headings = scanHeadingsOutsideFences(current);
37850
+ const target = headings.find(shouldStrip);
37851
+ if (!target) {
37852
+ return current;
37853
+ }
37854
+ const nextHeading = headings.find((heading) => heading.startOffset > target.startOffset && heading.level <= target.level);
37855
+ const end = nextHeading ? nextHeading.startOffset : current.length;
37856
+ current = `${current.slice(0, target.startOffset)}${current.slice(end)}`;
37857
+ }
37858
+ }
37859
+ function getMemfsTailFragment() {
37860
+ const tailAnchor = "# See what changed";
37861
+ const start = SYSTEM_PROMPT_MEMFS_ADDON.indexOf(tailAnchor);
37862
+ if (start === -1)
37863
+ return "";
37864
+ return SYSTEM_PROMPT_MEMFS_ADDON.slice(start).trim();
37865
+ }
37866
+ function stripExactAddon(text, addon) {
37867
+ const trimmedAddon = addon.trim();
37868
+ if (!trimmedAddon)
37869
+ return text;
37870
+ let current = text;
37871
+ while (current.includes(trimmedAddon)) {
37872
+ current = current.replace(trimmedAddon, "");
37873
+ }
37874
+ return current;
37875
+ }
37876
+ function stripOrphanMemfsTail(text) {
37877
+ const tail = getMemfsTailFragment();
37878
+ if (!tail)
37879
+ return text;
37880
+ let current = text;
37881
+ while (current.includes(tail)) {
37882
+ current = current.replace(tail, "");
37883
+ }
37884
+ return current;
37885
+ }
37886
+ function compactBlankLines(text) {
37887
+ return text.replace(/\n{3,}/g, `
37888
+
37889
+ `).trimEnd();
37890
+ }
37891
+ function stripManagedMemorySections(systemPrompt) {
37892
+ let current = normalizeNewlines(systemPrompt);
37893
+ current = stripExactAddon(current, SYSTEM_PROMPT_MEMORY_ADDON);
37894
+ current = stripExactAddon(current, SYSTEM_PROMPT_MEMFS_ADDON);
37895
+ current = stripOrphanMemfsTail(current);
37896
+ current = stripHeadingSections(current, (heading) => heading.title === "Memory");
37897
+ current = stripHeadingSections(current, (heading) => heading.title.startsWith("Memory Filesystem"));
37898
+ return compactBlankLines(current);
37899
+ }
37900
+ function reconcileMemoryPrompt(systemPrompt, mode) {
37901
+ const base2 = stripManagedMemorySections(systemPrompt).trimEnd();
37902
+ const addon = mode === "memfs" ? SYSTEM_PROMPT_MEMFS_ADDON.trimStart() : SYSTEM_PROMPT_MEMORY_ADDON.trimStart();
37903
+ return `${base2}
37904
+
37905
+ ${addon}`.trim();
37906
+ }
37907
+ function detectMemoryPromptDrift(systemPrompt, expectedMode) {
37908
+ const prompt = normalizeNewlines(systemPrompt);
37909
+ const drifts = [];
37910
+ const hasLegacyMemoryLanguage = prompt.includes("Your memory consists of core memory (composed of memory blocks)");
37911
+ const hasMemfsLanguage = prompt.includes("## Memory Filesystem") || prompt.includes("Your memory is stored in a git repository at");
37912
+ const hasOrphanFragment = prompt.includes("# See what changed") && prompt.includes("git add system/") && prompt.includes('git commit -m "<type>: <what changed>"');
37913
+ if (expectedMode === "memfs" && hasLegacyMemoryLanguage) {
37914
+ drifts.push({
37915
+ code: "legacy_memory_language_with_memfs",
37916
+ message: "System prompt contains legacy memory-block language while memfs is enabled."
37917
+ });
37918
+ }
37919
+ if (expectedMode === "standard" && hasMemfsLanguage) {
37920
+ drifts.push({
37921
+ code: "memfs_language_with_standard_mode",
37922
+ message: "System prompt contains Memory Filesystem language while memfs is disabled."
37923
+ });
37924
+ }
37925
+ if (hasOrphanFragment && !hasMemfsLanguage) {
37926
+ drifts.push({
37927
+ code: "orphan_memfs_fragment",
37928
+ message: "System prompt contains orphaned memfs sync fragment without a full memfs section."
37929
+ });
37930
+ }
37931
+ return drifts;
37932
+ }
37933
+ var init_memoryPrompt = __esm(() => {
37934
+ init_promptAssets();
37935
+ });
37936
+
37937
+ // src/agent/modify.ts
37938
+ var exports_modify = {};
37939
+ __export(exports_modify, {
37940
+ updateAgentSystemPromptRaw: () => updateAgentSystemPromptRaw,
37941
+ updateAgentSystemPromptMemfs: () => updateAgentSystemPromptMemfs,
37942
+ updateAgentSystemPrompt: () => updateAgentSystemPrompt,
37943
+ updateAgentLLMConfig: () => updateAgentLLMConfig
37944
+ });
37945
+ function buildModelSettings(modelHandle, updateArgs) {
37946
+ const isOpenAI = modelHandle.startsWith("openai/") || modelHandle.startsWith(`${OPENAI_CODEX_PROVIDER_NAME}/`);
37947
+ const isAnthropic = modelHandle.startsWith("anthropic/") || modelHandle.startsWith("claude-pro-max/");
37948
+ const isZai = modelHandle.startsWith("zai/");
37949
+ const isGoogleAI = modelHandle.startsWith("google_ai/");
37950
+ const isGoogleVertex = modelHandle.startsWith("google_vertex/");
37951
+ const isOpenRouter = modelHandle.startsWith("openrouter/");
37952
+ const isBedrock = modelHandle.startsWith("bedrock/");
37953
+ let settings;
37954
+ if (isOpenAI || isOpenRouter) {
37955
+ const openaiSettings = {
37956
+ provider_type: "openai",
37957
+ parallel_tool_calls: true
37958
+ };
37959
+ if (updateArgs?.reasoning_effort) {
37960
+ openaiSettings.reasoning = {
37961
+ reasoning_effort: updateArgs.reasoning_effort
37962
+ };
37963
+ }
37964
+ settings = openaiSettings;
37965
+ } else if (isAnthropic) {
37966
+ const anthropicSettings = {
37967
+ provider_type: "anthropic",
37968
+ parallel_tool_calls: true
37969
+ };
37970
+ if (updateArgs?.enable_reasoner !== undefined || typeof updateArgs?.max_reasoning_tokens === "number") {
37971
+ anthropicSettings.thinking = {
37972
+ type: updateArgs?.enable_reasoner === false ? "disabled" : "enabled",
37973
+ ...typeof updateArgs?.max_reasoning_tokens === "number" && {
37974
+ budget_tokens: updateArgs.max_reasoning_tokens
37975
+ }
37976
+ };
37977
+ }
37978
+ settings = anthropicSettings;
37979
+ } else if (isZai) {
37980
+ settings = {
37981
+ provider_type: "zai",
37982
+ parallel_tool_calls: true
37983
+ };
37984
+ } else if (isGoogleAI) {
37985
+ const googleSettings = {
37986
+ provider_type: "google_ai",
37987
+ parallel_tool_calls: true
37988
+ };
37989
+ if (updateArgs?.thinking_budget !== undefined) {
37990
+ googleSettings.thinking_config = {
37991
+ thinking_budget: updateArgs.thinking_budget
37992
+ };
37993
+ }
37994
+ if (typeof updateArgs?.temperature === "number") {
37995
+ googleSettings.temperature = updateArgs.temperature;
37996
+ }
37997
+ settings = googleSettings;
37998
+ } else if (isGoogleVertex) {
37999
+ const googleVertexSettings = {
38000
+ provider_type: "google_vertex",
38001
+ parallel_tool_calls: true
38002
+ };
38003
+ if (updateArgs?.thinking_budget !== undefined) {
38004
+ googleVertexSettings.thinking_config = {
38005
+ thinking_budget: updateArgs.thinking_budget
38006
+ };
38007
+ }
38008
+ if (typeof updateArgs?.temperature === "number") {
38009
+ googleVertexSettings.temperature = updateArgs.temperature;
38010
+ }
38011
+ settings = googleVertexSettings;
38012
+ } else if (isBedrock) {
38013
+ const bedrockSettings = {
38014
+ provider_type: "bedrock",
38015
+ parallel_tool_calls: true
38016
+ };
38017
+ if (updateArgs?.enable_reasoner !== undefined || typeof updateArgs?.max_reasoning_tokens === "number") {
38018
+ bedrockSettings.thinking = {
38019
+ type: updateArgs?.enable_reasoner === false ? "disabled" : "enabled",
38020
+ ...typeof updateArgs?.max_reasoning_tokens === "number" && {
38021
+ budget_tokens: updateArgs.max_reasoning_tokens
38022
+ }
38023
+ };
38024
+ }
38025
+ settings = bedrockSettings;
38026
+ } else {
38027
+ settings = {};
38028
+ }
38029
+ if (typeof updateArgs?.max_output_tokens === "number" && "provider_type" in settings) {
38030
+ settings.max_output_tokens = updateArgs.max_output_tokens;
38031
+ }
38032
+ return settings;
38033
+ }
38034
+ async function updateAgentLLMConfig(agentId, modelHandle, updateArgs) {
38035
+ const client = await getClient2();
38036
+ const modelSettings = buildModelSettings(modelHandle, updateArgs);
38037
+ const contextWindow = updateArgs?.context_window ?? await getModelContextWindow(modelHandle);
38038
+ const hasModelSettings = Object.keys(modelSettings).length > 0;
38039
+ await client.agents.update(agentId, {
38040
+ model: modelHandle,
38041
+ ...hasModelSettings && { model_settings: modelSettings },
38042
+ ...contextWindow && { context_window_limit: contextWindow },
38043
+ ...typeof updateArgs?.max_output_tokens === "number" && {
38044
+ max_tokens: updateArgs.max_output_tokens
38045
+ }
38046
+ });
38047
+ const finalAgent = await client.agents.retrieve(agentId);
38048
+ return finalAgent.llm_config;
38049
+ }
38050
+ async function updateAgentSystemPromptRaw(agentId, systemPromptContent) {
38051
+ try {
38052
+ const client = await getClient2();
38053
+ await client.agents.update(agentId, {
38054
+ system: systemPromptContent
38055
+ });
38056
+ return {
38057
+ success: true,
38058
+ message: "System prompt updated successfully"
38059
+ };
38060
+ } catch (error) {
38061
+ return {
38062
+ success: false,
38063
+ message: `Failed to update system prompt: ${error instanceof Error ? error.message : String(error)}`
38064
+ };
38065
+ }
38066
+ }
38067
+ async function updateAgentSystemPrompt(agentId, systemPromptId) {
38068
+ try {
38069
+ const { resolveSystemPrompt: resolveSystemPrompt2 } = await Promise.resolve().then(() => (init_promptAssets(), exports_promptAssets));
38070
+ const { detectMemoryPromptDrift: detectMemoryPromptDrift2, reconcileMemoryPrompt: reconcileMemoryPrompt2 } = await Promise.resolve().then(() => (init_memoryPrompt(), exports_memoryPrompt));
38071
+ const { settingsManager: settingsManager3 } = await init_settings_manager().then(() => exports_settings_manager);
38072
+ const client = await getClient2();
38073
+ const currentAgent = await client.agents.retrieve(agentId);
38074
+ const baseContent = await resolveSystemPrompt2(systemPromptId);
38075
+ const settingIndicatesMemfs = settingsManager3.isMemfsEnabled(agentId);
38076
+ const promptIndicatesMemfs = detectMemoryPromptDrift2(currentAgent.system || "", "standard").some((drift) => drift.code === "memfs_language_with_standard_mode");
38077
+ const memoryMode = settingIndicatesMemfs || promptIndicatesMemfs ? "memfs" : "standard";
38078
+ const systemPromptContent = reconcileMemoryPrompt2(baseContent, memoryMode);
38079
+ const updateResult = await updateAgentSystemPromptRaw(agentId, systemPromptContent);
38080
+ if (!updateResult.success) {
38081
+ return {
38082
+ success: false,
38083
+ message: updateResult.message,
38084
+ agent: null
38085
+ };
38086
+ }
38087
+ const agent = await client.agents.retrieve(agentId);
38088
+ return {
38089
+ success: true,
38090
+ message: "System prompt applied successfully",
38091
+ agent
38092
+ };
38093
+ } catch (error) {
38094
+ return {
38095
+ success: false,
38096
+ message: `Failed to apply system prompt: ${error instanceof Error ? error.message : String(error)}`,
38097
+ agent: null
38098
+ };
38099
+ }
38100
+ }
38101
+ async function updateAgentSystemPromptMemfs(agentId, enableMemfs) {
38102
+ try {
38103
+ const client = await getClient2();
38104
+ const agent = await client.agents.retrieve(agentId);
38105
+ const { reconcileMemoryPrompt: reconcileMemoryPrompt2 } = await Promise.resolve().then(() => (init_memoryPrompt(), exports_memoryPrompt));
38106
+ const nextSystemPrompt = reconcileMemoryPrompt2(agent.system || "", enableMemfs ? "memfs" : "standard");
38107
+ await client.agents.update(agentId, {
38108
+ system: nextSystemPrompt
38109
+ });
38110
+ return {
38111
+ success: true,
38112
+ message: enableMemfs ? "System prompt updated to include Memory Filesystem section" : "System prompt updated to include standard Memory section"
38113
+ };
38114
+ } catch (error) {
38115
+ return {
38116
+ success: false,
38117
+ message: `Failed to update system prompt memfs: ${error instanceof Error ? error.message : String(error)}`
38118
+ };
38119
+ }
38120
+ }
38121
+ var init_modify = __esm(async () => {
38122
+ await __promiseAll([
38123
+ init_openai_codex_provider(),
38124
+ init_available_models(),
38125
+ init_client2()
38126
+ ]);
38127
+ });
38128
+
38129
+ // src/tools/filter.ts
38130
+ var exports_filter = {};
38131
+ __export(exports_filter, {
38132
+ toolFilter: () => toolFilter
38133
+ });
38134
+
38135
+ class ToolFilterManager {
38136
+ enabledTools = null;
38137
+ setEnabledTools(toolsString) {
38138
+ if (toolsString === "") {
38139
+ this.enabledTools = [];
38140
+ } else {
38141
+ this.enabledTools = toolsString.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
38142
+ }
38143
+ }
38144
+ isEnabled(toolName) {
38145
+ if (this.enabledTools === null) {
38146
+ return true;
38147
+ }
38148
+ return this.enabledTools.includes(toolName);
38149
+ }
38150
+ getEnabledTools() {
38151
+ return this.enabledTools ? [...this.enabledTools] : null;
38152
+ }
38153
+ isActive() {
38154
+ return this.enabledTools !== null;
38155
+ }
38156
+ reset() {
38157
+ this.enabledTools = null;
38158
+ }
38159
+ }
38160
+ function getFilter() {
38161
+ const global2 = globalThis;
38162
+ if (!global2[FILTER_KEY]) {
38163
+ global2[FILTER_KEY] = new ToolFilterManager;
38164
+ }
38165
+ return global2[FILTER_KEY];
38166
+ }
38167
+ var FILTER_KEY, toolFilter;
38168
+ var init_filter = __esm(() => {
38169
+ FILTER_KEY = Symbol.for("@letta/toolFilter");
38170
+ toolFilter = getFilter();
38171
+ });
38172
+
38173
+ // src/tools/toolset.ts
38174
+ var exports_toolset = {};
38175
+ __export(exports_toolset, {
38176
+ switchToolsetForModel: () => switchToolsetForModel,
38177
+ reattachMemoryTool: () => reattachMemoryTool,
38178
+ forceToolsetSwitch: () => forceToolsetSwitch,
38179
+ ensureCorrectMemoryTool: () => ensureCorrectMemoryTool,
38180
+ detachMemoryTools: () => detachMemoryTools,
38181
+ MEMORY_TOOL_NAMES: () => MEMORY_TOOL_NAMES
38182
+ });
38183
+ async function ensureCorrectMemoryTool(agentId, modelIdentifier, useMemoryPatch) {
38184
+ const resolvedModel = resolveModel(modelIdentifier) ?? modelIdentifier;
38185
+ const client = await getClient2();
38186
+ const shouldUsePatch = useMemoryPatch !== undefined ? useMemoryPatch : isOpenAIModel(resolvedModel);
38187
+ try {
38188
+ const agentWithTools = await client.agents.retrieve(agentId, {
38189
+ include: ["agent.tools"]
38190
+ });
38191
+ const currentTools = agentWithTools.tools || [];
38192
+ const mapByName = new Map(currentTools.map((t) => [t.name, t.id]));
38193
+ const hasAnyMemoryTool = mapByName.has("memory") || mapByName.has("memory_apply_patch");
38194
+ if (!hasAnyMemoryTool) {
38195
+ return;
38196
+ }
38197
+ const desiredMemoryTool = shouldUsePatch ? "memory_apply_patch" : "memory";
38198
+ const otherMemoryTool = desiredMemoryTool === "memory" ? "memory_apply_patch" : "memory";
38199
+ let desiredId = mapByName.get(desiredMemoryTool);
38200
+ if (!desiredId) {
38201
+ const resp = await client.tools.list({ name: desiredMemoryTool });
38202
+ desiredId = resp.items[0]?.id;
38203
+ }
38204
+ if (!desiredId) {
38205
+ return;
38206
+ }
38207
+ const otherId = mapByName.get(otherMemoryTool);
38208
+ if (mapByName.has(desiredMemoryTool) && !otherId) {
38209
+ return;
38210
+ }
38211
+ const currentIds = currentTools.map((t) => t.id).filter((id) => typeof id === "string");
38212
+ const newIds = new Set(currentIds);
38213
+ if (otherId)
38214
+ newIds.delete(otherId);
38215
+ newIds.add(desiredId);
38216
+ const updatedRules = (agentWithTools.tool_rules || []).map((r) => r.tool_name === otherMemoryTool ? { ...r, tool_name: desiredMemoryTool } : r);
38217
+ await client.agents.update(agentId, {
38218
+ tool_ids: Array.from(newIds),
38219
+ tool_rules: updatedRules
38220
+ });
38221
+ } catch (err) {
38222
+ console.warn(`Warning: Failed to sync memory tool: ${err instanceof Error ? err.message : String(err)}`);
38223
+ }
38224
+ }
38225
+ async function detachMemoryTools(agentId) {
38226
+ const client = await getClient2();
38227
+ try {
38228
+ const agentWithTools = await client.agents.retrieve(agentId, {
38229
+ include: ["agent.tools"]
38230
+ });
38231
+ const currentTools = agentWithTools.tools || [];
38232
+ let detachedAny = false;
38233
+ for (const tool of currentTools) {
38234
+ if (tool.name && MEMORY_TOOL_NAMES.has(tool.name)) {
38235
+ if (tool.id) {
38236
+ await client.agents.tools.detach(tool.id, { agent_id: agentId });
38237
+ detachedAny = true;
38238
+ }
38239
+ }
38240
+ }
38241
+ return detachedAny;
38242
+ } catch (err) {
38243
+ console.warn(`Warning: Failed to detach memory tools: ${err instanceof Error ? err.message : String(err)}`);
38244
+ return false;
38245
+ }
38246
+ }
38247
+ async function reattachMemoryTool(agentId, modelIdentifier) {
38248
+ const resolvedModel = resolveModel(modelIdentifier) ?? modelIdentifier;
38249
+ const client = await getClient2();
38250
+ const shouldUsePatch = isOpenAIModel(resolvedModel);
38251
+ try {
38252
+ const agentWithTools = await client.agents.retrieve(agentId, {
38253
+ include: ["agent.tools"]
38254
+ });
38255
+ const currentTools = agentWithTools.tools || [];
38256
+ const mapByName = new Map(currentTools.map((t) => [t.name, t.id]));
38257
+ const desiredMemoryTool = shouldUsePatch ? "memory_apply_patch" : "memory";
38258
+ if (mapByName.has(desiredMemoryTool)) {
38259
+ return;
38260
+ }
38261
+ const resp = await client.tools.list({ name: desiredMemoryTool });
38262
+ const toolId = resp.items[0]?.id;
38263
+ if (!toolId) {
38264
+ console.warn(`Memory tool "${desiredMemoryTool}" not found on server`);
38265
+ return;
38266
+ }
38267
+ await client.agents.tools.attach(toolId, { agent_id: agentId });
38268
+ } catch (err) {
38269
+ console.warn(`Warning: Failed to reattach memory tool: ${err instanceof Error ? err.message : String(err)}`);
38270
+ }
38271
+ }
38272
+ async function forceToolsetSwitch(toolsetName, agentId) {
38273
+ let modelForLoading;
38274
+ if (toolsetName === "none") {
38275
+ clearToolsWithLock();
38276
+ return;
38277
+ } else if (toolsetName === "codex") {
38278
+ await loadSpecificTools([...CODEX_TOOLS]);
38279
+ modelForLoading = "openai/gpt-4";
38280
+ } else if (toolsetName === "codex_snake") {
38281
+ await loadTools("openai/gpt-4");
38282
+ modelForLoading = "openai/gpt-4";
38283
+ } else if (toolsetName === "gemini") {
38284
+ await loadSpecificTools([...GEMINI_TOOLS]);
38285
+ modelForLoading = "google_ai/gemini-3-pro-preview";
38286
+ } else if (toolsetName === "gemini_snake") {
38287
+ await loadTools("google_ai/gemini-3-pro-preview");
38288
+ modelForLoading = "google_ai/gemini-3-pro-preview";
38289
+ } else {
38290
+ await loadTools("anthropic/claude-sonnet-4");
38291
+ modelForLoading = "anthropic/claude-sonnet-4";
38292
+ }
38293
+ const useMemoryPatch = toolsetName === "codex" || toolsetName === "codex_snake";
38294
+ await ensureCorrectMemoryTool(agentId, modelForLoading, useMemoryPatch);
38295
+ }
38296
+ async function switchToolsetForModel(modelIdentifier, agentId) {
38297
+ const resolvedModel = resolveModel(modelIdentifier) ?? modelIdentifier;
38298
+ await loadTools(resolvedModel);
38299
+ const loadedAfterPrimary = getToolNames().length;
38300
+ if (loadedAfterPrimary === 0 && !toolFilter.isActive()) {
38301
+ await loadTools();
38302
+ if (getToolNames().length === 0) {
38303
+ throw new Error(`Failed to load any Letta tools for model "${resolvedModel}".`);
38304
+ }
38305
+ }
38306
+ await ensureCorrectMemoryTool(agentId, resolvedModel);
38307
+ const { isGeminiModel } = await init_manager3().then(() => exports_manager2);
38308
+ const toolsetName = isOpenAIModel(resolvedModel) ? "codex" : isGeminiModel(resolvedModel) ? "gemini" : "default";
38309
+ return toolsetName;
38310
+ }
38311
+ var CODEX_TOOLS, GEMINI_TOOLS, MEMORY_TOOL_NAMES;
38312
+ var init_toolset = __esm(async () => {
38313
+ init_model();
38314
+ init_filter();
38315
+ await __promiseAll([
38316
+ init_client2(),
38317
+ init_manager3()
38318
+ ]);
38319
+ CODEX_TOOLS = OPENAI_PASCAL_TOOLS;
38320
+ GEMINI_TOOLS = GEMINI_PASCAL_TOOLS;
38321
+ MEMORY_TOOL_NAMES = new Set([
38322
+ "memory",
38323
+ "memory_apply_patch",
38324
+ "memory_insert",
38325
+ "memory_replace",
38326
+ "memory_rethink"
38327
+ ]);
38328
+ });
38329
+
38330
+ // src/agent/memoryFilesystem.ts
38331
+ var exports_memoryFilesystem = {};
38332
+ __export(exports_memoryFilesystem, {
38333
+ renderMemoryFilesystemTree: () => renderMemoryFilesystemTree,
38334
+ labelFromRelativePath: () => labelFromRelativePath,
38335
+ getMemorySystemDir: () => getMemorySystemDir,
38336
+ getMemoryFilesystemRoot: () => getMemoryFilesystemRoot,
38337
+ ensureMemoryFilesystemDirs: () => ensureMemoryFilesystemDirs,
38338
+ enableMemfsIfCloud: () => enableMemfsIfCloud,
38339
+ applyMemfsFlags: () => applyMemfsFlags,
38340
+ MEMORY_SYSTEM_DIR: () => MEMORY_SYSTEM_DIR,
38341
+ MEMORY_FS_ROOT: () => MEMORY_FS_ROOT,
38342
+ MEMORY_FS_MEMORY_DIR: () => MEMORY_FS_MEMORY_DIR,
38343
+ MEMORY_FS_AGENTS_DIR: () => MEMORY_FS_AGENTS_DIR
38344
+ });
38345
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4 } from "node:fs";
38346
+ import { homedir as homedir8 } from "node:os";
38347
+ import { join as join7 } from "node:path";
38348
+ function getMemoryFilesystemRoot(agentId, homeDir = homedir8()) {
38349
+ return join7(homeDir, MEMORY_FS_ROOT, MEMORY_FS_AGENTS_DIR, agentId, MEMORY_FS_MEMORY_DIR);
38350
+ }
38351
+ function getMemorySystemDir(agentId, homeDir = homedir8()) {
38352
+ return join7(getMemoryFilesystemRoot(agentId, homeDir), MEMORY_SYSTEM_DIR);
38353
+ }
38354
+ function ensureMemoryFilesystemDirs(agentId, homeDir = homedir8()) {
38355
+ const root = getMemoryFilesystemRoot(agentId, homeDir);
38356
+ const systemDir = getMemorySystemDir(agentId, homeDir);
38357
+ if (!existsSync6(root)) {
38358
+ mkdirSync4(root, { recursive: true });
38359
+ }
38360
+ if (!existsSync6(systemDir)) {
38361
+ mkdirSync4(systemDir, { recursive: true });
38362
+ }
38363
+ }
38364
+ function labelFromRelativePath(relativePath) {
38365
+ const normalized = relativePath.replace(/\\/g, "/");
38366
+ return normalized.replace(/\.md$/, "");
38367
+ }
38368
+ function renderMemoryFilesystemTree(systemLabels, detachedLabels) {
38369
+ const makeNode = () => ({ children: new Map, isFile: false });
38370
+ const root = makeNode();
38371
+ const insertPath = (base2, label) => {
38372
+ const parts = base2 ? [base2, ...label.split("/")] : label.split("/");
38373
+ let current = root;
38374
+ for (const [i, partName] of parts.entries()) {
38375
+ const part = i === parts.length - 1 ? `${partName}.md` : partName;
38376
+ if (!current.children.has(part)) {
38377
+ current.children.set(part, makeNode());
38378
+ }
38379
+ current = current.children.get(part);
38380
+ if (i === parts.length - 1) {
38381
+ current.isFile = true;
38382
+ }
38383
+ }
38384
+ };
38385
+ for (const label of systemLabels) {
38386
+ insertPath(MEMORY_SYSTEM_DIR, label);
38387
+ }
38388
+ for (const label of detachedLabels) {
38389
+ insertPath(null, label);
38390
+ }
38391
+ if (!root.children.has(MEMORY_SYSTEM_DIR)) {
38392
+ root.children.set(MEMORY_SYSTEM_DIR, makeNode());
38393
+ }
38394
+ const sortedEntries = (node) => {
38395
+ const entries = Array.from(node.children.entries());
38396
+ return entries.sort(([nameA, nodeA], [nameB, nodeB]) => {
38397
+ if (nodeA.isFile !== nodeB.isFile) {
38398
+ return nodeA.isFile ? 1 : -1;
38399
+ }
38400
+ return nameA.localeCompare(nameB);
38401
+ });
38402
+ };
38403
+ const lines = ["/memory/"];
38404
+ const render2 = (node, prefix) => {
38405
+ const entries = sortedEntries(node);
38406
+ entries.forEach(([name, child], index) => {
38407
+ const isLast = index === entries.length - 1;
38408
+ const branch = isLast ? "└──" : "├──";
38409
+ lines.push(`${prefix}${branch} ${name}${child.isFile ? "" : "/"}`);
38410
+ if (child.children.size > 0) {
38411
+ const nextPrefix = `${prefix}${isLast ? " " : "│ "}`;
38412
+ render2(child, nextPrefix);
38413
+ }
38414
+ });
38415
+ };
38416
+ render2(root, "");
38417
+ return lines.join(`
38418
+ `);
38419
+ }
38420
+ async function applyMemfsFlags(agentId, memfsFlag, noMemfsFlag, options) {
38421
+ const { getServerUrl: getServerUrl2 } = await init_client2().then(() => exports_client);
38422
+ const { settingsManager: settingsManager3 } = await init_settings_manager().then(() => exports_settings_manager);
38423
+ if (memfsFlag) {
38424
+ const serverUrl = getServerUrl2();
38425
+ if (!serverUrl.includes("api.letta.com")) {
38426
+ throw new Error("--memfs is only available on Letta Cloud (api.letta.com).");
38427
+ }
38428
+ }
38429
+ const hasExplicitToggle = Boolean(memfsFlag || noMemfsFlag);
38430
+ const targetEnabled = memfsFlag ? true : noMemfsFlag ? false : settingsManager3.isMemfsEnabled(agentId);
38431
+ if (hasExplicitToggle) {
38432
+ const { updateAgentSystemPromptMemfs: updateAgentSystemPromptMemfs2 } = await init_modify().then(() => exports_modify);
38433
+ const promptUpdate = await updateAgentSystemPromptMemfs2(agentId, targetEnabled);
38434
+ if (!promptUpdate.success) {
38435
+ throw new Error(promptUpdate.message);
38436
+ }
38437
+ settingsManager3.setMemfsEnabled(agentId, targetEnabled);
38438
+ }
38439
+ const isEnabled = hasExplicitToggle ? targetEnabled : settingsManager3.isMemfsEnabled(agentId);
38440
+ if (isEnabled && memfsFlag) {
38441
+ const { detachMemoryTools: detachMemoryTools2 } = await init_toolset().then(() => exports_toolset);
38442
+ await detachMemoryTools2(agentId);
38443
+ }
38444
+ let pullSummary;
38445
+ if (isEnabled) {
38446
+ const { addGitMemoryTag: addGitMemoryTag2, isGitRepo: isGitRepo2, cloneMemoryRepo: cloneMemoryRepo2, pullMemory: pullMemory2 } = await init_memoryGit().then(() => exports_memoryGit);
38447
+ await addGitMemoryTag2(agentId);
38448
+ if (!isGitRepo2(agentId)) {
38449
+ await cloneMemoryRepo2(agentId);
38450
+ } else if (options?.pullOnExistingRepo) {
38451
+ const result = await pullMemory2(agentId);
38452
+ pullSummary = result.summary;
38453
+ }
38454
+ }
38455
+ const action = memfsFlag ? "enabled" : noMemfsFlag ? "disabled" : "unchanged";
38456
+ return {
38457
+ action,
38458
+ memoryDir: isEnabled ? getMemoryFilesystemRoot(agentId) : undefined,
38459
+ pullSummary
38460
+ };
38461
+ }
38462
+ async function enableMemfsIfCloud(agentId) {
38463
+ const { getServerUrl: getServerUrl2 } = await init_client2().then(() => exports_client);
38464
+ const serverUrl = getServerUrl2();
38465
+ if (!serverUrl.includes("api.letta.com"))
38466
+ return;
38467
+ try {
38468
+ await applyMemfsFlags(agentId, true, undefined);
38469
+ } catch (error) {
38470
+ console.warn(`Warning: Could not enable memfs for new agent: ${error instanceof Error ? error.message : String(error)}`);
38471
+ }
38472
+ }
38473
+ var MEMORY_FS_ROOT = ".letta", MEMORY_FS_AGENTS_DIR = "agents", MEMORY_FS_MEMORY_DIR = "memory", MEMORY_SYSTEM_DIR = "system";
38474
+ var init_memoryFilesystem = () => {};
38475
+
37552
38476
  // src/tools/impl/shellEnv.ts
37553
38477
  var exports_shellEnv = {};
37554
38478
  __export(exports_shellEnv, {
@@ -37556,7 +38480,7 @@ __export(exports_shellEnv, {
37556
38480
  getShellEnv: () => getShellEnv,
37557
38481
  ensureLettaShimDir: () => ensureLettaShimDir
37558
38482
  });
37559
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync2 } from "node:fs";
38483
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync2 } from "node:fs";
37560
38484
  import { createRequire as createRequire2 } from "node:module";
37561
38485
  import { tmpdir } from "node:os";
37562
38486
  import * as path3 from "node:path";
@@ -37629,7 +38553,7 @@ function ensureLettaShimDir(invocation) {
37629
38553
  if (!invocation.command)
37630
38554
  return null;
37631
38555
  const shimDir = path3.join(tmpdir(), "letta-code-shell-shim");
37632
- mkdirSync4(shimDir, { recursive: true });
38556
+ mkdirSync5(shimDir, { recursive: true });
37633
38557
  if (process.platform === "win32") {
37634
38558
  const cmdPath = path3.join(shimDir, "letta.cmd");
37635
38559
  const quotedCommand = `"${invocation.command.replaceAll('"', '""')}"`;
@@ -37669,9 +38593,33 @@ function getShellEnv() {
37669
38593
  const existingPath = env3[pathKey] || "";
37670
38594
  env3[pathKey] = existingPath ? `${pathPrefixes.join(path3.delimiter)}${path3.delimiter}${existingPath}` : pathPrefixes.join(path3.delimiter);
37671
38595
  }
38596
+ let agentId;
37672
38597
  try {
37673
- env3.LETTA_AGENT_ID = getCurrentAgentId();
38598
+ const resolvedAgentId = getCurrentAgentId();
38599
+ if (typeof resolvedAgentId === "string" && resolvedAgentId.trim()) {
38600
+ agentId = resolvedAgentId.trim();
38601
+ }
37674
38602
  } catch {}
38603
+ if (!agentId) {
38604
+ const fallbackAgentId = env3.AGENT_ID || env3.LETTA_AGENT_ID;
38605
+ if (typeof fallbackAgentId === "string" && fallbackAgentId.trim()) {
38606
+ agentId = fallbackAgentId.trim();
38607
+ }
38608
+ }
38609
+ if (agentId) {
38610
+ env3.LETTA_AGENT_ID = agentId;
38611
+ env3.AGENT_ID = agentId;
38612
+ try {
38613
+ if (settingsManager.isMemfsEnabled(agentId)) {
38614
+ const memoryDir = getMemoryFilesystemRoot(agentId);
38615
+ env3.LETTA_MEMORY_DIR = memoryDir;
38616
+ env3.MEMORY_DIR = memoryDir;
38617
+ } else {
38618
+ delete env3.LETTA_MEMORY_DIR;
38619
+ delete env3.MEMORY_DIR;
38620
+ }
38621
+ } catch {}
38622
+ }
37675
38623
  if (!env3.LETTA_API_KEY || !env3.LETTA_BASE_URL) {
37676
38624
  try {
37677
38625
  const settings = settingsManager.getSettings();
@@ -37699,6 +38647,7 @@ function getShellEnv() {
37699
38647
  var LETTA_BIN_ARGS_ENV = "LETTA_CODE_BIN_ARGS_JSON";
37700
38648
  var init_shellEnv = __esm(async () => {
37701
38649
  init_context();
38650
+ init_memoryFilesystem();
37702
38651
  await __promiseAll([
37703
38652
  init_client2(),
37704
38653
  init_settings_manager()
@@ -38472,8 +39421,8 @@ async function edit(args) {
38472
39421
  var init_Edit2 = () => {};
38473
39422
 
38474
39423
  // src/cli/helpers/planName.ts
38475
- import { homedir as homedir9 } from "node:os";
38476
- import { join as join9 } from "node:path";
39424
+ import { homedir as homedir10 } from "node:os";
39425
+ import { join as join10 } from "node:path";
38477
39426
  function randomElement(arr) {
38478
39427
  return arr[Math.floor(Math.random() * arr.length)];
38479
39428
  }
@@ -38485,7 +39434,7 @@ function generatePlanName() {
38485
39434
  }
38486
39435
  function generatePlanFilePath() {
38487
39436
  const name = generatePlanName();
38488
- return join9(homedir9(), ".letta", "plans", `${name}.md`);
39437
+ return join10(homedir10(), ".letta", "plans", `${name}.md`);
38489
39438
  }
38490
39439
  var adjectives, nouns;
38491
39440
  var init_planName = __esm(() => {
@@ -38594,8 +39543,8 @@ var exports_mode = {};
38594
39543
  __export(exports_mode, {
38595
39544
  permissionMode: () => permissionMode2
38596
39545
  });
38597
- import { homedir as homedir10 } from "node:os";
38598
- import { join as join10 } from "node:path";
39546
+ import { homedir as homedir11 } from "node:os";
39547
+ import { join as join11 } from "node:path";
38599
39548
  function getGlobalMode2() {
38600
39549
  const global2 = globalThis;
38601
39550
  if (!global2[MODE_KEY2]) {
@@ -38716,7 +39665,7 @@ class PermissionModeManager2 {
38716
39665
  return "allow";
38717
39666
  }
38718
39667
  if (writeTools.includes(toolName)) {
38719
- const plansDir = join10(homedir10(), ".letta", "plans");
39668
+ const plansDir = join11(homedir11(), ".letta", "plans");
38720
39669
  let targetPath = toolArgs?.file_path || toolArgs?.path;
38721
39670
  if ((toolName === "ApplyPatch" || toolName === "apply_patch") && toolArgs?.input) {
38722
39671
  const input = toolArgs.input;
@@ -40744,7 +41693,7 @@ var init_LS2 = __esm(() => {
40744
41693
 
40745
41694
  // src/tools/impl/LS.ts
40746
41695
  import { readdir as readdir3, stat } from "node:fs/promises";
40747
- import { join as join12, resolve as resolve7 } from "node:path";
41696
+ import { join as join13, resolve as resolve7 } from "node:path";
40748
41697
  async function ls(args) {
40749
41698
  validateRequiredParams(args, ["path"], "LS");
40750
41699
  validateParamTypes(args, LS_default2, "LS");
@@ -40754,7 +41703,7 @@ async function ls(args) {
40754
41703
  const items = await readdir3(dirPath);
40755
41704
  const filteredItems = items.filter((item) => !ignore.some((pattern) => import_picomatch.default.isMatch(item, pattern)));
40756
41705
  const fileInfos = await Promise.all(filteredItems.map(async (item) => {
40757
- const fullPath = join12(dirPath, item);
41706
+ const fullPath = join13(dirPath, item);
40758
41707
  try {
40759
41708
  const stats = await stat(fullPath);
40760
41709
  return {
@@ -40917,9 +41866,9 @@ __export(exports_imageResize_magick, {
40917
41866
  import { execSync } from "node:child_process";
40918
41867
  import { readFileSync as readFileSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
40919
41868
  import { tmpdir as tmpdir2 } from "node:os";
40920
- import { join as join13 } from "node:path";
41869
+ import { join as join14 } from "node:path";
40921
41870
  async function getImageDimensions(buffer) {
40922
- const tempInput = join13(tmpdir2(), `image-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
41871
+ const tempInput = join14(tmpdir2(), `image-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
40923
41872
  writeFileSync4(tempInput, buffer);
40924
41873
  try {
40925
41874
  const output = execSync(`magick identify -format "%w %h %m" "${tempInput}"`, {
@@ -40942,12 +41891,12 @@ async function compressToFitByteLimit(buffer, currentWidth, currentHeight) {
40942
41891
  if (buffer.length <= MAX_IMAGE_BYTES) {
40943
41892
  return null;
40944
41893
  }
40945
- const tempInput = join13(tmpdir2(), `compress-input-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
41894
+ const tempInput = join14(tmpdir2(), `compress-input-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
40946
41895
  writeFileSync4(tempInput, buffer);
40947
41896
  try {
40948
41897
  const qualities = [85, 70, 55, 40];
40949
41898
  for (const quality of qualities) {
40950
- const tempOutput = join13(tmpdir2(), `compress-output-${Date.now()}-${Math.random().toString(36).slice(2)}.jpg`);
41899
+ const tempOutput = join14(tmpdir2(), `compress-output-${Date.now()}-${Math.random().toString(36).slice(2)}.jpg`);
40951
41900
  try {
40952
41901
  execSync(`magick "${tempInput}" -quality ${quality} "${tempOutput}"`, {
40953
41902
  stdio: "ignore"
@@ -40973,7 +41922,7 @@ async function compressToFitByteLimit(buffer, currentWidth, currentHeight) {
40973
41922
  for (const scale of scales) {
40974
41923
  const scaledWidth = Math.floor(currentWidth * scale);
40975
41924
  const scaledHeight = Math.floor(currentHeight * scale);
40976
- const tempOutput = join13(tmpdir2(), `compress-output-${Date.now()}-${Math.random().toString(36).slice(2)}.jpg`);
41925
+ const tempOutput = join14(tmpdir2(), `compress-output-${Date.now()}-${Math.random().toString(36).slice(2)}.jpg`);
40977
41926
  try {
40978
41927
  execSync(`magick "${tempInput}" -resize ${scaledWidth}x${scaledHeight} -quality 70 "${tempOutput}"`, {
40979
41928
  stdio: "ignore"
@@ -41017,11 +41966,11 @@ async function resizeImageIfNeeded(buffer, inputMediaType) {
41017
41966
  resized: false
41018
41967
  };
41019
41968
  }
41020
- const tempInput = join13(tmpdir2(), `resize-input-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
41969
+ const tempInput = join14(tmpdir2(), `resize-input-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
41021
41970
  writeFileSync4(tempInput, buffer);
41022
41971
  try {
41023
41972
  if (needsResize) {
41024
- const tempOutput2 = join13(tmpdir2(), `resize-output-${Date.now()}-${Math.random().toString(36).slice(2)}`);
41973
+ const tempOutput2 = join14(tmpdir2(), `resize-output-${Date.now()}-${Math.random().toString(36).slice(2)}`);
41025
41974
  let outputBuffer2;
41026
41975
  let outputMediaType;
41027
41976
  if (format2 === "jpeg" || format2 === "jpg") {
@@ -41052,7 +42001,7 @@ async function resizeImageIfNeeded(buffer, inputMediaType) {
41052
42001
  resized: true
41053
42002
  };
41054
42003
  }
41055
- const tempOutput = join13(tmpdir2(), `convert-output-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);
42004
+ const tempOutput = join14(tmpdir2(), `convert-output-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);
41056
42005
  execSync(`magick "${tempInput}" "${tempOutput}"`, {
41057
42006
  stdio: "ignore"
41058
42007
  });
@@ -42272,7 +43221,7 @@ var require_range = __commonJS((exports, module) => {
42272
43221
  parseRange(range) {
42273
43222
  const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);
42274
43223
  const memoKey = memoOpts + ":" + range;
42275
- const cached = cache4.get(memoKey);
43224
+ const cached = cache5.get(memoKey);
42276
43225
  if (cached) {
42277
43226
  return cached;
42278
43227
  }
@@ -42306,7 +43255,7 @@ var require_range = __commonJS((exports, module) => {
42306
43255
  rangeMap.delete("");
42307
43256
  }
42308
43257
  const result = [...rangeMap.values()];
42309
- cache4.set(memoKey, result);
43258
+ cache5.set(memoKey, result);
42310
43259
  return result;
42311
43260
  }
42312
43261
  intersects(range, options) {
@@ -42344,7 +43293,7 @@ var require_range = __commonJS((exports, module) => {
42344
43293
  }
42345
43294
  module.exports = Range;
42346
43295
  var LRU = require_lrucache();
42347
- var cache4 = new LRU;
43296
+ var cache5 = new LRU;
42348
43297
  var parseOptions = require_parse_options();
42349
43298
  var Comparator = require_comparator();
42350
43299
  var debug = require_debug();
@@ -47387,7 +48336,7 @@ var require_utility = __commonJS((exports, module) => {
47387
48336
  format2.heif.input.fileSuffix = [".avif"];
47388
48337
  format2.heif.output.alias = ["avif"];
47389
48338
  }
47390
- function cache4(options) {
48339
+ function cache5(options) {
47391
48340
  if (is.bool(options)) {
47392
48341
  if (options) {
47393
48342
  return sharp.cache(50, 20, 100);
@@ -47400,7 +48349,7 @@ var require_utility = __commonJS((exports, module) => {
47400
48349
  return sharp.cache();
47401
48350
  }
47402
48351
  }
47403
- cache4(true);
48352
+ cache5(true);
47404
48353
  function concurrency(concurrency2) {
47405
48354
  return sharp.concurrency(is.integer(concurrency2) ? concurrency2 : null);
47406
48355
  }
@@ -47439,7 +48388,7 @@ var require_utility = __commonJS((exports, module) => {
47439
48388
  }
47440
48389
  }
47441
48390
  module.exports = (Sharp) => {
47442
- Sharp.cache = cache4;
48391
+ Sharp.cache = cache5;
47443
48392
  Sharp.concurrency = concurrency;
47444
48393
  Sharp.counters = counters;
47445
48394
  Sharp.simd = simd;
@@ -54321,19 +55270,19 @@ __export(exports_skills, {
54321
55270
  SKILLS_DIR: () => SKILLS_DIR,
54322
55271
  GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR
54323
55272
  });
54324
- import { existsSync as existsSync7 } from "node:fs";
55273
+ import { existsSync as existsSync8 } from "node:fs";
54325
55274
  import { readdir as readdir5, readFile as readFile3 } from "node:fs/promises";
54326
- import { dirname as dirname4, join as join14 } from "node:path";
55275
+ import { dirname as dirname4, join as join15 } from "node:path";
54327
55276
  import { fileURLToPath as fileURLToPath6 } from "node:url";
54328
55277
  function getBundledSkillsPath() {
54329
55278
  const thisDir = dirname4(fileURLToPath6(import.meta.url));
54330
55279
  if (thisDir.includes("src/agent") || thisDir.includes("src\\agent")) {
54331
- return join14(thisDir, "../skills/builtin");
55280
+ return join15(thisDir, "../skills/builtin");
54332
55281
  }
54333
- return join14(thisDir, "skills");
55282
+ return join15(thisDir, "skills");
54334
55283
  }
54335
55284
  function getAgentSkillsDir(agentId) {
54336
- return join14(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "skills");
55285
+ return join15(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "skills");
54337
55286
  }
54338
55287
  async function getBundledSkills() {
54339
55288
  const bundledPath = getBundledSkillsPath();
@@ -54342,7 +55291,7 @@ async function getBundledSkills() {
54342
55291
  }
54343
55292
  async function discoverSkillsFromDir(skillsPath, source) {
54344
55293
  const errors = [];
54345
- if (!existsSync7(skillsPath)) {
55294
+ if (!existsSync8(skillsPath)) {
54346
55295
  return { skills: [], errors: [] };
54347
55296
  }
54348
55297
  const skills = [];
@@ -54356,7 +55305,7 @@ async function discoverSkillsFromDir(skillsPath, source) {
54356
55305
  }
54357
55306
  return { skills, errors };
54358
55307
  }
54359
- async function discoverSkills(projectSkillsPath = join14(process.cwd(), SKILLS_DIR), agentId, options) {
55308
+ async function discoverSkills(projectSkillsPath = join15(process.cwd(), SKILLS_DIR), agentId, options) {
54360
55309
  const allErrors = [];
54361
55310
  const skillsById = new Map;
54362
55311
  if (!options?.skipBundled) {
@@ -54392,7 +55341,7 @@ async function findSkillFiles(currentPath, rootPath, skills, errors, source) {
54392
55341
  try {
54393
55342
  const entries = await readdir5(currentPath, { withFileTypes: true });
54394
55343
  for (const entry of entries) {
54395
- const fullPath = join14(currentPath, entry.name);
55344
+ const fullPath = join15(currentPath, entry.name);
54396
55345
  if (entry.isDirectory()) {
54397
55346
  await findSkillFiles(fullPath, rootPath, skills, errors, source);
54398
55347
  } else if (entry.isFile() && entry.name.toUpperCase() === "SKILL.MD") {
@@ -54466,7 +55415,7 @@ ${lines.join(`
54466
55415
  }
54467
55416
  var SKILLS_DIR = ".skills", GLOBAL_SKILLS_DIR;
54468
55417
  var init_skills = __esm(() => {
54469
- GLOBAL_SKILLS_DIR = join14(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
55418
+ GLOBAL_SKILLS_DIR = join15(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
54470
55419
  });
54471
55420
 
54472
55421
  // src/tools/impl/skillContentRegistry.ts
@@ -54491,7 +55440,7 @@ var init_skillContentRegistry = __esm(() => {
54491
55440
  // src/tools/impl/Skill.ts
54492
55441
  import { readdirSync as readdirSync3 } from "node:fs";
54493
55442
  import { readFile as readFile4 } from "node:fs/promises";
54494
- import { dirname as dirname5, join as join15 } from "node:path";
55443
+ import { dirname as dirname5, join as join16 } from "node:path";
54495
55444
  function hasAdditionalFiles(skillMdPath) {
54496
55445
  try {
54497
55446
  const skillDir = dirname5(skillMdPath);
@@ -54502,19 +55451,19 @@ function hasAdditionalFiles(skillMdPath) {
54502
55451
  }
54503
55452
  }
54504
55453
  async function readSkillContent(skillId, skillsDir, agentId) {
54505
- const projectSkillPath = join15(skillsDir, skillId, "SKILL.md");
55454
+ const projectSkillPath = join16(skillsDir, skillId, "SKILL.md");
54506
55455
  try {
54507
55456
  const content = await readFile4(projectSkillPath, "utf-8");
54508
55457
  return { content, path: projectSkillPath };
54509
55458
  } catch {}
54510
55459
  if (agentId) {
54511
- const agentSkillPath = join15(getAgentSkillsDir(agentId), skillId, "SKILL.md");
55460
+ const agentSkillPath = join16(getAgentSkillsDir(agentId), skillId, "SKILL.md");
54512
55461
  try {
54513
55462
  const content = await readFile4(agentSkillPath, "utf-8");
54514
55463
  return { content, path: agentSkillPath };
54515
55464
  } catch {}
54516
55465
  }
54517
- const globalSkillPath = join15(GLOBAL_SKILLS_DIR, skillId, "SKILL.md");
55466
+ const globalSkillPath = join16(GLOBAL_SKILLS_DIR, skillId, "SKILL.md");
54518
55467
  try {
54519
55468
  const content = await readFile4(globalSkillPath, "utf-8");
54520
55469
  return { content, path: globalSkillPath };
@@ -54528,8 +55477,8 @@ async function readSkillContent(skillId, skillsDir, agentId) {
54528
55477
  } catch {}
54529
55478
  }
54530
55479
  try {
54531
- const bundledSkillsDir = join15(process.cwd(), "skills", "skills");
54532
- const bundledSkillPath = join15(bundledSkillsDir, skillId, "SKILL.md");
55480
+ const bundledSkillsDir = join16(process.cwd(), "skills", "skills");
55481
+ const bundledSkillPath = join16(bundledSkillsDir, skillId, "SKILL.md");
54533
55482
  const content = await readFile4(bundledSkillPath, "utf-8");
54534
55483
  return { content, path: bundledSkillPath };
54535
55484
  } catch {
@@ -54541,7 +55490,7 @@ async function getResolvedSkillsDir() {
54541
55490
  if (skillsDir) {
54542
55491
  return skillsDir;
54543
55492
  }
54544
- return join15(process.cwd(), SKILLS_DIR);
55493
+ return join16(process.cwd(), SKILLS_DIR);
54545
55494
  }
54546
55495
  async function skill(args) {
54547
55496
  validateRequiredParams(args, ["skill"], "Skill");
@@ -54806,109 +55755,6 @@ var init_cli = __esm(() => {
54806
55755
  cliPermissions = new CliPermissions;
54807
55756
  });
54808
55757
 
54809
- // src/agent/available-models.ts
54810
- var exports_available_models = {};
54811
- __export(exports_available_models, {
54812
- prefetchAvailableModelHandles: () => prefetchAvailableModelHandles,
54813
- getModelContextWindow: () => getModelContextWindow,
54814
- getAvailableModelsCacheInfo: () => getAvailableModelsCacheInfo,
54815
- getAvailableModelHandles: () => getAvailableModelHandles,
54816
- clearAvailableModelsCache: () => clearAvailableModelsCache
54817
- });
54818
- function isFresh(now = Date.now()) {
54819
- return cache4 !== null && now - cache4.fetchedAt < CACHE_TTL_MS;
54820
- }
54821
- function clearAvailableModelsCache() {
54822
- cache4 = null;
54823
- }
54824
- function getAvailableModelsCacheInfo() {
54825
- const now = Date.now();
54826
- return {
54827
- hasCache: cache4 !== null,
54828
- isFresh: isFresh(now),
54829
- fetchedAt: cache4?.fetchedAt ?? null,
54830
- ageMs: cache4 ? now - cache4.fetchedAt : null,
54831
- ttlMs: CACHE_TTL_MS
54832
- };
54833
- }
54834
- async function refreshByokProviders() {
54835
- const client = await getClient2();
54836
- try {
54837
- const providers = await client.get("/v1/providers/");
54838
- const byokProviders = providers.filter((p) => p.provider_category === "byok");
54839
- await Promise.allSettled(byokProviders.map(async (provider) => {
54840
- try {
54841
- await client.patch(`/v1/providers/${provider.id}/refresh`);
54842
- } catch (error) {
54843
- debugWarn("available-models", `Failed to refresh provider ${provider.name} (${provider.id}):`, error);
54844
- }
54845
- }));
54846
- } catch (error) {
54847
- debugWarn("available-models", "Failed to list providers for refresh:", error);
54848
- }
54849
- }
54850
- async function fetchFromNetwork() {
54851
- const client = await getClient2();
54852
- const modelsList = await client.models.list();
54853
- const handles = new Set(modelsList.map((m) => m.handle).filter((h) => !!h));
54854
- const contextWindows = new Map;
54855
- for (const model of modelsList) {
54856
- if (model.handle && model.max_context_window) {
54857
- contextWindows.set(model.handle, model.max_context_window);
54858
- }
54859
- }
54860
- return { handles, contextWindows, fetchedAt: Date.now() };
54861
- }
54862
- async function getAvailableModelHandles(options) {
54863
- const forceRefresh = options?.forceRefresh === true;
54864
- const now = Date.now();
54865
- if (!forceRefresh && isFresh(now) && cache4) {
54866
- return {
54867
- handles: cache4.handles,
54868
- source: "cache",
54869
- fetchedAt: cache4.fetchedAt
54870
- };
54871
- }
54872
- if (!forceRefresh && inflight) {
54873
- const entry2 = await inflight;
54874
- return {
54875
- handles: entry2.handles,
54876
- source: "network",
54877
- fetchedAt: entry2.fetchedAt
54878
- };
54879
- }
54880
- if (forceRefresh) {
54881
- await refreshByokProviders();
54882
- }
54883
- inflight = fetchFromNetwork().then((entry2) => {
54884
- cache4 = entry2;
54885
- return entry2;
54886
- }).finally(() => {
54887
- inflight = null;
54888
- });
54889
- const entry = await inflight;
54890
- return {
54891
- handles: entry.handles,
54892
- source: "network",
54893
- fetchedAt: entry.fetchedAt
54894
- };
54895
- }
54896
- function prefetchAvailableModelHandles() {
54897
- getAvailableModelHandles().catch(() => {});
54898
- }
54899
- async function getModelContextWindow(handle) {
54900
- if (!cache4) {
54901
- await getAvailableModelHandles();
54902
- }
54903
- return cache4?.contextWindows.get(handle);
54904
- }
54905
- var CACHE_TTL_MS, cache4 = null, inflight = null;
54906
- var init_available_models = __esm(async () => {
54907
- init_debug();
54908
- await init_client2();
54909
- CACHE_TTL_MS = 5 * 60 * 1000;
54910
- });
54911
-
54912
55758
  // src/agent/subagents/manager.ts
54913
55759
  import { spawn as spawn4 } from "node:child_process";
54914
55760
  import { createInterface } from "node:readline";
@@ -56798,11 +57644,6 @@ var init_Task3 = __esm(() => {
56798
57644
  conversation_id: {
56799
57645
  type: "string",
56800
57646
  description: "Resume from an existing conversation. Does NOT require agent_id (conversation IDs are unique and encode the agent)."
56801
- },
56802
- max_turns: {
56803
- type: "integer",
56804
- exclusiveMinimum: 0,
56805
- description: "Maximum number of agentic turns (API round-trips) before stopping. Defaults to unlimited (recommended for most use cases)."
56806
57647
  }
56807
57648
  },
56808
57649
  required: ["description", "prompt", "subagent_type"],
@@ -58665,8 +59506,8 @@ function matchesFilePattern(query, pattern, workingDirectory) {
58665
59506
  globPattern = globPattern.slice(2);
58666
59507
  }
58667
59508
  if (globPattern.startsWith("~/")) {
58668
- const homedir11 = __require("node:os").homedir();
58669
- globPattern = globPattern.replace(/^~/, homedir11);
59509
+ const homedir12 = __require("node:os").homedir();
59510
+ globPattern = globPattern.replace(/^~/, homedir12);
58670
59511
  }
58671
59512
  globPattern = normalizeAbsolutePattern(globPattern, workingDirectory);
58672
59513
  const windowsContext = isWindowsContext(workingDirectory);
@@ -59088,8 +59929,8 @@ __export(exports_loader, {
59088
59929
  savePermissionRule: () => savePermissionRule,
59089
59930
  loadPermissions: () => loadPermissions
59090
59931
  });
59091
- import { homedir as homedir11 } from "node:os";
59092
- import { join as join16 } from "node:path";
59932
+ import { homedir as homedir12 } from "node:os";
59933
+ import { join as join17 } from "node:path";
59093
59934
  async function loadPermissions(workingDirectory = process.cwd()) {
59094
59935
  const merged = {
59095
59936
  allow: [],
@@ -59098,10 +59939,10 @@ async function loadPermissions(workingDirectory = process.cwd()) {
59098
59939
  additionalDirectories: []
59099
59940
  };
59100
59941
  const sources = [
59101
- join16(process.env.XDG_CONFIG_HOME || join16(homedir11(), ".config"), "letta", "settings.json"),
59102
- join16(homedir11(), ".letta", "settings.json"),
59103
- join16(workingDirectory, ".letta", "settings.json"),
59104
- join16(workingDirectory, ".letta", "settings.local.json")
59942
+ join17(process.env.XDG_CONFIG_HOME || join17(homedir12(), ".config"), "letta", "settings.json"),
59943
+ join17(homedir12(), ".letta", "settings.json"),
59944
+ join17(workingDirectory, ".letta", "settings.json"),
59945
+ join17(workingDirectory, ".letta", "settings.local.json")
59105
59946
  ];
59106
59947
  for (const settingsPath of sources) {
59107
59948
  try {
@@ -59137,13 +59978,13 @@ async function savePermissionRule(rule, ruleType, scope, workingDirectory = proc
59137
59978
  let settingsPath;
59138
59979
  switch (scope) {
59139
59980
  case "user":
59140
- settingsPath = join16(process.env.XDG_CONFIG_HOME || join16(homedir11(), ".config"), "letta", "settings.json");
59981
+ settingsPath = join17(process.env.XDG_CONFIG_HOME || join17(homedir12(), ".config"), "letta", "settings.json");
59141
59982
  break;
59142
59983
  case "project":
59143
- settingsPath = join16(workingDirectory, ".letta", "settings.json");
59984
+ settingsPath = join17(workingDirectory, ".letta", "settings.json");
59144
59985
  break;
59145
59986
  case "local":
59146
- settingsPath = join16(workingDirectory, ".letta", "settings.local.json");
59987
+ settingsPath = join17(workingDirectory, ".letta", "settings.local.json");
59147
59988
  break;
59148
59989
  }
59149
59990
  let settings = {};
@@ -59168,7 +60009,7 @@ async function savePermissionRule(rule, ruleType, scope, workingDirectory = proc
59168
60009
  }
59169
60010
  }
59170
60011
  async function ensureLocalSettingsIgnored(workingDirectory) {
59171
- const gitignorePath = join16(workingDirectory, ".gitignore");
60012
+ const gitignorePath = join17(workingDirectory, ".gitignore");
59172
60013
  const pattern = ".letta/settings.local.json";
59173
60014
  try {
59174
60015
  let content = "";
@@ -59193,7 +60034,7 @@ var exports_analyzer = {};
59193
60034
  __export(exports_analyzer, {
59194
60035
  analyzeApprovalContext: () => analyzeApprovalContext
59195
60036
  });
59196
- import { homedir as homedir12 } from "node:os";
60037
+ import { homedir as homedir13 } from "node:os";
59197
60038
  import { dirname as dirname7, relative, resolve as resolve16, win32 as win322 } from "node:path";
59198
60039
  function normalizeOsPath(path18) {
59199
60040
  return path18.replace(/\\/g, "/");
@@ -59230,7 +60071,7 @@ function formatAbsoluteRulePath(path18) {
59230
60071
  return `//${normalized.replace(/^\/+/, "")}`;
59231
60072
  }
59232
60073
  function formatDisplayPath(path18) {
59233
- return normalizeOsPath(path18).replace(normalizeOsPath(homedir12()), "~");
60074
+ return normalizeOsPath(path18).replace(normalizeOsPath(homedir13()), "~");
59234
60075
  }
59235
60076
  function analyzeApprovalContext(toolName, toolArgs, workingDirectory) {
59236
60077
  const resolveFilePath = () => {
@@ -59373,7 +60214,7 @@ function detectSkillScript(command, workingDir) {
59373
60214
  return null;
59374
60215
  }
59375
60216
  const normalizedWorkingDir = normalizePathSeparators(workingDir).replace(/\/$/, "");
59376
- const normalizedHomeDir = normalizePathSeparators(homedir12()).replace(/\/$/, "");
60217
+ const normalizedHomeDir = normalizePathSeparators(homedir13()).replace(/\/$/, "");
59377
60218
  const detect = (source, regex2) => {
59378
60219
  for (const candidate of pathCandidates) {
59379
60220
  const match3 = candidate.match(regex2);
@@ -59687,50 +60528,6 @@ var init_analyzer = __esm(() => {
59687
60528
  ];
59688
60529
  });
59689
60530
 
59690
- // src/tools/filter.ts
59691
- var exports_filter = {};
59692
- __export(exports_filter, {
59693
- toolFilter: () => toolFilter
59694
- });
59695
-
59696
- class ToolFilterManager {
59697
- enabledTools = null;
59698
- setEnabledTools(toolsString) {
59699
- if (toolsString === "") {
59700
- this.enabledTools = [];
59701
- } else {
59702
- this.enabledTools = toolsString.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
59703
- }
59704
- }
59705
- isEnabled(toolName) {
59706
- if (this.enabledTools === null) {
59707
- return true;
59708
- }
59709
- return this.enabledTools.includes(toolName);
59710
- }
59711
- getEnabledTools() {
59712
- return this.enabledTools ? [...this.enabledTools] : null;
59713
- }
59714
- isActive() {
59715
- return this.enabledTools !== null;
59716
- }
59717
- reset() {
59718
- this.enabledTools = null;
59719
- }
59720
- }
59721
- function getFilter() {
59722
- const global2 = globalThis;
59723
- if (!global2[FILTER_KEY]) {
59724
- global2[FILTER_KEY] = new ToolFilterManager;
59725
- }
59726
- return global2[FILTER_KEY];
59727
- }
59728
- var FILTER_KEY, toolFilter;
59729
- var init_filter = __esm(() => {
59730
- FILTER_KEY = Symbol.for("@letta/toolFilter");
59731
- toolFilter = getFilter();
59732
- });
59733
-
59734
60531
  // src/tools/manager.ts
59735
60532
  var exports_manager2 = {};
59736
60533
  __export(exports_manager2, {
@@ -60778,19 +61575,19 @@ __export(exports_skills2, {
60778
61575
  SKILLS_DIR: () => SKILLS_DIR2,
60779
61576
  GLOBAL_SKILLS_DIR: () => GLOBAL_SKILLS_DIR2
60780
61577
  });
60781
- import { existsSync as existsSync8 } from "node:fs";
61578
+ import { existsSync as existsSync9 } from "node:fs";
60782
61579
  import { readdir as readdir6, readFile as readFile5 } from "node:fs/promises";
60783
- import { dirname as dirname8, join as join17 } from "node:path";
61580
+ import { dirname as dirname8, join as join18 } from "node:path";
60784
61581
  import { fileURLToPath as fileURLToPath7 } from "node:url";
60785
61582
  function getBundledSkillsPath2() {
60786
61583
  const thisDir = dirname8(fileURLToPath7(import.meta.url));
60787
61584
  if (thisDir.includes("src/agent") || thisDir.includes("src\\agent")) {
60788
- return join17(thisDir, "../skills/builtin");
61585
+ return join18(thisDir, "../skills/builtin");
60789
61586
  }
60790
- return join17(thisDir, "skills");
61587
+ return join18(thisDir, "skills");
60791
61588
  }
60792
61589
  function getAgentSkillsDir2(agentId) {
60793
- return join17(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "skills");
61590
+ return join18(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents", agentId, "skills");
60794
61591
  }
60795
61592
  async function getBundledSkills2() {
60796
61593
  const bundledPath = getBundledSkillsPath2();
@@ -60799,7 +61596,7 @@ async function getBundledSkills2() {
60799
61596
  }
60800
61597
  async function discoverSkillsFromDir2(skillsPath, source) {
60801
61598
  const errors = [];
60802
- if (!existsSync8(skillsPath)) {
61599
+ if (!existsSync9(skillsPath)) {
60803
61600
  return { skills: [], errors: [] };
60804
61601
  }
60805
61602
  const skills = [];
@@ -60813,7 +61610,7 @@ async function discoverSkillsFromDir2(skillsPath, source) {
60813
61610
  }
60814
61611
  return { skills, errors };
60815
61612
  }
60816
- async function discoverSkills2(projectSkillsPath = join17(process.cwd(), SKILLS_DIR2), agentId, options) {
61613
+ async function discoverSkills2(projectSkillsPath = join18(process.cwd(), SKILLS_DIR2), agentId, options) {
60817
61614
  const allErrors = [];
60818
61615
  const skillsById = new Map;
60819
61616
  if (!options?.skipBundled) {
@@ -60849,7 +61646,7 @@ async function findSkillFiles2(currentPath, rootPath, skills, errors, source) {
60849
61646
  try {
60850
61647
  const entries = await readdir6(currentPath, { withFileTypes: true });
60851
61648
  for (const entry of entries) {
60852
- const fullPath = join17(currentPath, entry.name);
61649
+ const fullPath = join18(currentPath, entry.name);
60853
61650
  if (entry.isDirectory()) {
60854
61651
  await findSkillFiles2(fullPath, rootPath, skills, errors, source);
60855
61652
  } else if (entry.isFile() && entry.name.toUpperCase() === "SKILL.MD") {
@@ -60923,7 +61720,7 @@ ${lines.join(`
60923
61720
  }
60924
61721
  var SKILLS_DIR2 = ".skills", GLOBAL_SKILLS_DIR2;
60925
61722
  var init_skills2 = __esm(() => {
60926
- GLOBAL_SKILLS_DIR2 = join17(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
61723
+ GLOBAL_SKILLS_DIR2 = join18(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
60927
61724
  });
60928
61725
 
60929
61726
  // src/utils/fs.ts
@@ -60937,10 +61734,10 @@ __export(exports_fs, {
60937
61734
  exists: () => exists2
60938
61735
  });
60939
61736
  import {
60940
- existsSync as existsSync9,
61737
+ existsSync as existsSync10,
60941
61738
  readFileSync as fsReadFileSync2,
60942
61739
  writeFileSync as fsWriteFileSync2,
60943
- mkdirSync as mkdirSync6
61740
+ mkdirSync as mkdirSync7
60944
61741
  } from "node:fs";
60945
61742
  import { dirname as dirname9 } from "node:path";
60946
61743
  async function readFile6(path19) {
@@ -60948,16 +61745,16 @@ async function readFile6(path19) {
60948
61745
  }
60949
61746
  async function writeFile2(path19, content) {
60950
61747
  const dir = dirname9(path19);
60951
- if (!existsSync9(dir)) {
60952
- mkdirSync6(dir, { recursive: true });
61748
+ if (!existsSync10(dir)) {
61749
+ mkdirSync7(dir, { recursive: true });
60953
61750
  }
60954
61751
  fsWriteFileSync2(path19, content, { encoding: "utf-8", flush: true });
60955
61752
  }
60956
61753
  function exists2(path19) {
60957
- return existsSync9(path19);
61754
+ return existsSync10(path19);
60958
61755
  }
60959
61756
  async function mkdir2(path19, options) {
60960
- mkdirSync6(path19, options);
61757
+ mkdirSync7(path19, options);
60961
61758
  }
60962
61759
  async function readJsonFile(path19) {
60963
61760
  const text = await readFile6(path19);
@@ -61263,21 +62060,85 @@ var init_manager4 = __esm(() => {
61263
62060
  // src/updater/auto-update.ts
61264
62061
  var exports_auto_update = {};
61265
62062
  __export(exports_auto_update, {
62063
+ resolveUpdateRegistryBaseUrl: () => resolveUpdateRegistryBaseUrl,
62064
+ resolveUpdatePackageName: () => resolveUpdatePackageName,
62065
+ resolveUpdateInstallRegistryUrl: () => resolveUpdateInstallRegistryUrl,
61266
62066
  manualUpdate: () => manualUpdate,
61267
62067
  detectPackageManager: () => detectPackageManager,
61268
62068
  checkForUpdate: () => checkForUpdate,
61269
- checkAndAutoUpdate: () => checkAndAutoUpdate
62069
+ checkAndAutoUpdate: () => checkAndAutoUpdate,
62070
+ buildLatestVersionUrl: () => buildLatestVersionUrl,
62071
+ buildInstallCommand: () => buildInstallCommand,
62072
+ buildInstallArgs: () => buildInstallArgs
61270
62073
  });
61271
- import { exec as exec2 } from "node:child_process";
62074
+ import { execFile as execFile4 } from "node:child_process";
61272
62075
  import { realpathSync as realpathSync2 } from "node:fs";
61273
62076
  import { readdir as readdir7, rm } from "node:fs/promises";
61274
- import { join as join18 } from "node:path";
62077
+ import { join as join19 } from "node:path";
61275
62078
  import { promisify as promisify4 } from "node:util";
61276
62079
  function debugLog2(...args) {
61277
62080
  if (DEBUG) {
61278
62081
  console.error("[auto-update]", ...args);
61279
62082
  }
61280
62083
  }
62084
+ function normalizeUpdatePackageName(raw) {
62085
+ if (!raw)
62086
+ return null;
62087
+ const value = raw.trim();
62088
+ if (!value)
62089
+ return null;
62090
+ if (/\s/.test(value) || /["'`;|&$]/.test(value))
62091
+ return null;
62092
+ return value;
62093
+ }
62094
+ function normalizeRegistryUrl(raw) {
62095
+ if (!raw)
62096
+ return null;
62097
+ const value = raw.trim();
62098
+ if (!value || /\s/.test(value) || /["'`;|&$]/.test(value))
62099
+ return null;
62100
+ try {
62101
+ const url = new URL(value);
62102
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
62103
+ return null;
62104
+ }
62105
+ return value.replace(/\/+$/, "");
62106
+ } catch {
62107
+ return null;
62108
+ }
62109
+ }
62110
+ function resolveUpdatePackageName(env3 = process.env) {
62111
+ const custom = normalizeUpdatePackageName(env3[UPDATE_PACKAGE_NAME_ENV]);
62112
+ if (custom) {
62113
+ return custom;
62114
+ }
62115
+ return DEFAULT_UPDATE_PACKAGE_NAME;
62116
+ }
62117
+ function resolveUpdateRegistryBaseUrl(env3 = process.env) {
62118
+ const custom = normalizeRegistryUrl(env3[UPDATE_REGISTRY_BASE_URL_ENV]);
62119
+ if (custom) {
62120
+ return custom;
62121
+ }
62122
+ return DEFAULT_UPDATE_REGISTRY_BASE_URL;
62123
+ }
62124
+ function resolveUpdateInstallRegistryUrl(env3 = process.env) {
62125
+ return normalizeRegistryUrl(env3[UPDATE_INSTALL_REGISTRY_URL_ENV]);
62126
+ }
62127
+ function buildLatestVersionUrl(packageName, registryBaseUrl) {
62128
+ return `${registryBaseUrl.replace(/\/+$/, "")}/${packageName}/latest`;
62129
+ }
62130
+ function buildInstallCommand(pm, env3 = process.env) {
62131
+ return `${pm} ${buildInstallArgs(pm, env3).join(" ")}`;
62132
+ }
62133
+ function buildInstallArgs(pm, env3 = process.env) {
62134
+ const packageName = resolveUpdatePackageName(env3);
62135
+ const installRegistry = resolveUpdateInstallRegistryUrl(env3);
62136
+ const args = [...INSTALL_ARG_PREFIX[pm], `${packageName}@latest`];
62137
+ if (installRegistry) {
62138
+ args.push("--registry", installRegistry);
62139
+ }
62140
+ return args;
62141
+ }
61281
62142
  function detectPackageManager() {
61282
62143
  const envOverride = process.env.LETTA_PACKAGE_MANAGER;
61283
62144
  if (envOverride) {
@@ -61323,9 +62184,14 @@ async function checkForUpdate() {
61323
62184
  debugLog2("Prerelease version detected, skipping auto-update check");
61324
62185
  return { updateAvailable: false, currentVersion };
61325
62186
  }
62187
+ const packageName = resolveUpdatePackageName();
62188
+ const registryBaseUrl = resolveUpdateRegistryBaseUrl();
62189
+ const latestUrl = buildLatestVersionUrl(packageName, registryBaseUrl);
61326
62190
  try {
61327
- debugLog2("Checking registry for latest version...");
61328
- const res = await fetch("https://registry.npmjs.org/@letta-ai/letta-code/latest", { signal: AbortSignal.timeout(5000) });
62191
+ debugLog2("Checking registry for latest version:", latestUrl);
62192
+ const res = await fetch(latestUrl, {
62193
+ signal: AbortSignal.timeout(5000)
62194
+ });
61329
62195
  if (!res.ok) {
61330
62196
  throw new Error(`Registry returned ${res.status}`);
61331
62197
  }
@@ -61359,19 +62225,21 @@ async function checkForUpdate() {
61359
62225
  }
61360
62226
  async function getNpmGlobalPath() {
61361
62227
  try {
61362
- const { stdout } = await execAsync("npm prefix -g", { timeout: 5000 });
62228
+ const { stdout } = await execFileAsync3("npm", ["prefix", "-g"], {
62229
+ timeout: 5000
62230
+ });
61363
62231
  return stdout.trim();
61364
62232
  } catch {
61365
62233
  return null;
61366
62234
  }
61367
62235
  }
61368
62236
  async function cleanupOrphanedDirs(globalPath) {
61369
- const lettaAiDir = join18(globalPath, "lib/node_modules/@letta-ai");
62237
+ const lettaAiDir = join19(globalPath, "lib/node_modules/@letta-ai");
61370
62238
  try {
61371
62239
  const entries = await readdir7(lettaAiDir);
61372
62240
  for (const entry of entries) {
61373
62241
  if (entry.startsWith(".letta-code-")) {
61374
- const orphanPath = join18(lettaAiDir, entry);
62242
+ const orphanPath = join19(lettaAiDir, entry);
61375
62243
  debugLog2("Cleaning orphaned temp directory:", orphanPath);
61376
62244
  await rm(orphanPath, { recursive: true, force: true });
61377
62245
  }
@@ -61380,7 +62248,8 @@ async function cleanupOrphanedDirs(globalPath) {
61380
62248
  }
61381
62249
  async function performUpdate() {
61382
62250
  const pm = detectPackageManager();
61383
- const installCmd = INSTALL_CMD[pm];
62251
+ const installCmd = buildInstallCommand(pm);
62252
+ const installArgs = buildInstallArgs(pm);
61384
62253
  debugLog2("Detected package manager:", pm);
61385
62254
  debugLog2("Install command:", installCmd);
61386
62255
  let globalPath = null;
@@ -61393,7 +62262,7 @@ async function performUpdate() {
61393
62262
  }
61394
62263
  try {
61395
62264
  debugLog2(`Running ${installCmd}...`);
61396
- await execAsync(installCmd, { timeout: 60000 });
62265
+ await execFileAsync3(pm, installArgs, { timeout: 60000 });
61397
62266
  debugLog2("Update completed successfully");
61398
62267
  return { success: true };
61399
62268
  } catch (error) {
@@ -61402,7 +62271,7 @@ async function performUpdate() {
61402
62271
  debugLog2("ENOTEMPTY detected, attempting cleanup and retry...");
61403
62272
  await cleanupOrphanedDirs(globalPath);
61404
62273
  try {
61405
- await execAsync(installCmd, { timeout: 60000 });
62274
+ await execFileAsync3(pm, installArgs, { timeout: 60000 });
61406
62275
  debugLog2("Update succeeded after cleanup retry");
61407
62276
  return { success: true };
61408
62277
  } catch (retryError) {
@@ -61476,17 +62345,17 @@ async function manualUpdate() {
61476
62345
  message: `Update failed: ${updateResult.error}`
61477
62346
  };
61478
62347
  }
61479
- var execAsync, DEBUG, INSTALL_CMD, VALID_PACKAGE_MANAGERS;
62348
+ var execFileAsync3, DEBUG, DEFAULT_UPDATE_PACKAGE_NAME = "@letta-ai/letta-code", DEFAULT_UPDATE_REGISTRY_BASE_URL = "https://registry.npmjs.org", UPDATE_PACKAGE_NAME_ENV = "LETTA_UPDATE_PACKAGE_NAME", UPDATE_REGISTRY_BASE_URL_ENV = "LETTA_UPDATE_REGISTRY_BASE_URL", UPDATE_INSTALL_REGISTRY_URL_ENV = "LETTA_UPDATE_INSTALL_REGISTRY_URL", INSTALL_ARG_PREFIX, VALID_PACKAGE_MANAGERS;
61480
62349
  var init_auto_update = __esm(() => {
61481
62350
  init_version();
61482
- execAsync = promisify4(exec2);
62351
+ execFileAsync3 = promisify4(execFile4);
61483
62352
  DEBUG = process.env.LETTA_DEBUG_AUTOUPDATE === "1";
61484
- INSTALL_CMD = {
61485
- npm: "npm install -g @letta-ai/letta-code@latest",
61486
- bun: "bun add -g @letta-ai/letta-code@latest",
61487
- pnpm: "pnpm add -g @letta-ai/letta-code@latest"
62353
+ INSTALL_ARG_PREFIX = {
62354
+ npm: ["install", "-g"],
62355
+ bun: ["add", "-g"],
62356
+ pnpm: ["add", "-g"]
61488
62357
  };
61489
- VALID_PACKAGE_MANAGERS = new Set(Object.keys(INSTALL_CMD));
62358
+ VALID_PACKAGE_MANAGERS = new Set(Object.keys(INSTALL_ARG_PREFIX));
61490
62359
  });
61491
62360
 
61492
62361
  // src/tools/impl/overflow.ts
@@ -61726,9 +62595,9 @@ __export(exports_subagents2, {
61726
62595
  GLOBAL_AGENTS_DIR: () => GLOBAL_AGENTS_DIR2,
61727
62596
  AGENTS_DIR: () => AGENTS_DIR2
61728
62597
  });
61729
- import { existsSync as existsSync11 } from "node:fs";
62598
+ import { existsSync as existsSync12 } from "node:fs";
61730
62599
  import { readdir as readdir8, readFile as readFile7 } from "node:fs/promises";
61731
- import { join as join20 } from "node:path";
62600
+ import { join as join21 } from "node:path";
61732
62601
  function isValidName2(name) {
61733
62602
  return /^[a-z][a-z0-9-]*$/.test(name);
61734
62603
  }
@@ -61810,7 +62679,7 @@ function getBuiltinSubagentNames2() {
61810
62679
  return new Set(Object.keys(getBuiltinSubagents2()));
61811
62680
  }
61812
62681
  async function discoverSubagentsFromDir2(agentsDir, seenNames, subagents, errors) {
61813
- if (!existsSync11(agentsDir)) {
62682
+ if (!existsSync12(agentsDir)) {
61814
62683
  return;
61815
62684
  }
61816
62685
  try {
@@ -61819,7 +62688,7 @@ async function discoverSubagentsFromDir2(agentsDir, seenNames, subagents, errors
61819
62688
  if (!entry.isFile() || !entry.name.endsWith(".md")) {
61820
62689
  continue;
61821
62690
  }
61822
- const filePath = join20(agentsDir, entry.name);
62691
+ const filePath = join21(agentsDir, entry.name);
61823
62692
  try {
61824
62693
  const config = await parseSubagentFile2(filePath);
61825
62694
  if (config) {
@@ -61851,7 +62720,7 @@ async function discoverSubagents2(workingDirectory = process.cwd()) {
61851
62720
  const subagents = [];
61852
62721
  const seenNames = new Set;
61853
62722
  await discoverSubagentsFromDir2(GLOBAL_AGENTS_DIR2, seenNames, subagents, errors);
61854
- const projectAgentsDir = join20(workingDirectory, AGENTS_DIR2);
62723
+ const projectAgentsDir = join21(workingDirectory, AGENTS_DIR2);
61855
62724
  await discoverSubagentsFromDir2(projectAgentsDir, seenNames, subagents, errors);
61856
62725
  return { subagents, errors };
61857
62726
  }
@@ -61894,7 +62763,7 @@ var init_subagents2 = __esm(() => {
61894
62763
  recall_default,
61895
62764
  reflection_default
61896
62765
  ];
61897
- GLOBAL_AGENTS_DIR2 = join20(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents");
62766
+ GLOBAL_AGENTS_DIR2 = join21(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents");
61898
62767
  VALID_MEMORY_BLOCKS2 = new Set(MEMORY_BLOCK_LABELS);
61899
62768
  cache5 = {
61900
62769
  builtins: null,
@@ -62038,24 +62907,24 @@ function defineLazyProperty(object, propertyName, valueGetter) {
62038
62907
  // node_modules/default-browser-id/index.js
62039
62908
  import { promisify as promisify5 } from "node:util";
62040
62909
  import process15 from "node:process";
62041
- import { execFile as execFile4 } from "node:child_process";
62910
+ import { execFile as execFile5 } from "node:child_process";
62042
62911
  async function defaultBrowserId() {
62043
62912
  if (process15.platform !== "darwin") {
62044
62913
  throw new Error("macOS only");
62045
62914
  }
62046
- const { stdout } = await execFileAsync3("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
62915
+ const { stdout } = await execFileAsync4("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
62047
62916
  const match3 = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
62048
62917
  return match3?.groups.id ?? "com.apple.Safari";
62049
62918
  }
62050
- var execFileAsync3;
62919
+ var execFileAsync4;
62051
62920
  var init_default_browser_id = __esm(() => {
62052
- execFileAsync3 = promisify5(execFile4);
62921
+ execFileAsync4 = promisify5(execFile5);
62053
62922
  });
62054
62923
 
62055
62924
  // node_modules/run-applescript/index.js
62056
62925
  import process16 from "node:process";
62057
62926
  import { promisify as promisify6 } from "node:util";
62058
- import { execFile as execFile5, execFileSync } from "node:child_process";
62927
+ import { execFile as execFile6, execFileSync } from "node:child_process";
62059
62928
  async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
62060
62929
  if (process16.platform !== "darwin") {
62061
62930
  throw new Error("macOS only");
@@ -62065,12 +62934,12 @@ async function runAppleScript(script, { humanReadableOutput = true, signal } = {
62065
62934
  if (signal) {
62066
62935
  execOptions.signal = signal;
62067
62936
  }
62068
- const { stdout } = await execFileAsync4("osascript", ["-e", script, outputArguments], execOptions);
62937
+ const { stdout } = await execFileAsync5("osascript", ["-e", script, outputArguments], execOptions);
62069
62938
  return stdout.trim();
62070
62939
  }
62071
- var execFileAsync4;
62940
+ var execFileAsync5;
62072
62941
  var init_run_applescript = __esm(() => {
62073
- execFileAsync4 = promisify6(execFile5);
62942
+ execFileAsync5 = promisify6(execFile6);
62074
62943
  });
62075
62944
 
62076
62945
  // node_modules/bundle-name/index.js
@@ -62084,8 +62953,8 @@ var init_bundle_name = __esm(() => {
62084
62953
 
62085
62954
  // node_modules/default-browser/windows.js
62086
62955
  import { promisify as promisify7 } from "node:util";
62087
- import { execFile as execFile6 } from "node:child_process";
62088
- async function defaultBrowser(_execFileAsync = execFileAsync5) {
62956
+ import { execFile as execFile7 } from "node:child_process";
62957
+ async function defaultBrowser(_execFileAsync = execFileAsync6) {
62089
62958
  const { stdout } = await _execFileAsync("reg", [
62090
62959
  "QUERY",
62091
62960
  " HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
@@ -62103,9 +62972,9 @@ async function defaultBrowser(_execFileAsync = execFileAsync5) {
62103
62972
  }
62104
62973
  return browser;
62105
62974
  }
62106
- var execFileAsync5, windowsBrowserProgIds, UnknownBrowserError;
62975
+ var execFileAsync6, windowsBrowserProgIds, UnknownBrowserError;
62107
62976
  var init_windows = __esm(() => {
62108
- execFileAsync5 = promisify7(execFile6);
62977
+ execFileAsync6 = promisify7(execFile7);
62109
62978
  windowsBrowserProgIds = {
62110
62979
  AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
62111
62980
  MSEdgeDHTML: { name: "Edge", id: "com.microsoft.edge" },
@@ -62124,7 +62993,7 @@ var init_windows = __esm(() => {
62124
62993
  // node_modules/default-browser/index.js
62125
62994
  import { promisify as promisify8 } from "node:util";
62126
62995
  import process17 from "node:process";
62127
- import { execFile as execFile7 } from "node:child_process";
62996
+ import { execFile as execFile8 } from "node:child_process";
62128
62997
  async function defaultBrowser2() {
62129
62998
  if (process17.platform === "darwin") {
62130
62999
  const id = await defaultBrowserId();
@@ -62132,7 +63001,7 @@ async function defaultBrowser2() {
62132
63001
  return { name, id };
62133
63002
  }
62134
63003
  if (process17.platform === "linux") {
62135
- const { stdout } = await execFileAsync6("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
63004
+ const { stdout } = await execFileAsync7("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
62136
63005
  const id = stdout.trim();
62137
63006
  const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
62138
63007
  return { name, id };
@@ -62142,12 +63011,12 @@ async function defaultBrowser2() {
62142
63011
  }
62143
63012
  throw new Error("Only macOS, Linux, and Windows are supported");
62144
63013
  }
62145
- var execFileAsync6, titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
63014
+ var execFileAsync7, titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
62146
63015
  var init_default_browser = __esm(() => {
62147
63016
  init_default_browser_id();
62148
63017
  init_bundle_name();
62149
63018
  init_windows();
62150
- execFileAsync6 = promisify8(execFile7);
63019
+ execFileAsync7 = promisify8(execFile8);
62151
63020
  });
62152
63021
 
62153
63022
  // node_modules/open/index.js
@@ -62168,7 +63037,7 @@ async function getWindowsDefaultBrowserFromWsl() {
62168
63037
  const powershellPath = await powerShellPath();
62169
63038
  const rawCommand = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
62170
63039
  const encodedCommand = Buffer3.from(rawCommand, "utf16le").toString("base64");
62171
- const { stdout } = await execFile8(powershellPath, [
63040
+ const { stdout } = await execFile9(powershellPath, [
62172
63041
  "-NoProfile",
62173
63042
  "-NonInteractive",
62174
63043
  "-ExecutionPolicy",
@@ -62204,7 +63073,7 @@ function detectPlatformBinary({ [platform2]: platformBinary }, { wsl }) {
62204
63073
  }
62205
63074
  return detectArchBinary(platformBinary);
62206
63075
  }
62207
- var execFile8, __dirname2, localXdgOpenPath, platform2, arch, pTryEach = async (array, mapper) => {
63076
+ var execFile9, __dirname2, localXdgOpenPath, platform2, arch, pTryEach = async (array, mapper) => {
62208
63077
  let latestError;
62209
63078
  for (const item of array) {
62210
63079
  try {
@@ -62383,7 +63252,7 @@ var init_open = __esm(() => {
62383
63252
  init_wsl_utils();
62384
63253
  init_default_browser();
62385
63254
  init_is_inside_container();
62386
- execFile8 = promisify9(childProcess.execFile);
63255
+ execFile9 = promisify9(childProcess.execFile);
62387
63256
  __dirname2 = path21.dirname(fileURLToPath8(import.meta.url));
62388
63257
  localXdgOpenPath = path21.join(__dirname2, "xdg-open");
62389
63258
  ({ platform: platform2, arch } = process18);
@@ -62803,6 +63672,58 @@ function isConversationBusyError(detail) {
62803
63672
  return false;
62804
63673
  return detail.toLowerCase().includes(CONVERSATION_BUSY_DETAIL_FRAGMENT);
62805
63674
  }
63675
+ function isRetryableProviderErrorDetail(detail) {
63676
+ if (typeof detail !== "string")
63677
+ return false;
63678
+ return RETRYABLE_PROVIDER_DETAIL_PATTERNS.some((pattern) => detail.includes(pattern));
63679
+ }
63680
+ function isNonRetryableProviderErrorDetail(detail) {
63681
+ if (typeof detail !== "string")
63682
+ return false;
63683
+ const normalized = detail.toLowerCase();
63684
+ if (NON_RETRYABLE_4XX_PATTERN.test(detail))
63685
+ return true;
63686
+ return NON_RETRYABLE_PROVIDER_DETAIL_PATTERNS.some((pattern) => normalized.includes(pattern));
63687
+ }
63688
+ function shouldRetryRunMetadataError(errorType, detail) {
63689
+ const explicitLlmError = errorType === "llm_error";
63690
+ const retryable429Detail = typeof detail === "string" && RETRYABLE_429_PATTERN.test(detail);
63691
+ const retryableDetail = isRetryableProviderErrorDetail(detail);
63692
+ const nonRetryableDetail = isNonRetryableProviderErrorDetail(detail);
63693
+ if (nonRetryableDetail && !retryable429Detail)
63694
+ return false;
63695
+ if (explicitLlmError)
63696
+ return true;
63697
+ return retryable429Detail || retryableDetail;
63698
+ }
63699
+ function shouldRetryPreStreamTransientError(opts) {
63700
+ const { status, detail } = opts;
63701
+ if (status === 429)
63702
+ return true;
63703
+ if (status !== undefined && status >= 500)
63704
+ return true;
63705
+ if (status !== undefined && status >= 400)
63706
+ return false;
63707
+ const retryable429Detail = typeof detail === "string" && RETRYABLE_429_PATTERN.test(detail);
63708
+ if (retryable429Detail)
63709
+ return true;
63710
+ if (isNonRetryableProviderErrorDetail(detail))
63711
+ return false;
63712
+ return isRetryableProviderErrorDetail(detail);
63713
+ }
63714
+ function parseRetryAfterHeaderMs(retryAfterValue) {
63715
+ if (!retryAfterValue)
63716
+ return null;
63717
+ const seconds = Number(retryAfterValue);
63718
+ if (Number.isFinite(seconds) && seconds >= 0) {
63719
+ return Math.round(seconds * 1000);
63720
+ }
63721
+ const retryAtMs = Date.parse(retryAfterValue);
63722
+ if (Number.isNaN(retryAtMs))
63723
+ return null;
63724
+ const delayMs = retryAtMs - Date.now();
63725
+ return delayMs > 0 ? delayMs : 0;
63726
+ }
62806
63727
  function classifyPreStreamConflict(detail) {
62807
63728
  if (isApprovalPendingError(detail))
62808
63729
  return "approval_pending";
@@ -62810,7 +63731,7 @@ function classifyPreStreamConflict(detail) {
62810
63731
  return "conversation_busy";
62811
63732
  return null;
62812
63733
  }
62813
- function getPreStreamErrorAction(detail, conversationBusyRetries, maxConversationBusyRetries) {
63734
+ function getPreStreamErrorAction(detail, conversationBusyRetries, maxConversationBusyRetries, opts) {
62814
63735
  const kind = classifyPreStreamConflict(detail);
62815
63736
  if (kind === "approval_pending") {
62816
63737
  return "resolve_approval_pending";
@@ -62818,6 +63739,9 @@ function getPreStreamErrorAction(detail, conversationBusyRetries, maxConversatio
62818
63739
  if (kind === "conversation_busy" && conversationBusyRetries < maxConversationBusyRetries) {
62819
63740
  return "retry_conversation_busy";
62820
63741
  }
63742
+ if (opts && shouldRetryPreStreamTransientError({ status: opts.status, detail }) && (opts.transientRetries ?? 0) < (opts.maxTransientRetries ?? 0)) {
63743
+ return "retry_transient";
63744
+ }
62821
63745
  return "rethrow";
62822
63746
  }
62823
63747
  function extractConflictDetail(error) {
@@ -62861,7 +63785,42 @@ function rebuildInputWithFreshDenials(currentInput, serverApprovals, denialReaso
62861
63785
  function shouldAttemptApprovalRecovery(opts) {
62862
63786
  return opts.approvalPendingDetected && opts.retries < opts.maxRetries;
62863
63787
  }
62864
- var INVALID_TOOL_CALL_IDS_FRAGMENT = "invalid tool call ids", APPROVAL_PENDING_DETAIL_FRAGMENT = "waiting for approval", CONVERSATION_BUSY_DETAIL_FRAGMENT = "another request is currently being processed";
63788
+ var INVALID_TOOL_CALL_IDS_FRAGMENT = "invalid tool call ids", APPROVAL_PENDING_DETAIL_FRAGMENT = "waiting for approval", CONVERSATION_BUSY_DETAIL_FRAGMENT = "another request is currently being processed", RETRYABLE_PROVIDER_DETAIL_PATTERNS, NON_RETRYABLE_PROVIDER_DETAIL_PATTERNS, NON_RETRYABLE_4XX_PATTERN, RETRYABLE_429_PATTERN;
63789
+ var init_turn_recovery_policy = __esm(() => {
63790
+ RETRYABLE_PROVIDER_DETAIL_PATTERNS = [
63791
+ "Anthropic API error",
63792
+ "OpenAI API error",
63793
+ "Google Vertex API error",
63794
+ "ChatGPT API error",
63795
+ "ChatGPT server error",
63796
+ "Connection error during Anthropic streaming",
63797
+ "Connection error during streaming",
63798
+ "upstream connect error",
63799
+ "connection termination",
63800
+ "peer closed connection",
63801
+ "incomplete chunked read",
63802
+ "Network error",
63803
+ "Connection error",
63804
+ "Request timed out",
63805
+ "overloaded",
63806
+ "api_error"
63807
+ ];
63808
+ NON_RETRYABLE_PROVIDER_DETAIL_PATTERNS = [
63809
+ "invalid api key",
63810
+ "incorrect api key",
63811
+ "authentication error",
63812
+ "unauthorized",
63813
+ "permission denied",
63814
+ "forbidden",
63815
+ "invalid_request_error",
63816
+ "invalid model",
63817
+ "model_not_found",
63818
+ "context_length_exceeded",
63819
+ "invalid_encrypted_content"
63820
+ ];
63821
+ NON_RETRYABLE_4XX_PATTERN = /Error code:\s*4(0[0-8]|1\d|2\d|3\d|4\d|51)/i;
63822
+ RETRYABLE_429_PATTERN = /Error code:\s*429|rate limit|too many requests/i;
63823
+ });
62865
63824
 
62866
63825
  // src/agent/approval-recovery.ts
62867
63826
  async function fetchRunErrorDetail(runId) {
@@ -62877,336 +63836,10 @@ async function fetchRunErrorDetail(runId) {
62877
63836
  }
62878
63837
  }
62879
63838
  var init_approval_recovery = __esm(async () => {
63839
+ init_turn_recovery_policy();
62880
63840
  await init_client2();
62881
63841
  });
62882
63842
 
62883
- // src/providers/openai-codex-provider.ts
62884
- var exports_openai_codex_provider = {};
62885
- __export(exports_openai_codex_provider, {
62886
- updateOpenAICodexProvider: () => updateOpenAICodexProvider,
62887
- removeOpenAICodexProvider: () => removeOpenAICodexProvider,
62888
- listProviders: () => listProviders,
62889
- getOpenAICodexProvider: () => getOpenAICodexProvider,
62890
- deleteOpenAICodexProvider: () => deleteOpenAICodexProvider,
62891
- createOrUpdateOpenAICodexProvider: () => createOrUpdateOpenAICodexProvider,
62892
- createOpenAICodexProvider: () => createOpenAICodexProvider,
62893
- checkOpenAICodexEligibility: () => checkOpenAICodexEligibility,
62894
- OPENAI_CODEX_PROVIDER_NAME: () => OPENAI_CODEX_PROVIDER_NAME,
62895
- CHATGPT_OAUTH_PROVIDER_TYPE: () => CHATGPT_OAUTH_PROVIDER_TYPE
62896
- });
62897
- async function getLettaConfig() {
62898
- const settings = await settingsManager.getSettingsWithSecureTokens();
62899
- const baseUrl = process.env.LETTA_BASE_URL || settings.env?.LETTA_BASE_URL || LETTA_CLOUD_API_URL;
62900
- const apiKey = process.env.LETTA_API_KEY || settings.env?.LETTA_API_KEY || "";
62901
- return { baseUrl, apiKey };
62902
- }
62903
- async function providersRequest(method, path22, body) {
62904
- const { baseUrl, apiKey } = await getLettaConfig();
62905
- const url = `${baseUrl}${path22}`;
62906
- const response = await fetch(url, {
62907
- method,
62908
- headers: getLettaCodeHeaders2(apiKey),
62909
- ...body && { body: JSON.stringify(body) }
62910
- });
62911
- if (!response.ok) {
62912
- const errorText = await response.text();
62913
- if (response.status === 403) {
62914
- try {
62915
- const errorData = JSON.parse(errorText);
62916
- if (errorData.error && typeof errorData.error === "string" && errorData.error.includes("only available for pro or enterprise")) {
62917
- throw new Error("PLAN_UPGRADE_REQUIRED");
62918
- }
62919
- } catch (parseError) {
62920
- if (parseError instanceof Error && parseError.message === "PLAN_UPGRADE_REQUIRED") {
62921
- throw parseError;
62922
- }
62923
- }
62924
- }
62925
- throw new Error(`Provider API error (${response.status}): ${errorText}`);
62926
- }
62927
- const text = await response.text();
62928
- if (!text) {
62929
- return {};
62930
- }
62931
- return JSON.parse(text);
62932
- }
62933
- async function listProviders() {
62934
- try {
62935
- const response = await providersRequest("GET", "/v1/providers");
62936
- return response;
62937
- } catch {
62938
- return [];
62939
- }
62940
- }
62941
- async function getOpenAICodexProvider() {
62942
- const providers = await listProviders();
62943
- return providers.find((p) => p.name === OPENAI_CODEX_PROVIDER_NAME) || null;
62944
- }
62945
- async function createOpenAICodexProvider(config) {
62946
- const apiKeyJson = JSON.stringify({
62947
- access_token: config.access_token,
62948
- id_token: config.id_token,
62949
- refresh_token: config.refresh_token,
62950
- account_id: config.account_id,
62951
- expires_at: config.expires_at
62952
- });
62953
- return providersRequest("POST", "/v1/providers", {
62954
- name: OPENAI_CODEX_PROVIDER_NAME,
62955
- provider_type: CHATGPT_OAUTH_PROVIDER_TYPE,
62956
- api_key: apiKeyJson
62957
- });
62958
- }
62959
- async function updateOpenAICodexProvider(providerId, config) {
62960
- const apiKeyJson = JSON.stringify({
62961
- access_token: config.access_token,
62962
- id_token: config.id_token,
62963
- refresh_token: config.refresh_token,
62964
- account_id: config.account_id,
62965
- expires_at: config.expires_at
62966
- });
62967
- return providersRequest("PATCH", `/v1/providers/${providerId}`, {
62968
- api_key: apiKeyJson
62969
- });
62970
- }
62971
- async function deleteOpenAICodexProvider(providerId) {
62972
- await providersRequest("DELETE", `/v1/providers/${providerId}`);
62973
- }
62974
- async function createOrUpdateOpenAICodexProvider(config) {
62975
- const existing = await getOpenAICodexProvider();
62976
- if (existing) {
62977
- return updateOpenAICodexProvider(existing.id, config);
62978
- } else {
62979
- return createOpenAICodexProvider(config);
62980
- }
62981
- }
62982
- async function removeOpenAICodexProvider() {
62983
- const existing = await getOpenAICodexProvider();
62984
- if (existing) {
62985
- await deleteOpenAICodexProvider(existing.id);
62986
- }
62987
- }
62988
- async function checkOpenAICodexEligibility() {
62989
- try {
62990
- const balance = await providersRequest("GET", "/v1/metadata/balance");
62991
- const billingTier = balance.billing_tier.toLowerCase();
62992
- if (billingTier === "pro" || billingTier === "enterprise") {
62993
- return {
62994
- eligible: true,
62995
- billing_tier: balance.billing_tier
62996
- };
62997
- }
62998
- return {
62999
- eligible: false,
63000
- billing_tier: balance.billing_tier,
63001
- reason: `ChatGPT OAuth requires a Pro or Enterprise plan. Current plan: ${balance.billing_tier}`
63002
- };
63003
- } catch (error) {
63004
- console.warn("Failed to check ChatGPT OAuth eligibility:", error);
63005
- return {
63006
- eligible: true,
63007
- billing_tier: "unknown"
63008
- };
63009
- }
63010
- }
63011
- var OPENAI_CODEX_PROVIDER_NAME = "chatgpt-plus-pro", CHATGPT_OAUTH_PROVIDER_TYPE = "chatgpt_oauth";
63012
- var init_openai_codex_provider = __esm(async () => {
63013
- init_http_headers();
63014
- init_oauth();
63015
- await init_settings_manager();
63016
- });
63017
-
63018
- // src/agent/modify.ts
63019
- var exports_modify = {};
63020
- __export(exports_modify, {
63021
- updateAgentSystemPromptRaw: () => updateAgentSystemPromptRaw,
63022
- updateAgentSystemPromptMemfs: () => updateAgentSystemPromptMemfs,
63023
- updateAgentSystemPrompt: () => updateAgentSystemPrompt,
63024
- updateAgentLLMConfig: () => updateAgentLLMConfig
63025
- });
63026
- function buildModelSettings(modelHandle, updateArgs) {
63027
- const isOpenAI = modelHandle.startsWith("openai/") || modelHandle.startsWith(`${OPENAI_CODEX_PROVIDER_NAME}/`);
63028
- const isAnthropic = modelHandle.startsWith("anthropic/") || modelHandle.startsWith("claude-pro-max/");
63029
- const isZai = modelHandle.startsWith("zai/");
63030
- const isGoogleAI = modelHandle.startsWith("google_ai/");
63031
- const isGoogleVertex = modelHandle.startsWith("google_vertex/");
63032
- const isOpenRouter = modelHandle.startsWith("openrouter/");
63033
- const isBedrock = modelHandle.startsWith("bedrock/");
63034
- let settings;
63035
- if (isOpenAI || isOpenRouter) {
63036
- const openaiSettings = {
63037
- provider_type: "openai",
63038
- parallel_tool_calls: true
63039
- };
63040
- if (updateArgs?.reasoning_effort) {
63041
- openaiSettings.reasoning = {
63042
- reasoning_effort: updateArgs.reasoning_effort
63043
- };
63044
- }
63045
- settings = openaiSettings;
63046
- } else if (isAnthropic) {
63047
- const anthropicSettings = {
63048
- provider_type: "anthropic",
63049
- parallel_tool_calls: true
63050
- };
63051
- if (updateArgs?.enable_reasoner !== undefined || typeof updateArgs?.max_reasoning_tokens === "number") {
63052
- anthropicSettings.thinking = {
63053
- type: updateArgs?.enable_reasoner === false ? "disabled" : "enabled",
63054
- ...typeof updateArgs?.max_reasoning_tokens === "number" && {
63055
- budget_tokens: updateArgs.max_reasoning_tokens
63056
- }
63057
- };
63058
- }
63059
- settings = anthropicSettings;
63060
- } else if (isZai) {
63061
- settings = {
63062
- provider_type: "zai",
63063
- parallel_tool_calls: true
63064
- };
63065
- } else if (isGoogleAI) {
63066
- const googleSettings = {
63067
- provider_type: "google_ai",
63068
- parallel_tool_calls: true
63069
- };
63070
- if (updateArgs?.thinking_budget !== undefined) {
63071
- googleSettings.thinking_config = {
63072
- thinking_budget: updateArgs.thinking_budget
63073
- };
63074
- }
63075
- if (typeof updateArgs?.temperature === "number") {
63076
- googleSettings.temperature = updateArgs.temperature;
63077
- }
63078
- settings = googleSettings;
63079
- } else if (isGoogleVertex) {
63080
- const googleVertexSettings = {
63081
- provider_type: "google_vertex",
63082
- parallel_tool_calls: true
63083
- };
63084
- if (updateArgs?.thinking_budget !== undefined) {
63085
- googleVertexSettings.thinking_config = {
63086
- thinking_budget: updateArgs.thinking_budget
63087
- };
63088
- }
63089
- if (typeof updateArgs?.temperature === "number") {
63090
- googleVertexSettings.temperature = updateArgs.temperature;
63091
- }
63092
- settings = googleVertexSettings;
63093
- } else if (isBedrock) {
63094
- const bedrockSettings = {
63095
- provider_type: "bedrock",
63096
- parallel_tool_calls: true
63097
- };
63098
- if (updateArgs?.enable_reasoner !== undefined || typeof updateArgs?.max_reasoning_tokens === "number") {
63099
- bedrockSettings.thinking = {
63100
- type: updateArgs?.enable_reasoner === false ? "disabled" : "enabled",
63101
- ...typeof updateArgs?.max_reasoning_tokens === "number" && {
63102
- budget_tokens: updateArgs.max_reasoning_tokens
63103
- }
63104
- };
63105
- }
63106
- settings = bedrockSettings;
63107
- } else {
63108
- settings = {};
63109
- }
63110
- if (typeof updateArgs?.max_output_tokens === "number" && "provider_type" in settings) {
63111
- settings.max_output_tokens = updateArgs.max_output_tokens;
63112
- }
63113
- return settings;
63114
- }
63115
- async function updateAgentLLMConfig(agentId, modelHandle, updateArgs) {
63116
- const client = await getClient2();
63117
- const modelSettings = buildModelSettings(modelHandle, updateArgs);
63118
- const contextWindow = updateArgs?.context_window ?? await getModelContextWindow(modelHandle);
63119
- const hasModelSettings = Object.keys(modelSettings).length > 0;
63120
- await client.agents.update(agentId, {
63121
- model: modelHandle,
63122
- ...hasModelSettings && { model_settings: modelSettings },
63123
- ...contextWindow && { context_window_limit: contextWindow },
63124
- ...typeof updateArgs?.max_output_tokens === "number" && {
63125
- max_tokens: updateArgs.max_output_tokens
63126
- }
63127
- });
63128
- const finalAgent = await client.agents.retrieve(agentId);
63129
- return finalAgent.llm_config;
63130
- }
63131
- async function updateAgentSystemPromptRaw(agentId, systemPromptContent) {
63132
- try {
63133
- const client = await getClient2();
63134
- await client.agents.update(agentId, {
63135
- system: systemPromptContent
63136
- });
63137
- return {
63138
- success: true,
63139
- message: "System prompt updated successfully"
63140
- };
63141
- } catch (error) {
63142
- return {
63143
- success: false,
63144
- message: `Failed to update system prompt: ${error instanceof Error ? error.message : String(error)}`
63145
- };
63146
- }
63147
- }
63148
- async function updateAgentSystemPrompt(agentId, systemPromptId) {
63149
- try {
63150
- const { resolveSystemPrompt: resolveSystemPrompt3, SYSTEM_PROMPT_MEMORY_ADDON: SYSTEM_PROMPT_MEMORY_ADDON3 } = await Promise.resolve().then(() => (init_promptAssets(), exports_promptAssets));
63151
- const baseContent = await resolveSystemPrompt3(systemPromptId);
63152
- const systemPromptContent = `${baseContent}
63153
- ${SYSTEM_PROMPT_MEMORY_ADDON3}`;
63154
- const updateResult = await updateAgentSystemPromptRaw(agentId, systemPromptContent);
63155
- if (!updateResult.success) {
63156
- return {
63157
- success: false,
63158
- message: updateResult.message,
63159
- agent: null
63160
- };
63161
- }
63162
- const client = await getClient2();
63163
- const agent = await client.agents.retrieve(agentId);
63164
- return {
63165
- success: true,
63166
- message: "System prompt applied successfully",
63167
- agent
63168
- };
63169
- } catch (error) {
63170
- return {
63171
- success: false,
63172
- message: `Failed to apply system prompt: ${error instanceof Error ? error.message : String(error)}`,
63173
- agent: null
63174
- };
63175
- }
63176
- }
63177
- async function updateAgentSystemPromptMemfs(agentId, enableMemfs) {
63178
- try {
63179
- const client = await getClient2();
63180
- const agent = await client.agents.retrieve(agentId);
63181
- let currentSystemPrompt = agent.system || "";
63182
- const { SYSTEM_PROMPT_MEMFS_ADDON: SYSTEM_PROMPT_MEMFS_ADDON3, SYSTEM_PROMPT_MEMORY_ADDON: SYSTEM_PROMPT_MEMORY_ADDON3 } = await Promise.resolve().then(() => (init_promptAssets(), exports_promptAssets));
63183
- const memoryHeaderRegex = /\n#{1,2} Memory\b[\s\S]*?(?=\n#{1,2} (?!Memory|Filesystem|Structure|How It Works|Syncing|History)[^\n]|$)/;
63184
- currentSystemPrompt = currentSystemPrompt.replace(memoryHeaderRegex, "");
63185
- const addon = enableMemfs ? SYSTEM_PROMPT_MEMFS_ADDON3 : SYSTEM_PROMPT_MEMORY_ADDON3;
63186
- currentSystemPrompt = `${currentSystemPrompt}
63187
- ${addon}`;
63188
- await client.agents.update(agentId, {
63189
- system: currentSystemPrompt
63190
- });
63191
- return {
63192
- success: true,
63193
- message: enableMemfs ? "System prompt updated to include Memory Filesystem section" : "System prompt updated to include standard Memory section"
63194
- };
63195
- } catch (error) {
63196
- return {
63197
- success: false,
63198
- message: `Failed to update system prompt memfs: ${error instanceof Error ? error.message : String(error)}`
63199
- };
63200
- }
63201
- }
63202
- var init_modify = __esm(async () => {
63203
- await __promiseAll([
63204
- init_openai_codex_provider(),
63205
- init_available_models(),
63206
- init_client2()
63207
- ]);
63208
- });
63209
-
63210
63843
  // src/agent/prompts/sleeptime.ts
63211
63844
  var SLEEPTIME_MEMORY_PERSONA = `I am a sleep-time memory management agent. I observe the conversation between the user and their primary agent, then actively maintain memory blocks to keep them accurate, concise, and useful.
63212
63845
 
@@ -63364,8 +63997,7 @@ async function createAgent(nameOrOptions = DEFAULT_AGENT_NAME, model, embeddingM
63364
63997
  } else {
63365
63998
  systemPromptContent = await resolveSystemPrompt(options.systemPromptPreset);
63366
63999
  }
63367
- systemPromptContent = `${systemPromptContent}
63368
- ${SYSTEM_PROMPT_MEMORY_ADDON}`;
64000
+ systemPromptContent = reconcileMemoryPrompt(systemPromptContent, options.memoryPromptMode ?? "standard");
63369
64001
  if (options.systemPromptAppend) {
63370
64002
  systemPromptContent = `${systemPromptContent}
63371
64003
 
@@ -63435,6 +64067,7 @@ ${options.systemPromptAppend}`;
63435
64067
  var init_create = __esm(async () => {
63436
64068
  init_constants();
63437
64069
  init_memory();
64070
+ init_memoryPrompt();
63438
64071
  init_model();
63439
64072
  init_promptAssets();
63440
64073
  await __promiseAll([
@@ -64025,163 +64658,6 @@ var init_interactivePolicy = __esm(() => {
64025
64658
  HEADLESS_AUTO_ALLOW_TOOLS = new Set(["EnterPlanMode"]);
64026
64659
  });
64027
64660
 
64028
- // src/tools/toolset.ts
64029
- var exports_toolset = {};
64030
- __export(exports_toolset, {
64031
- switchToolsetForModel: () => switchToolsetForModel,
64032
- reattachMemoryTool: () => reattachMemoryTool,
64033
- forceToolsetSwitch: () => forceToolsetSwitch,
64034
- ensureCorrectMemoryTool: () => ensureCorrectMemoryTool,
64035
- detachMemoryTools: () => detachMemoryTools,
64036
- MEMORY_TOOL_NAMES: () => MEMORY_TOOL_NAMES
64037
- });
64038
- async function ensureCorrectMemoryTool(agentId, modelIdentifier, useMemoryPatch) {
64039
- const resolvedModel = resolveModel(modelIdentifier) ?? modelIdentifier;
64040
- const client = await getClient2();
64041
- const shouldUsePatch = useMemoryPatch !== undefined ? useMemoryPatch : isOpenAIModel(resolvedModel);
64042
- try {
64043
- const agentWithTools = await client.agents.retrieve(agentId, {
64044
- include: ["agent.tools"]
64045
- });
64046
- const currentTools = agentWithTools.tools || [];
64047
- const mapByName = new Map(currentTools.map((t) => [t.name, t.id]));
64048
- const hasAnyMemoryTool = mapByName.has("memory") || mapByName.has("memory_apply_patch");
64049
- if (!hasAnyMemoryTool) {
64050
- return;
64051
- }
64052
- const desiredMemoryTool = shouldUsePatch ? "memory_apply_patch" : "memory";
64053
- const otherMemoryTool = desiredMemoryTool === "memory" ? "memory_apply_patch" : "memory";
64054
- let desiredId = mapByName.get(desiredMemoryTool);
64055
- if (!desiredId) {
64056
- const resp = await client.tools.list({ name: desiredMemoryTool });
64057
- desiredId = resp.items[0]?.id;
64058
- }
64059
- if (!desiredId) {
64060
- return;
64061
- }
64062
- const otherId = mapByName.get(otherMemoryTool);
64063
- if (mapByName.has(desiredMemoryTool) && !otherId) {
64064
- return;
64065
- }
64066
- const currentIds = currentTools.map((t) => t.id).filter((id) => typeof id === "string");
64067
- const newIds = new Set(currentIds);
64068
- if (otherId)
64069
- newIds.delete(otherId);
64070
- newIds.add(desiredId);
64071
- const updatedRules = (agentWithTools.tool_rules || []).map((r) => r.tool_name === otherMemoryTool ? { ...r, tool_name: desiredMemoryTool } : r);
64072
- await client.agents.update(agentId, {
64073
- tool_ids: Array.from(newIds),
64074
- tool_rules: updatedRules
64075
- });
64076
- } catch (err) {
64077
- console.warn(`Warning: Failed to sync memory tool: ${err instanceof Error ? err.message : String(err)}`);
64078
- }
64079
- }
64080
- async function detachMemoryTools(agentId) {
64081
- const client = await getClient2();
64082
- try {
64083
- const agentWithTools = await client.agents.retrieve(agentId, {
64084
- include: ["agent.tools"]
64085
- });
64086
- const currentTools = agentWithTools.tools || [];
64087
- let detachedAny = false;
64088
- for (const tool of currentTools) {
64089
- if (tool.name && MEMORY_TOOL_NAMES.has(tool.name)) {
64090
- if (tool.id) {
64091
- await client.agents.tools.detach(tool.id, { agent_id: agentId });
64092
- detachedAny = true;
64093
- }
64094
- }
64095
- }
64096
- return detachedAny;
64097
- } catch (err) {
64098
- console.warn(`Warning: Failed to detach memory tools: ${err instanceof Error ? err.message : String(err)}`);
64099
- return false;
64100
- }
64101
- }
64102
- async function reattachMemoryTool(agentId, modelIdentifier) {
64103
- const resolvedModel = resolveModel(modelIdentifier) ?? modelIdentifier;
64104
- const client = await getClient2();
64105
- const shouldUsePatch = isOpenAIModel(resolvedModel);
64106
- try {
64107
- const agentWithTools = await client.agents.retrieve(agentId, {
64108
- include: ["agent.tools"]
64109
- });
64110
- const currentTools = agentWithTools.tools || [];
64111
- const mapByName = new Map(currentTools.map((t) => [t.name, t.id]));
64112
- const desiredMemoryTool = shouldUsePatch ? "memory_apply_patch" : "memory";
64113
- if (mapByName.has(desiredMemoryTool)) {
64114
- return;
64115
- }
64116
- const resp = await client.tools.list({ name: desiredMemoryTool });
64117
- const toolId = resp.items[0]?.id;
64118
- if (!toolId) {
64119
- console.warn(`Memory tool "${desiredMemoryTool}" not found on server`);
64120
- return;
64121
- }
64122
- await client.agents.tools.attach(toolId, { agent_id: agentId });
64123
- } catch (err) {
64124
- console.warn(`Warning: Failed to reattach memory tool: ${err instanceof Error ? err.message : String(err)}`);
64125
- }
64126
- }
64127
- async function forceToolsetSwitch(toolsetName, agentId) {
64128
- let modelForLoading;
64129
- if (toolsetName === "none") {
64130
- clearToolsWithLock();
64131
- return;
64132
- } else if (toolsetName === "codex") {
64133
- await loadSpecificTools([...CODEX_TOOLS]);
64134
- modelForLoading = "openai/gpt-4";
64135
- } else if (toolsetName === "codex_snake") {
64136
- await loadTools("openai/gpt-4");
64137
- modelForLoading = "openai/gpt-4";
64138
- } else if (toolsetName === "gemini") {
64139
- await loadSpecificTools([...GEMINI_TOOLS]);
64140
- modelForLoading = "google_ai/gemini-3-pro-preview";
64141
- } else if (toolsetName === "gemini_snake") {
64142
- await loadTools("google_ai/gemini-3-pro-preview");
64143
- modelForLoading = "google_ai/gemini-3-pro-preview";
64144
- } else {
64145
- await loadTools("anthropic/claude-sonnet-4");
64146
- modelForLoading = "anthropic/claude-sonnet-4";
64147
- }
64148
- const useMemoryPatch = toolsetName === "codex" || toolsetName === "codex_snake";
64149
- await ensureCorrectMemoryTool(agentId, modelForLoading, useMemoryPatch);
64150
- }
64151
- async function switchToolsetForModel(modelIdentifier, agentId) {
64152
- const resolvedModel = resolveModel(modelIdentifier) ?? modelIdentifier;
64153
- await loadTools(resolvedModel);
64154
- const loadedAfterPrimary = getToolNames().length;
64155
- if (loadedAfterPrimary === 0 && !toolFilter.isActive()) {
64156
- await loadTools();
64157
- if (getToolNames().length === 0) {
64158
- throw new Error(`Failed to load any Letta tools for model "${resolvedModel}".`);
64159
- }
64160
- }
64161
- await ensureCorrectMemoryTool(agentId, resolvedModel);
64162
- const { isGeminiModel: isGeminiModel3 } = await init_manager3().then(() => exports_manager2);
64163
- const toolsetName = isOpenAIModel(resolvedModel) ? "codex" : isGeminiModel3(resolvedModel) ? "gemini" : "default";
64164
- return toolsetName;
64165
- }
64166
- var CODEX_TOOLS, GEMINI_TOOLS, MEMORY_TOOL_NAMES;
64167
- var init_toolset = __esm(async () => {
64168
- init_model();
64169
- init_filter();
64170
- await __promiseAll([
64171
- init_client2(),
64172
- init_manager3()
64173
- ]);
64174
- CODEX_TOOLS = OPENAI_PASCAL_TOOLS;
64175
- GEMINI_TOOLS = GEMINI_PASCAL_TOOLS;
64176
- MEMORY_TOOL_NAMES = new Set([
64177
- "memory",
64178
- "memory_apply_patch",
64179
- "memory_insert",
64180
- "memory_replace",
64181
- "memory_rethink"
64182
- ]);
64183
- });
64184
-
64185
64661
  // src/cli/helpers/toolNameMapping.ts
64186
64662
  function getDisplayToolName(rawName) {
64187
64663
  if (rawName === "write")
@@ -65320,6 +65796,14 @@ function getRetryStatusMessage(errorDetail) {
65320
65796
  return DEFAULT_RETRY_MESSAGE;
65321
65797
  if (errorDetail.includes("Anthropic API is overloaded"))
65322
65798
  return "Anthropic API is overloaded, retrying...";
65799
+ if (errorDetail.includes("ChatGPT API error") || errorDetail.includes("ChatGPT server error") || errorDetail.includes("upstream connect error")) {
65800
+ return "OpenAI ChatGPT backend connection failed, retrying...";
65801
+ }
65802
+ if (errorDetail.includes("Connection error during streaming") || errorDetail.includes("incomplete chunked read") || errorDetail.includes("connection termination")) {
65803
+ return "OpenAI ChatGPT streaming connection dropped, retrying...";
65804
+ }
65805
+ if (errorDetail.includes("OpenAI API error"))
65806
+ return "OpenAI API error, retrying...";
65323
65807
  return DEFAULT_RETRY_MESSAGE;
65324
65808
  }
65325
65809
  function createAgentLink(runId, agentId, conversationId) {
@@ -65525,7 +66009,7 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
65525
66009
  if (!streamProcessor.lastRunId) {
65526
66010
  fallbackError = errorMessage;
65527
66011
  }
65528
- stopReason = "error";
66012
+ stopReason = streamProcessor.stopReason || "error";
65529
66013
  markIncompleteToolsAsCancelled(buffers, true, "stream_error");
65530
66014
  queueMicrotask(refresh);
65531
66015
  } finally {
@@ -65763,7 +66247,7 @@ function parseRegistryHandle(handle) {
65763
66247
  }
65764
66248
  async function importAgentFromRegistry(options) {
65765
66249
  const { tmpdir: tmpdir3 } = await import("node:os");
65766
- const { join: join21 } = await import("node:path");
66250
+ const { join: join22 } = await import("node:path");
65767
66251
  const { writeFile: writeFile4, unlink } = await import("node:fs/promises");
65768
66252
  const { author, name } = parseRegistryHandle(options.handle);
65769
66253
  const rawUrl = `https://raw.githubusercontent.com/${AGENT_REGISTRY_OWNER}/${AGENT_REGISTRY_REPO}/refs/heads/${AGENT_REGISTRY_BRANCH}/agents/@${author}/${name}/${name}.af`;
@@ -65775,7 +66259,7 @@ async function importAgentFromRegistry(options) {
65775
66259
  throw new Error(`Failed to download agent @${author}/${name}: ${response.statusText}`);
65776
66260
  }
65777
66261
  const afContent = await response.text();
65778
- const tempPath = join21(tmpdir3(), `letta-import-${author}-${name}-${Date.now()}.af`);
66262
+ const tempPath = join22(tmpdir3(), `letta-import-${author}-${name}-${Date.now()}.af`);
65779
66263
  await writeFile4(tempPath, afContent, "utf-8");
65780
66264
  try {
65781
66265
  const result = await importAgentFromFile({
@@ -65800,149 +66284,6 @@ var init_import = __esm(async () => {
65800
66284
  ]);
65801
66285
  });
65802
66286
 
65803
- // src/agent/memoryFilesystem.ts
65804
- var exports_memoryFilesystem = {};
65805
- __export(exports_memoryFilesystem, {
65806
- renderMemoryFilesystemTree: () => renderMemoryFilesystemTree,
65807
- labelFromRelativePath: () => labelFromRelativePath,
65808
- getMemorySystemDir: () => getMemorySystemDir,
65809
- getMemoryFilesystemRoot: () => getMemoryFilesystemRoot,
65810
- ensureMemoryFilesystemDirs: () => ensureMemoryFilesystemDirs,
65811
- enableMemfsIfCloud: () => enableMemfsIfCloud,
65812
- applyMemfsFlags: () => applyMemfsFlags,
65813
- MEMORY_SYSTEM_DIR: () => MEMORY_SYSTEM_DIR,
65814
- MEMORY_FS_ROOT: () => MEMORY_FS_ROOT,
65815
- MEMORY_FS_MEMORY_DIR: () => MEMORY_FS_MEMORY_DIR,
65816
- MEMORY_FS_AGENTS_DIR: () => MEMORY_FS_AGENTS_DIR
65817
- });
65818
- import { existsSync as existsSync12, mkdirSync as mkdirSync8 } from "node:fs";
65819
- import { homedir as homedir14 } from "node:os";
65820
- import { join as join21 } from "node:path";
65821
- function getMemoryFilesystemRoot(agentId, homeDir = homedir14()) {
65822
- return join21(homeDir, MEMORY_FS_ROOT, MEMORY_FS_AGENTS_DIR, agentId, MEMORY_FS_MEMORY_DIR);
65823
- }
65824
- function getMemorySystemDir(agentId, homeDir = homedir14()) {
65825
- return join21(getMemoryFilesystemRoot(agentId, homeDir), MEMORY_SYSTEM_DIR);
65826
- }
65827
- function ensureMemoryFilesystemDirs(agentId, homeDir = homedir14()) {
65828
- const root = getMemoryFilesystemRoot(agentId, homeDir);
65829
- const systemDir = getMemorySystemDir(agentId, homeDir);
65830
- if (!existsSync12(root)) {
65831
- mkdirSync8(root, { recursive: true });
65832
- }
65833
- if (!existsSync12(systemDir)) {
65834
- mkdirSync8(systemDir, { recursive: true });
65835
- }
65836
- }
65837
- function labelFromRelativePath(relativePath) {
65838
- const normalized = relativePath.replace(/\\/g, "/");
65839
- return normalized.replace(/\.md$/, "");
65840
- }
65841
- function renderMemoryFilesystemTree(systemLabels, detachedLabels) {
65842
- const makeNode = () => ({ children: new Map, isFile: false });
65843
- const root = makeNode();
65844
- const insertPath = (base2, label) => {
65845
- const parts = base2 ? [base2, ...label.split("/")] : label.split("/");
65846
- let current = root;
65847
- for (const [i, partName] of parts.entries()) {
65848
- const part = i === parts.length - 1 ? `${partName}.md` : partName;
65849
- if (!current.children.has(part)) {
65850
- current.children.set(part, makeNode());
65851
- }
65852
- current = current.children.get(part);
65853
- if (i === parts.length - 1) {
65854
- current.isFile = true;
65855
- }
65856
- }
65857
- };
65858
- for (const label of systemLabels) {
65859
- insertPath(MEMORY_SYSTEM_DIR, label);
65860
- }
65861
- for (const label of detachedLabels) {
65862
- insertPath(null, label);
65863
- }
65864
- if (!root.children.has(MEMORY_SYSTEM_DIR)) {
65865
- root.children.set(MEMORY_SYSTEM_DIR, makeNode());
65866
- }
65867
- const sortedEntries = (node) => {
65868
- const entries = Array.from(node.children.entries());
65869
- return entries.sort(([nameA, nodeA], [nameB, nodeB]) => {
65870
- if (nodeA.isFile !== nodeB.isFile) {
65871
- return nodeA.isFile ? 1 : -1;
65872
- }
65873
- return nameA.localeCompare(nameB);
65874
- });
65875
- };
65876
- const lines = ["/memory/"];
65877
- const render2 = (node, prefix) => {
65878
- const entries = sortedEntries(node);
65879
- entries.forEach(([name, child], index) => {
65880
- const isLast = index === entries.length - 1;
65881
- const branch = isLast ? "└──" : "├──";
65882
- lines.push(`${prefix}${branch} ${name}${child.isFile ? "" : "/"}`);
65883
- if (child.children.size > 0) {
65884
- const nextPrefix = `${prefix}${isLast ? " " : "│ "}`;
65885
- render2(child, nextPrefix);
65886
- }
65887
- });
65888
- };
65889
- render2(root, "");
65890
- return lines.join(`
65891
- `);
65892
- }
65893
- async function applyMemfsFlags(agentId, memfsFlag, noMemfsFlag, options) {
65894
- const { getServerUrl: getServerUrl2 } = await init_client2().then(() => exports_client);
65895
- const { settingsManager: settingsManager3 } = await init_settings_manager().then(() => exports_settings_manager);
65896
- if (memfsFlag) {
65897
- const serverUrl = getServerUrl2();
65898
- if (!serverUrl.includes("api.letta.com")) {
65899
- throw new Error("--memfs is only available on Letta Cloud (api.letta.com).");
65900
- }
65901
- settingsManager3.setMemfsEnabled(agentId, true);
65902
- } else if (noMemfsFlag) {
65903
- settingsManager3.setMemfsEnabled(agentId, false);
65904
- }
65905
- const isEnabled = settingsManager3.isMemfsEnabled(agentId);
65906
- if (isEnabled && memfsFlag) {
65907
- const { detachMemoryTools: detachMemoryTools2 } = await init_toolset().then(() => exports_toolset);
65908
- await detachMemoryTools2(agentId);
65909
- }
65910
- if (memfsFlag || noMemfsFlag) {
65911
- const { updateAgentSystemPromptMemfs: updateAgentSystemPromptMemfs2 } = await init_modify().then(() => exports_modify);
65912
- await updateAgentSystemPromptMemfs2(agentId, isEnabled);
65913
- }
65914
- let pullSummary;
65915
- if (isEnabled) {
65916
- const { addGitMemoryTag: addGitMemoryTag2, isGitRepo: isGitRepo2, cloneMemoryRepo: cloneMemoryRepo2, pullMemory: pullMemory2 } = await init_memoryGit().then(() => exports_memoryGit);
65917
- await addGitMemoryTag2(agentId);
65918
- if (!isGitRepo2(agentId)) {
65919
- await cloneMemoryRepo2(agentId);
65920
- } else if (options?.pullOnExistingRepo) {
65921
- const result = await pullMemory2(agentId);
65922
- pullSummary = result.summary;
65923
- }
65924
- }
65925
- const action = memfsFlag ? "enabled" : noMemfsFlag ? "disabled" : "unchanged";
65926
- return {
65927
- action,
65928
- memoryDir: isEnabled ? getMemoryFilesystemRoot(agentId) : undefined,
65929
- pullSummary
65930
- };
65931
- }
65932
- async function enableMemfsIfCloud(agentId) {
65933
- const { getServerUrl: getServerUrl2 } = await init_client2().then(() => exports_client);
65934
- const serverUrl = getServerUrl2();
65935
- if (!serverUrl.includes("api.letta.com"))
65936
- return;
65937
- try {
65938
- await applyMemfsFlags(agentId, true, undefined);
65939
- } catch (error) {
65940
- console.warn(`Warning: Could not enable memfs for new agent: ${error instanceof Error ? error.message : String(error)}`);
65941
- }
65942
- }
65943
- var MEMORY_FS_ROOT = ".letta", MEMORY_FS_AGENTS_DIR = "agents", MEMORY_FS_MEMORY_DIR = "memory", MEMORY_SYSTEM_DIR = "system";
65944
- var init_memoryFilesystem = () => {};
65945
-
65946
66287
  // src/agent/defaults.ts
65947
66288
  var exports_defaults = {};
65948
66289
  __export(exports_defaults, {
@@ -66180,9 +66521,36 @@ var init_check_approval = __esm(() => {
66180
66521
  // src/headless.ts
66181
66522
  var exports_headless = {};
66182
66523
  __export(exports_headless, {
66524
+ shouldReinjectSkillsAfterCompaction: () => shouldReinjectSkillsAfterCompaction,
66525
+ prependSkillsReminderToContent: () => prependSkillsReminderToContent,
66183
66526
  handleHeadlessCommand: () => handleHeadlessCommand
66184
66527
  });
66185
66528
  import { parseArgs as parseArgs5 } from "node:util";
66529
+ function prependSkillsReminderToContent(content, skillsReminder) {
66530
+ if (!skillsReminder) {
66531
+ return content;
66532
+ }
66533
+ if (typeof content === "string") {
66534
+ return `${skillsReminder}
66535
+
66536
+ ${content}`;
66537
+ }
66538
+ if (Array.isArray(content)) {
66539
+ return [
66540
+ {
66541
+ type: "text",
66542
+ text: `${skillsReminder}
66543
+
66544
+ `
66545
+ },
66546
+ ...content
66547
+ ];
66548
+ }
66549
+ return content;
66550
+ }
66551
+ function shouldReinjectSkillsAfterCompaction(lines) {
66552
+ return lines.some((line) => line.kind === "event" && line.eventType === "compaction" && line.phase === "finished" && (line.summary !== undefined || line.stats !== undefined));
66553
+ }
66186
66554
  async function handleHeadlessCommand(argv, model, skillsDirectory, noSkills) {
66187
66555
  const { values, positionals } = parseArgs5({
66188
66556
  args: argv,
@@ -66317,10 +66685,12 @@ In headless mode, use:
66317
66685
  const baseToolsRaw = values["base-tools"];
66318
66686
  const memfsFlag = values.memfs;
66319
66687
  const noMemfsFlag = values["no-memfs"];
66688
+ const requestedMemoryPromptMode = memfsFlag ? "memfs" : noMemfsFlag ? "standard" : undefined;
66689
+ const shouldAutoEnableMemfsForNewAgent = !memfsFlag && !noMemfsFlag;
66320
66690
  const fromAfFile = values["from-af"];
66321
66691
  const preLoadSkillsRaw = values["pre-load-skills"];
66322
66692
  const maxTurnsRaw = values["max-turns"];
66323
- const tagsRaw = values["tags"];
66693
+ const tagsRaw = values.tags;
66324
66694
  let tags;
66325
66695
  if (tagsRaw !== undefined) {
66326
66696
  const trimmed = tagsRaw.trim();
@@ -66547,6 +66917,7 @@ In headless mode, use:
66547
66917
  systemPromptPreset,
66548
66918
  systemPromptCustom: systemCustom,
66549
66919
  systemPromptAppend: systemAppend,
66920
+ memoryPromptMode: requestedMemoryPromptMode,
66550
66921
  initBlocks,
66551
66922
  baseTools,
66552
66923
  memoryBlocks,
@@ -66555,8 +66926,10 @@ In headless mode, use:
66555
66926
  };
66556
66927
  const result = await createAgent(createOptions);
66557
66928
  agent = result.agent;
66558
- const { enableMemfsIfCloud: enableMemfsIfCloud2 } = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
66559
- await enableMemfsIfCloud2(agent.id);
66929
+ if (shouldAutoEnableMemfsForNewAgent) {
66930
+ const { enableMemfsIfCloud: enableMemfsIfCloud2 } = await Promise.resolve().then(() => (init_memoryFilesystem(), exports_memoryFilesystem));
66931
+ await enableMemfsIfCloud2(agent.id);
66932
+ }
66560
66933
  }
66561
66934
  let resolvedLocalConvId = null;
66562
66935
  if (!agent) {
@@ -66959,7 +67332,11 @@ ${loadedContents.join(`
66959
67332
  });
66960
67333
  } catch (preStreamError) {
66961
67334
  const errorDetail = extractConflictDetail(preStreamError);
66962
- const preStreamAction = getPreStreamErrorAction(errorDetail, conversationBusyRetries, CONVERSATION_BUSY_MAX_RETRIES);
67335
+ const preStreamAction = getPreStreamErrorAction(errorDetail, conversationBusyRetries, CONVERSATION_BUSY_MAX_RETRIES, {
67336
+ status: preStreamError instanceof APIError2 ? preStreamError.status : undefined,
67337
+ transientRetries: llmApiErrorRetries,
67338
+ maxTransientRetries: LLM_API_ERROR_MAX_RETRIES
67339
+ });
66963
67340
  if (preStreamAction === "resolve_approval_pending") {
66964
67341
  if (outputFormat === "stream-json") {
66965
67342
  const recoveryMsg = {
@@ -66995,6 +67372,30 @@ ${loadedContents.join(`
66995
67372
  await new Promise((resolve20) => setTimeout(resolve20, CONVERSATION_BUSY_RETRY_DELAY_MS));
66996
67373
  continue;
66997
67374
  }
67375
+ if (preStreamAction === "retry_transient") {
67376
+ const attempt = llmApiErrorRetries + 1;
67377
+ const retryAfterMs = preStreamError instanceof APIError2 ? parseRetryAfterHeaderMs(preStreamError.headers?.get("retry-after")) : null;
67378
+ const delayMs = retryAfterMs ?? 1000 * 2 ** (attempt - 1);
67379
+ llmApiErrorRetries = attempt;
67380
+ if (outputFormat === "stream-json") {
67381
+ const retryMsg = {
67382
+ type: "retry",
67383
+ reason: "llm_api_error",
67384
+ attempt,
67385
+ max_attempts: LLM_API_ERROR_MAX_RETRIES,
67386
+ delay_ms: delayMs,
67387
+ session_id: sessionId,
67388
+ uuid: `retry-pre-stream-${crypto.randomUUID()}`
67389
+ };
67390
+ console.log(JSON.stringify(retryMsg));
67391
+ } else {
67392
+ const delaySeconds = Math.round(delayMs / 1000);
67393
+ console.error(`Transient API error before streaming (attempt ${attempt} of ${LLM_API_ERROR_MAX_RETRIES}), retrying in ${delaySeconds}s...`);
67394
+ }
67395
+ await new Promise((resolve20) => setTimeout(resolve20, delayMs));
67396
+ conversationBusyRetries = 0;
67397
+ continue;
67398
+ }
66998
67399
  conversationBusyRetries = 0;
66999
67400
  throw preStreamError;
67000
67401
  }
@@ -67257,18 +67658,7 @@ ${loadedContents.join(`
67257
67658
  const metaError = run.metadata?.error;
67258
67659
  const errorType = metaError?.error_type ?? metaError?.error?.error_type;
67259
67660
  const detail = metaError?.detail ?? metaError?.error?.detail ?? "";
67260
- const is4xxError = /Error code: 4\d{2}/.test(detail);
67261
- const llmProviderPatterns = [
67262
- "Anthropic API error",
67263
- "OpenAI API error",
67264
- "Google Vertex API error",
67265
- "overloaded",
67266
- "api_error",
67267
- "Network error",
67268
- "Connection error during Anthropic streaming"
67269
- ];
67270
- const isLlmErrorFromDetail = llmProviderPatterns.some((pattern) => detail.includes(pattern));
67271
- if ((errorType === "llm_error" || isLlmErrorFromDetail) && !is4xxError) {
67661
+ if (shouldRetryRunMetadataError(errorType, detail)) {
67272
67662
  const attempt = llmApiErrorRetries + 1;
67273
67663
  const baseDelayMs = 1000;
67274
67664
  const delayMs = baseDelayMs * 2 ** (attempt - 1);
@@ -67433,6 +67823,9 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
67433
67823
  };
67434
67824
  console.log(JSON.stringify(initEvent));
67435
67825
  let currentAbortController = null;
67826
+ let hasInjectedSkillsReminder = false;
67827
+ let pendingSkillsReinject = false;
67828
+ let cachedSkillsReminder = null;
67436
67829
  const resolveAllPendingApprovals = async () => {
67437
67830
  const { getResumeData: getResumeData3 } = await Promise.resolve().then(() => (init_check_approval(), exports_check_approval));
67438
67831
  while (true) {
@@ -67699,7 +68092,7 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
67699
68092
  }
67700
68093
  continue;
67701
68094
  }
67702
- if (message.type === "user" && message.message?.content) {
68095
+ if (message.type === "user" && message.message?.content !== undefined) {
67703
68096
  const userContent = message.message.content;
67704
68097
  currentAbortController = new AbortController;
67705
68098
  try {
@@ -67708,26 +68101,32 @@ async function runBidirectionalMode(agent, conversationId, client, _outputFormat
67708
68101
  let numTurns = 0;
67709
68102
  let lastStopReason = null;
67710
68103
  let sawStreamError = false;
68104
+ let preStreamTransientRetries = 0;
67711
68105
  let enrichedContent = userContent;
67712
- if (typeof enrichedContent === "string") {
67713
- try {
67714
- const {
67715
- discoverSkills: discover,
67716
- SKILLS_DIR: defaultDir,
67717
- formatSkillsAsSystemReminder: formatSkillsAsSystemReminder3
67718
- } = await Promise.resolve().then(() => (init_skills(), exports_skills));
67719
- const { getSkillsDirectory: getSkillsDirectory2 } = await Promise.resolve().then(() => (init_context(), exports_context));
67720
- const { join: join22 } = await import("node:path");
67721
- const skillsDir = getSkillsDirectory2() || join22(process.cwd(), defaultDir);
67722
- const { skills } = await discover(skillsDir, agent.id);
67723
- const skillsReminder = formatSkillsAsSystemReminder3(skills);
67724
- if (skillsReminder) {
67725
- enrichedContent = `${skillsReminder}
67726
-
67727
- ${enrichedContent}`;
67728
- }
67729
- } catch {}
67730
- }
68106
+ try {
68107
+ const {
68108
+ discoverSkills: discover,
68109
+ SKILLS_DIR: defaultDir,
68110
+ formatSkillsAsSystemReminder: formatSkillsAsSystemReminder3
68111
+ } = await Promise.resolve().then(() => (init_skills(), exports_skills));
68112
+ const { getSkillsDirectory: getSkillsDirectory2 } = await Promise.resolve().then(() => (init_context(), exports_context));
68113
+ const { join: join22 } = await import("node:path");
68114
+ const skillsDir = getSkillsDirectory2() || join22(process.cwd(), defaultDir);
68115
+ const { skills } = await discover(skillsDir, agent.id);
68116
+ const latestSkillsReminder = formatSkillsAsSystemReminder3(skills);
68117
+ if (cachedSkillsReminder !== null && latestSkillsReminder !== cachedSkillsReminder) {
68118
+ pendingSkillsReinject = true;
68119
+ }
68120
+ cachedSkillsReminder = latestSkillsReminder;
68121
+ const shouldInjectSkillsReminder = !hasInjectedSkillsReminder || pendingSkillsReinject;
68122
+ if (shouldInjectSkillsReminder && latestSkillsReminder) {
68123
+ enrichedContent = prependSkillsReminderToContent(enrichedContent, latestSkillsReminder);
68124
+ }
68125
+ if (shouldInjectSkillsReminder) {
68126
+ hasInjectedSkillsReminder = true;
68127
+ pendingSkillsReinject = false;
68128
+ }
68129
+ } catch {}
67731
68130
  let currentInput = [
67732
68131
  { role: "user", content: enrichedContent }
67733
68132
  ];
@@ -67759,7 +68158,11 @@ ${enrichedContent}`;
67759
68158
  });
67760
68159
  } catch (preStreamError) {
67761
68160
  const errorDetail = extractConflictDetail(preStreamError);
67762
- const preStreamAction = getPreStreamErrorAction(errorDetail, 0, 0);
68161
+ const preStreamAction = getPreStreamErrorAction(errorDetail, 0, 0, {
68162
+ status: preStreamError instanceof APIError2 ? preStreamError.status : undefined,
68163
+ transientRetries: preStreamTransientRetries,
68164
+ maxTransientRetries: LLM_API_ERROR_MAX_RETRIES
68165
+ });
67763
68166
  if (preStreamAction === "resolve_approval_pending") {
67764
68167
  const recoveryMsg = {
67765
68168
  type: "recovery",
@@ -67772,8 +68175,27 @@ ${enrichedContent}`;
67772
68175
  await resolveAllPendingApprovals();
67773
68176
  continue;
67774
68177
  }
68178
+ if (preStreamAction === "retry_transient") {
68179
+ const attempt = preStreamTransientRetries + 1;
68180
+ const retryAfterMs = preStreamError instanceof APIError2 ? parseRetryAfterHeaderMs(preStreamError.headers?.get("retry-after")) : null;
68181
+ const delayMs = retryAfterMs ?? 1000 * 2 ** (attempt - 1);
68182
+ preStreamTransientRetries = attempt;
68183
+ const retryMsg = {
68184
+ type: "retry",
68185
+ reason: "llm_api_error",
68186
+ attempt,
68187
+ max_attempts: LLM_API_ERROR_MAX_RETRIES,
68188
+ delay_ms: delayMs,
68189
+ session_id: sessionId,
68190
+ uuid: `retry-bidir-${crypto.randomUUID()}`
68191
+ };
68192
+ console.log(JSON.stringify(retryMsg));
68193
+ await new Promise((resolve20) => setTimeout(resolve20, delayMs));
68194
+ continue;
68195
+ }
67775
68196
  throw preStreamError;
67776
68197
  }
68198
+ preStreamTransientRetries = 0;
67777
68199
  const streamJsonHook = ({
67778
68200
  chunk,
67779
68201
  shouldOutput,
@@ -67923,6 +68345,9 @@ ${enrichedContent}`;
67923
68345
  }
67924
68346
  const durationMs = performance.now() - startTime;
67925
68347
  const lines = toLines(buffers);
68348
+ if (shouldReinjectSkillsAfterCompaction(lines)) {
68349
+ pendingSkillsReinject = true;
68350
+ }
67926
68351
  const reversed = [...lines].reverse();
67927
68352
  const lastAssistant = reversed.find((line2) => line2.kind === "assistant" && ("text" in line2) && typeof line2.text === "string" && line2.text.trim().length > 0);
67928
68353
  const lastReasoning = reversed.find((line2) => line2.kind === "reasoning" && ("text" in line2) && typeof line2.text === "string" && line2.text.trim().length > 0);
@@ -92683,6 +93108,15 @@ function buildSessionContext(options) {
92683
93108
  lastRunInfo = "(failed to parse last run time)";
92684
93109
  }
92685
93110
  }
93111
+ const showMemoryDir = (() => {
93112
+ try {
93113
+ return settingsManager.isMemfsEnabled(agentInfo.id);
93114
+ } catch {
93115
+ return false;
93116
+ }
93117
+ })();
93118
+ const memoryDirLine = showMemoryDir ? `
93119
+ - **Memory directory (also stored in \`MEMORY_DIR\` env var)**: \`${getMemoryFilesystemRoot(agentInfo.id)}\`` : "";
92686
93120
  let context3 = `${SYSTEM_REMINDER_OPEN}
92687
93121
  This is an automated message providing context about the user's environment.
92688
93122
  The user has just initiated a new connection via the [Letta Code CLI client](https://docs.letta.com/letta-code/index.md).
@@ -92720,7 +93154,7 @@ ${gitInfo.status}
92720
93154
  }
92721
93155
  context3 += `
92722
93156
  ## Agent Information (i.e. information about you)
92723
- - **Agent ID**: ${agentInfo.id}
93157
+ - **Agent ID (also stored in \`AGENT_ID\` env var)**: ${agentInfo.id}${memoryDirLine}
92724
93158
  - **Agent name**: ${agentInfo.name || "(unnamed)"} (the user can change this with /rename)
92725
93159
  - **Agent description**: ${agentInfo.description || "(no description)"} (the user can change this with /description)
92726
93160
  - **Last message**: ${lastRunInfo}
@@ -92732,6 +93166,7 @@ ${SYSTEM_REMINDER_CLOSE}`;
92732
93166
  }
92733
93167
  }
92734
93168
  var init_sessionContext = __esm(async () => {
93169
+ init_memoryFilesystem();
92735
93170
  init_oauth();
92736
93171
  init_constants();
92737
93172
  init_version();
@@ -94835,19 +95270,7 @@ async function isRetriableError(stopReason, lastRunId) {
94835
95270
  const metaError = run.metadata?.error;
94836
95271
  const errorType = metaError?.error_type ?? metaError?.error?.error_type;
94837
95272
  const detail = metaError?.detail ?? metaError?.error?.detail ?? "";
94838
- const is4xxError = /Error code: 4\d{2}/.test(detail);
94839
- if (errorType === "llm_error" && !is4xxError)
94840
- return true;
94841
- const llmProviderPatterns = [
94842
- "Anthropic API error",
94843
- "OpenAI API error",
94844
- "Google Vertex API error",
94845
- "overloaded",
94846
- "api_error",
94847
- "Network error",
94848
- "Connection error during Anthropic streaming"
94849
- ];
94850
- if (llmProviderPatterns.some((pattern) => detail.includes(pattern)) && !is4xxError) {
95273
+ if (shouldRetryRunMetadataError(errorType, detail)) {
94851
95274
  return true;
94852
95275
  }
94853
95276
  return false;
@@ -96407,7 +96830,11 @@ ${newState.originalPrompt}`
96407
96830
  stream2 = await sendMessageStream(conversationIdRef.current, currentInput, { agentId: agentIdRef.current });
96408
96831
  } catch (preStreamError) {
96409
96832
  const errorDetail = extractConflictDetail(preStreamError);
96410
- const preStreamAction = getPreStreamErrorAction(errorDetail, conversationBusyRetriesRef.current, CONVERSATION_BUSY_MAX_RETRIES2);
96833
+ const preStreamAction = getPreStreamErrorAction(errorDetail, conversationBusyRetriesRef.current, CONVERSATION_BUSY_MAX_RETRIES2, {
96834
+ status: preStreamError instanceof APIError2 ? preStreamError.status : undefined,
96835
+ transientRetries: llmApiErrorRetriesRef.current,
96836
+ maxTransientRetries: LLM_API_ERROR_MAX_RETRIES2
96837
+ });
96411
96838
  if (shouldAttemptApprovalRecovery({
96412
96839
  approvalPendingDetected: preStreamAction === "resolve_approval_pending",
96413
96840
  retries: llmApiErrorRetriesRef.current,
@@ -96453,6 +96880,37 @@ ${newState.originalPrompt}`
96453
96880
  continue;
96454
96881
  }
96455
96882
  }
96883
+ if (preStreamAction === "retry_transient") {
96884
+ llmApiErrorRetriesRef.current += 1;
96885
+ const attempt = llmApiErrorRetriesRef.current;
96886
+ const retryAfterMs = preStreamError instanceof APIError2 ? parseRetryAfterHeaderMs(preStreamError.headers?.get("retry-after")) : null;
96887
+ const delayMs = retryAfterMs ?? 1000 * 2 ** (attempt - 1);
96888
+ const statusId = uid4("status");
96889
+ buffersRef.current.byId.set(statusId, {
96890
+ kind: "status",
96891
+ id: statusId,
96892
+ lines: [getRetryStatusMessage(errorDetail)]
96893
+ });
96894
+ buffersRef.current.order.push(statusId);
96895
+ refreshDerived();
96896
+ let cancelled = false;
96897
+ const startTime = Date.now();
96898
+ while (Date.now() - startTime < delayMs) {
96899
+ if (abortControllerRef.current?.signal.aborted || userCancelledRef.current) {
96900
+ cancelled = true;
96901
+ break;
96902
+ }
96903
+ await new Promise((resolve23) => setTimeout(resolve23, 100));
96904
+ }
96905
+ buffersRef.current.byId.delete(statusId);
96906
+ buffersRef.current.order = buffersRef.current.order.filter((id) => id !== statusId);
96907
+ refreshDerived();
96908
+ if (!cancelled) {
96909
+ buffersRef.current.interrupted = false;
96910
+ conversationBusyRetriesRef.current = 0;
96911
+ continue;
96912
+ }
96913
+ }
96456
96914
  conversationBusyRetriesRef.current = 0;
96457
96915
  const hasApprovalInPayload2 = currentInput.some((item) => item?.type === "approval");
96458
96916
  if (hasApprovalInPayload2) {
@@ -97317,6 +97775,7 @@ ${feedback}
97317
97775
  pendingInterruptRecoveryConversationIdRef.current = conversationIdRef.current;
97318
97776
  userCancelledRef.current = true;
97319
97777
  setStreaming(false);
97778
+ resetTrajectoryBases();
97320
97779
  setIsExecutingTool(false);
97321
97780
  toolResultsInFlightRef.current = false;
97322
97781
  refreshDerived();
@@ -97351,6 +97810,7 @@ ${feedback}
97351
97810
  conversationGenerationRef.current += 1;
97352
97811
  processingConversationRef.current = 0;
97353
97812
  setStreaming(false);
97813
+ resetTrajectoryBases();
97354
97814
  toolResultsInFlightRef.current = false;
97355
97815
  if (!toolsCancelled) {
97356
97816
  appendError(INTERRUPT_MESSAGE, true);
@@ -97430,7 +97890,8 @@ ${feedback}
97430
97890
  pendingApprovals,
97431
97891
  autoHandledResults,
97432
97892
  autoDeniedApprovals,
97433
- queueApprovalResults
97893
+ queueApprovalResults,
97894
+ resetTrajectoryBases
97434
97895
  ]);
97435
97896
  const processConversationRef = import_react94.useRef(processConversation);
97436
97897
  import_react94.useEffect(() => {
@@ -97867,6 +98328,14 @@ ${SYSTEM_REMINDER_CLOSE}` : "";
97867
98328
  debugLog("queue", `Bumping dequeueEpoch: userCancelledRef was reset, ${messageQueue.length} message(s) queued, agent not busy`);
97868
98329
  setDequeueEpoch((e) => e + 1);
97869
98330
  }
98331
+ const isSlashCommand = userTextForInput.startsWith("/");
98332
+ if (isAgentBusy() && isSlashCommand) {
98333
+ const attemptedCommand = userTextForInput.split(/\s+/)[0] || "/";
98334
+ const disabledMessage = `'${attemptedCommand}' is disabled while the agent is running.`;
98335
+ const cmd = commandRunner.start(userTextForInput, disabledMessage);
98336
+ cmd.fail(disabledMessage);
98337
+ return { submitted: true };
98338
+ }
97870
98339
  const shouldBypassQueue = isInteractiveCommand(userTextForInput) || isNonStateCommand(userTextForInput);
97871
98340
  if (isAgentBusy() && !shouldBypassQueue) {
97872
98341
  setMessageQueue((prev) => {
@@ -99131,9 +99600,13 @@ ${recentCommits}
99131
99600
  ## Memory Filesystem Location
99132
99601
 
99133
99602
  Your memory blocks are synchronized with the filesystem at:
99134
- \`~/.letta/agents/${agentId}/memory/\`
99603
+ \`${getMemoryFilesystemRoot(agentId)}\`
99135
99604
 
99136
- Use this path when working with memory files during initialization.
99605
+ Environment variables available in Letta Code:
99606
+ - \`AGENT_ID=${agentId}\`
99607
+ - \`MEMORY_DIR=${getMemoryFilesystemRoot(agentId)}\`
99608
+
99609
+ Use \`$MEMORY_DIR\` when working with memory files during initialization.
99137
99610
  ` : "";
99138
99611
  const initMessage = `${SYSTEM_REMINDER_OPEN}
99139
99612
  The user has requested memory initialization via /init.
@@ -99353,25 +99826,30 @@ ${SYSTEM_REMINDER_CLOSE}
99353
99826
  };
99354
99827
  pushReminder(sessionContextReminder);
99355
99828
  {
99356
- if (!discoveredSkillsRef.current) {
99357
- try {
99358
- const { discoverSkills: discover, SKILLS_DIR: defaultDir } = await Promise.resolve().then(() => (init_skills(), exports_skills));
99359
- const { getSkillsDirectory: getSkillsDirectory2, getNoSkills: getNoSkills2 } = await Promise.resolve().then(() => (init_context(), exports_context));
99360
- const skillsDir = getSkillsDirectory2() || join30(process.cwd(), defaultDir);
99361
- const { skills } = await discover(skillsDir, agentId, {
99362
- skipBundled: getNoSkills2()
99363
- });
99364
- discoveredSkillsRef.current = skills;
99365
- } catch {
99366
- discoveredSkillsRef.current = [];
99367
- }
99829
+ const {
99830
+ discoverSkills: discover,
99831
+ SKILLS_DIR: defaultDir,
99832
+ formatSkillsAsSystemReminder: formatSkillsAsSystemReminder3
99833
+ } = await Promise.resolve().then(() => (init_skills(), exports_skills));
99834
+ const { getSkillsDirectory: getSkillsDirectory2, getNoSkills: getNoSkills2 } = await Promise.resolve().then(() => (init_context(), exports_context));
99835
+ const previousSkillsReminder = discoveredSkillsRef.current ? formatSkillsAsSystemReminder3(discoveredSkillsRef.current) : null;
99836
+ let latestSkills = discoveredSkillsRef.current ?? [];
99837
+ try {
99838
+ const skillsDir = getSkillsDirectory2() || join30(process.cwd(), defaultDir);
99839
+ const { skills } = await discover(skillsDir, agentId, {
99840
+ skipBundled: getNoSkills2()
99841
+ });
99842
+ latestSkills = skills;
99843
+ } catch {}
99844
+ discoveredSkillsRef.current = latestSkills;
99845
+ const latestSkillsReminder = formatSkillsAsSystemReminder3(discoveredSkillsRef.current);
99846
+ if (previousSkillsReminder !== null && previousSkillsReminder !== latestSkillsReminder) {
99847
+ contextTrackerRef.current.pendingSkillsReinject = true;
99368
99848
  }
99369
99849
  const needsSkillsReinject = contextTrackerRef.current.pendingSkillsReinject;
99370
99850
  if (!hasInjectedSkillsRef.current || needsSkillsReinject) {
99371
- const { formatSkillsAsSystemReminder: formatSkillsAsSystemReminder3 } = await Promise.resolve().then(() => (init_skills(), exports_skills));
99372
- const skillsReminder = formatSkillsAsSystemReminder3(discoveredSkillsRef.current);
99373
- if (skillsReminder) {
99374
- pushReminder(skillsReminder);
99851
+ if (latestSkillsReminder) {
99852
+ pushReminder(latestSkillsReminder);
99375
99853
  }
99376
99854
  hasInjectedSkillsRef.current = true;
99377
99855
  contextTrackerRef.current.pendingSkillsReinject = false;
@@ -100349,8 +100827,8 @@ ${guidance}`);
100349
100827
  output: `Switching system prompt to ${prompt.label}...`,
100350
100828
  phase: "running"
100351
100829
  });
100352
- const { updateAgentSystemPromptRaw: updateAgentSystemPromptRaw2 } = await init_modify().then(() => exports_modify);
100353
- const result = await updateAgentSystemPromptRaw2(agentId, prompt.content);
100830
+ const { updateAgentSystemPrompt: updateAgentSystemPrompt2 } = await init_modify().then(() => exports_modify);
100831
+ const result = await updateAgentSystemPrompt2(agentId, promptId);
100354
100832
  if (result.success) {
100355
100833
  setCurrentSystemPromptId(promptId);
100356
100834
  cmd.finish(`Switched system prompt to ${prompt.label}`, true);
@@ -102747,8 +103225,7 @@ async function createAgent2(nameOrOptions = DEFAULT_AGENT_NAME, model, embedding
102747
103225
  } else {
102748
103226
  systemPromptContent = await resolveSystemPrompt(options.systemPromptPreset);
102749
103227
  }
102750
- systemPromptContent = `${systemPromptContent}
102751
- ${SYSTEM_PROMPT_MEMORY_ADDON}`;
103228
+ systemPromptContent = reconcileMemoryPrompt(systemPromptContent, options.memoryPromptMode ?? "standard");
102752
103229
  if (options.systemPromptAppend) {
102753
103230
  systemPromptContent = `${systemPromptContent}
102754
103231
 
@@ -102818,6 +103295,7 @@ ${options.systemPromptAppend}`;
102818
103295
  var init_create3 = __esm(async () => {
102819
103296
  init_constants();
102820
103297
  init_memory();
103298
+ init_memoryPrompt();
102821
103299
  init_model();
102822
103300
  init_promptAssets();
102823
103301
  await __promiseAll([
@@ -103117,10 +103595,16 @@ async function updateAgentSystemPromptRaw2(agentId, systemPromptContent) {
103117
103595
  }
103118
103596
  async function updateAgentSystemPrompt2(agentId, systemPromptId) {
103119
103597
  try {
103120
- const { resolveSystemPrompt: resolveSystemPrompt3, SYSTEM_PROMPT_MEMORY_ADDON: SYSTEM_PROMPT_MEMORY_ADDON3 } = await Promise.resolve().then(() => (init_promptAssets(), exports_promptAssets));
103598
+ const { resolveSystemPrompt: resolveSystemPrompt3 } = await Promise.resolve().then(() => (init_promptAssets(), exports_promptAssets));
103599
+ const { detectMemoryPromptDrift: detectMemoryPromptDrift2, reconcileMemoryPrompt: reconcileMemoryPrompt2 } = await Promise.resolve().then(() => (init_memoryPrompt(), exports_memoryPrompt));
103600
+ const { settingsManager: settingsManager3 } = await init_settings_manager().then(() => exports_settings_manager);
103601
+ const client = await getClient2();
103602
+ const currentAgent = await client.agents.retrieve(agentId);
103121
103603
  const baseContent = await resolveSystemPrompt3(systemPromptId);
103122
- const systemPromptContent = `${baseContent}
103123
- ${SYSTEM_PROMPT_MEMORY_ADDON3}`;
103604
+ const settingIndicatesMemfs = settingsManager3.isMemfsEnabled(agentId);
103605
+ const promptIndicatesMemfs = detectMemoryPromptDrift2(currentAgent.system || "", "standard").some((drift) => drift.code === "memfs_language_with_standard_mode");
103606
+ const memoryMode = settingIndicatesMemfs || promptIndicatesMemfs ? "memfs" : "standard";
103607
+ const systemPromptContent = reconcileMemoryPrompt2(baseContent, memoryMode);
103124
103608
  const updateResult = await updateAgentSystemPromptRaw2(agentId, systemPromptContent);
103125
103609
  if (!updateResult.success) {
103126
103610
  return {
@@ -103129,7 +103613,6 @@ ${SYSTEM_PROMPT_MEMORY_ADDON3}`;
103129
103613
  agent: null
103130
103614
  };
103131
103615
  }
103132
- const client = await getClient2();
103133
103616
  const agent = await client.agents.retrieve(agentId);
103134
103617
  return {
103135
103618
  success: true,
@@ -103148,15 +103631,10 @@ async function updateAgentSystemPromptMemfs2(agentId, enableMemfs) {
103148
103631
  try {
103149
103632
  const client = await getClient2();
103150
103633
  const agent = await client.agents.retrieve(agentId);
103151
- let currentSystemPrompt = agent.system || "";
103152
- const { SYSTEM_PROMPT_MEMFS_ADDON: SYSTEM_PROMPT_MEMFS_ADDON3, SYSTEM_PROMPT_MEMORY_ADDON: SYSTEM_PROMPT_MEMORY_ADDON3 } = await Promise.resolve().then(() => (init_promptAssets(), exports_promptAssets));
103153
- const memoryHeaderRegex = /\n#{1,2} Memory\b[\s\S]*?(?=\n#{1,2} (?!Memory|Filesystem|Structure|How It Works|Syncing|History)[^\n]|$)/;
103154
- currentSystemPrompt = currentSystemPrompt.replace(memoryHeaderRegex, "");
103155
- const addon = enableMemfs ? SYSTEM_PROMPT_MEMFS_ADDON3 : SYSTEM_PROMPT_MEMORY_ADDON3;
103156
- currentSystemPrompt = `${currentSystemPrompt}
103157
- ${addon}`;
103634
+ const { reconcileMemoryPrompt: reconcileMemoryPrompt2 } = await Promise.resolve().then(() => (init_memoryPrompt(), exports_memoryPrompt));
103635
+ const nextSystemPrompt = reconcileMemoryPrompt2(agent.system || "", enableMemfs ? "memfs" : "standard");
103158
103636
  await client.agents.update(agentId, {
103159
- system: currentSystemPrompt
103637
+ system: nextSystemPrompt
103160
103638
  });
103161
103639
  return {
103162
103640
  success: true,
@@ -103275,19 +103753,22 @@ async function applyMemfsFlags2(agentId, memfsFlag, noMemfsFlag, options) {
103275
103753
  if (!serverUrl.includes("api.letta.com")) {
103276
103754
  throw new Error("--memfs is only available on Letta Cloud (api.letta.com).");
103277
103755
  }
103278
- settingsManager3.setMemfsEnabled(agentId, true);
103279
- } else if (noMemfsFlag) {
103280
- settingsManager3.setMemfsEnabled(agentId, false);
103281
103756
  }
103282
- const isEnabled = settingsManager3.isMemfsEnabled(agentId);
103757
+ const hasExplicitToggle = Boolean(memfsFlag || noMemfsFlag);
103758
+ const targetEnabled = memfsFlag ? true : noMemfsFlag ? false : settingsManager3.isMemfsEnabled(agentId);
103759
+ if (hasExplicitToggle) {
103760
+ const { updateAgentSystemPromptMemfs: updateAgentSystemPromptMemfs3 } = await init_modify().then(() => exports_modify);
103761
+ const promptUpdate = await updateAgentSystemPromptMemfs3(agentId, targetEnabled);
103762
+ if (!promptUpdate.success) {
103763
+ throw new Error(promptUpdate.message);
103764
+ }
103765
+ settingsManager3.setMemfsEnabled(agentId, targetEnabled);
103766
+ }
103767
+ const isEnabled = hasExplicitToggle ? targetEnabled : settingsManager3.isMemfsEnabled(agentId);
103283
103768
  if (isEnabled && memfsFlag) {
103284
103769
  const { detachMemoryTools: detachMemoryTools2 } = await init_toolset().then(() => exports_toolset);
103285
103770
  await detachMemoryTools2(agentId);
103286
103771
  }
103287
- if (memfsFlag || noMemfsFlag) {
103288
- const { updateAgentSystemPromptMemfs: updateAgentSystemPromptMemfs3 } = await init_modify().then(() => exports_modify);
103289
- await updateAgentSystemPromptMemfs3(agentId, isEnabled);
103290
- }
103291
103772
  let pullSummary;
103292
103773
  if (isEnabled) {
103293
103774
  const { addGitMemoryTag: addGitMemoryTag2, isGitRepo: isGitRepo2, cloneMemoryRepo: cloneMemoryRepo2, pullMemory: pullMemory2 } = await init_memoryGit().then(() => exports_memoryGit);
@@ -106382,6 +106863,18 @@ if (!globalThis.__lettaSettingsManager) {
106382
106863
  }
106383
106864
  var settingsManager2 = globalThis.__lettaSettingsManager;
106384
106865
 
106866
+ // src/startup-auto-update.ts
106867
+ function startStartupAutoUpdateCheck(checkAndAutoUpdate, logError = console.error) {
106868
+ checkAndAutoUpdate().then((result) => {
106869
+ if (result?.enotemptyFailed) {
106870
+ logError(`
106871
+ Auto-update failed due to filesystem issue (ENOTEMPTY).`);
106872
+ logError(`Fix: rm -rf $(npm prefix -g)/lib/node_modules/@letta-ai/letta-code && npm i -g @letta-ai/letta-code
106873
+ `);
106874
+ }
106875
+ }).catch(() => {});
106876
+ }
106877
+
106385
106878
  // src/telemetry/index.ts
106386
106879
  init_http_headers();
106387
106880
  await init_settings_manager();
@@ -107095,14 +107588,7 @@ async function main() {
107095
107588
  }
107096
107589
  telemetry.init();
107097
107590
  const { checkAndAutoUpdate: checkAndAutoUpdate2 } = await Promise.resolve().then(() => (init_auto_update(), exports_auto_update));
107098
- checkAndAutoUpdate2().then((result) => {
107099
- if (result?.enotemptyFailed) {
107100
- console.error(`
107101
- Auto-update failed due to filesystem issue (ENOTEMPTY).`);
107102
- console.error(`Fix: rm -rf $(npm prefix -g)/lib/node_modules/@letta-ai/letta-code && npm i -g @letta-ai/letta-code
107103
- `);
107104
- }
107105
- }).catch(() => {});
107591
+ startStartupAutoUpdateCheck(checkAndAutoUpdate2);
107106
107592
  const { cleanupOldOverflowFiles: cleanupOldOverflowFiles2 } = await Promise.resolve().then(() => (init_overflow2(), exports_overflow));
107107
107593
  Promise.resolve().then(() => {
107108
107594
  try {
@@ -107178,6 +107664,10 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
107178
107664
  const command = positionals[2];
107179
107665
  if (values.help) {
107180
107666
  printHelp();
107667
+ const helpDelayMs = Number.parseInt(process.env.LETTA_TEST_HELP_EXIT_DELAY_MS ?? "", 10);
107668
+ if (Number.isFinite(helpDelayMs) && helpDelayMs > 0) {
107669
+ await new Promise((resolve24) => setTimeout(resolve24, helpDelayMs));
107670
+ }
107181
107671
  process.exit(0);
107182
107672
  }
107183
107673
  if (values.version) {
@@ -107234,6 +107724,8 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
107234
107724
  const skillsDirectory = values.skills ?? undefined;
107235
107725
  const memfsFlag = values.memfs;
107236
107726
  const noMemfsFlag = values["no-memfs"];
107727
+ const requestedMemoryPromptMode = memfsFlag ? "memfs" : noMemfsFlag ? "standard" : undefined;
107728
+ const shouldAutoEnableMemfsForNewAgent = !memfsFlag && !noMemfsFlag;
107237
107729
  const noSkillsFlag = values["no-skills"];
107238
107730
  const fromAfFile = values.import ?? values["from-af"];
107239
107731
  const isHeadless = values.prompt || values.run || !process.stdin.isTTY;
@@ -107927,13 +108419,16 @@ Error: ${message}`);
107927
108419
  skillsDirectory: skillsDirectory2,
107928
108420
  parallelToolCalls: true,
107929
108421
  systemPromptPreset: systemPromptPreset2,
108422
+ memoryPromptMode: requestedMemoryPromptMode,
107930
108423
  initBlocks: initBlocks2,
107931
108424
  baseTools: baseTools2
107932
108425
  });
107933
108426
  agent = result.agent;
107934
108427
  setAgentProvenance(result.provenance);
107935
- const { enableMemfsIfCloud: enableMemfsIfCloud3 } = await Promise.resolve().then(() => (init_memoryFilesystem2(), exports_memoryFilesystem2));
107936
- await enableMemfsIfCloud3(agent.id);
108428
+ if (shouldAutoEnableMemfsForNewAgent) {
108429
+ const { enableMemfsIfCloud: enableMemfsIfCloud3 } = await Promise.resolve().then(() => (init_memoryFilesystem2(), exports_memoryFilesystem2));
108430
+ await enableMemfsIfCloud3(agent.id);
108431
+ }
107937
108432
  }
107938
108433
  if (!agent && resumingAgentId) {
107939
108434
  try {
@@ -108237,4 +108732,4 @@ Error during initialization: ${message}`);
108237
108732
  }
108238
108733
  main();
108239
108734
 
108240
- //# debugId=2DEF3E9D56D2EFE964756E2164756E21
108735
+ //# debugId=28BAE9B7158D2B3E64756E2164756E21