@letta-ai/letta-code 0.31.11 → 0.31.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/letta.js CHANGED
@@ -5400,7 +5400,7 @@ var package_default;
5400
5400
  var init_package = __esm(() => {
5401
5401
  package_default = {
5402
5402
  name: "@letta-ai/letta-code",
5403
- version: "0.31.11",
5403
+ version: "0.31.12",
5404
5404
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5405
5405
  type: "module",
5406
5406
  packageManager: "bun@1.3.10",
@@ -7968,7 +7968,7 @@ Other
7968
7968
  - [ ] Make a permissions edit: let the user know that you can modify permissions (what commands are automatically approved/denied). Ask them if there are certain actions they would like you to avoid.
7969
7969
  - [ ] Create a local mod: let the user know you can customize Letta Code with trusted local mods for new tools, slash commands, provider integrations, UI panels/status, events, or permission overlays. Explain that mods are for executable harness behavior, while memory and skills are for retained knowledge and reusable procedures.
7970
7970
  - [ ] Worktrees: let the user know that you can help them orchestrate many agents in parallel, and also work in parallel to other agents. Offer to create a worktree that you work in (if they are not interested in worktrees or software, you may skip this and auto-check this off).
7971
- - [ ] Moving machines: ask the user to add another remote environment (they can either run another desktop instance or run \`letta server\` on another machine) and run you there instead.
7971
+ - [ ] Moving machines: ask the user to connect another computer (they can either run another desktop instance or run \`letta server\` on another machine) and run you there instead.
7972
7972
  `;
7973
7973
  var init_onboarding = () => {};
7974
7974
 
@@ -8021,7 +8021,7 @@ Other
8021
8021
  - [ ] Make a permissions edit: let the user know that you can modify permissions (what commands are automatically approved/denied). Ask them if there are certain actions they would like you to avoid.
8022
8022
  - [ ] Create a local mod: let the user know you can customize Letta Code with trusted local mods for new tools, slash commands, provider integrations, UI panels/status, events, or permission overlays. Explain that mods are for executable harness behavior, while memory and skills are for retained knowledge and reusable procedures.
8023
8023
  - [ ] Worktrees: let the user know that you can help them orchestrate many agents in parallel, and also work in parallel to other agents. Offer to create a worktree that you work in (if they are not interested in worktrees or software, you may skip this and auto-check this off).
8024
- - [ ] Moving machines: ask the user to add another remote environment (they can either run another desktop instance or run \`letta server\` on another machine) and run you there instead.
8024
+ - [ ] Moving machines: ask the user to connect another computer (they can either run another desktop instance or run \`letta server\` on another machine) and run you there instead.
8025
8025
  `;
8026
8026
  var init_onboarding_local = () => {};
8027
8027
 
@@ -114801,7 +114801,7 @@ function buildSubagentArgs(type3, config, model, userPrompt, existingAgentId, ex
114801
114801
  args.push("--backend", options.backendMode);
114802
114802
  }
114803
114803
  if (options.environment) {
114804
- args.push("--environment", options.environment);
114804
+ args.push("--computer", options.environment);
114805
114805
  }
114806
114806
  if (isDeployingExisting) {
114807
114807
  if (existingConversationId) {
@@ -137024,14 +137024,15 @@ var init_args = __esm(() => {
137024
137024
  description: "Inject agent-to-agent system reminder (headless mode)"
137025
137025
  }
137026
137026
  },
137027
- environment: {
137027
+ computer: {
137028
137028
  parser: { type: "string" },
137029
137029
  mode: "headless",
137030
137030
  help: {
137031
137031
  argLabel: "<selector>",
137032
- description: "Route headless message through 'cloud' sandbox or an environment by name, device ID, or connection ID"
137032
+ description: "Route headless message through 'cloud' or a computer by name, device ID, or connection ID"
137033
137033
  }
137034
137034
  },
137035
+ environment: { parser: { type: "string" }, mode: "headless" },
137035
137036
  env: { parser: { type: "string" }, mode: "headless" },
137036
137037
  skills: {
137037
137038
  parser: { type: "string" },
@@ -209602,10 +209603,10 @@ async function resolveDesktopEnvironmentConnectionId(list = listEnvironments) {
209602
209603
  const response = await list({ limit: 100, onlineOnly: true });
209603
209604
  const matches3 = response.connections.filter((environment3) => environment3.listenerInstanceId?.startsWith("desktop-direct-cloud:") === true && isEnvironmentOnline(environment3));
209604
209605
  if (matches3.length === 0) {
209605
- throw new Error("Desktop Local is unavailable. Open Letta Desktop, enable Remote Access, and wait for its environment to come online.");
209606
+ throw new Error("Desktop Local is unavailable. Open Letta Desktop, enable Remote Access, and wait for its computer connection to come online.");
209606
209607
  }
209607
209608
  if (matches3.length > 1) {
209608
- throw new Error(`Multiple Desktop environments are online. Run \`letta teleport list\` and choose one by name, device ID, or connection ID. Matched: ${matches3.map(describeEnvironment).join(", ")}`);
209609
+ throw new Error(`Multiple Desktop computers are online. Run \`letta teleport list\` and choose one by name, device ID, or connection ID. Matched: ${matches3.map(describeEnvironment).join(", ")}`);
209609
209610
  }
209610
209611
  const environment2 = matches3[0];
209611
209612
  if (!environment2?.connectionId) {
@@ -209616,28 +209617,28 @@ async function resolveDesktopEnvironmentConnectionId(list = listEnvironments) {
209616
209617
  async function resolveEnvironmentConnectionId(selector) {
209617
209618
  const trimmed = selector.trim();
209618
209619
  if (!trimmed) {
209619
- throw new Error("Environment selector must not be empty");
209620
+ throw new Error("Computer selector must not be empty");
209620
209621
  }
209621
209622
  const response = await listEnvironments({ limit: 100 });
209622
209623
  const matches3 = response.connections.filter((environment3) => {
209623
209624
  return environment3.connectionId === trimmed || environment3.id === trimmed || environment3.deviceId === trimmed || environment3.connectionName === trimmed;
209624
209625
  });
209625
209626
  if (matches3.length === 0) {
209626
- throw new Error(`Environment "${trimmed}" not found. Run \`letta environments list\` to discover available environments.`);
209627
+ throw new Error(`Computer "${trimmed}" not found. Run \`letta computers list\` to discover available computers.`);
209627
209628
  }
209628
209629
  const onlineMatches = matches3.filter(isEnvironmentOnline);
209629
209630
  if (onlineMatches.length === 0) {
209630
- throw new Error(`Environment "${trimmed}" is offline. Matched: ${matches3.map(describeEnvironment).join(", ")}`);
209631
+ throw new Error(`Computer "${trimmed}" is offline. Matched: ${matches3.map(describeEnvironment).join(", ")}`);
209631
209632
  }
209632
209633
  if (onlineMatches.length > 1) {
209633
- throw new Error(`Environment "${trimmed}" is ambiguous. Matched: ${onlineMatches.map(describeEnvironment).join(", ")}`);
209634
+ throw new Error(`Computer "${trimmed}" is ambiguous. Matched: ${onlineMatches.map(describeEnvironment).join(", ")}`);
209634
209635
  }
209635
209636
  const environment2 = onlineMatches[0];
209636
209637
  if (!environment2) {
209637
- throw new Error(`Environment "${trimmed}" is offline`);
209638
+ throw new Error(`Computer "${trimmed}" is offline`);
209638
209639
  }
209639
209640
  if (!environment2.connectionId) {
209640
- throw new Error(`Environment "${trimmed}" has no active connection id`);
209641
+ throw new Error(`Computer "${trimmed}" has no active connection id`);
209641
209642
  }
209642
209643
  return { connectionId: environment2.connectionId, environment: environment2 };
209643
209644
  }
@@ -209908,8 +209909,8 @@ Add options:
209908
209909
  the fallback when Cloud scheduling cannot
209909
209910
  reach this computer)
209910
209911
  --computer <id> (cloud runner only) Override execution with a
209911
- connected external environment (deviceId from
209912
- \`letta environments list\`). Falls back to the Cloud
209912
+ connected external computer (deviceId from
209913
+ \`letta computers list\`). Falls back to the Cloud
209913
209914
  sandbox if the computer is offline at fire time.
209914
209915
  Managed sandboxes and Desktop-local connections are
209915
209916
  not currently valid Cloud schedule targets.
@@ -210096,7 +210097,7 @@ async function handleAdd(values3) {
210096
210097
  targetDeviceId = inferredDeviceId;
210097
210098
  } else if (resolution.kind === "local-fallback") {
210098
210099
  runner = "local";
210099
- localFallbackNote = `This schedule is local to this computer (${resolution.reason}): it only fires while a Letta session is running here. For a schedule that fires regardless, pass --runner cloud (runs in the agent's cloud sandbox) or --computer <deviceId> (runs on a connected computer, from \`letta environments list\`).`;
210100
+ localFallbackNote = `This schedule is local to this computer (${resolution.reason}): it only fires while a Letta session is running here. For a schedule that fires regardless, pass --runner cloud (runs in the agent's cloud sandbox) or --computer <deviceId> (runs on a connected computer, from \`letta computers list\`).`;
210100
210101
  }
210101
210102
  }
210102
210103
  if (runner === "cloud") {
@@ -210544,25 +210545,27 @@ import { parseArgs as parseArgs6 } from "node:util";
210544
210545
  function printUsage5() {
210545
210546
  console.log(`
210546
210547
  Usage:
210547
- letta environments list [options]
210548
- letta environments current
210548
+ letta computers list [options]
210549
+ letta computers current
210549
210550
 
210550
- Aliases:
210551
+ Legacy aliases:
210552
+ letta environments list
210553
+ letta environments current
210551
210554
  letta envs list
210552
210555
  letta envs current
210553
210556
 
210554
210557
  List options:
210555
210558
  --limit <n> Max results (default: 50)
210556
- --after <id> Pagination cursor from a previous environment id
210557
- --online-only Only include environments with a fresh active connection
210559
+ --after <id> Pagination cursor from a previous computer id
210560
+ --online-only Only include computers with a fresh active connection
210558
210561
 
210559
210562
  Notes:
210560
210563
  - Output is JSON only.
210561
210564
  - Uses CLI auth; override with LETTA_API_KEY/LETTA_BASE_URL if needed.
210562
- - Use letta environments current to get this machine's connectionId.
210563
- - Use --environment cloud to route through the target agent's cloud sandbox.
210564
- - Use --environment <name|device-id|connection-id> with headless messaging
210565
- to route a message through a specific registered environment.
210565
+ - Use letta computers current to get this computer's connectionId.
210566
+ - Use --computer cloud to route through the target agent's cloud sandbox.
210567
+ - Use --computer <name|device-id|connection-id> with headless messaging
210568
+ to route a message through a specific registered computer.
210566
210569
  `.trim());
210567
210570
  }
210568
210571
  function parseLimit2(value, fallback) {
@@ -210649,7 +210652,7 @@ async function runEnvironmentsSubcommand(argv, deps = {}) {
210649
210652
  currentVersion
210650
210653
  });
210651
210654
  if (!current2) {
210652
- console.error("No online environment found for this device. Start one with `letta server` and try again.");
210655
+ console.error("No online computer found for this device. Start one with `letta server` and try again.");
210653
210656
  return 1;
210654
210657
  }
210655
210658
  console.log(JSON.stringify(formatEnvironmentForCli(current2, {
@@ -212471,7 +212474,7 @@ function ListenerStatusUI(props) {
212471
212474
  bold: true,
212472
212475
  color: "green",
212473
212476
  children: [
212474
- "The name of your environment is: ",
212477
+ "The name of your computer is: ",
212475
212478
  envName
212476
212479
  ]
212477
212480
  }, undefined, true, undefined, this)
@@ -212504,7 +212507,7 @@ function ListenerStatusUI(props) {
212504
212507
  children: /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
212505
212508
  dimColor: true,
212506
212509
  children: [
212507
- 'Connect to this environment by visiting any agent and clicking the "cloud" button at the bottom left of the messenger input and swapping your environment to ',
212510
+ 'Connect to this computer by visiting any agent and clicking the "cloud" button at the bottom left of the messenger input and swapping your computer to ',
212508
212511
  envName
212509
212512
  ]
212510
212513
  }, undefined, true, undefined, this)
@@ -393285,8 +393288,15 @@ function isChatGPTByokHandleInModels(handle2, models3) {
393285
393288
  const entry = models3.find((m4) => m4.handle === handle2);
393286
393289
  return entry?.providerType === "chatgpt_oauth" && entry?.providerCategory === "byok";
393287
393290
  }
393288
- async function resolveAgentModelHandle2(agentId) {
393291
+ async function resolveScopedModelHandle(agentId, conversationId) {
393289
393292
  try {
393293
+ if (conversationId !== "default") {
393294
+ const conversation = await getBackend().retrieveConversation(conversationId);
393295
+ const conversationRecord = conversation;
393296
+ if (typeof conversationRecord.model === "string" && conversationRecord.model.length > 0) {
393297
+ return conversationRecord.model;
393298
+ }
393299
+ }
393290
393300
  const agent = await getBackend().retrieveAgent(agentId);
393291
393301
  const record3 = agent;
393292
393302
  if (typeof record3.model === "string" && record3.model.length > 0) {
@@ -393298,7 +393308,7 @@ async function resolveAgentModelHandle2(agentId) {
393298
393308
  }
393299
393309
  }
393300
393310
  async function rotateChatGPTPlanOnQuotaLimit(params) {
393301
- const { agentId, error: error4 } = params;
393311
+ const { agentId, conversationId, error: error4, exhaustedProviders } = params;
393302
393312
  const parsedDetail = parseChatGPTUsageLimitDetail(error4);
393303
393313
  if (!parsedDetail)
393304
393314
  return null;
@@ -393313,9 +393323,9 @@ async function rotateChatGPTPlanOnQuotaLimit(params) {
393313
393323
  }
393314
393324
  if (!models3)
393315
393325
  return null;
393316
- let currentHandle = params.currentHandle;
393326
+ let currentHandle = await resolveScopedModelHandle(agentId, conversationId);
393317
393327
  if (!currentHandle || !isChatGPTByokHandleInModels(currentHandle, models3)) {
393318
- currentHandle = await resolveAgentModelHandle2(agentId);
393328
+ currentHandle = params.currentHandle;
393319
393329
  }
393320
393330
  if (!currentHandle || !isChatGPTByokHandleInModels(currentHandle, models3)) {
393321
393331
  return null;
@@ -393335,9 +393345,15 @@ async function rotateChatGPTPlanOnQuotaLimit(params) {
393335
393345
  if (!toProvider)
393336
393346
  return null;
393337
393347
  try {
393338
- await updateAgentLLMConfig(agentId, toHandle, {
393339
- provider_type: "chatgpt_oauth"
393340
- });
393348
+ if (conversationId === "default") {
393349
+ await updateAgentLLMConfig(agentId, toHandle, {
393350
+ provider_type: "chatgpt_oauth"
393351
+ });
393352
+ } else {
393353
+ await updateConversationLLMConfig(conversationId, toHandle, {
393354
+ provider_type: "chatgpt_oauth"
393355
+ });
393356
+ }
393341
393357
  } catch {
393342
393358
  return null;
393343
393359
  }
@@ -393356,14 +393372,13 @@ function formatPlanRotationNotice(params) {
393356
393372
  })})` : "";
393357
393373
  return `${fromProvider} hit its usage limit${resetSuffix} — switched to ${toProvider}`;
393358
393374
  }
393359
- var CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN = 3, exhaustedProviders;
393375
+ var CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN = 3;
393360
393376
  var init_chatgpt_plan_rotation = __esm(() => {
393361
393377
  init_available_models();
393362
393378
  init_model_handles();
393363
393379
  init_modify();
393364
393380
  init_turn_recovery_policy();
393365
393381
  init_backend2();
393366
- exhaustedProviders = new Set;
393367
393382
  });
393368
393383
 
393369
393384
  // src/websocket/listener/skill-injection.ts
@@ -404261,6 +404276,7 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
404261
404276
  const turnWorkingDirectory = getConversationWorkingDirectory(runtime.listener, agentId, conversationId);
404262
404277
  const turnPermissionModeState = getOrCreateConversationPermissionModeStateRef(runtime.listener, agentId, conversationId);
404263
404278
  let postStopApprovalRecoveryRetries = 0, llmApiErrorRetries = 0, emptyResponseRetries = 0, chatgptPlanSwaps = 0, lastApprovalContinuationAccepted = false, activeDequeuedBatchId = dequeuedBatchId;
404279
+ const chatgptExhaustedProviders = new Set;
404264
404280
  const turnCorrelation = existingTurnCorrelation ?? createTurnCorrelation(runtime, msg, activeDequeuedBatchId);
404265
404281
  const msgRunIds = [];
404266
404282
  let lastExecutionResults = null;
@@ -404627,8 +404643,10 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
404627
404643
  if (agentId && chatgptPlanSwaps < CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN) {
404628
404644
  const rotation = await rotateChatGPTPlanOnQuotaLimit({
404629
404645
  agentId,
404646
+ conversationId,
404630
404647
  currentHandle: null,
404631
- error: quotaError
404648
+ error: quotaError,
404649
+ exhaustedProviders: chatgptExhaustedProviders
404632
404650
  });
404633
404651
  if (rotation) {
404634
404652
  chatgptPlanSwaps += 1;
@@ -407651,11 +407669,11 @@ function scheduleRemoteRestart(connectionName, log2) {
407651
407669
  log2(`restart skipped (entrypoint=${entrypoint ?? "missing"}, connectionName=${connectionName ?? "missing"})`);
407652
407670
  return;
407653
407671
  }
407654
- log2(`scheduling remote listener restart for env ${connectionName}`);
407672
+ log2(`scheduling remote listener restart for computer ${connectionName}`);
407655
407673
  setTimeout(async () => {
407656
407674
  await flushRemoteSettingsWrites();
407657
- log2(`spawning replacement listener: ${process.execPath} ${entrypoint} remote --env-name ${connectionName}`);
407658
- const child = spawn9(process.execPath, [entrypoint, "remote", "--env-name", connectionName], {
407675
+ log2(`spawning replacement listener: ${process.execPath} ${entrypoint} remote --computer-name ${connectionName}`);
407676
+ const child = spawn9(process.execPath, [entrypoint, "remote", "--computer-name", connectionName], {
407659
407677
  cwd: process.cwd(),
407660
407678
  detached: true,
407661
407679
  env: process.env,
@@ -414034,7 +414052,7 @@ function PromptEnvName(props) {
414034
414052
  flexDirection: "column",
414035
414053
  children: [
414036
414054
  /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
414037
- children: "Enter environment name (or press Enter for hostname): "
414055
+ children: "Enter computer name (or press Enter for hostname): "
414038
414056
  }, undefined, false, undefined, this),
414039
414057
  /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(build_default, {
414040
414058
  value,
@@ -414111,14 +414129,14 @@ function shouldAcquireStandaloneListenerLock() {
414111
414129
  return shouldAcquireManualListenerLock(getSpawnerListenerInstanceId(), process.env.LETTA_DESKTOP_MODE === "1");
414112
414130
  }
414113
414131
  function printListenUsage() {
414114
- console.log(`Usage: letta server [--env-name <name>] [--channels <list>] [--skills <path>] [--debug]
414132
+ console.log(`Usage: letta server [--computer-name <name>] [--channels <list>] [--skills <path>] [--debug]
414115
414133
  `);
414116
- console.log(`Register this letta-code instance to receive messages from Letta Cloud.
414134
+ console.log(`Register this computer to receive messages from Letta Cloud.
414117
414135
  `);
414118
414136
  console.log("Options:");
414119
- console.log(" --env-name <name> Friendly name for this environment (uses hostname if not provided)");
414137
+ console.log(" --computer-name <name> Friendly name for this computer (uses hostname if not provided)");
414120
414138
  console.log(" --channels <list> Comma-separated channel names to enable (e.g. telegram)");
414121
- console.log(" --skills <path> Use this directory for environment-provided skills");
414139
+ console.log(" --skills <path> Use this directory for computer-provided skills");
414122
414140
  console.log(" --install-channel-runtimes Install missing runtime deps for the selected channels before startup");
414123
414141
  console.log(" --debug Plain-text mode: log all WebSocket events instead of interactive UI");
414124
414142
  console.log(` -h, --help Show this help message
@@ -414126,13 +414144,13 @@ function printListenUsage() {
414126
414144
  console.log("Examples:");
414127
414145
  console.log(" letta channels configure telegram # Configure Telegram first");
414128
414146
  console.log(" letta server # Uses hostname as default");
414129
- console.log(' letta server --env-name "work-laptop"');
414147
+ console.log(' letta server --computer-name "work-laptop"');
414130
414148
  console.log(" letta server --channels telegram # Enable Telegram channel");
414131
414149
  console.log(" letta server --channels telegram --install-channel-runtimes");
414132
414150
  console.log(` letta server --debug # Log all WS events
414133
414151
  `);
414134
414152
  console.log("Once connected, this instance will listen for incoming messages from cloud agents.");
414135
- console.log("Messages will be executed locally using your letta-code environment.");
414153
+ console.log("Messages will be executed locally on this computer.");
414136
414154
  console.log("Telegram flow: configure the bot, start the listener with --channels telegram,");
414137
414155
  console.log("then message the bot from Telegram and run /channels telegram pair <code> in the target conversation.");
414138
414156
  }
@@ -414221,8 +414239,9 @@ async function runListenSubcommand(argv) {
414221
414239
  const restoreAgentScope = restoreEnabledChannels ? resolveChannelRestoreAgentScope(scopedRestoreAgentScope) : null;
414222
414240
  const channelNames = values3.channels ? values3.channels.split(",").map((s3) => s3.trim()).filter(Boolean) : [];
414223
414241
  let connectionName;
414224
- if (values3["env-name"]) {
414225
- connectionName = values3["env-name"];
414242
+ const explicitComputerName = values3["computer-name"] ?? values3["env-name"];
414243
+ if (explicitComputerName) {
414244
+ connectionName = explicitComputerName;
414226
414245
  settingsManager.setListenerEnvName(connectionName);
414227
414246
  } else {
414228
414247
  const savedName = settingsManager.getListenerEnvName();
@@ -414251,7 +414270,7 @@ async function runListenSubcommand(argv) {
414251
414270
  const startupMode = await resolveListenerStartupMode(channelNames, channelNames.length > 0 || restoreEnabledChannels);
414252
414271
  if (startupMode.kind === "unsupported-self-hosted") {
414253
414272
  console.error(`Self-hosted listener registration is not available for ${startupMode.serverUrl}.`);
414254
- console.error("Start with --channels to run local channel adapters, or unset LETTA_BASE_URL to use Letta API remote environments.");
414273
+ console.error("Start with --channels to run local channel adapters, or unset LETTA_BASE_URL to use Letta API remote computers.");
414255
414274
  await flushListenerTelemetryEnd("listener_self_hosted_no_channels");
414256
414275
  return 1;
414257
414276
  }
@@ -414283,8 +414302,8 @@ async function runListenSubcommand(argv) {
414283
414302
  });
414284
414303
  } catch (lockError) {
414285
414304
  if (lockError instanceof ManualListenerAlreadyRunningError) {
414286
- console.error(`A letta server for environment "${connectionName}" is already running on this machine (pid ${lockError.holderPid}).`);
414287
- console.error("Stop that process, or choose a different logical listener with --env-name.");
414305
+ console.error(`A letta server for computer "${connectionName}" is already running on this machine (pid ${lockError.holderPid}).`);
414306
+ console.error("Stop that process, or choose a different logical listener with --computer-name.");
414288
414307
  console.error(`Lock: ${lockError.lockPath}`);
414289
414308
  await flushListenerTelemetryEnd("listener_already_running");
414290
414309
  return 1;
@@ -414373,9 +414392,9 @@ async function runListenSubcommand(argv) {
414373
414392
  const connectionId2 = `local-${deviceId}`;
414374
414393
  const startupLabel = startupMode.backend === "local" ? "local backend" : `self-hosted server ${startupMode.serverUrl}`;
414375
414394
  sessionLog.log(`Starting local channel listener for ${startupLabel}`);
414376
- sessionLog.log("Skipping environment registration");
414395
+ sessionLog.log("Skipping computer registration");
414377
414396
  console.log(`Starting local channel listener for ${startupLabel}`);
414378
- console.log(`Skipping environment registration. Press Ctrl+C to stop.
414397
+ console.log(`Skipping computer registration. Press Ctrl+C to stop.
414379
414398
  `);
414380
414399
  const { startLocalChannelListener: startLocalChannelListener2 } = await init_listen_client().then(() => exports_listen_client);
414381
414400
  await startLocalChannelListener2({
@@ -414497,7 +414516,7 @@ async function runListenSubcommand(argv) {
414497
414516
  console.log(`[${formatTimestamp3()}] Reconnecting (attempt ${attempt2}, retry in ${Math.round(nextRetryIn / 1000)}s)`);
414498
414517
  },
414499
414518
  onNeedsReregister: async () => {
414500
- console.log(`[${formatTimestamp3()}] Environment expired, re-registering...`);
414519
+ console.log(`[${formatTimestamp3()}] Computer connection expired, re-registering...`);
414501
414520
  try {
414502
414521
  const result2 = await reregister();
414503
414522
  await startDebugClient(result2.connectionId, result2.wsUrl, result2.supportsSplitStatusChannels, result2.supportsPairedListenerGenerations);
@@ -414565,7 +414584,7 @@ async function runListenSubcommand(argv) {
414565
414584
  updateRetryStatusCallback?.(attempt2, nextRetryIn);
414566
414585
  },
414567
414586
  onNeedsReregister: async () => {
414568
- sessionLog.log("Environment expired, re-registering...");
414587
+ sessionLog.log("Computer connection expired, re-registering...");
414569
414588
  try {
414570
414589
  const result2 = await reregister();
414571
414590
  await startNormalClient(result2.connectionId, result2.wsUrl, result2.supportsSplitStatusChannels, result2.supportsPairedListenerGenerations);
@@ -414634,6 +414653,7 @@ var init_listen = __esm(async () => {
414634
414653
  jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
414635
414654
  activeListenerProcessAnchors = new Set;
414636
414655
  LISTEN_OPTIONS = {
414656
+ "computer-name": { type: "string" },
414637
414657
  "env-name": { type: "string" },
414638
414658
  channels: { type: "string" },
414639
414659
  skills: { type: "string" },
@@ -431950,7 +431970,7 @@ var init_mcp_client = __esm(() => {
431950
431970
  init_streamableHttp();
431951
431971
  DEFAULT_CLIENT_INFO = {
431952
431972
  name: "letta-code",
431953
- version: "0.31.11"
431973
+ version: "0.31.12"
431954
431974
  };
431955
431975
  });
431956
431976
 
@@ -432238,7 +432258,6 @@ async function replaceClientMcpServers(agentId, configs, options = {}) {
432238
432258
  const generation2 = ++runtime.generation;
432239
432259
  await closeActiveServers(runtime);
432240
432260
  runtime.agentId = agentId;
432241
- const usedToolNames = new Set;
432242
432261
  const states2 = await Promise.all(configs.map(async (config2) => {
432243
432262
  let oauth;
432244
432263
  try {
@@ -432257,20 +432276,8 @@ async function replaceClientMcpServers(agentId, configs, options = {}) {
432257
432276
  await connection.close();
432258
432277
  return { config: config2, status: "failed", tools: [], error: "Superseded" };
432259
432278
  }
432260
- const tools = connection.tools.map((tool) => {
432261
- const name = uniqueToolName(formatClientMcpToolName(config2.name, tool.name), usedToolNames);
432262
- const definition = {
432263
- name,
432264
- label: tool.title ?? tool.name,
432265
- description: tool.description ?? `Tool ${tool.name} from MCP server ${config2.name}`,
432266
- parameters: tool.inputSchema,
432267
- executor: async (_toolCallId, _toolName, input) => toExternalToolResult(await connection.callTool(tool.name, input))
432268
- };
432269
- return definition;
432270
- });
432271
- registerExternalTools(tools);
432272
- runtime.active.set(config2.name, { connection, tools });
432273
- return { config: config2, status: "connected", tools };
432279
+ runtime.active.set(config2.name, { connection });
432280
+ return { config: config2, status: "connected", tools: connection.tools };
432274
432281
  } catch (error5) {
432275
432282
  return {
432276
432283
  config: config2,
@@ -432318,23 +432325,11 @@ async function closeActiveServers(runtime) {
432318
432325
  runtime.pendingOAuth.clear();
432319
432326
  runtime.active.clear();
432320
432327
  runtime.states = [];
432321
- for (const server2 of active)
432322
- unregisterExternalTools(server2.tools);
432323
432328
  await Promise.allSettled([
432324
432329
  ...pendingOAuth.map((oauth) => oauth.close()),
432325
432330
  ...active.map((server2) => server2.connection.close())
432326
432331
  ]);
432327
432332
  }
432328
- function uniqueToolName(base2, used) {
432329
- let name = base2;
432330
- let suffix = 2;
432331
- while (used.has(name)) {
432332
- name = `${base2}_${suffix}`;
432333
- suffix++;
432334
- }
432335
- used.add(name);
432336
- return name;
432337
- }
432338
432333
  function formatClientMcpToolName(serverName, toolName) {
432339
432334
  return `mcp__${normalizeMcpName(serverName)}__${normalizeMcpName(toolName)}`;
432340
432335
  }
@@ -432342,35 +432337,10 @@ function normalizeMcpName(value) {
432342
432337
  const normalized = value.replace(/[^a-zA-Z0-9_-]/g, "_");
432343
432338
  return normalized || "tool";
432344
432339
  }
432345
- function toExternalToolResult(result2) {
432346
- return {
432347
- content: result2.content.map((item) => normalizeContent2(item)),
432348
- isError: result2.isError === true
432349
- };
432350
- }
432351
- function normalizeContent2(item) {
432352
- if (isRecord17(item)) {
432353
- if (item.type === "text" && typeof item.text === "string") {
432354
- return { type: "text", text: item.text };
432355
- }
432356
- if ((item.type === "image" || item.type === "audio") && typeof item.data === "string") {
432357
- return {
432358
- type: item.type,
432359
- data: item.data,
432360
- ...typeof item.mimeType === "string" ? { mimeType: item.mimeType } : {}
432361
- };
432362
- }
432363
- }
432364
- return { type: "text", text: JSON.stringify(item) };
432365
- }
432366
- function isRecord17(value) {
432367
- return typeof value === "object" && value !== null && !Array.isArray(value);
432368
- }
432369
432340
  var CLIENT_MCP_RUNTIME_KEY;
432370
- var init_mcp_runtime = __esm(async () => {
432341
+ var init_mcp_runtime = __esm(() => {
432371
432342
  init_mcp_client();
432372
432343
  init_mcp_oauth();
432373
- await init_manager4();
432374
432344
  CLIENT_MCP_RUNTIME_KEY = Symbol.for("@letta/clientMcpRuntime");
432375
432345
  });
432376
432346
 
@@ -432611,8 +432581,8 @@ function formatServerMcpToolName(serverName, alias, toolName) {
432611
432581
  const rawName = toolName.startsWith(sourcePrefix) ? toolName.slice(sourcePrefix.length) : toolName;
432612
432582
  return formatClientMcpToolName(alias, rawName);
432613
432583
  }
432614
- var init_mcp_tool_names = __esm(async () => {
432615
- await init_mcp_runtime();
432584
+ var init_mcp_tool_names = __esm(() => {
432585
+ init_mcp_runtime();
432616
432586
  });
432617
432587
 
432618
432588
  // src/cli/subcommands/mcp.ts
@@ -433139,7 +433109,7 @@ async function runMcpSubcommand(argv, deps = {}) {
433139
433109
  }
433140
433110
  }
433141
433111
  var SENSITIVE_NAME;
433142
- var init_mcp = __esm(async () => {
433112
+ var init_mcp = __esm(() => {
433143
433113
  init_oauth();
433144
433114
  init_backend2();
433145
433115
  init_client2();
@@ -433147,13 +433117,11 @@ var init_mcp = __esm(async () => {
433147
433117
  init_unified_mcp();
433148
433118
  init_mcp_client();
433149
433119
  init_mcp_oauth();
433120
+ init_mcp_runtime();
433150
433121
  init_settings_manager();
433151
433122
  init_mcp_io();
433152
433123
  init_mcp_search();
433153
- await __promiseAll([
433154
- init_mcp_runtime(),
433155
- init_mcp_tool_names()
433156
- ]);
433124
+ init_mcp_tool_names();
433157
433125
  SENSITIVE_NAME = /token|key|secret|password|signature|credential|auth/i;
433158
433126
  });
433159
433127
 
@@ -434234,7 +434202,7 @@ import {
434234
434202
  } from "node:fs";
434235
434203
  import { tmpdir as tmpdir10 } from "node:os";
434236
434204
  import path46 from "node:path";
434237
- function isRecord18(value) {
434205
+ function isRecord17(value) {
434238
434206
  return typeof value === "object" && value !== null && !Array.isArray(value);
434239
434207
  }
434240
434208
  function isPathInsideOrEqual2(childPath, parentPath) {
@@ -434250,7 +434218,7 @@ function readPackageJson(packageJsonPath) {
434250
434218
  } catch (error5) {
434251
434219
  throw new Error(`Could not read package.json: ${error5 instanceof Error ? error5.message : String(error5)}`);
434252
434220
  }
434253
- if (!isRecord18(parsed)) {
434221
+ if (!isRecord17(parsed)) {
434254
434222
  throw new Error("package.json must be an object");
434255
434223
  }
434256
434224
  return parsed;
@@ -434260,7 +434228,7 @@ function formatRepository(repository) {
434260
434228
  const trimmed2 = repository.trim();
434261
434229
  return trimmed2 || undefined;
434262
434230
  }
434263
- if (!isRecord18(repository))
434231
+ if (!isRecord17(repository))
434264
434232
  return;
434265
434233
  const url2 = repository.url;
434266
434234
  if (typeof url2 !== "string")
@@ -434790,7 +434758,7 @@ function hasRuntimeDependencies(packageJson) {
434790
434758
  if (!packageJson)
434791
434759
  return false;
434792
434760
  const dependencies4 = packageJson.dependencies;
434793
- return isRecord18(dependencies4) && Object.keys(dependencies4).length > 0;
434761
+ return isRecord17(dependencies4) && Object.keys(dependencies4).length > 0;
434794
434762
  }
434795
434763
  function readPackageJsonIfExists(packageDirectory) {
434796
434764
  const packageJsonPath = path46.join(packageDirectory, "package.json");
@@ -436028,10 +435996,10 @@ function printServerHelp() {
436028
435996
  letta server [remote options]
436029
435997
  letta server --listen [url] [App Server options]
436030
435998
 
436031
- Run the local agent server as a remote environment, with messaging channels, or as an App Server.
435999
+ Run the local agent server as a remote computer, with messaging channels, or as an App Server.
436032
436000
 
436033
- Remote environment options:
436034
- --env-name <name> Friendly name for this environment (uses hostname if not provided)
436001
+ Remote computer options:
436002
+ --computer-name <name> Friendly name for this computer (uses hostname if not provided)
436035
436003
  --channels <list> Comma-separated channel names to enable (e.g. telegram)
436036
436004
  --install-channel-runtimes Install missing runtime dependencies for selected channels
436037
436005
  --debug Log WebSocket events instead of showing the interactive status UI
@@ -436052,7 +436020,7 @@ Common options:
436052
436020
 
436053
436021
  Examples:
436054
436022
  letta server
436055
- letta server --env-name "work-laptop"
436023
+ letta server --computer-name "work-laptop"
436056
436024
  letta server --channels telegram
436057
436025
  letta server --listen
436058
436026
  letta server --listen ws://127.0.0.1:4500
@@ -436091,7 +436059,7 @@ function resolveServerCommand(argv) {
436091
436059
  }
436092
436060
  }
436093
436061
  if (foundListen) {
436094
- const conflictingOption = argv.find((arg) => arg === "--env-name" || arg.startsWith("--env-name=") || arg === "--channels" || arg.startsWith("--channels="));
436062
+ const conflictingOption = argv.find((arg) => arg === "--computer-name" || arg.startsWith("--computer-name=") || arg === "--env-name" || arg.startsWith("--env-name=") || arg === "--channels" || arg.startsWith("--channels="));
436095
436063
  if (conflictingOption) {
436096
436064
  throw new Error(`${conflictingOption.split("=")[0]} cannot be used with --listen`);
436097
436065
  }
@@ -439192,19 +439160,19 @@ Usage:
439192
439160
  letta teleport list
439193
439161
  letta teleport cloud
439194
439162
  letta teleport local
439195
- letta teleport <environment>
439163
+ letta teleport <computer>
439196
439164
 
439197
439165
  Notes:
439198
439166
  - Operates on the current agent/conversation from LETTA_AGENT_ID /
439199
439167
  LETTA_CONVERSATION_ID (or AGENT_ID / CONVERSATION_ID), falling back to the
439200
439168
  last active session.
439201
439169
  - Requires a Letta Cloud agent and an active conversation.
439202
- - list: prints accessible online remote environments as JSON.
439170
+ - list: prints accessible online remote computers as JSON.
439203
439171
  - cloud: teleports to the agent's Cloud sandbox.
439204
- - local: teleports to the one online Desktop environment. Desktop Remote
439172
+ - local: teleports to the one online Desktop computer. Desktop Remote
439205
439173
  Access must be enabled; if several are online, choose one explicitly.
439206
- - <environment>: teleports to a specific remote environment by name,
439207
- device-id, connection-id, or environment id.
439174
+ - <computer>: teleports to a specific remote computer by name,
439175
+ device-id, connection-id, or computer id.
439208
439176
  - Output is JSON only.
439209
439177
  `.trim());
439210
439178
  }
@@ -439269,7 +439237,7 @@ function isTeleportableRemoteEnvironment(environment2) {
439269
439237
  }
439270
439238
  function assertTeleportableRemoteEnvironment(environment2) {
439271
439239
  if (!isTeleportableRemoteEnvironment(environment2)) {
439272
- throw new Error("The Desktop-local connection is not Cloud-routable. Use `letta teleport local` to resolve its Remote Access environment.");
439240
+ throw new Error("The Desktop-local connection is not Cloud-routable. Use `letta teleport local` to resolve its Remote Access computer.");
439273
439241
  }
439274
439242
  }
439275
439243
  async function initializeTeleportSettings() {
@@ -439312,7 +439280,7 @@ async function runTeleportSubcommand(argv, deps = {}) {
439312
439280
  const result3 = await resolve38();
439313
439281
  targetConnectionId = result3.connectionId;
439314
439282
  } else if (action3 === "back") {
439315
- throw new Error("Teleport back is not supported. Use `letta teleport local` or choose an explicit environment.");
439283
+ throw new Error("Teleport back is not supported. Use `letta teleport local` or choose an explicit computer.");
439316
439284
  } else {
439317
439285
  const resolve38 = deps.resolveEnvironmentConnectionId ?? resolveEnvironmentConnectionId;
439318
439286
  const resolved = await resolve38(action3);
@@ -444885,6 +444853,7 @@ function subcommandNeedsEarlyBackendMode(command) {
444885
444853
  case "channel-gateway":
444886
444854
  case "agents":
444887
444855
  case "connect":
444856
+ case "computers":
444888
444857
  case "environments":
444889
444858
  case "envs":
444890
444859
  case "feedback":
@@ -444929,6 +444898,7 @@ async function runSubcommand(argv) {
444929
444898
  return runMessagesSubcommand(rest4);
444930
444899
  case "mcp":
444931
444900
  return runMcpSubcommand(rest4);
444901
+ case "computers":
444932
444902
  case "environments":
444933
444903
  case "envs":
444934
444904
  return runEnvironmentsSubcommand(rest4);
@@ -444983,6 +444953,7 @@ var init_router = __esm(async () => {
444983
444953
  init_environments3();
444984
444954
  init_feedback3();
444985
444955
  init_local_backend2();
444956
+ init_mcp();
444986
444957
  init_memory7();
444987
444958
  init_messages10();
444988
444959
  init_sandbox2();
@@ -444994,7 +444965,6 @@ var init_router = __esm(async () => {
444994
444965
  await __promiseAll([
444995
444966
  init_cron2(),
444996
444967
  init_listen(),
444997
- init_mcp(),
444998
444968
  init_mods(),
444999
444969
  init_server(),
445000
444970
  init_setup7()
@@ -447156,7 +447126,7 @@ function getEnvironmentRoutedMessagingUnsupportedReason(environment2) {
447156
447126
  if (environment2.metadata?.environmentMessageProtocol === "v2-input") {
447157
447127
  return null;
447158
447128
  }
447159
- return `Environment ${environment2.connectionName} (${environment2.deviceId}) is running Letta Code ${environment2.metadata?.lettaCodeVersion ?? "unknown"} and does not advertise environment-routed headless messaging support. Update that runtime or omit --environment to use same-environment messaging.`;
447129
+ return `Computer ${environment2.connectionName} (${environment2.deviceId}) is running Letta Code ${environment2.metadata?.lettaCodeVersion ?? "unknown"} and does not advertise computer-routed headless messaging support. Update that runtime or omit --computer to use same-computer messaging.`;
447160
447130
  }
447161
447131
  async function handleHeadlessCommand(parsedArgs, model, skillsDirectoryOverride, skillSourcesOverride, systemInfoReminderEnabledOverride, startupOptions = {}) {
447162
447132
  const { values: values3, positionals } = parsedArgs;
@@ -447229,7 +447199,7 @@ In headless mode, use:
447229
447199
  }
447230
447200
  let forceNewConversation = values3.new ?? false;
447231
447201
  const fromAgentId = values3["from-agent"];
447232
- const explicitEnvironmentSelector = values3.environment || values3.env;
447202
+ const explicitEnvironmentSelector = values3.computer ?? values3.environment ?? values3.env;
447233
447203
  const usesRemoteEnvironment = typeof explicitEnvironmentSelector === "string" && explicitEnvironmentSelector.trim().length > 0;
447234
447204
  let agent = null;
447235
447205
  let ephemeralConversationId = null;
@@ -447597,9 +447567,6 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
447597
447567
  markMilestone("HEADLESS_AGENT_RESOLVED");
447598
447568
  const publicAgentId = ephemeralFlag ? null : agent.id;
447599
447569
  telemetry.setCurrentAgent(publicAgentId, agent.tags);
447600
- if (!ephemeralFlag) {
447601
- await replaceClientMcpServers(agent.id, settingsManager.getMcpServers(agent.id), { stderr: "pipe" });
447602
- }
447603
447570
  const isResumingAgent = !ephemeralFlag && !!(specifiedAgentId || !forceNew && !fromAfFile);
447604
447571
  if (isResumingAgent) {
447605
447572
  if (model) {
@@ -447788,7 +447755,7 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
447788
447755
  process.exit(1);
447789
447756
  }
447790
447757
  if (usesRemoteEnvironment && isBidirectionalMode) {
447791
- console.error("Error: remote environment routing cannot be used with --input-format stream-json");
447758
+ console.error("Error: remote computer routing cannot be used with --input-format stream-json");
447792
447759
  process.exit(1);
447793
447760
  }
447794
447761
  const sessionStats = new SessionStats;
@@ -448225,6 +448192,7 @@ ${loadedContents.join(`
448225
448192
  let emptyResponseRetries = 0;
448226
448193
  let conversationBusyRetries = 0;
448227
448194
  let chatgptPlanSwaps = 0;
448195
+ const chatgptExhaustedProviders = new Set;
448228
448196
  markMilestone("HEADLESS_FIRST_STREAM_START");
448229
448197
  measureSinceMilestone("headless-setup-total", "HEADLESS_CLIENT_READY");
448230
448198
  const checkMaxTurns = async () => {
@@ -448492,6 +448460,7 @@ ${loadedContents.join(`
448492
448460
  emptyResponseRetries = 0;
448493
448461
  conversationBusyRetries = 0;
448494
448462
  chatgptPlanSwaps = 0;
448463
+ chatgptExhaustedProviders.clear();
448495
448464
  const continueMessage = await emitHeadlessTurnEnd({
448496
448465
  agent,
448497
448466
  conversationId,
@@ -448595,8 +448564,10 @@ ${loadedContents.join(`
448595
448564
  if (chatgptPlanSwaps < CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN) {
448596
448565
  const rotation = await rotateChatGPTPlanOnQuotaLimit({
448597
448566
  agentId: agent.id,
448567
+ conversationId,
448598
448568
  currentHandle: null,
448599
- error: runErrorInfo2 ?? detailFromRun ?? latestErrorText
448569
+ error: runErrorInfo2 ?? detailFromRun ?? latestErrorText,
448570
+ exhaustedProviders: chatgptExhaustedProviders
448600
448571
  });
448601
448572
  if (rotation) {
448602
448573
  chatgptPlanSwaps += 1;
@@ -450012,6 +449983,7 @@ var init_headless = __esm(async () => {
450012
449983
  init_headless_environment_response();
450013
449984
  init_headless_reflection_settings();
450014
449985
  init_diff_preview();
449986
+ init_mcp_runtime();
450015
449987
  init_format_denial();
450016
449988
  init_startup();
450017
449989
  init_queue_runtime();
@@ -450030,7 +450002,6 @@ var init_headless = __esm(async () => {
450030
450002
  init_headless_ephemeral_startup(),
450031
450003
  init_headless_mod_adapter(),
450032
450004
  init_headless_tool_events(),
450033
- init_mcp_runtime(),
450034
450005
  init_manager4(),
450035
450006
  init_toolset()
450036
450007
  ]);
@@ -465913,11 +465884,11 @@ var init_McpSelector = __esm(async () => {
465913
465884
  init_truncate_text();
465914
465885
  init_use_terminal_width();
465915
465886
  init_mcp_oauth();
465887
+ init_mcp_runtime();
465916
465888
  init_settings_manager();
465917
465889
  init_colors();
465918
465890
  await __promiseAll([
465919
465891
  init_build4(),
465920
- init_mcp_runtime(),
465921
465892
  init_Text2()
465922
465893
  ]);
465923
465894
  import_react87 = __toESM(require_react(), 1);
@@ -466219,7 +466190,7 @@ var init_McpSelector = __esm(async () => {
466219
466190
  flexDirection: "column",
466220
466191
  children: [
466221
466192
  /* @__PURE__ */ jsx_dev_runtime64.jsxDEV(Text2, {
466222
- children: tool.label ?? tool.name
466193
+ children: tool.title ?? tool.name
466223
466194
  }, undefined, false, undefined, this),
466224
466195
  /* @__PURE__ */ jsx_dev_runtime64.jsxDEV(Text2, {
466225
466196
  dimColor: true,
@@ -466229,7 +466200,7 @@ var init_McpSelector = __esm(async () => {
466229
466200
  ]
466230
466201
  }, undefined, true, undefined, this)
466231
466202
  ]
466232
- }, tool.registrationKey ?? tool.name, true, undefined, this)),
466203
+ }, tool.name, true, undefined, this)),
466233
466204
  /* @__PURE__ */ jsx_dev_runtime64.jsxDEV(Box_default, {
466234
466205
  marginTop: 1,
466235
466206
  children: /* @__PURE__ */ jsx_dev_runtime64.jsxDEV(Text2, {
@@ -493860,20 +493831,20 @@ var init_session3 = __esm(() => {
493860
493831
  });
493861
493832
 
493862
493833
  // src/cli/app/use-agent-mcp-servers.ts
493863
- function useAgentMcpServers(agentId) {
493834
+ function useMcpCleanup(agentId) {
493835
+ const previousAgentId = import_react110.useRef(agentId);
493864
493836
  import_react110.useEffect(() => {
493865
- const refresh = agentId ? replaceClientMcpServers(agentId, settingsManager.getMcpServers(agentId)) : closeClientMcpServers();
493866
- refresh.catch((error5) => debugWarn("mcp", `Failed to switch agent MCP servers: ${String(error5)}`));
493837
+ if (previousAgentId.current === agentId)
493838
+ return;
493839
+ previousAgentId.current = agentId;
493840
+ closeClientMcpServers().catch((error5) => debugWarn("mcp", `Failed to close client MCP servers: ${String(error5)}`));
493867
493841
  }, [agentId]);
493868
493842
  }
493869
493843
  var import_react110;
493870
- var init_use_agent_mcp_servers = __esm(async () => {
493871
- init_settings_manager();
493844
+ var init_use_agent_mcp_servers = __esm(() => {
493845
+ init_mcp_runtime();
493846
+ init_mcp_runtime();
493872
493847
  init_debug();
493873
- await __promiseAll([
493874
- init_mcp_runtime(),
493875
- init_mcp_runtime()
493876
- ]);
493877
493848
  import_react110 = __toESM(require_react(), 1);
493878
493849
  });
493879
493850
 
@@ -495863,6 +495834,7 @@ function useConversationLoop(ctx) {
495863
495834
  clearApprovalToolContext,
495864
495835
  closeTrajectorySegment,
495865
495836
  chatgptPlanSwapsRef,
495837
+ chatgptExhaustedProvidersRef,
495866
495838
  consumeQueuedMessages,
495867
495839
  queueModeRef,
495868
495840
  contextTrackerRef,
@@ -496095,6 +496067,7 @@ function useConversationLoop(ctx) {
496095
496067
  conversationBusyRetriesRef.current = 0;
496096
496068
  quotaAutoSwapAttemptedRef.current = false;
496097
496069
  chatgptPlanSwapsRef.current = 0;
496070
+ chatgptExhaustedProvidersRef.current.clear();
496098
496071
  }
496099
496072
  let currentRunId;
496100
496073
  let preserveTranscriptStartForApproval = false;
@@ -497062,8 +497035,10 @@ ${feedback}
497062
497035
  if (chatgptPlanSwapsRef.current < CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN) {
497063
497036
  const rotation = await rotateChatGPTPlanOnQuotaLimit({
497064
497037
  agentId: agentIdRef.current,
497038
+ conversationId: conversationIdRef.current,
497065
497039
  currentHandle: currentModelId,
497066
- error: runErrorInfo2 ?? detailFromRun ?? fallbackError
497040
+ error: runErrorInfo2 ?? detailFromRun ?? fallbackError,
497041
+ exhaustedProviders: chatgptExhaustedProvidersRef.current
497067
497042
  });
497068
497043
  if (rotation) {
497069
497044
  chatgptPlanSwapsRef.current += 1;
@@ -501399,10 +501374,10 @@ function mcpHelpText() {
501399
501374
  `);
501400
501375
  }
501401
501376
  var activeCommandId2 = null;
501402
- var init_mcp2 = __esm(async () => {
501377
+ var init_mcp2 = __esm(() => {
501403
501378
  init_error_formatter();
501379
+ init_mcp_runtime();
501404
501380
  init_settings_manager();
501405
- await init_mcp_runtime();
501406
501381
  });
501407
501382
 
501408
501383
  // src/cli/commands/listen.ts
@@ -501465,24 +501440,24 @@ Listener disconnected from Letta Cloud.`, true);
501465
501440
  return;
501466
501441
  }
501467
501442
  if (msg.includes("--help") || msg.includes("-h")) {
501468
- addCommandResult3(ctx.buffersRef, ctx.refreshDerived, msg, `Usage: /server [--env-name <name>]
501443
+ addCommandResult3(ctx.buffersRef, ctx.refreshDerived, msg, `Usage: /server [--computer-name <name>]
501469
501444
  /server off
501470
501445
 
501471
- Register this letta-code instance to receive messages from Letta Cloud.
501446
+ Register this computer to receive messages from Letta Cloud.
501472
501447
  Alias: /remote
501473
501448
 
501474
501449
  Options:
501475
- --env-name <name> Friendly name for this environment (uses hostname if not provided)
501450
+ --computer-name <name> Friendly name for this computer (uses hostname if not provided)
501476
501451
  off Stop the active listener connection
501477
501452
  -h, --help Show this help message
501478
501453
 
501479
501454
  Examples:
501480
501455
  /server # Start listener with hostname
501481
- /server --env-name "work-laptop" # Start with custom name
501456
+ /server --computer-name "work-laptop" # Start with custom name
501482
501457
  /server off # Stop listening
501483
501458
 
501484
501459
  Once connected, this instance will listen for incoming messages from cloud agents.
501485
- Messages will be executed locally using your letta-code environment.`, true);
501460
+ Messages will be executed locally on this computer.`, true);
501486
501461
  return;
501487
501462
  }
501488
501463
  let connectionName;
@@ -501532,7 +501507,7 @@ Retry ${attempt2} in ${Math.round(delayMs / 1000)}s: ${error5.message}`, true, "
501532
501507
  updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `✓ Registered successfully!
501533
501508
 
501534
501509
  ` + `Connection ID: ${connectionId}
501535
- Environment: "${connectionName}"
501510
+ Computer: "${connectionName}"
501536
501511
  WebSocket: ${wsUrl}
501537
501512
 
501538
501513
  Starting WebSocket connection...`, true, "running");
@@ -501550,18 +501525,18 @@ Starting WebSocket connection...`, true, "running");
501550
501525
  const url2 = buildConnectionUrl(id2);
501551
501526
  const urlText = url2 ? `
501552
501527
 
501553
- Connect to this environment:
501528
+ Connect to this computer:
501554
501529
  ${url2}` : "";
501555
- updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment initialized: ${connectionName}
501530
+ updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Computer initialized: ${connectionName}
501556
501531
  ${statusText}${urlText}`, true, "finished");
501557
501532
  },
501558
501533
  onRetrying: (attempt2, _maxAttempts, nextRetryIn, id2) => {
501559
501534
  const url2 = buildConnectionUrl(id2);
501560
501535
  const urlText = url2 ? `
501561
501536
 
501562
- Connect to this environment:
501537
+ Connect to this computer:
501563
501538
  ${url2}` : "";
501564
- updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment initialized: ${connectionName}
501539
+ updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Computer initialized: ${connectionName}
501565
501540
  Reconnecting to Letta Cloud...
501566
501541
  Attempt ${attempt2}, retrying in ${Math.round(nextRetryIn / 1000)}s${urlText}`, true, "running");
501567
501542
  },
@@ -501569,14 +501544,14 @@ Attempt ${attempt2}, retrying in ${Math.round(nextRetryIn / 1000)}s${urlText}`,
501569
501544
  const url2 = buildConnectionUrl(id2);
501570
501545
  const urlText = url2 ? `
501571
501546
 
501572
- Connect to this environment:
501547
+ Connect to this computer:
501573
501548
  ${url2}` : "";
501574
- updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment initialized: ${connectionName}
501549
+ updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Computer initialized: ${connectionName}
501575
501550
  Awaiting instructions${urlText}`, true, "finished");
501576
501551
  ctx.setCommandRunning(false);
501577
501552
  },
501578
501553
  onNeedsReregister: async () => {
501579
- updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment expired, re-registering "${connectionName}"...`, true, "running");
501554
+ updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Computer connection expired, re-registering "${connectionName}"...`, true, "running");
501580
501555
  try {
501581
501556
  const nextRegisterOptions = await resolveRegisterOptions();
501582
501557
  const reregisterResult = await registerWithCloudRetry(nextRegisterOptions, {
@@ -501702,7 +501677,7 @@ async function handleConnectionCommand(msg, trimmed, ctx) {
501702
501677
  for (let i4 = 1;i4 < parts.length; i4++) {
501703
501678
  const part = parts[i4];
501704
501679
  const nextPart = parts[i4 + 1];
501705
- if (part === "--env-name" && nextPart) {
501680
+ if ((part === "--computer-name" || part === "--env-name") && nextPart) {
501706
501681
  name = nextPart;
501707
501682
  i4++;
501708
501683
  }
@@ -501725,8 +501700,8 @@ async function handleConnectionCommand(msg, trimmed, ctx) {
501725
501700
  }
501726
501701
  return null;
501727
501702
  }
501728
- var init_submit_connection_commands = __esm(async () => {
501729
- await init_mcp2();
501703
+ var init_submit_connection_commands = __esm(() => {
501704
+ init_mcp2();
501730
501705
  });
501731
501706
 
501732
501707
  // src/cli/helpers/context-chart.ts
@@ -505508,6 +505483,7 @@ var init_use_submit_handler = __esm(async () => {
505508
505483
  init_command_routing();
505509
505484
  init_ids();
505510
505485
  init_session3();
505486
+ init_submit_connection_commands();
505511
505487
  init_submit_diagnostics_commands();
505512
505488
  init_submit_profile_commands();
505513
505489
  await __promiseAll([
@@ -505515,7 +505491,6 @@ var init_use_submit_handler = __esm(async () => {
505515
505491
  init_mods2(),
505516
505492
  init_PinDialog(),
505517
505493
  init_accumulator(),
505518
- init_submit_connection_commands(),
505519
505494
  init_submit_navigation_commands()
505520
505495
  ]);
505521
505496
  import_react120 = __toESM(require_react(), 1);
@@ -506211,6 +506186,7 @@ function App2({
506211
506186
  const quotaAutoSwapAttemptedRef = import_react121.useRef(false);
506212
506187
  const emptyResponseRetriesRef = import_react121.useRef(0);
506213
506188
  const chatgptPlanSwapsRef = import_react121.useRef(0);
506189
+ const chatgptExhaustedProvidersRef = import_react121.useRef(new Set);
506214
506190
  const conversationBusyRetriesRef = import_react121.useRef(0);
506215
506191
  const [queueDisplay, setQueueDisplay] = import_react121.useState([]);
506216
506192
  const tuiQueueRef = import_react121.useRef(null);
@@ -506867,7 +506843,7 @@ function App2({
506867
506843
  import_react121.useEffect(() => {
506868
506844
  buffersRef.current.agentId = agentState?.id;
506869
506845
  }, [agentState?.id]);
506870
- useAgentMcpServers(agentState?.id);
506846
+ useMcpCleanup(agentState?.id);
506871
506847
  const precomputedDiffsRef = import_react121.useRef(new Map);
506872
506848
  const eagerCommittedPreviewsRef = import_react121.useRef(new Set);
506873
506849
  const estimateApprovalPreviewLines = import_react121.useCallback((approval) => {
@@ -507700,6 +507676,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
507700
507676
  buffersRef,
507701
507677
  clearApprovalToolContext,
507702
507678
  chatgptPlanSwapsRef,
507679
+ chatgptExhaustedProvidersRef,
507703
507680
  closeTrajectorySegment,
507704
507681
  consumeQueuedMessages,
507705
507682
  queueModeRef,
@@ -508861,6 +508838,7 @@ var init_AppCoordinator = __esm(async () => {
508861
508838
  init_ids();
508862
508839
  init_model_config();
508863
508840
  init_session3();
508841
+ init_use_agent_mcp_servers();
508864
508842
  init_use_feedback_handler();
508865
508843
  init_use_queued_approval_submit();
508866
508844
  init_use_reasoning_cycle();
@@ -508876,7 +508854,6 @@ var init_AppCoordinator = __esm(async () => {
508876
508854
  init_manager4(),
508877
508855
  init_toolset(),
508878
508856
  init_AppView(),
508879
- init_use_agent_mcp_servers(),
508880
508857
  init_use_approval_flow(),
508881
508858
  init_use_bash_handlers(),
508882
508859
  init_use_configuration_handlers(),
@@ -509093,13 +509070,13 @@ USAGE
509093
509070
  letta update Check for updates and install (aliases: upgrade, --update, --upgrade)
509094
509071
  letta memory ... Memory filesystem subcommands
509095
509072
  letta agents ... Agents subcommands (JSON-only)
509096
- letta environments ... List available remote environments (JSON-only)
509097
- letta teleport ... Move the current conversation between environments
509073
+ letta computers ... List available remote computers (JSON-only)
509074
+ letta teleport ... Move the current conversation between computers
509098
509075
  letta messages ... Messages subcommands (JSON-only)
509099
509076
  letta mcp ... List, search, and call MCP servers available to an agent
509100
509077
  letta mods ... List and manage local mods
509101
509078
  letta sandbox ... Transfer files to or from the current Cloud sandbox
509102
- letta server ... Run a remote environment, channels, or the App Server
509079
+ letta server ... Run a remote computer, channels, or the App Server
509103
509080
  letta connect ... Connect providers from terminal
509104
509081
  letta backend ... Show or set the default backend
509105
509082
  letta setup Re-run first-run setup
@@ -509118,9 +509095,9 @@ SUBCOMMANDS
509118
509095
  letta memory pull --agent <id>
509119
509096
  letta memory tokens [--memory-dir <path>] [--agent <id>] [--format text|json]
509120
509097
  letta agents list [--query <text> | --name <name> | --tags <tags>]
509121
- letta environments list [--online-only]
509122
- letta environments current
509123
- letta teleport list|cloud|local|<environment>
509098
+ letta computers list [--online-only]
509099
+ letta computers current
509100
+ letta teleport list|cloud|local|<computer>
509124
509101
  letta messages search --query <text> [--all-agents]
509125
509102
  letta messages list [--agent <id>]
509126
509103
  letta messages transcript --conversation <id> [--out <path>]
@@ -509130,7 +509107,7 @@ SUBCOMMANDS
509130
509107
  letta mods disable <package-spec>
509131
509108
  letta mods remove <package-spec>
509132
509109
  letta mcp list|get|tools|search|call ... [--agent <id>]
509133
- letta server [--env-name <name> | --listen [url]] [options]
509110
+ letta server [--computer-name <name> | --listen [url]] [options]
509134
509111
  letta connect <provider> [options]
509135
509112
  letta install <thing> [--agent <id> | -n <name>]
509136
509113
  letta skills list [--agent <id> | -n <name>]
@@ -509891,7 +509868,7 @@ Error: ${message}`);
509891
509868
  markMilestone("REACT_IMPORT_DONE");
509892
509869
  await terminalPreflightPromise;
509893
509870
  markMilestone("TERMINAL_PREFLIGHT_DONE");
509894
- const { useState: useState56, useEffect: useEffect50, useRef: useRef20 } = React14;
509871
+ const { useState: useState56, useEffect: useEffect50, useRef: useRef21 } = React14;
509895
509872
  const App3 = AppModule.App;
509896
509873
  function LoadingApp({
509897
509874
  forceNew: forceNew2,
@@ -509915,7 +509892,7 @@ Error: ${message}`);
509915
509892
  const [resumedExistingConversation, setResumedExistingConversation] = useState56(false);
509916
509893
  const [agentProvenance, setAgentProvenance] = useState56(null);
509917
509894
  const [selectedGlobalAgentId, setSelectedGlobalAgentId] = useState56(null);
509918
- const startupCreatedAgentRef = useRef20(null);
509895
+ const startupCreatedAgentRef = useRef21(null);
509919
509896
  const [startupHasCloudCredentials, setStartupHasCloudCredentials] = useState56(Boolean(settings3.refreshToken || apiKey));
509920
509897
  const [fileAutocompleteFdPath, setFileAutocompleteFdPath] = useState56(() => resolveFdPath());
509921
509898
  const [startupHasAvailableLocalModels, setStartupHasAvailableLocalModels] = useState56(true);
@@ -512950,4 +512927,4 @@ function registerBunOAuthFlows() {
512950
512927
  registerBunOAuthFlows();
512951
512928
  await init_src5().then(() => exports_src2);
512952
512929
 
512953
- //# debugId=A04282B12C1CC94F64756E2164756E21
512930
+ //# debugId=D6C12B8170F7A1C664756E2164756E21