@letta-ai/letta-code 0.31.10 → 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.10",
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",
@@ -5781,6 +5781,15 @@ function isLoopbackUrl(value, options = {}) {
5781
5781
  }
5782
5782
 
5783
5783
  // src/backend/api/metadata.ts
5784
+ function getFeedbackClientType(env = process.env) {
5785
+ if (env.LETTA_DESKTOP_MODE === "1") {
5786
+ return "desktop";
5787
+ }
5788
+ if (env.LETTA_RUNTIME_ENVIRONMENT_DEVICE_ID) {
5789
+ return "chat.letta.com";
5790
+ }
5791
+ return "cli";
5792
+ }
5784
5793
  async function getBalanceMetadata() {
5785
5794
  return apiRequest("GET", "/v1/metadata/balance");
5786
5795
  }
@@ -7959,7 +7968,7 @@ Other
7959
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.
7960
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.
7961
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).
7962
- - [ ] 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.
7963
7972
  `;
7964
7973
  var init_onboarding = () => {};
7965
7974
 
@@ -8012,7 +8021,7 @@ Other
8012
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.
8013
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.
8014
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).
8015
- - [ ] 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.
8016
8025
  `;
8017
8026
  var init_onboarding_local = () => {};
8018
8027
 
@@ -90861,6 +90870,9 @@ function createSharedReminderState() {
90861
90870
  hasSentSecretsInfo: false,
90862
90871
  pendingSecretsInfoRefresh: false,
90863
90872
  lastSentSecretNamesKey: null,
90873
+ hasSentMcpServersInfo: false,
90874
+ lastSentMcpServerNamesKey: null,
90875
+ lastMcpServersFetchedAtMs: null,
90864
90876
  lastNotifiedPermissionMode: null,
90865
90877
  turnCount: 0,
90866
90878
  pendingReflectionTrigger: false,
@@ -90877,6 +90889,8 @@ function markPostCompactionContextRemindersPending(state) {
90877
90889
  state.hasSentSessionContext = false;
90878
90890
  state.pendingSessionContextReason ??= "post_compaction";
90879
90891
  state.hasSentSecretsInfo = false;
90892
+ state.hasSentMcpServersInfo = false;
90893
+ state.lastMcpServersFetchedAtMs = null;
90880
90894
  state.lastNotifiedPermissionMode = null;
90881
90895
  }
90882
90896
  function syncReminderStateFromContextTracker(state, contextTracker) {
@@ -113434,8 +113448,7 @@ var init_skills3 = __esm(() => {
113434
113448
  init_skill_sources();
113435
113449
  LOCAL_AGENT_EXCLUDED_BUNDLED_SKILLS = new Set([
113436
113450
  "image-generation",
113437
- "managing-shared-memory",
113438
- "using-cloud-mcp"
113451
+ "managing-shared-memory"
113439
113452
  ]);
113440
113453
  PROJECT_SKILLS_DIR = join24(".agents", "skills");
113441
113454
  GLOBAL_SKILLS_DIR = join24(process.env.HOME || process.env.USERPROFILE || "~", ".letta/skills");
@@ -114788,7 +114801,7 @@ function buildSubagentArgs(type3, config, model, userPrompt, existingAgentId, ex
114788
114801
  args.push("--backend", options.backendMode);
114789
114802
  }
114790
114803
  if (options.environment) {
114791
- args.push("--environment", options.environment);
114804
+ args.push("--computer", options.environment);
114792
114805
  }
114793
114806
  if (isDeployingExisting) {
114794
114807
  if (existingConversationId) {
@@ -137011,14 +137024,15 @@ var init_args = __esm(() => {
137011
137024
  description: "Inject agent-to-agent system reminder (headless mode)"
137012
137025
  }
137013
137026
  },
137014
- environment: {
137027
+ computer: {
137015
137028
  parser: { type: "string" },
137016
137029
  mode: "headless",
137017
137030
  help: {
137018
137031
  argLabel: "<selector>",
137019
- 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"
137020
137033
  }
137021
137034
  },
137035
+ environment: { parser: { type: "string" }, mode: "headless" },
137022
137036
  env: { parser: { type: "string" }, mode: "headless" },
137023
137037
  skills: {
137024
137038
  parser: { type: "string" },
@@ -185677,6 +185691,8 @@ function buildChannelFeedbackPayload(submission) {
185677
185691
  return withDefinedValues2({
185678
185692
  message: submission.message,
185679
185693
  feature: CHANNEL_FEEDBACK_FEATURE,
185694
+ submission_source: "slash_command",
185695
+ client_type: process.env.LETTA_DESKTOP_MODE === "1" ? "desktop" : "cli",
185680
185696
  version: getVersion(),
185681
185697
  platform: process.platform,
185682
185698
  channel: submission.channel,
@@ -199431,330 +199447,6 @@ var init_channels = __esm(() => {
199431
199447
  };
199432
199448
  });
199433
199449
 
199434
- // src/backend/api/mcp-servers.ts
199435
- function getString(record3, key2) {
199436
- const value = record3[key2];
199437
- return typeof value === "string" ? value : null;
199438
- }
199439
- function parseAgentConnectedMcpServer(value) {
199440
- if (!isRecord(value)) {
199441
- return null;
199442
- }
199443
- const id2 = getString(value, "id");
199444
- const serverName = getString(value, "server_name");
199445
- const serverType = getString(value, "mcp_server_type");
199446
- if (!id2 || !serverName || !serverType) {
199447
- return null;
199448
- }
199449
- const target2 = getString(value, "server_url") ?? [
199450
- getString(value, "command"),
199451
- ...Array.isArray(value.args) ? value.args : []
199452
- ].filter((item) => typeof item === "string").join(" ");
199453
- return { id: id2, serverName, serverType, target: target2 };
199454
- }
199455
- function parseAgentConnectedMcpTool(value) {
199456
- if (!isRecord(value)) {
199457
- return null;
199458
- }
199459
- const id2 = getString(value, "id");
199460
- const name = getString(value, "name");
199461
- if (!id2 || !name) {
199462
- return null;
199463
- }
199464
- const description = getString(value, "description");
199465
- return { id: id2, name, description };
199466
- }
199467
- function parseAgentMcpToolRunResult(value) {
199468
- if (!isRecord(value)) {
199469
- throw new Error("MCP tool run returned an invalid response");
199470
- }
199471
- const status = getString(value, "status") ?? "unknown";
199472
- return {
199473
- status,
199474
- funcReturn: value.func_return,
199475
- stdout: value.stdout,
199476
- stderr: value.stderr
199477
- };
199478
- }
199479
- function withTimeout(promise, timeoutMs, label) {
199480
- let timer;
199481
- const timeout = new Promise((_4, reject2) => {
199482
- timer = setTimeout(() => reject2(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs);
199483
- });
199484
- return Promise.race([promise, timeout]).finally(() => {
199485
- if (timer !== undefined)
199486
- clearTimeout(timer);
199487
- });
199488
- }
199489
- function listServerMcpServers(client, timeoutMs = 1e4) {
199490
- return withTimeout(client.mcpServers.list(), timeoutMs, "Listing server-side MCP servers");
199491
- }
199492
- async function listAgentConnectedMcpServers(client, agentId, timeoutMs = 1e4) {
199493
- const result2 = await withTimeout(client.get(`/v1/agents/${encodeURIComponent(agentId)}/mcp-servers`), timeoutMs, "Listing agent-connected MCP servers");
199494
- if (!Array.isArray(result2)) {
199495
- return [];
199496
- }
199497
- return result2.map(parseAgentConnectedMcpServer).filter((server2) => server2 !== null);
199498
- }
199499
- async function listAgentConnectedMcpTools(client, agentId, mcpServerId, timeoutMs = 1e4) {
199500
- const result2 = await withTimeout(client.get(`/v1/agents/${encodeURIComponent(agentId)}/mcp-servers/${encodeURIComponent(mcpServerId)}/tools`), timeoutMs, "Listing agent-connected MCP server tools");
199501
- if (!Array.isArray(result2)) {
199502
- return [];
199503
- }
199504
- return result2.map(parseAgentConnectedMcpTool).filter((tool) => tool !== null);
199505
- }
199506
- async function runAgentConnectedMcpTool(params) {
199507
- const result2 = await withTimeout(params.client.post(`/v1/agents/${encodeURIComponent(params.agentId)}/mcp-servers/${encodeURIComponent(params.mcpServerId)}/tools/${encodeURIComponent(params.toolId)}/run`, { args: params.args }), params.timeoutMs ?? 60000, "Running agent-connected MCP tool");
199508
- return parseAgentMcpToolRunResult(result2);
199509
- }
199510
- async function listLiveServerMcpTools(client, serverName, timeoutMs = 15000) {
199511
- const result2 = await withTimeout(client.get(`/v1/tools/mcp/servers/${encodeURIComponent(serverName)}/tools`), timeoutMs, `Listing tools for MCP server "${serverName}"`);
199512
- if (!Array.isArray(result2))
199513
- return [];
199514
- return result2.filter((tool) => typeof tool === "object" && tool !== null && typeof tool.name === "string");
199515
- }
199516
- async function loadServerMcpEntries(client, timeoutMs = 15000) {
199517
- const servers = await listServerMcpServers(client, timeoutMs);
199518
- return Promise.all(servers.map(async (server2) => {
199519
- try {
199520
- const tools = await listLiveServerMcpTools(client, server2.server_name, timeoutMs);
199521
- return { server: server2, tools };
199522
- } catch (cause) {
199523
- return {
199524
- server: server2,
199525
- tools: [],
199526
- toolsError: cause instanceof Error ? cause.message : String(cause)
199527
- };
199528
- }
199529
- }));
199530
- }
199531
- function parseMcpMetadata(tool) {
199532
- const metadata = tool.metadata_;
199533
- const mcp = metadata?.mcp;
199534
- if (typeof mcp !== "object" || mcp === null)
199535
- return null;
199536
- const { server_id, server_name } = mcp;
199537
- return {
199538
- ...typeof server_id === "string" && { serverId: server_id },
199539
- ...typeof server_name === "string" && { serverName: server_name }
199540
- };
199541
- }
199542
- async function listAgentMcpAttachments(client, agentId) {
199543
- const attachments = [];
199544
- for await (const tool of client.agents.tools.list(agentId, { limit: 100 })) {
199545
- if (tool.tool_type !== "external_mcp" || !tool.id || !tool.name)
199546
- continue;
199547
- attachments.push({
199548
- toolId: tool.id,
199549
- toolName: tool.name,
199550
- ...parseMcpMetadata(tool)
199551
- });
199552
- }
199553
- return attachments;
199554
- }
199555
- function attachmentsForEntry(entry, attachments) {
199556
- return attachments.filter((attachment) => attachment.serverId && entry.server.id ? attachment.serverId === entry.server.id : attachment.serverName === entry.server.server_name);
199557
- }
199558
- function attachedToolNamesForEntry(entry, attachments) {
199559
- return new Set(attachmentsForEntry(entry, attachments).map((attachment) => attachment.toolName));
199560
- }
199561
- async function registerServerMcpTool(client, serverName, toolName) {
199562
- const result2 = await client.post(`/v1/tools/mcp/servers/${encodeURIComponent(serverName)}/${encodeURIComponent(toolName)}`);
199563
- if (typeof result2?.id !== "string") {
199564
- throw new Error(`Registering MCP tool "${toolName}" on server "${serverName}" returned no tool id`);
199565
- }
199566
- return { id: result2.id };
199567
- }
199568
- async function attachServerMcpTools(client, agentId, serverName, toolNames) {
199569
- await Promise.all(toolNames.map(async (toolName) => {
199570
- const { id: id2 } = await registerServerMcpTool(client, serverName, toolName);
199571
- await client.agents.tools.attach(id2, { agent_id: agentId });
199572
- }));
199573
- }
199574
- async function detachServerMcpTools(client, agentId, toolIds) {
199575
- await Promise.all(toolIds.map((toolId) => client.agents.tools.detach(toolId, { agent_id: agentId })));
199576
- }
199577
- function refreshServerMcpServer(client, mcpServerId, agentId) {
199578
- return client.mcpServers.refresh(mcpServerId, { agent_id: agentId });
199579
- }
199580
- function planServerMcpToggle(entry, attachments) {
199581
- const attached = attachmentsForEntry(entry, attachments);
199582
- if (attached.length > 0) {
199583
- return {
199584
- action: "detach",
199585
- toolIds: attached.map((attachment) => attachment.toolId)
199586
- };
199587
- }
199588
- return { action: "attach", toolNames: entry.tools.map((tool) => tool.name) };
199589
- }
199590
- function describeServerMcpTarget(server2) {
199591
- if ("server_url" in server2 && server2.server_url) {
199592
- return server2.server_url;
199593
- }
199594
- if ("command" in server2 && server2.command) {
199595
- return [server2.command, ...server2.args ?? []].join(" ");
199596
- }
199597
- return "";
199598
- }
199599
- var init_mcp_servers2 = () => {};
199600
-
199601
- // src/cli/subcommands/cloud-mcp.ts
199602
- import { parseArgs as parseArgs4 } from "node:util";
199603
- function printUsage4(stdout = console.log) {
199604
- stdout(`
199605
- Usage:
199606
- letta cloud-mcp list [--agent <id>]
199607
- letta cloud-mcp tools <mcp-server-id> [--agent <id>]
199608
- letta cloud-mcp run <mcp-server-id> <tool-id> [--args '<json>'] [--agent <id>]
199609
-
199610
- Actions:
199611
- list List MCP servers connected to the agent
199612
- tools List registered tools for one connected MCP server
199613
- run Run one registered MCP tool through the agent-scoped server route
199614
-
199615
- Aliases:
199616
- list-servers, list_servers Alias for list
199617
- list-tools, list_tools Alias for tools
199618
- call, run-tool, run_tool Alias for run
199619
-
199620
- Options:
199621
- --agent <id> Agent ID. Defaults to LETTA_AGENT_ID or AGENT_ID
199622
- --agent-id <id> Alias for --agent
199623
- --args '<json>' JSON object passed as MCP tool arguments for run
199624
- -h, --help Show this help
199625
-
199626
- Notes:
199627
- - Output is JSON only.
199628
- - Requires a signed-in Letta Cloud agent with server-side MCP support.
199629
- - Uses CLI auth; override with LETTA_API_KEY/LETTA_BASE_URL if needed.
199630
- `.trim());
199631
- }
199632
- function parseCloudMcpArgs(argv) {
199633
- return parseArgs4({
199634
- args: argv,
199635
- options: {
199636
- help: { type: "boolean", short: "h" },
199637
- agent: { type: "string" },
199638
- "agent-id": { type: "string" },
199639
- args: { type: "string" }
199640
- },
199641
- strict: true,
199642
- allowPositionals: true
199643
- });
199644
- }
199645
- function stringValue3(value) {
199646
- return typeof value === "string" ? value : undefined;
199647
- }
199648
- function resolveCloudMcpAgentId(agent, agentId, env4 = process.env) {
199649
- return (agent || agentId || env4.LETTA_AGENT_ID || env4.AGENT_ID || "").trim();
199650
- }
199651
- function parseToolArgs(value) {
199652
- const raw2 = stringValue3(value);
199653
- if (!raw2) {
199654
- return {};
199655
- }
199656
- let parsed;
199657
- try {
199658
- parsed = JSON.parse(raw2);
199659
- } catch (error4) {
199660
- const message = error4 instanceof Error ? error4.message : String(error4);
199661
- throw new Error(`Invalid --args JSON: ${message}`);
199662
- }
199663
- if (!isRecord(parsed)) {
199664
- throw new Error("Invalid --args JSON: expected a JSON object");
199665
- }
199666
- return parsed;
199667
- }
199668
- function printJson(stdout, result2) {
199669
- stdout(JSON.stringify(result2, null, 2));
199670
- }
199671
- async function defaultGetClient() {
199672
- const client = await getClient();
199673
- return client;
199674
- }
199675
- async function runCloudMcpSubcommand(argv, deps = {}) {
199676
- const stdout = deps.stdout ?? console.log;
199677
- const stderr = deps.stderr ?? console.error;
199678
- let parsed;
199679
- try {
199680
- parsed = parseCloudMcpArgs(argv);
199681
- } catch (error4) {
199682
- const message = error4 instanceof Error ? error4.message : String(error4);
199683
- stderr(`Error: ${message}`);
199684
- printUsage4(stdout);
199685
- return 1;
199686
- }
199687
- const [action3, mcpServerId, toolId] = parsed.positionals;
199688
- if (parsed.values.help || !action3 || action3 === "help") {
199689
- printUsage4(stdout);
199690
- return 0;
199691
- }
199692
- const isAvailable = deps.isServerSideMcpAvailable ?? (() => getBackend().capabilities.serverSideToolManagement);
199693
- if (!isAvailable()) {
199694
- stderr("Server-side MCP requires a signed-in Letta Cloud agent; the local backend does not support it.");
199695
- return 1;
199696
- }
199697
- const agentId = resolveCloudMcpAgentId(stringValue3(parsed.values.agent), stringValue3(parsed.values["agent-id"]));
199698
- if (!agentId) {
199699
- stderr("Agent id required: pass --agent <id> or set LETTA_AGENT_ID/AGENT_ID.");
199700
- return 1;
199701
- }
199702
- await (deps.initializeSettings ?? (() => settingsManager.initialize()))();
199703
- const client = await (deps.getClient ?? defaultGetClient)();
199704
- try {
199705
- if (action3 === "list" || action3 === "list-servers" || action3 === "list_servers") {
199706
- printJson(stdout, {
199707
- agent_id: agentId,
199708
- servers: await listAgentConnectedMcpServers(client, agentId)
199709
- });
199710
- return 0;
199711
- }
199712
- if (action3 === "tools" || action3 === "list-tools" || action3 === "list_tools") {
199713
- if (!mcpServerId) {
199714
- stderr("Usage: letta cloud-mcp tools <mcp-server-id> [--agent <id>]");
199715
- return 1;
199716
- }
199717
- printJson(stdout, {
199718
- agent_id: agentId,
199719
- mcp_server_id: mcpServerId,
199720
- tools: await listAgentConnectedMcpTools(client, agentId, mcpServerId)
199721
- });
199722
- return 0;
199723
- }
199724
- if (action3 === "run" || action3 === "call" || action3 === "run-tool" || action3 === "run_tool") {
199725
- if (!mcpServerId || !toolId) {
199726
- stderr("Usage: letta cloud-mcp run <mcp-server-id> <tool-id> [--args '<json>'] [--agent <id>]");
199727
- return 1;
199728
- }
199729
- printJson(stdout, {
199730
- agent_id: agentId,
199731
- mcp_server_id: mcpServerId,
199732
- tool_id: toolId,
199733
- result: await runAgentConnectedMcpTool({
199734
- client,
199735
- agentId,
199736
- mcpServerId,
199737
- toolId,
199738
- args: parseToolArgs(parsed.values.args)
199739
- })
199740
- });
199741
- return 0;
199742
- }
199743
- stderr(`Unknown cloud-mcp action: ${action3}`);
199744
- printUsage4(stdout);
199745
- return 1;
199746
- } catch (error4) {
199747
- stderr(error4 instanceof Error ? error4.message : String(error4));
199748
- return 1;
199749
- }
199750
- }
199751
- var init_cloud_mcp = __esm(() => {
199752
- init_backend2();
199753
- init_client2();
199754
- init_mcp_servers2();
199755
- init_settings_manager();
199756
- });
199757
-
199758
199450
  // src/auth/openai-oauth.ts
199759
199451
  import http3 from "node:http";
199760
199452
  function renderOAuthPage(options) {
@@ -200878,7 +200570,7 @@ var init_connect_normalize = __esm(() => {
200878
200570
  // src/cli/subcommands/connect.ts
200879
200571
  import { createInterface as createInterface6 } from "node:readline/promises";
200880
200572
  import { Writable } from "node:stream";
200881
- import { parseArgs as parseArgs5 } from "node:util";
200573
+ import { parseArgs as parseArgs4 } from "node:util";
200882
200574
  function readStringOption(value) {
200883
200575
  if (typeof value === "string") {
200884
200576
  return value;
@@ -200970,7 +200662,7 @@ async function runConnectSubcommand(argv, deps = {}) {
200970
200662
  const io = { ...DEFAULT_DEPS2, ...deps };
200971
200663
  let parsed;
200972
200664
  try {
200973
- parsed = parseArgs5({
200665
+ parsed = parseArgs4({
200974
200666
  args: argv,
200975
200667
  options: CONNECT_OPTIONS,
200976
200668
  strict: true,
@@ -209911,10 +209603,10 @@ async function resolveDesktopEnvironmentConnectionId(list = listEnvironments) {
209911
209603
  const response = await list({ limit: 100, onlineOnly: true });
209912
209604
  const matches3 = response.connections.filter((environment3) => environment3.listenerInstanceId?.startsWith("desktop-direct-cloud:") === true && isEnvironmentOnline(environment3));
209913
209605
  if (matches3.length === 0) {
209914
- 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.");
209915
209607
  }
209916
209608
  if (matches3.length > 1) {
209917
- 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(", ")}`);
209918
209610
  }
209919
209611
  const environment2 = matches3[0];
209920
209612
  if (!environment2?.connectionId) {
@@ -209925,28 +209617,28 @@ async function resolveDesktopEnvironmentConnectionId(list = listEnvironments) {
209925
209617
  async function resolveEnvironmentConnectionId(selector) {
209926
209618
  const trimmed = selector.trim();
209927
209619
  if (!trimmed) {
209928
- throw new Error("Environment selector must not be empty");
209620
+ throw new Error("Computer selector must not be empty");
209929
209621
  }
209930
209622
  const response = await listEnvironments({ limit: 100 });
209931
209623
  const matches3 = response.connections.filter((environment3) => {
209932
209624
  return environment3.connectionId === trimmed || environment3.id === trimmed || environment3.deviceId === trimmed || environment3.connectionName === trimmed;
209933
209625
  });
209934
209626
  if (matches3.length === 0) {
209935
- 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.`);
209936
209628
  }
209937
209629
  const onlineMatches = matches3.filter(isEnvironmentOnline);
209938
209630
  if (onlineMatches.length === 0) {
209939
- 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(", ")}`);
209940
209632
  }
209941
209633
  if (onlineMatches.length > 1) {
209942
- 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(", ")}`);
209943
209635
  }
209944
209636
  const environment2 = onlineMatches[0];
209945
209637
  if (!environment2) {
209946
- throw new Error(`Environment "${trimmed}" is offline`);
209638
+ throw new Error(`Computer "${trimmed}" is offline`);
209947
209639
  }
209948
209640
  if (!environment2.connectionId) {
209949
- throw new Error(`Environment "${trimmed}" has no active connection id`);
209641
+ throw new Error(`Computer "${trimmed}" has no active connection id`);
209950
209642
  }
209951
209643
  return { connectionId: environment2.connectionId, environment: environment2 };
209952
209644
  }
@@ -210180,8 +209872,8 @@ var init_cron_task_ref = __esm(async () => {
210180
209872
  });
210181
209873
 
210182
209874
  // src/cli/subcommands/cron.ts
210183
- import { parseArgs as parseArgs6 } from "node:util";
210184
- function printUsage5() {
209875
+ import { parseArgs as parseArgs5 } from "node:util";
209876
+ function printUsage4() {
210185
209877
  console.log(`
210186
209878
  Usage:
210187
209879
  letta cron add --prompt <text> --every <interval> [options]
@@ -210217,8 +209909,8 @@ Add options:
210217
209909
  the fallback when Cloud scheduling cannot
210218
209910
  reach this computer)
210219
209911
  --computer <id> (cloud runner only) Override execution with a
210220
- connected external environment (deviceId from
210221
- \`letta environments list\`). Falls back to the Cloud
209912
+ connected external computer (deviceId from
209913
+ \`letta computers list\`). Falls back to the Cloud
210222
209914
  sandbox if the computer is offline at fire time.
210223
209915
  Managed sandboxes and Desktop-local connections are
210224
209916
  not currently valid Cloud schedule targets.
@@ -210235,7 +209927,7 @@ Output is JSON.
210235
209927
  `.trim());
210236
209928
  }
210237
209929
  function parseCronArgs(argv) {
210238
- return parseArgs6({
209930
+ return parseArgs5({
210239
209931
  args: argv,
210240
209932
  options: CRON_OPTIONS,
210241
209933
  strict: true,
@@ -210405,7 +210097,7 @@ async function handleAdd(values3) {
210405
210097
  targetDeviceId = inferredDeviceId;
210406
210098
  } else if (resolution.kind === "local-fallback") {
210407
210099
  runner = "local";
210408
- 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\`).`;
210409
210101
  }
210410
210102
  }
210411
210103
  if (runner === "cloud") {
@@ -210791,12 +210483,12 @@ async function runCronSubcommand(argv) {
210791
210483
  parsed = parseCronArgs(argv);
210792
210484
  } catch (err) {
210793
210485
  console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
210794
- printUsage5();
210486
+ printUsage4();
210795
210487
  return 1;
210796
210488
  }
210797
210489
  const [action3] = parsed.positionals;
210798
210490
  if (parsed.values.help || !action3 || action3 === "help") {
210799
- printUsage5();
210491
+ printUsage4();
210800
210492
  return 0;
210801
210493
  }
210802
210494
  switch (action3) {
@@ -210813,7 +210505,7 @@ async function runCronSubcommand(argv) {
210813
210505
  return handleDelete(parsed.values, parsed.positionals);
210814
210506
  default:
210815
210507
  console.error(`Unknown action: ${action3}`);
210816
- printUsage5();
210508
+ printUsage4();
210817
210509
  return 1;
210818
210510
  }
210819
210511
  }
@@ -210849,29 +210541,31 @@ var init_cron2 = __esm(async () => {
210849
210541
  });
210850
210542
 
210851
210543
  // src/cli/subcommands/environments.ts
210852
- import { parseArgs as parseArgs7 } from "node:util";
210853
- function printUsage6() {
210544
+ import { parseArgs as parseArgs6 } from "node:util";
210545
+ function printUsage5() {
210854
210546
  console.log(`
210855
210547
  Usage:
210856
- letta environments list [options]
210857
- letta environments current
210548
+ letta computers list [options]
210549
+ letta computers current
210858
210550
 
210859
- Aliases:
210551
+ Legacy aliases:
210552
+ letta environments list
210553
+ letta environments current
210860
210554
  letta envs list
210861
210555
  letta envs current
210862
210556
 
210863
210557
  List options:
210864
210558
  --limit <n> Max results (default: 50)
210865
- --after <id> Pagination cursor from a previous environment id
210866
- --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
210867
210561
 
210868
210562
  Notes:
210869
210563
  - Output is JSON only.
210870
210564
  - Uses CLI auth; override with LETTA_API_KEY/LETTA_BASE_URL if needed.
210871
- - Use letta environments current to get this machine's connectionId.
210872
- - Use --environment cloud to route through the target agent's cloud sandbox.
210873
- - Use --environment <name|device-id|connection-id> with headless messaging
210874
- 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.
210875
210569
  `.trim());
210876
210570
  }
210877
210571
  function parseLimit2(value, fallback) {
@@ -210918,7 +210612,7 @@ function scoreCurrentEnvironment(environment2, options) {
210918
210612
  return score;
210919
210613
  }
210920
210614
  function parseEnvironmentsArgs(argv) {
210921
- return parseArgs7({
210615
+ return parseArgs6({
210922
210616
  args: argv,
210923
210617
  options: ENVIRONMENTS_OPTIONS,
210924
210618
  strict: true,
@@ -210932,17 +210626,17 @@ async function runEnvironmentsSubcommand(argv, deps = {}) {
210932
210626
  } catch (error4) {
210933
210627
  const message = error4 instanceof Error ? error4.message : String(error4);
210934
210628
  console.error(`Error: ${message}`);
210935
- printUsage6();
210629
+ printUsage5();
210936
210630
  return 1;
210937
210631
  }
210938
210632
  const [action3] = parsed.positionals;
210939
210633
  if (parsed.values.help || !action3 || action3 === "help") {
210940
- printUsage6();
210634
+ printUsage5();
210941
210635
  return 0;
210942
210636
  }
210943
210637
  if (action3 !== "list" && action3 !== "current") {
210944
210638
  console.error(`Unknown action: ${action3}`);
210945
- printUsage6();
210639
+ printUsage5();
210946
210640
  return 1;
210947
210641
  }
210948
210642
  await (deps.initializeSettings ?? (() => settingsManager.initialize()))();
@@ -210958,7 +210652,7 @@ async function runEnvironmentsSubcommand(argv, deps = {}) {
210958
210652
  currentVersion
210959
210653
  });
210960
210654
  if (!current2) {
210961
- 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.");
210962
210656
  return 1;
210963
210657
  }
210964
210658
  console.log(JSON.stringify(formatEnvironmentForCli(current2, {
@@ -211004,8 +210698,8 @@ var init_environments3 = __esm(() => {
211004
210698
  });
211005
210699
 
211006
210700
  // src/cli/subcommands/feedback.ts
211007
- import { parseArgs as parseArgs8 } from "node:util";
211008
- function printUsage7(stdout = console.log) {
210701
+ import { parseArgs as parseArgs7 } from "node:util";
210702
+ function printUsage6(stdout = console.log) {
211009
210703
  stdout(`
211010
210704
  Usage:
211011
210705
  letta feedback --message <text>
@@ -211023,7 +210717,7 @@ async function runFeedbackSubcommand(argv, deps = {}) {
211023
210717
  const stderr = deps.stderr ?? console.error;
211024
210718
  let parsed;
211025
210719
  try {
211026
- parsed = parseArgs8({
210720
+ parsed = parseArgs7({
211027
210721
  args: argv,
211028
210722
  options: {
211029
210723
  help: { type: "boolean", short: "h" },
@@ -211034,11 +210728,11 @@ async function runFeedbackSubcommand(argv, deps = {}) {
211034
210728
  });
211035
210729
  } catch (error4) {
211036
210730
  stderr(error4 instanceof Error ? error4.message : String(error4));
211037
- printUsage7(stdout);
210731
+ printUsage6(stdout);
211038
210732
  return 1;
211039
210733
  }
211040
210734
  if (parsed.values.help) {
211041
- printUsage7(stdout);
210735
+ printUsage6(stdout);
211042
210736
  return 0;
211043
210737
  }
211044
210738
  const message = typeof parsed.values.message === "string" ? parsed.values.message.trim() : "";
@@ -211061,6 +210755,8 @@ async function runFeedbackSubcommand(argv, deps = {}) {
211061
210755
  await (deps.submitFeedback ?? submitFeedbackMetadata)(apiKey, (deps.getDeviceId ?? (() => settingsManager.getOrCreateDeviceId()))(), {
211062
210756
  message,
211063
210757
  feature: "letta-code-agent-feedback",
210758
+ submission_source: "agent_skill",
210759
+ client_type: (deps.getClientType ?? getFeedbackClientType)(),
211064
210760
  version: getVersion(),
211065
210761
  platform: process.platform,
211066
210762
  agent_id: agentId || undefined,
@@ -212778,7 +212474,7 @@ function ListenerStatusUI(props) {
212778
212474
  bold: true,
212779
212475
  color: "green",
212780
212476
  children: [
212781
- "The name of your environment is: ",
212477
+ "The name of your computer is: ",
212782
212478
  envName
212783
212479
  ]
212784
212480
  }, undefined, true, undefined, this)
@@ -212811,7 +212507,7 @@ function ListenerStatusUI(props) {
212811
212507
  children: /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
212812
212508
  dimColor: true,
212813
212509
  children: [
212814
- '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 ',
212815
212511
  envName
212816
212512
  ]
212817
212513
  }, undefined, true, undefined, this)
@@ -238784,9 +238480,9 @@ ${lanes.join(`
238784
238480
  function isJsonEqual(a2, b3) {
238785
238481
  return a2 === b3 || typeof a2 === "object" && a2 !== null && typeof b3 === "object" && b3 !== null && equalOwnProperties(a2, b3, isJsonEqual);
238786
238482
  }
238787
- function parsePseudoBigInt(stringValue4) {
238483
+ function parsePseudoBigInt(stringValue3) {
238788
238484
  let log2Base;
238789
- switch (stringValue4.charCodeAt(1)) {
238485
+ switch (stringValue3.charCodeAt(1)) {
238790
238486
  case 98:
238791
238487
  case 66:
238792
238488
  log2Base = 1;
@@ -238800,19 +238496,19 @@ ${lanes.join(`
238800
238496
  log2Base = 4;
238801
238497
  break;
238802
238498
  default:
238803
- const nIndex = stringValue4.length - 1;
238499
+ const nIndex = stringValue3.length - 1;
238804
238500
  let nonZeroStart = 0;
238805
- while (stringValue4.charCodeAt(nonZeroStart) === 48) {
238501
+ while (stringValue3.charCodeAt(nonZeroStart) === 48) {
238806
238502
  nonZeroStart++;
238807
238503
  }
238808
- return stringValue4.slice(nonZeroStart, nIndex) || "0";
238504
+ return stringValue3.slice(nonZeroStart, nIndex) || "0";
238809
238505
  }
238810
- const startIndex = 2, endIndex = stringValue4.length - 1;
238506
+ const startIndex = 2, endIndex = stringValue3.length - 1;
238811
238507
  const bitsNeeded = (endIndex - startIndex) * log2Base;
238812
238508
  const segments = new Uint16Array((bitsNeeded >>> 4) + (bitsNeeded & 15 ? 1 : 0));
238813
238509
  for (let i4 = endIndex - 1, bitOffset = 0;i4 >= startIndex; i4--, bitOffset += log2Base) {
238814
238510
  const segment = bitOffset >>> 4;
238815
- const digitChar = stringValue4.charCodeAt(i4);
238511
+ const digitChar = stringValue3.charCodeAt(i4);
238816
238512
  const digit = digitChar <= 57 ? digitChar - 48 : 10 + digitChar - (digitChar <= 70 ? 65 : 97);
238817
238513
  const shiftedDigit = digit << (bitOffset & 15);
238818
238514
  segments[segment] |= shiftedDigit;
@@ -391876,7 +391572,7 @@ function toRunsArray(listResponse) {
391876
391572
  }
391877
391573
  return [];
391878
391574
  }
391879
- function withTimeout2(promise, timeoutMs, timeoutMessage) {
391575
+ function withTimeout(promise, timeoutMs, timeoutMessage) {
391880
391576
  return new Promise((resolve34, reject2) => {
391881
391577
  const timer = setTimeout(() => reject2(new Error(timeoutMessage)), timeoutMs);
391882
391578
  promise.then((value) => {
@@ -391890,7 +391586,7 @@ function withTimeout2(promise, timeoutMs, timeoutMessage) {
391890
391586
  }
391891
391587
  async function discoverFallbackRunIdWithTimeout(ctx) {
391892
391588
  const client = await getClient();
391893
- return withTimeout2(discoverFallbackRunIdForResume(client, ctx), FALLBACK_RUN_DISCOVERY_TIMEOUT_MS, `Fallback run discovery timed out after ${FALLBACK_RUN_DISCOVERY_TIMEOUT_MS}ms`);
391589
+ return withTimeout(discoverFallbackRunIdForResume(client, ctx), FALLBACK_RUN_DISCOVERY_TIMEOUT_MS, `Fallback run discovery timed out after ${FALLBACK_RUN_DISCOVERY_TIMEOUT_MS}ms`);
391894
391590
  }
391895
391591
  async function discoverFallbackRunIdForResume(client, ctx) {
391896
391592
  const statuses = ["running"];
@@ -392627,7 +392323,7 @@ function formatMissingRequiredArgsReason(toolName, parsedArgs, missingRequiredAr
392627
392323
  }
392628
392324
  return base2;
392629
392325
  }
392630
- function parseToolArgs2(rawArgs) {
392326
+ function parseToolArgs(rawArgs) {
392631
392327
  const raw2 = rawArgs ?? "";
392632
392328
  const trimmed = raw2.trim();
392633
392329
  if (!trimmed) {
@@ -392672,7 +392368,7 @@ async function classifyApprovals(approvals, opts = {}) {
392672
392368
  });
392673
392369
  continue;
392674
392370
  }
392675
- const argsParse = parseToolArgs2(approval.toolArgs);
392371
+ const argsParse = parseToolArgs(approval.toolArgs);
392676
392372
  const parsedArgs = argsParse.parsedArgs;
392677
392373
  if (argsParse.parseFailed) {
392678
392374
  debugWarn("approval-classification", `Tool call ${approval.toolCallId} (${toolName}) had unparseable arguments ` + `(${argsParse.rawLength} chars); treating as empty`);
@@ -393592,8 +393288,15 @@ function isChatGPTByokHandleInModels(handle2, models3) {
393592
393288
  const entry = models3.find((m4) => m4.handle === handle2);
393593
393289
  return entry?.providerType === "chatgpt_oauth" && entry?.providerCategory === "byok";
393594
393290
  }
393595
- async function resolveAgentModelHandle2(agentId) {
393291
+ async function resolveScopedModelHandle(agentId, conversationId) {
393596
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
+ }
393597
393300
  const agent = await getBackend().retrieveAgent(agentId);
393598
393301
  const record3 = agent;
393599
393302
  if (typeof record3.model === "string" && record3.model.length > 0) {
@@ -393605,7 +393308,7 @@ async function resolveAgentModelHandle2(agentId) {
393605
393308
  }
393606
393309
  }
393607
393310
  async function rotateChatGPTPlanOnQuotaLimit(params) {
393608
- const { agentId, error: error4 } = params;
393311
+ const { agentId, conversationId, error: error4, exhaustedProviders } = params;
393609
393312
  const parsedDetail = parseChatGPTUsageLimitDetail(error4);
393610
393313
  if (!parsedDetail)
393611
393314
  return null;
@@ -393620,9 +393323,9 @@ async function rotateChatGPTPlanOnQuotaLimit(params) {
393620
393323
  }
393621
393324
  if (!models3)
393622
393325
  return null;
393623
- let currentHandle = params.currentHandle;
393326
+ let currentHandle = await resolveScopedModelHandle(agentId, conversationId);
393624
393327
  if (!currentHandle || !isChatGPTByokHandleInModels(currentHandle, models3)) {
393625
- currentHandle = await resolveAgentModelHandle2(agentId);
393328
+ currentHandle = params.currentHandle;
393626
393329
  }
393627
393330
  if (!currentHandle || !isChatGPTByokHandleInModels(currentHandle, models3)) {
393628
393331
  return null;
@@ -393642,9 +393345,15 @@ async function rotateChatGPTPlanOnQuotaLimit(params) {
393642
393345
  if (!toProvider)
393643
393346
  return null;
393644
393347
  try {
393645
- await updateAgentLLMConfig(agentId, toHandle, {
393646
- provider_type: "chatgpt_oauth"
393647
- });
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
+ }
393648
393357
  } catch {
393649
393358
  return null;
393650
393359
  }
@@ -393663,14 +393372,13 @@ function formatPlanRotationNotice(params) {
393663
393372
  })})` : "";
393664
393373
  return `${fromProvider} hit its usage limit${resetSuffix} — switched to ${toProvider}`;
393665
393374
  }
393666
- var CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN = 3, exhaustedProviders;
393375
+ var CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN = 3;
393667
393376
  var init_chatgpt_plan_rotation = __esm(() => {
393668
393377
  init_available_models();
393669
393378
  init_model_handles();
393670
393379
  init_modify();
393671
393380
  init_turn_recovery_policy();
393672
393381
  init_backend2();
393673
- exhaustedProviders = new Set;
393674
393382
  });
393675
393383
 
393676
393384
  // src/websocket/listener/skill-injection.ts
@@ -403564,6 +403272,16 @@ var init_catalog = __esm(() => {
403564
403272
  "listen"
403565
403273
  ]
403566
403274
  },
403275
+ {
403276
+ id: "mcp-servers-info",
403277
+ description: "MCP servers with tools available through letta mcp",
403278
+ modes: [
403279
+ "interactive",
403280
+ "headless-one-shot",
403281
+ "headless-bidirectional",
403282
+ "listen"
403283
+ ]
403284
+ },
403567
403285
  {
403568
403286
  id: "permission-mode",
403569
403287
  description: "Permission mode reminder",
@@ -403599,6 +403317,167 @@ var init_catalog = __esm(() => {
403599
403317
  SHARED_REMINDER_BY_ID = new Map(SHARED_REMINDER_CATALOG.map((entry) => [entry.id, entry]));
403600
403318
  });
403601
403319
 
403320
+ // src/backend/api/unified-mcp.ts
403321
+ var exports_unified_mcp = {};
403322
+ __export(exports_unified_mcp, {
403323
+ searchUnifiedMcpTools: () => searchUnifiedMcpTools,
403324
+ runUnifiedMcpTool: () => runUnifiedMcpTool,
403325
+ listUnifiedMcpTools: () => listUnifiedMcpTools,
403326
+ listUnifiedMcpServers: () => listUnifiedMcpServers
403327
+ });
403328
+ function stringField2(value, key2) {
403329
+ return typeof value[key2] === "string" ? value[key2] : null;
403330
+ }
403331
+ function recordField(value, ...names2) {
403332
+ for (const name of names2) {
403333
+ const field = value[name];
403334
+ if (isRecord(field))
403335
+ return field;
403336
+ }
403337
+ return;
403338
+ }
403339
+ function parseServer(value, registered) {
403340
+ if (!isRecord(value))
403341
+ return null;
403342
+ const id2 = stringField2(value, "id");
403343
+ const serverName = stringField2(value, "server_name") ?? (registered ? stringField2(registered, "server_name") : null);
403344
+ const serverType = stringField2(value, "mcp_server_type") ?? (registered ? stringField2(registered, "mcp_server_type") : null) ?? "unknown";
403345
+ if (!id2 || !serverName)
403346
+ return null;
403347
+ const serverUrl = stringField2(value, "server_url") ?? (registered ? stringField2(registered, "server_url") : null) ?? undefined;
403348
+ const command = stringField2(value, "command") ?? (registered ? stringField2(registered, "command") : null) ?? undefined;
403349
+ const argsValue = value.args ?? registered?.args;
403350
+ const args = Array.isArray(argsValue) ? argsValue.filter((item) => typeof item === "string") : [];
403351
+ const target2 = serverUrl ?? [command, ...args].filter(Boolean).join(" ");
403352
+ return {
403353
+ id: id2,
403354
+ serverName,
403355
+ serverType,
403356
+ target: target2,
403357
+ ...serverUrl ? { serverUrl } : {},
403358
+ ...command ? { command, args } : {}
403359
+ };
403360
+ }
403361
+ function parseTool(value) {
403362
+ if (!isRecord(value))
403363
+ return null;
403364
+ const id2 = stringField2(value, "id");
403365
+ const name = stringField2(value, "name");
403366
+ if (!id2 || !name)
403367
+ return null;
403368
+ const description = stringField2(value, "description");
403369
+ const jsonSchema = isRecord(value.json_schema) ? value.json_schema : {};
403370
+ const inputSchema = isRecord(jsonSchema.parameters) ? jsonSchema.parameters : isRecord(value.args_json_schema) ? value.args_json_schema : { type: "object", properties: {} };
403371
+ const title = stringField2(value, "title") ?? stringField2(jsonSchema, "title");
403372
+ const outputSchema = recordField(value, "outputSchema", "output_schema") ?? recordField(jsonSchema, "outputSchema", "output_schema");
403373
+ const annotations = recordField(value, "annotations") ?? recordField(jsonSchema, "annotations");
403374
+ const execution = recordField(value, "execution") ?? recordField(jsonSchema, "execution");
403375
+ const meta = recordField(value, "_meta") ?? recordField(jsonSchema, "_meta");
403376
+ const iconsValue = value.icons ?? jsonSchema.icons;
403377
+ const icons = Array.isArray(iconsValue) ? iconsValue.filter(isRecord) : undefined;
403378
+ return {
403379
+ id: id2,
403380
+ name,
403381
+ ...title ? { title } : {},
403382
+ description,
403383
+ inputSchema,
403384
+ ...outputSchema ? { outputSchema } : {},
403385
+ ...annotations ? { annotations } : {},
403386
+ ...execution ? { execution } : {},
403387
+ ...meta ? { _meta: meta } : {},
403388
+ ...icons ? { icons } : {}
403389
+ };
403390
+ }
403391
+ function parseRunResult(value) {
403392
+ if (!isRecord(value))
403393
+ throw new Error("Invalid MCP tool run response");
403394
+ return {
403395
+ status: stringField2(value, "status") ?? "unknown",
403396
+ funcReturn: value.func_return,
403397
+ stdout: value.stdout,
403398
+ stderr: value.stderr
403399
+ };
403400
+ }
403401
+ function parseSearchResult(value) {
403402
+ if (!isRecord(value) || !isRecord(value.tool))
403403
+ return null;
403404
+ const toolId = stringField2(value.tool, "id");
403405
+ const jsonSchema = value.tool.json_schema;
403406
+ const score = value.combined_score;
403407
+ if (!toolId || jsonSchema !== null && !isRecord(jsonSchema) || typeof score !== "number") {
403408
+ return null;
403409
+ }
403410
+ return { toolId, jsonSchema, score };
403411
+ }
403412
+ async function withTimeout2(promise, timeoutMs, operation) {
403413
+ let timer;
403414
+ try {
403415
+ return await Promise.race([
403416
+ promise,
403417
+ new Promise((_resolve, reject2) => {
403418
+ timer = setTimeout(() => reject2(new Error(`${operation} timed out after ${timeoutMs}ms`)), timeoutMs);
403419
+ })
403420
+ ]);
403421
+ } finally {
403422
+ if (timer)
403423
+ clearTimeout(timer);
403424
+ }
403425
+ }
403426
+ async function listUnifiedMcpServers(client, agentId, timeoutMs = 1e4) {
403427
+ const value = await withTimeout2(client.get(`/v1/agents/${encodeURIComponent(agentId)}/mcp-servers`), timeoutMs, "Listing agent MCP servers");
403428
+ if (!Array.isArray(value))
403429
+ return [];
403430
+ const needsEnrichment = value.some((item) => isRecord(item) && !stringField2(item, "mcp_server_type"));
403431
+ const registeredById = new Map;
403432
+ if (needsEnrichment && client.mcpServers) {
403433
+ try {
403434
+ const registered = await withTimeout2(client.mcpServers.list(), timeoutMs, "Listing registered MCP servers");
403435
+ for (const item of registered) {
403436
+ if (!isRecord(item))
403437
+ continue;
403438
+ const id2 = stringField2(item, "id");
403439
+ if (id2)
403440
+ registeredById.set(id2, item);
403441
+ }
403442
+ } catch {}
403443
+ }
403444
+ return value.map((item) => {
403445
+ const registered = isRecord(item) ? registeredById.get(stringField2(item, "id") ?? "") : undefined;
403446
+ return parseServer(item, registered);
403447
+ }).filter((server2) => server2 !== null);
403448
+ }
403449
+ async function listUnifiedMcpTools(client, agentId, mcpServerId, timeoutMs = 1e4) {
403450
+ const value = await withTimeout2(client.get(`/v1/agents/${encodeURIComponent(agentId)}/mcp-servers/${encodeURIComponent(mcpServerId)}/tools`), timeoutMs, "Listing agent MCP server tools");
403451
+ if (!Array.isArray(value))
403452
+ return [];
403453
+ return value.map(parseTool).filter((tool) => tool !== null);
403454
+ }
403455
+ async function searchUnifiedMcpTools(params) {
403456
+ const value = await withTimeout2(params.client.post(`/v1/agents/${encodeURIComponent(params.agentId)}/mcp-servers/tools/search`, {
403457
+ body: {
403458
+ query: params.query,
403459
+ search_mode: params.searchMode,
403460
+ limit: params.limit
403461
+ }
403462
+ }), params.timeoutMs ?? 60000, "Searching agent MCP tools");
403463
+ if (!Array.isArray(value)) {
403464
+ throw new Error("Invalid MCP tool search response");
403465
+ }
403466
+ const results = [];
403467
+ for (const item of value) {
403468
+ const result2 = parseSearchResult(item);
403469
+ if (!result2)
403470
+ throw new Error("Invalid MCP tool search result");
403471
+ results.push(result2);
403472
+ }
403473
+ return results;
403474
+ }
403475
+ async function runUnifiedMcpTool(params) {
403476
+ const value = await withTimeout2(params.client.post(`/v1/agents/${encodeURIComponent(params.agentId)}/mcp-servers/${encodeURIComponent(params.mcpServerId)}/tools/${encodeURIComponent(params.toolId)}/run`, { body: { args: params.args } }), params.timeoutMs ?? 60000, "Running agent MCP tool");
403477
+ return parseRunResult(value);
403478
+ }
403479
+ var init_unified_mcp = () => {};
403480
+
403602
403481
  // src/reminders/engine.ts
403603
403482
  async function buildAgentInfoReminder(context3) {
403604
403483
  if (!context3.systemInfoReminderEnabled || context3.state.hasSentAgentInfo) {
@@ -403658,6 +403537,80 @@ ${SYSTEM_REMINDER_CLOSE}`;
403658
403537
  return null;
403659
403538
  }
403660
403539
  }
403540
+ async function defaultListServerSideServers(agentId) {
403541
+ let serverSideAvailable = false;
403542
+ try {
403543
+ const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_backend2(), exports_backend));
403544
+ serverSideAvailable = getBackend2().capabilities.serverSideToolManagement;
403545
+ } catch {
403546
+ return null;
403547
+ }
403548
+ if (!serverSideAvailable) {
403549
+ return null;
403550
+ }
403551
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
403552
+ const { getServerUrl: getServerUrl2 } = await Promise.resolve().then(() => (init_server_url(), exports_server_url));
403553
+ const { LETTA_CLOUD_API_URL: LETTA_CLOUD_API_URL2 } = await Promise.resolve().then(() => (init_oauth(), exports_oauth));
403554
+ const { listUnifiedMcpServers: listUnifiedMcpServers2, listUnifiedMcpTools: listUnifiedMcpTools2 } = await Promise.resolve().then(() => (init_unified_mcp(), exports_unified_mcp));
403555
+ const client = await getClient2();
403556
+ const allServers = await listUnifiedMcpServers2(client, agentId, 3000);
403557
+ const servers = getServerUrl2() === LETTA_CLOUD_API_URL2 ? allServers.filter((server2) => server2.serverType !== "stdio") : allServers;
403558
+ return Promise.all(servers.map(async (server2) => ({
403559
+ name: server2.serverName,
403560
+ toolCount: await listUnifiedMcpTools2(client, agentId, server2.id, 3000).then((tools) => tools.length).catch(() => null)
403561
+ })));
403562
+ }
403563
+ function formatMcpServerEntry(entry) {
403564
+ if (entry.toolCount === null) {
403565
+ return entry.name;
403566
+ }
403567
+ return `${entry.name} (${entry.toolCount} ${entry.toolCount === 1 ? "tool" : "tools"})`;
403568
+ }
403569
+ async function buildMcpServersInfoReminderText(context3, deps = {}) {
403570
+ try {
403571
+ const now2 = Date.now();
403572
+ const lastFetched = context3.state.lastMcpServersFetchedAtMs;
403573
+ const due = !context3.state.hasSentMcpServersInfo || lastFetched === null || now2 - lastFetched > MCP_SERVERS_REFRESH_MS;
403574
+ if (!due) {
403575
+ return null;
403576
+ }
403577
+ context3.state.lastMcpServersFetchedAtMs = now2;
403578
+ const localNames = (deps.getLocalServerNames ?? ((agentId) => settingsManager.getMcpServers(agentId).map((server2) => server2.name)))(context3.agent.id);
403579
+ const entries = localNames.map((name) => ({
403580
+ name,
403581
+ toolCount: null
403582
+ }));
403583
+ const serverSideEntries = await (deps.listServerSideServers ?? defaultListServerSideServers)(context3.agent.id);
403584
+ if (serverSideEntries) {
403585
+ entries.push(...serverSideEntries);
403586
+ }
403587
+ const uniqueEntries = [
403588
+ ...new Map(entries.map((entry) => [entry.name, entry])).values()
403589
+ ];
403590
+ const namesKey = uniqueEntries.map((entry) => `${entry.name}\x01${entry.toolCount ?? ""}`).join("\x00");
403591
+ if (context3.state.hasSentMcpServersInfo && context3.state.lastSentMcpServerNamesKey === namesKey) {
403592
+ return null;
403593
+ }
403594
+ context3.state.hasSentMcpServersInfo = true;
403595
+ context3.state.lastSentMcpServerNamesKey = namesKey;
403596
+ if (uniqueEntries.length === 0) {
403597
+ return `${SYSTEM_REMINDER_OPEN}
403598
+ MCP servers with available tools: None
403599
+ ${SYSTEM_REMINDER_CLOSE}`;
403600
+ }
403601
+ const rendered = uniqueEntries.map(formatMcpServerEntry).join(", ");
403602
+ return `${SYSTEM_REMINDER_OPEN}
403603
+ MCP servers with available tools: ${rendered}
403604
+ Find tools (with schemas) with \`letta mcp search "<what you want to do>"\`, list one server's tools with \`letta mcp tools <server>\` (\`--full\` includes schemas, \`letta mcp schema <tool-name>\` fetches one), and invoke one with \`letta mcp call <tool-name> --args '{"key":"value"}'\`.
403605
+ ${SYSTEM_REMINDER_CLOSE}`;
403606
+ } catch (error4) {
403607
+ debugLog("mcp", `Failed to build MCP servers reminder: ${error4 instanceof Error ? error4.message : String(error4)}`);
403608
+ return null;
403609
+ }
403610
+ }
403611
+ async function buildMcpServersInfoReminder(context3) {
403612
+ return buildMcpServersInfoReminderText(context3);
403613
+ }
403661
403614
  async function buildSessionContextReminder(context3) {
403662
403615
  if (!context3.systemInfoReminderEnabled || context3.state.hasSentSessionContext) {
403663
403616
  return null;
@@ -403853,7 +403806,7 @@ function prependReminderPartsToContent(content, reminderParts) {
403853
403806
  }
403854
403807
  return [...reminderParts, { type: "text", text: text2 }];
403855
403808
  }
403856
- var PERMISSION_MODE_DESCRIPTIONS, MAX_COMMAND_REMINDERS_PER_TURN = 10, MAX_TOOLSET_REMINDERS_PER_TURN = 5, MAX_COMMAND_INPUT_CHARS = 2000, MAX_COMMAND_OUTPUT_CHARS = 4000, MAX_TOOL_LIST_CHARS = 3000, sharedReminderProviders;
403809
+ var MCP_SERVERS_REFRESH_MS = 300000, PERMISSION_MODE_DESCRIPTIONS, MAX_COMMAND_REMINDERS_PER_TURN = 10, MAX_TOOLSET_REMINDERS_PER_TURN = 5, MAX_COMMAND_INPUT_CHARS = 2000, MAX_COMMAND_OUTPUT_CHARS = 4000, MAX_TOOL_LIST_CHARS = 3000, sharedReminderProviders;
403857
403810
  var init_engine3 = __esm(() => {
403858
403811
  init_agent_info();
403859
403812
  init_conversation_bootstrap();
@@ -403874,6 +403827,7 @@ var init_engine3 = __esm(() => {
403874
403827
  "agent-info": buildAgentInfoReminder,
403875
403828
  "conversation-bootstrap": buildConversationBootstrapReminderPart,
403876
403829
  "secrets-info": buildSecretsInfoReminder,
403830
+ "mcp-servers-info": buildMcpServersInfoReminder,
403877
403831
  "session-context": buildSessionContextReminder,
403878
403832
  "permission-mode": buildPermissionModeReminder,
403879
403833
  "memory-git-sync": buildMemoryGitSyncReminder,
@@ -404322,6 +404276,7 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
404322
404276
  const turnWorkingDirectory = getConversationWorkingDirectory(runtime.listener, agentId, conversationId);
404323
404277
  const turnPermissionModeState = getOrCreateConversationPermissionModeStateRef(runtime.listener, agentId, conversationId);
404324
404278
  let postStopApprovalRecoveryRetries = 0, llmApiErrorRetries = 0, emptyResponseRetries = 0, chatgptPlanSwaps = 0, lastApprovalContinuationAccepted = false, activeDequeuedBatchId = dequeuedBatchId;
404279
+ const chatgptExhaustedProviders = new Set;
404325
404280
  const turnCorrelation = existingTurnCorrelation ?? createTurnCorrelation(runtime, msg, activeDequeuedBatchId);
404326
404281
  const msgRunIds = [];
404327
404282
  let lastExecutionResults = null;
@@ -404688,8 +404643,10 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
404688
404643
  if (agentId && chatgptPlanSwaps < CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN) {
404689
404644
  const rotation = await rotateChatGPTPlanOnQuotaLimit({
404690
404645
  agentId,
404646
+ conversationId,
404691
404647
  currentHandle: null,
404692
- error: quotaError
404648
+ error: quotaError,
404649
+ exhaustedProviders: chatgptExhaustedProviders
404693
404650
  });
404694
404651
  if (rotation) {
404695
404652
  chatgptPlanSwaps += 1;
@@ -407712,11 +407669,11 @@ function scheduleRemoteRestart(connectionName, log2) {
407712
407669
  log2(`restart skipped (entrypoint=${entrypoint ?? "missing"}, connectionName=${connectionName ?? "missing"})`);
407713
407670
  return;
407714
407671
  }
407715
- log2(`scheduling remote listener restart for env ${connectionName}`);
407672
+ log2(`scheduling remote listener restart for computer ${connectionName}`);
407716
407673
  setTimeout(async () => {
407717
407674
  await flushRemoteSettingsWrites();
407718
- log2(`spawning replacement listener: ${process.execPath} ${entrypoint} remote --env-name ${connectionName}`);
407719
- 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], {
407720
407677
  cwd: process.cwd(),
407721
407678
  detached: true,
407722
407679
  env: process.env,
@@ -408217,7 +408174,7 @@ function getNumber(record3, keys3) {
408217
408174
  }
408218
408175
  return null;
408219
408176
  }
408220
- function getString2(record3, keys3) {
408177
+ function getString(record3, keys3) {
408221
408178
  const value = getValue(record3, keys3);
408222
408179
  if (typeof value === "string" && value.trim())
408223
408180
  return value.trim();
@@ -408303,7 +408260,7 @@ function normalizeCredits(raw2, rateLimit) {
408303
408260
  const resetCredits = getRecord(raw2, ["rate_limit_reset_credits", "rateLimitResetCredits"]) ?? getRecord(rateLimit, ["rate_limit_reset_credits", "rateLimitResetCredits"]);
408304
408261
  if (!credits && !resetCredits)
408305
408262
  return null;
408306
- const balance = getString2(credits, ["balance", "credit_balance", "amount"]);
408263
+ const balance = getString(credits, ["balance", "credit_balance", "amount"]);
408307
408264
  const availableCount = getNumber(credits, ["available_count", "availableCount", "count"]) ?? getNumber(resetCredits, ["available_count", "availableCount", "count"]);
408308
408265
  const hasCredits = getBoolean(credits, ["has_credits", "hasCredits"]);
408309
408266
  const unlimited = getBoolean(credits, ["unlimited", "is_unlimited"]);
@@ -408322,8 +408279,8 @@ function normalizeIndividualLimit(raw2, nowMs) {
408322
408279
  const record3 = getRecord(raw2, ["individual_limit", "individualLimit"]) ?? getRecord(spendControl, ["individual_limit", "individualLimit"]);
408323
408280
  if (!record3)
408324
408281
  return null;
408325
- const limit3 = getString2(record3, ["limit"]);
408326
- const used = getString2(record3, ["used"]);
408282
+ const limit3 = getString(record3, ["limit"]);
408283
+ const used = getString(record3, ["used"]);
408327
408284
  const remainingPercent = getNumber(record3, [
408328
408285
  "remaining_percent",
408329
408286
  "remainingPercent"
@@ -408352,10 +408309,10 @@ function normalizeCloudUsageWindow(value, fallbackLabel, nowMs) {
408352
408309
  const record3 = asRecord8(value);
408353
408310
  if (!record3)
408354
408311
  return null;
408355
- return normalizeUsageWindow(record3, getString2(record3, ["label", "name"]) ?? fallbackLabel, nowMs);
408312
+ return normalizeUsageWindow(record3, getString(record3, ["label", "name"]) ?? fallbackLabel, nowMs);
408356
408313
  }
408357
408314
  function normalizeAdditionalRateLimit(details, index, nowMs) {
408358
- const label = getString2(details, [
408315
+ const label = getString(details, [
408359
408316
  "limit_name",
408360
408317
  "limitName",
408361
408318
  "metered_feature",
@@ -408381,7 +408338,7 @@ function getRateLimitReachedType(raw2) {
408381
408338
  if (typeof value === "string" && value.trim())
408382
408339
  return value.trim();
408383
408340
  const record3 = asRecord8(value);
408384
- return getString2(record3, ["type", "kind"]);
408341
+ return getString(record3, ["type", "kind"]);
408385
408342
  }
408386
408343
  function formatPercent(value) {
408387
408344
  const rounded = Math.round(value);
@@ -408496,7 +408453,7 @@ function normalizeWhamUsageResponse(input) {
408496
408453
  const snapshotWithoutSummary = {
408497
408454
  providerName: input.providerName,
408498
408455
  fetchedAt,
408499
- planType: getString2(raw2, ["plan_type", "planType"]),
408456
+ planType: getString(raw2, ["plan_type", "planType"]),
408500
408457
  limitReached: getBoolean(rateLimit, ["limit_reached", "limitReached"]) ?? getBoolean(spendControl, ["reached"]),
408501
408458
  rateLimitReachedType: getRateLimitReachedType(raw2),
408502
408459
  primary,
@@ -408515,18 +408472,18 @@ function normalizeCloudChatGPTUsageResponse(input) {
408515
408472
  if (!raw2)
408516
408473
  return null;
408517
408474
  const nowMs = input.nowMs ?? Date.now();
408518
- const fetchedAt = getString2(raw2, ["fetchedAt", "fetched_at"]) ?? new Date(nowMs).toISOString();
408475
+ const fetchedAt = getString(raw2, ["fetchedAt", "fetched_at"]) ?? new Date(nowMs).toISOString();
408519
408476
  const additional = getRecordArray(raw2, [
408520
408477
  "additional",
408521
408478
  "additional_rate_limits",
408522
408479
  "additionalRateLimits"
408523
408480
  ]).map((window2, index) => normalizeCloudUsageWindow(window2, `limit ${index + 1}`, nowMs)).filter((window2) => !!window2);
408524
408481
  const snapshotWithoutSummary = {
408525
- providerName: getString2(raw2, ["providerName", "provider_name"]) ?? input.providerName,
408482
+ providerName: getString(raw2, ["providerName", "provider_name"]) ?? input.providerName,
408526
408483
  fetchedAt,
408527
- planType: getString2(raw2, ["planType", "plan_type"]),
408484
+ planType: getString(raw2, ["planType", "plan_type"]),
408528
408485
  limitReached: getBoolean(raw2, ["limitReached", "limit_reached"]),
408529
- rateLimitReachedType: getString2(raw2, [
408486
+ rateLimitReachedType: getString(raw2, [
408530
408487
  "rateLimitReachedType",
408531
408488
  "rate_limit_reached_type"
408532
408489
  ]),
@@ -408538,7 +408495,7 @@ function normalizeCloudChatGPTUsageResponse(input) {
408538
408495
  };
408539
408496
  return {
408540
408497
  ...snapshotWithoutSummary,
408541
- summary: getString2(raw2, ["summary"]) ?? formatChatGPTUsageSnapshot(snapshotWithoutSummary, new Date(nowMs))
408498
+ summary: getString(raw2, ["summary"]) ?? formatChatGPTUsageSnapshot(snapshotWithoutSummary, new Date(nowMs))
408542
408499
  };
408543
408500
  }
408544
408501
  function retryAfterMs(response) {
@@ -408563,7 +408520,7 @@ async function readJsonRecord(response) {
408563
408520
  }
408564
408521
  }
408565
408522
  function responseMessage(raw2, fallback) {
408566
- return getString2(raw2 ?? undefined, ["message", "error", "detail"]) ?? fallback;
408523
+ return getString(raw2 ?? undefined, ["message", "error", "detail"]) ?? fallback;
408567
408524
  }
408568
408525
  function chatGPTUsageError(code2, message, retryAfter) {
408569
408526
  return {
@@ -412332,7 +412289,7 @@ var init_app_server_openai_common = __esm(() => {
412332
412289
  function asRecord9(value) {
412333
412290
  return value !== null && typeof value === "object" ? value : null;
412334
412291
  }
412335
- function stringValue4(value) {
412292
+ function stringValue3(value) {
412336
412293
  return typeof value === "string" ? value : undefined;
412337
412294
  }
412338
412295
  function extractToolCallFragments(record3) {
@@ -412346,12 +412303,12 @@ function extractToolCallFragments(record3) {
412346
412303
  if (!toolCall) {
412347
412304
  continue;
412348
412305
  }
412349
- const toolCallId = stringValue4(toolCall.tool_call_id);
412306
+ const toolCallId = stringValue3(toolCall.tool_call_id);
412350
412307
  if (!toolCallId) {
412351
412308
  continue;
412352
412309
  }
412353
- const name = stringValue4(toolCall.name) ?? null;
412354
- const argumentsDelta = stringValue4(toolCall.arguments) ?? null;
412310
+ const name = stringValue3(toolCall.name) ?? null;
412311
+ const argumentsDelta = stringValue3(toolCall.arguments) ?? null;
412355
412312
  fragments.push({ toolCallId, name, argumentsDelta });
412356
412313
  }
412357
412314
  return fragments;
@@ -412391,7 +412348,7 @@ function extractToolReturns(record3) {
412391
412348
  if (!rec) {
412392
412349
  continue;
412393
412350
  }
412394
- const toolCallId = stringValue4(rec.tool_call_id);
412351
+ const toolCallId = stringValue3(rec.tool_call_id);
412395
412352
  const status = asToolReturnStatus2(rec.status);
412396
412353
  if (!toolCallId || !status) {
412397
412354
  continue;
@@ -412406,7 +412363,7 @@ function extractToolReturns(record3) {
412406
412363
  return results;
412407
412364
  }
412408
412365
  }
412409
- const topLevelToolCallId = stringValue4(record3.tool_call_id);
412366
+ const topLevelToolCallId = stringValue3(record3.tool_call_id);
412410
412367
  const topLevelStatus = asToolReturnStatus2(record3.status);
412411
412368
  if (!topLevelToolCallId || !topLevelStatus) {
412412
412369
  return [];
@@ -412494,13 +412451,13 @@ function createToolLifecycleTracker(onEvent) {
412494
412451
  return;
412495
412452
  }
412496
412453
  const record3 = delta2;
412497
- const messageType = stringValue4(record3.message_type);
412498
- const toolCallId = stringValue4(record3.tool_call_id);
412454
+ const messageType = stringValue3(record3.message_type);
412455
+ const toolCallId = stringValue3(record3.tool_call_id);
412499
412456
  if (messageType === "client_tool_start" && toolCallId) {
412500
412457
  const state = getOrCreate(toolCallId);
412501
412458
  state.clientManaged = true;
412502
412459
  if (!state.name)
412503
- state.name = stringValue4(record3.tool_name) ?? null;
412460
+ state.name = stringValue3(record3.tool_name) ?? null;
412504
412461
  return;
412505
412462
  }
412506
412463
  if (messageType === "client_tool_end" && toolCallId) {
@@ -414087,7 +414044,7 @@ var init_gateway_supervisor = __esm(() => {
414087
414044
 
414088
414045
  // src/cli/subcommands/listen.tsx
414089
414046
  import { hostname as hostname4 } from "node:os";
414090
- import { parseArgs as parseArgs9 } from "node:util";
414047
+ import { parseArgs as parseArgs8 } from "node:util";
414091
414048
  import { MessageChannel as MessageChannel2 } from "node:worker_threads";
414092
414049
  function PromptEnvName(props) {
414093
414050
  const [value, setValue] = import_react33.useState("");
@@ -414095,7 +414052,7 @@ function PromptEnvName(props) {
414095
414052
  flexDirection: "column",
414096
414053
  children: [
414097
414054
  /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
414098
- children: "Enter environment name (or press Enter for hostname): "
414055
+ children: "Enter computer name (or press Enter for hostname): "
414099
414056
  }, undefined, false, undefined, this),
414100
414057
  /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(build_default, {
414101
414058
  value,
@@ -414172,14 +414129,14 @@ function shouldAcquireStandaloneListenerLock() {
414172
414129
  return shouldAcquireManualListenerLock(getSpawnerListenerInstanceId(), process.env.LETTA_DESKTOP_MODE === "1");
414173
414130
  }
414174
414131
  function printListenUsage() {
414175
- 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]
414176
414133
  `);
414177
- 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.
414178
414135
  `);
414179
414136
  console.log("Options:");
414180
- 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)");
414181
414138
  console.log(" --channels <list> Comma-separated channel names to enable (e.g. telegram)");
414182
- console.log(" --skills <path> Use this directory for environment-provided skills");
414139
+ console.log(" --skills <path> Use this directory for computer-provided skills");
414183
414140
  console.log(" --install-channel-runtimes Install missing runtime deps for the selected channels before startup");
414184
414141
  console.log(" --debug Plain-text mode: log all WebSocket events instead of interactive UI");
414185
414142
  console.log(` -h, --help Show this help message
@@ -414187,20 +414144,20 @@ function printListenUsage() {
414187
414144
  console.log("Examples:");
414188
414145
  console.log(" letta channels configure telegram # Configure Telegram first");
414189
414146
  console.log(" letta server # Uses hostname as default");
414190
- console.log(' letta server --env-name "work-laptop"');
414147
+ console.log(' letta server --computer-name "work-laptop"');
414191
414148
  console.log(" letta server --channels telegram # Enable Telegram channel");
414192
414149
  console.log(" letta server --channels telegram --install-channel-runtimes");
414193
414150
  console.log(` letta server --debug # Log all WS events
414194
414151
  `);
414195
414152
  console.log("Once connected, this instance will listen for incoming messages from cloud agents.");
414196
- console.log("Messages will be executed locally using your letta-code environment.");
414153
+ console.log("Messages will be executed locally on this computer.");
414197
414154
  console.log("Telegram flow: configure the bot, start the listener with --channels telegram,");
414198
414155
  console.log("then message the bot from Telegram and run /channels telegram pair <code> in the target conversation.");
414199
414156
  }
414200
414157
  async function runListenSubcommand(argv) {
414201
414158
  let values3;
414202
414159
  try {
414203
- ({ values: values3 } = parseArgs9({
414160
+ ({ values: values3 } = parseArgs8({
414204
414161
  args: argv,
414205
414162
  options: LISTEN_OPTIONS,
414206
414163
  strict: true,
@@ -414282,8 +414239,9 @@ async function runListenSubcommand(argv) {
414282
414239
  const restoreAgentScope = restoreEnabledChannels ? resolveChannelRestoreAgentScope(scopedRestoreAgentScope) : null;
414283
414240
  const channelNames = values3.channels ? values3.channels.split(",").map((s3) => s3.trim()).filter(Boolean) : [];
414284
414241
  let connectionName;
414285
- if (values3["env-name"]) {
414286
- connectionName = values3["env-name"];
414242
+ const explicitComputerName = values3["computer-name"] ?? values3["env-name"];
414243
+ if (explicitComputerName) {
414244
+ connectionName = explicitComputerName;
414287
414245
  settingsManager.setListenerEnvName(connectionName);
414288
414246
  } else {
414289
414247
  const savedName = settingsManager.getListenerEnvName();
@@ -414312,7 +414270,7 @@ async function runListenSubcommand(argv) {
414312
414270
  const startupMode = await resolveListenerStartupMode(channelNames, channelNames.length > 0 || restoreEnabledChannels);
414313
414271
  if (startupMode.kind === "unsupported-self-hosted") {
414314
414272
  console.error(`Self-hosted listener registration is not available for ${startupMode.serverUrl}.`);
414315
- 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.");
414316
414274
  await flushListenerTelemetryEnd("listener_self_hosted_no_channels");
414317
414275
  return 1;
414318
414276
  }
@@ -414344,8 +414302,8 @@ async function runListenSubcommand(argv) {
414344
414302
  });
414345
414303
  } catch (lockError) {
414346
414304
  if (lockError instanceof ManualListenerAlreadyRunningError) {
414347
- console.error(`A letta server for environment "${connectionName}" is already running on this machine (pid ${lockError.holderPid}).`);
414348
- 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.");
414349
414307
  console.error(`Lock: ${lockError.lockPath}`);
414350
414308
  await flushListenerTelemetryEnd("listener_already_running");
414351
414309
  return 1;
@@ -414434,9 +414392,9 @@ async function runListenSubcommand(argv) {
414434
414392
  const connectionId2 = `local-${deviceId}`;
414435
414393
  const startupLabel = startupMode.backend === "local" ? "local backend" : `self-hosted server ${startupMode.serverUrl}`;
414436
414394
  sessionLog.log(`Starting local channel listener for ${startupLabel}`);
414437
- sessionLog.log("Skipping environment registration");
414395
+ sessionLog.log("Skipping computer registration");
414438
414396
  console.log(`Starting local channel listener for ${startupLabel}`);
414439
- console.log(`Skipping environment registration. Press Ctrl+C to stop.
414397
+ console.log(`Skipping computer registration. Press Ctrl+C to stop.
414440
414398
  `);
414441
414399
  const { startLocalChannelListener: startLocalChannelListener2 } = await init_listen_client().then(() => exports_listen_client);
414442
414400
  await startLocalChannelListener2({
@@ -414558,7 +414516,7 @@ async function runListenSubcommand(argv) {
414558
414516
  console.log(`[${formatTimestamp3()}] Reconnecting (attempt ${attempt2}, retry in ${Math.round(nextRetryIn / 1000)}s)`);
414559
414517
  },
414560
414518
  onNeedsReregister: async () => {
414561
- console.log(`[${formatTimestamp3()}] Environment expired, re-registering...`);
414519
+ console.log(`[${formatTimestamp3()}] Computer connection expired, re-registering...`);
414562
414520
  try {
414563
414521
  const result2 = await reregister();
414564
414522
  await startDebugClient(result2.connectionId, result2.wsUrl, result2.supportsSplitStatusChannels, result2.supportsPairedListenerGenerations);
@@ -414626,7 +414584,7 @@ async function runListenSubcommand(argv) {
414626
414584
  updateRetryStatusCallback?.(attempt2, nextRetryIn);
414627
414585
  },
414628
414586
  onNeedsReregister: async () => {
414629
- sessionLog.log("Environment expired, re-registering...");
414587
+ sessionLog.log("Computer connection expired, re-registering...");
414630
414588
  try {
414631
414589
  const result2 = await reregister();
414632
414590
  await startNormalClient(result2.connectionId, result2.wsUrl, result2.supportsSplitStatusChannels, result2.supportsPairedListenerGenerations);
@@ -414695,6 +414653,7 @@ var init_listen = __esm(async () => {
414695
414653
  jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
414696
414654
  activeListenerProcessAnchors = new Set;
414697
414655
  LISTEN_OPTIONS = {
414656
+ "computer-name": { type: "string" },
414698
414657
  "env-name": { type: "string" },
414699
414658
  channels: { type: "string" },
414700
414659
  skills: { type: "string" },
@@ -415108,15 +415067,15 @@ var init_transcript_migration = __esm(() => {
415108
415067
  });
415109
415068
 
415110
415069
  // src/cli/subcommands/local-backend.ts
415111
- import { parseArgs as parseArgs10 } from "node:util";
415070
+ import { parseArgs as parseArgs9 } from "node:util";
415112
415071
  function parseLocalBackendArgs(argv) {
415113
- return parseArgs10({
415072
+ return parseArgs9({
415114
415073
  args: argv,
415115
415074
  options: LOCAL_BACKEND_OPTIONS,
415116
415075
  strict: true
415117
415076
  });
415118
415077
  }
415119
- function printUsage8() {
415078
+ function printUsage7() {
415120
415079
  console.log(`
415121
415080
  Usage:
415122
415081
  letta local-backend migrate-transcripts [--storage-dir <path>] [--dry-run]
@@ -415129,12 +415088,12 @@ before it is replaced.
415129
415088
  async function runLocalBackendSubcommand(argv) {
415130
415089
  const [command, ...rest4] = argv;
415131
415090
  if (!command || command === "help" || command === "--help" || command === "-h") {
415132
- printUsage8();
415091
+ printUsage7();
415133
415092
  return command ? 0 : 1;
415134
415093
  }
415135
415094
  if (command !== "migrate-transcripts") {
415136
415095
  console.error(`Unknown local-backend command: ${command}`);
415137
- printUsage8();
415096
+ printUsage7();
415138
415097
  return 1;
415139
415098
  }
415140
415099
  let parsed;
@@ -415143,11 +415102,11 @@ async function runLocalBackendSubcommand(argv) {
415143
415102
  } catch (error4) {
415144
415103
  const message = error4 instanceof Error ? error4.message : String(error4);
415145
415104
  console.error(`Error: ${message}`);
415146
- printUsage8();
415105
+ printUsage7();
415147
415106
  return 1;
415148
415107
  }
415149
415108
  if (parsed.values.help) {
415150
- printUsage8();
415109
+ printUsage7();
415151
415110
  return 0;
415152
415111
  }
415153
415112
  const storageDir = parsed.values["storage-dir"] ?? getLocalBackendStorageDir();
@@ -415169,160 +415128,6 @@ var init_local_backend2 = __esm(() => {
415169
415128
  };
415170
415129
  });
415171
415130
 
415172
- // src/backend/api/unified-mcp.ts
415173
- function stringField2(value, key2) {
415174
- return typeof value[key2] === "string" ? value[key2] : null;
415175
- }
415176
- function recordField(value, ...names2) {
415177
- for (const name of names2) {
415178
- const field = value[name];
415179
- if (isRecord(field))
415180
- return field;
415181
- }
415182
- return;
415183
- }
415184
- function parseServer(value, registered) {
415185
- if (!isRecord(value))
415186
- return null;
415187
- const id2 = stringField2(value, "id");
415188
- const serverName = stringField2(value, "server_name") ?? (registered ? stringField2(registered, "server_name") : null);
415189
- const serverType = stringField2(value, "mcp_server_type") ?? (registered ? stringField2(registered, "mcp_server_type") : null) ?? "unknown";
415190
- if (!id2 || !serverName)
415191
- return null;
415192
- const serverUrl = stringField2(value, "server_url") ?? (registered ? stringField2(registered, "server_url") : null) ?? undefined;
415193
- const command = stringField2(value, "command") ?? (registered ? stringField2(registered, "command") : null) ?? undefined;
415194
- const argsValue = value.args ?? registered?.args;
415195
- const args = Array.isArray(argsValue) ? argsValue.filter((item) => typeof item === "string") : [];
415196
- const target2 = serverUrl ?? [command, ...args].filter(Boolean).join(" ");
415197
- return {
415198
- id: id2,
415199
- serverName,
415200
- serverType,
415201
- target: target2,
415202
- ...serverUrl ? { serverUrl } : {},
415203
- ...command ? { command, args } : {}
415204
- };
415205
- }
415206
- function parseTool(value) {
415207
- if (!isRecord(value))
415208
- return null;
415209
- const id2 = stringField2(value, "id");
415210
- const name = stringField2(value, "name");
415211
- if (!id2 || !name)
415212
- return null;
415213
- const description = stringField2(value, "description");
415214
- const jsonSchema = isRecord(value.json_schema) ? value.json_schema : {};
415215
- const inputSchema = isRecord(jsonSchema.parameters) ? jsonSchema.parameters : isRecord(value.args_json_schema) ? value.args_json_schema : { type: "object", properties: {} };
415216
- const title = stringField2(value, "title") ?? stringField2(jsonSchema, "title");
415217
- const outputSchema = recordField(value, "outputSchema", "output_schema") ?? recordField(jsonSchema, "outputSchema", "output_schema");
415218
- const annotations = recordField(value, "annotations") ?? recordField(jsonSchema, "annotations");
415219
- const execution = recordField(value, "execution") ?? recordField(jsonSchema, "execution");
415220
- const meta = recordField(value, "_meta") ?? recordField(jsonSchema, "_meta");
415221
- const iconsValue = value.icons ?? jsonSchema.icons;
415222
- const icons = Array.isArray(iconsValue) ? iconsValue.filter(isRecord) : undefined;
415223
- return {
415224
- id: id2,
415225
- name,
415226
- ...title ? { title } : {},
415227
- description,
415228
- inputSchema,
415229
- ...outputSchema ? { outputSchema } : {},
415230
- ...annotations ? { annotations } : {},
415231
- ...execution ? { execution } : {},
415232
- ...meta ? { _meta: meta } : {},
415233
- ...icons ? { icons } : {}
415234
- };
415235
- }
415236
- function parseRunResult(value) {
415237
- if (!isRecord(value))
415238
- throw new Error("Invalid MCP tool run response");
415239
- return {
415240
- status: stringField2(value, "status") ?? "unknown",
415241
- funcReturn: value.func_return,
415242
- stdout: value.stdout,
415243
- stderr: value.stderr
415244
- };
415245
- }
415246
- function parseSearchResult(value) {
415247
- if (!isRecord(value) || !isRecord(value.tool))
415248
- return null;
415249
- const toolId = stringField2(value.tool, "id");
415250
- const jsonSchema = value.tool.json_schema;
415251
- const score = value.combined_score;
415252
- if (!toolId || jsonSchema !== null && !isRecord(jsonSchema) || typeof score !== "number") {
415253
- return null;
415254
- }
415255
- return { toolId, jsonSchema, score };
415256
- }
415257
- async function withTimeout3(promise, timeoutMs, operation) {
415258
- let timer;
415259
- try {
415260
- return await Promise.race([
415261
- promise,
415262
- new Promise((_resolve, reject2) => {
415263
- timer = setTimeout(() => reject2(new Error(`${operation} timed out after ${timeoutMs}ms`)), timeoutMs);
415264
- })
415265
- ]);
415266
- } finally {
415267
- if (timer)
415268
- clearTimeout(timer);
415269
- }
415270
- }
415271
- async function listUnifiedMcpServers(client, agentId, timeoutMs = 1e4) {
415272
- const value = await withTimeout3(client.get(`/v1/agents/${encodeURIComponent(agentId)}/mcp-servers`), timeoutMs, "Listing agent MCP servers");
415273
- if (!Array.isArray(value))
415274
- return [];
415275
- const needsEnrichment = value.some((item) => isRecord(item) && !stringField2(item, "mcp_server_type"));
415276
- const registeredById = new Map;
415277
- if (needsEnrichment && client.mcpServers) {
415278
- try {
415279
- const registered = await withTimeout3(client.mcpServers.list(), timeoutMs, "Listing registered MCP servers");
415280
- for (const item of registered) {
415281
- if (!isRecord(item))
415282
- continue;
415283
- const id2 = stringField2(item, "id");
415284
- if (id2)
415285
- registeredById.set(id2, item);
415286
- }
415287
- } catch {}
415288
- }
415289
- return value.map((item) => {
415290
- const registered = isRecord(item) ? registeredById.get(stringField2(item, "id") ?? "") : undefined;
415291
- return parseServer(item, registered);
415292
- }).filter((server2) => server2 !== null);
415293
- }
415294
- async function listUnifiedMcpTools(client, agentId, mcpServerId, timeoutMs = 1e4) {
415295
- const value = await withTimeout3(client.get(`/v1/agents/${encodeURIComponent(agentId)}/mcp-servers/${encodeURIComponent(mcpServerId)}/tools`), timeoutMs, "Listing agent MCP server tools");
415296
- if (!Array.isArray(value))
415297
- return [];
415298
- return value.map(parseTool).filter((tool) => tool !== null);
415299
- }
415300
- async function searchUnifiedMcpTools(params) {
415301
- const value = await withTimeout3(params.client.post(`/v1/agents/${encodeURIComponent(params.agentId)}/mcp-servers/tools/search`, {
415302
- body: {
415303
- query: params.query,
415304
- search_mode: params.searchMode,
415305
- limit: params.limit
415306
- }
415307
- }), params.timeoutMs ?? 60000, "Searching agent MCP tools");
415308
- if (!Array.isArray(value)) {
415309
- throw new Error("Invalid MCP tool search response");
415310
- }
415311
- const results = [];
415312
- for (const item of value) {
415313
- const result2 = parseSearchResult(item);
415314
- if (!result2)
415315
- throw new Error("Invalid MCP tool search result");
415316
- results.push(result2);
415317
- }
415318
- return results;
415319
- }
415320
- async function runUnifiedMcpTool(params) {
415321
- const value = await withTimeout3(params.client.post(`/v1/agents/${encodeURIComponent(params.agentId)}/mcp-servers/${encodeURIComponent(params.mcpServerId)}/tools/${encodeURIComponent(params.toolId)}/run`, { body: { args: params.args } }), params.timeoutMs ?? 60000, "Running agent MCP tool");
415322
- return parseRunResult(value);
415323
- }
415324
- var init_unified_mcp = () => {};
415325
-
415326
415131
  // node_modules/pkce-challenge/dist/index.node.js
415327
415132
  async function getRandomValues(size2) {
415328
415133
  return (await crypto2).getRandomValues(new Uint8Array(size2));
@@ -432165,7 +431970,7 @@ var init_mcp_client = __esm(() => {
432165
431970
  init_streamableHttp();
432166
431971
  DEFAULT_CLIENT_INFO = {
432167
431972
  name: "letta-code",
432168
- version: "0.31.10"
431973
+ version: "0.31.12"
432169
431974
  };
432170
431975
  });
432171
431976
 
@@ -432453,7 +432258,6 @@ async function replaceClientMcpServers(agentId, configs, options = {}) {
432453
432258
  const generation2 = ++runtime.generation;
432454
432259
  await closeActiveServers(runtime);
432455
432260
  runtime.agentId = agentId;
432456
- const usedToolNames = new Set;
432457
432261
  const states2 = await Promise.all(configs.map(async (config2) => {
432458
432262
  let oauth;
432459
432263
  try {
@@ -432472,20 +432276,8 @@ async function replaceClientMcpServers(agentId, configs, options = {}) {
432472
432276
  await connection.close();
432473
432277
  return { config: config2, status: "failed", tools: [], error: "Superseded" };
432474
432278
  }
432475
- const tools = connection.tools.map((tool) => {
432476
- const name = uniqueToolName(formatClientMcpToolName(config2.name, tool.name), usedToolNames);
432477
- const definition = {
432478
- name,
432479
- label: tool.title ?? tool.name,
432480
- description: tool.description ?? `Tool ${tool.name} from MCP server ${config2.name}`,
432481
- parameters: tool.inputSchema,
432482
- executor: async (_toolCallId, _toolName, input) => toExternalToolResult(await connection.callTool(tool.name, input))
432483
- };
432484
- return definition;
432485
- });
432486
- registerExternalTools(tools);
432487
- runtime.active.set(config2.name, { connection, tools });
432488
- return { config: config2, status: "connected", tools };
432279
+ runtime.active.set(config2.name, { connection });
432280
+ return { config: config2, status: "connected", tools: connection.tools };
432489
432281
  } catch (error5) {
432490
432282
  return {
432491
432283
  config: config2,
@@ -432533,23 +432325,11 @@ async function closeActiveServers(runtime) {
432533
432325
  runtime.pendingOAuth.clear();
432534
432326
  runtime.active.clear();
432535
432327
  runtime.states = [];
432536
- for (const server2 of active)
432537
- unregisterExternalTools(server2.tools);
432538
432328
  await Promise.allSettled([
432539
432329
  ...pendingOAuth.map((oauth) => oauth.close()),
432540
432330
  ...active.map((server2) => server2.connection.close())
432541
432331
  ]);
432542
432332
  }
432543
- function uniqueToolName(base2, used) {
432544
- let name = base2;
432545
- let suffix = 2;
432546
- while (used.has(name)) {
432547
- name = `${base2}_${suffix}`;
432548
- suffix++;
432549
- }
432550
- used.add(name);
432551
- return name;
432552
- }
432553
432333
  function formatClientMcpToolName(serverName, toolName) {
432554
432334
  return `mcp__${normalizeMcpName(serverName)}__${normalizeMcpName(toolName)}`;
432555
432335
  }
@@ -432557,35 +432337,10 @@ function normalizeMcpName(value) {
432557
432337
  const normalized = value.replace(/[^a-zA-Z0-9_-]/g, "_");
432558
432338
  return normalized || "tool";
432559
432339
  }
432560
- function toExternalToolResult(result2) {
432561
- return {
432562
- content: result2.content.map((item) => normalizeContent2(item)),
432563
- isError: result2.isError === true
432564
- };
432565
- }
432566
- function normalizeContent2(item) {
432567
- if (isRecord17(item)) {
432568
- if (item.type === "text" && typeof item.text === "string") {
432569
- return { type: "text", text: item.text };
432570
- }
432571
- if ((item.type === "image" || item.type === "audio") && typeof item.data === "string") {
432572
- return {
432573
- type: item.type,
432574
- data: item.data,
432575
- ...typeof item.mimeType === "string" ? { mimeType: item.mimeType } : {}
432576
- };
432577
- }
432578
- }
432579
- return { type: "text", text: JSON.stringify(item) };
432580
- }
432581
- function isRecord17(value) {
432582
- return typeof value === "object" && value !== null && !Array.isArray(value);
432583
- }
432584
432340
  var CLIENT_MCP_RUNTIME_KEY;
432585
- var init_mcp_runtime = __esm(async () => {
432341
+ var init_mcp_runtime = __esm(() => {
432586
432342
  init_mcp_client();
432587
432343
  init_mcp_oauth();
432588
- await init_manager4();
432589
432344
  CLIENT_MCP_RUNTIME_KEY = Symbol.for("@letta/clientMcpRuntime");
432590
432345
  });
432591
432346
 
@@ -432606,20 +432361,23 @@ function printMcpUsage(stdout) {
432606
432361
  Usage:
432607
432362
  letta mcp list [--agent <id>]
432608
432363
  letta mcp get <server> [--agent <id>]
432609
- letta mcp tools [server] [--agent <id>]
432364
+ letta mcp tools [server] [--full] [--agent <id>]
432365
+ letta mcp schema <tool-name> [--agent <id>]
432610
432366
  letta mcp search <query> [--mode <hybrid|vector|fts>] [--limit <n>] [--agent <id>]
432611
432367
  letta mcp call <tool-name> [--args '<json>' | --args-file <path|->] [--agent <id>]
432612
432368
 
432613
432369
  Commands:
432614
432370
  list List MCP servers available to the agent
432615
432371
  get Print one server's redacted connection configuration
432616
- tools Print complete MCP tool schemas; names are accepted by call
432372
+ tools List tool names and descriptions; names are accepted by call
432373
+ schema Print one tool's complete schema
432617
432374
  search Search tools available to the agent
432618
432375
  call Call one exact tool name and print an MCP CallToolResult
432619
432376
 
432620
432377
  Options:
432621
432378
  --agent <id> Agent ID. Defaults to LETTA_AGENT_ID or AGENT_ID
432622
432379
  --agent-id <id> Alias for --agent
432380
+ --full Include complete schemas in tools output
432623
432381
  --mode <mode> Search mode: hybrid (default), vector, or fts
432624
432382
  --limit <n> Search result limit from 1 to 100 (default: 5)
432625
432383
  --args <json> JSON object passed to a tool
@@ -432823,14 +432581,21 @@ function formatServerMcpToolName(serverName, alias, toolName) {
432823
432581
  const rawName = toolName.startsWith(sourcePrefix) ? toolName.slice(sourcePrefix.length) : toolName;
432824
432582
  return formatClientMcpToolName(alias, rawName);
432825
432583
  }
432826
- var init_mcp_tool_names = __esm(async () => {
432827
- await init_mcp_runtime();
432584
+ var init_mcp_tool_names = __esm(() => {
432585
+ init_mcp_runtime();
432828
432586
  });
432829
432587
 
432830
432588
  // src/cli/subcommands/mcp.ts
432831
- import { parseArgs as parseArgs11 } from "node:util";
432589
+ import { parseArgs as parseArgs10 } from "node:util";
432590
+ function defaultIsHostedLettaCloud() {
432591
+ try {
432592
+ return getServerUrl() === LETTA_CLOUD_API_URL;
432593
+ } catch {
432594
+ return !process.env.LETTA_BASE_URL;
432595
+ }
432596
+ }
432832
432597
  function parseMcpArgs(argv) {
432833
- return parseArgs11({
432598
+ return parseArgs10({
432834
432599
  args: argv,
432835
432600
  options: {
432836
432601
  help: { type: "boolean", short: "h" },
@@ -432838,6 +432603,7 @@ function parseMcpArgs(argv) {
432838
432603
  "agent-id": { type: "string" },
432839
432604
  mode: { type: "string" },
432840
432605
  limit: { type: "string" },
432606
+ full: { type: "boolean" },
432841
432607
  args: { type: "string" },
432842
432608
  "args-file": { type: "string" }
432843
432609
  },
@@ -432853,7 +432619,7 @@ function parseCommandLine(argv) {
432853
432619
  }
432854
432620
  return { action: action3, target: target2, values: parsed.values };
432855
432621
  }
432856
- function stringValue5(value) {
432622
+ function stringValue4(value) {
432857
432623
  return typeof value === "string" ? value : undefined;
432858
432624
  }
432859
432625
  function getLocalServers(deps, agentId) {
@@ -432892,9 +432658,8 @@ function redactUrl(value) {
432892
432658
  const url2 = new URL(value);
432893
432659
  url2.username = "";
432894
432660
  url2.password = "";
432895
- const sensitive = /token|key|secret|password|signature|credential/i;
432896
432661
  for (const key2 of url2.searchParams.keys()) {
432897
- if (sensitive.test(key2))
432662
+ if (SENSITIVE_NAME.test(key2))
432898
432663
  url2.searchParams.set(key2, "[REDACTED]");
432899
432664
  }
432900
432665
  return url2.toString();
@@ -432902,6 +432667,32 @@ function redactUrl(value) {
432902
432667
  return value;
432903
432668
  }
432904
432669
  }
432670
+ function redactArgs(args) {
432671
+ const redacted = [];
432672
+ let redactNext = false;
432673
+ for (const arg of args) {
432674
+ if (redactNext) {
432675
+ redacted.push("[REDACTED]");
432676
+ redactNext = false;
432677
+ continue;
432678
+ }
432679
+ if (arg.startsWith("-")) {
432680
+ const equalsIndex = arg.indexOf("=");
432681
+ const flagName = equalsIndex === -1 ? arg : arg.slice(0, equalsIndex);
432682
+ if (SENSITIVE_NAME.test(flagName)) {
432683
+ if (equalsIndex === -1) {
432684
+ redactNext = true;
432685
+ redacted.push(arg);
432686
+ } else {
432687
+ redacted.push(`${flagName}=[REDACTED]`);
432688
+ }
432689
+ continue;
432690
+ }
432691
+ }
432692
+ redacted.push(arg);
432693
+ }
432694
+ return redacted;
432695
+ }
432905
432696
  function serverDetails(target2) {
432906
432697
  if (target2.kind === "client") {
432907
432698
  const config2 = target2.config;
@@ -432917,7 +432708,7 @@ function serverDetails(target2) {
432917
432708
  name: config2.name,
432918
432709
  transport: "stdio",
432919
432710
  command: config2.command,
432920
- args: config2.args ?? [],
432711
+ args: redactArgs(config2.args ?? []),
432921
432712
  ...config2.cwd ? { cwd: config2.cwd } : {},
432922
432713
  env: redactValues(config2.env)
432923
432714
  };
@@ -432931,7 +432722,7 @@ function serverDetails(target2) {
432931
432722
  name: server2.serverName,
432932
432723
  transport: "stdio",
432933
432724
  command: server2.command ?? server2.target.split(" ")[0] ?? "",
432934
- args: server2.args ?? [],
432725
+ args: redactArgs(server2.args ?? []),
432935
432726
  env: {}
432936
432727
  };
432937
432728
  }
@@ -433021,7 +432812,10 @@ async function buildToolCatalog(deps, agentId, options = {}) {
433021
432812
  const connections = [];
433022
432813
  const usedNames = new Set;
433023
432814
  try {
433024
- const serverTargets = activeServers.filter((target2) => target2.kind === "server");
432815
+ const hostedLettaCloud = (deps.isHostedLettaCloud ?? defaultIsHostedLettaCloud)();
432816
+ const allServerTargets = activeServers.filter((target2) => target2.kind === "server");
432817
+ const serverTargets = hostedLettaCloud ? allServerTargets.filter(({ server: server2 }) => server2.serverType !== "stdio") : allServerTargets;
432818
+ const excludedHostedStdioServers = serverTargets.length !== allServerTargets.length;
433025
432819
  if (serverTargets.length > 0) {
433026
432820
  const client = await getServerClient(deps);
433027
432821
  const toolLists = await Promise.all(serverTargets.map(async ({ server: server2 }) => ({
@@ -433084,6 +432878,7 @@ async function buildToolCatalog(deps, agentId, options = {}) {
433084
432878
  }
433085
432879
  return {
433086
432880
  tools: catalog,
432881
+ excludedHostedStdioServers,
433087
432882
  close: async () => {
433088
432883
  await Promise.allSettled(connections.map((connection) => connection.close()));
433089
432884
  }
@@ -433126,12 +432921,12 @@ function mcpToolResultFromServer(result2) {
433126
432921
  isError: !success || normalized.isError === true
433127
432922
  };
433128
432923
  }
433129
- function printJson2(stdout, value) {
432924
+ function printJson(stdout, value) {
433130
432925
  stdout(JSON.stringify(value, null, 2));
433131
432926
  }
433132
432927
  async function runList(deps, agentId, stdout) {
433133
432928
  const servers = await listUnifiedServers(deps, agentId);
433134
- printJson2(stdout, servers.map(serverSummary));
432929
+ printJson(stdout, servers.map(serverSummary));
433135
432930
  return 0;
433136
432931
  }
433137
432932
  async function runGet(deps, agentId, selector, stdout) {
@@ -433139,25 +432934,45 @@ async function runGet(deps, agentId, selector, stdout) {
433139
432934
  throw new McpCliError("invalid_arguments", "Usage: letta mcp get <server>");
433140
432935
  }
433141
432936
  const server2 = resolveServer(await listUnifiedServers(deps, agentId), selector);
433142
- printJson2(stdout, serverDetails(server2));
432937
+ printJson(stdout, serverDetails(server2));
433143
432938
  return 0;
433144
432939
  }
433145
- async function runTools(deps, agentId, serverSelector, stdout) {
432940
+ async function runTools(deps, agentId, serverSelector, full, stdout) {
433146
432941
  const catalog = await buildToolCatalog(deps, agentId, { serverSelector });
433147
432942
  try {
433148
- printJson2(stdout, catalog.tools.map((tool) => tool.schema));
432943
+ printJson(stdout, catalog.tools.map((tool) => full ? tool.schema : {
432944
+ name: tool.schema.name,
432945
+ ...tool.schema.title ? { title: tool.schema.title } : {},
432946
+ ...tool.schema.description ? { description: tool.schema.description } : {}
432947
+ }));
433149
432948
  } finally {
433150
432949
  await catalog.close();
433151
432950
  }
433152
432951
  return 0;
433153
432952
  }
432953
+ async function runSchema(deps, agentId, toolName, stdout) {
432954
+ if (!toolName) {
432955
+ throw new McpCliError("invalid_arguments", "Usage: letta mcp schema <tool-name>");
432956
+ }
432957
+ const catalog = await buildToolCatalog(deps, agentId, { toolName });
432958
+ try {
432959
+ const tool = catalog.tools.find((candidate) => candidate.schema.name === toolName);
432960
+ if (!tool) {
432961
+ throw new McpCliError("tool_not_found", `MCP tool '${toolName}' is not available`);
432962
+ }
432963
+ printJson(stdout, tool.schema);
432964
+ return 0;
432965
+ } finally {
432966
+ await catalog.close();
432967
+ }
432968
+ }
433154
432969
  async function runSearch(parsed, deps, agentId, stdout) {
433155
432970
  const serverSearchAvailable = serverMcpAvailable(deps);
433156
432971
  const hasClientLocalServers = getLocalServers(deps, agentId).length > 0;
433157
432972
  return runMcpSearch({
433158
432973
  query: parsed.target,
433159
- mode: stringValue5(parsed.values.mode),
433160
- limit: stringValue5(parsed.values.limit),
432974
+ mode: stringValue4(parsed.values.mode),
432975
+ limit: stringValue4(parsed.values.limit),
433161
432976
  stdout,
433162
432977
  searchTools: async (request) => {
433163
432978
  if (!serverSearchAvailable) {
@@ -433190,15 +433005,20 @@ async function runSearch(parsed, deps, agentId, stdout) {
433190
433005
  catalogPromise
433191
433006
  ]);
433192
433007
  catalog = resolvedCatalog;
433193
- const serverResults = searchResults.map((result2) => {
433008
+ const serverResults = searchResults.flatMap((result2) => {
433194
433009
  const callable = resolvedCatalog.tools.find((tool) => tool.target.kind === "server" && tool.target.toolId === result2.toolId);
433195
433010
  if (!callable) {
433011
+ if (resolvedCatalog.excludedHostedStdioServers) {
433012
+ return [];
433013
+ }
433196
433014
  throw new Error(`MCP search returned unavailable tool '${result2.toolId}'`);
433197
433015
  }
433198
- return {
433199
- tool: result2.jsonSchema === null ? null : { ...result2.jsonSchema, name: callable.schema.name },
433200
- score: result2.score
433201
- };
433016
+ return [
433017
+ {
433018
+ tool: result2.jsonSchema === null ? null : { ...result2.jsonSchema, name: callable.schema.name },
433019
+ score: result2.score
433020
+ }
433021
+ ];
433202
433022
  });
433203
433023
  if (!includeLocal)
433204
433024
  return serverResults;
@@ -433221,7 +433041,7 @@ async function runCall(parsed, deps, agentId, stdout) {
433221
433041
  if (!toolName) {
433222
433042
  throw new McpCliError("invalid_arguments", "Usage: letta mcp call <tool-name> [--args '<json>']");
433223
433043
  }
433224
- const args = await loadMcpToolArgs(stringValue5(parsed.values.args), stringValue5(parsed.values["args-file"]), deps);
433044
+ const args = await loadMcpToolArgs(stringValue4(parsed.values.args), stringValue4(parsed.values["args-file"]), deps);
433225
433045
  const catalog = await buildToolCatalog(deps, agentId, { toolName });
433226
433046
  try {
433227
433047
  const tool = catalog.tools.find((candidate) => candidate.schema.name === toolName);
@@ -433235,7 +433055,7 @@ async function runCall(parsed, deps, agentId, stdout) {
433235
433055
  toolId: tool.target.toolId,
433236
433056
  args
433237
433057
  }));
433238
- printJson2(stdout, result2);
433058
+ printJson(stdout, result2);
433239
433059
  return result2.isError === true ? 2 : 0;
433240
433060
  } finally {
433241
433061
  await catalog.close();
@@ -433255,7 +433075,7 @@ async function runMcpSubcommand(argv, deps = {}) {
433255
433075
  printMcpUsage(stdout);
433256
433076
  return 0;
433257
433077
  }
433258
- const agentId = resolveMcpAgentId(stringValue5(parsed.values.agent), stringValue5(parsed.values["agent-id"]), deps.env ?? process.env);
433078
+ const agentId = resolveMcpAgentId(stringValue4(parsed.values.agent), stringValue4(parsed.values["agent-id"]), deps.env ?? process.env);
433259
433079
  if (!agentId) {
433260
433080
  printMcpError(stderr, new McpCliError("agent_id_required", "No agent context found", "Pass --agent <agent-id> or set LETTA_AGENT_ID."));
433261
433081
  return 1;
@@ -433270,7 +433090,9 @@ async function runMcpSubcommand(argv, deps = {}) {
433270
433090
  case "tools":
433271
433091
  case "list-tools":
433272
433092
  case "list_tools":
433273
- return await runTools(deps, agentId, parsed.target, stdout);
433093
+ return await runTools(deps, agentId, parsed.target, parsed.values.full === true, stdout);
433094
+ case "schema":
433095
+ return await runSchema(deps, agentId, parsed.target, stdout);
433274
433096
  case "search":
433275
433097
  return await runSearch(parsed, deps, agentId, stdout);
433276
433098
  case "call":
@@ -433286,19 +433108,21 @@ async function runMcpSubcommand(argv, deps = {}) {
433286
433108
  return 1;
433287
433109
  }
433288
433110
  }
433289
- var init_mcp = __esm(async () => {
433111
+ var SENSITIVE_NAME;
433112
+ var init_mcp = __esm(() => {
433113
+ init_oauth();
433290
433114
  init_backend2();
433291
433115
  init_client2();
433116
+ init_server_url();
433292
433117
  init_unified_mcp();
433293
433118
  init_mcp_client();
433294
433119
  init_mcp_oauth();
433120
+ init_mcp_runtime();
433295
433121
  init_settings_manager();
433296
433122
  init_mcp_io();
433297
433123
  init_mcp_search();
433298
- await __promiseAll([
433299
- init_mcp_runtime(),
433300
- init_mcp_tool_names()
433301
- ]);
433124
+ init_mcp_tool_names();
433125
+ SENSITIVE_NAME = /token|key|secret|password|signature|credential|auth/i;
433302
433126
  });
433303
433127
 
433304
433128
  // src/cli/subcommands/memory-tokens.ts
@@ -433327,7 +433151,7 @@ function printText(total, files, top, quiet) {
433327
433151
  console.log(` ${formatNumber(row.tokens).padStart(8)} ${row.path}`);
433328
433152
  }
433329
433153
  }
433330
- function printJson3(total, files) {
433154
+ function printJson2(total, files) {
433331
433155
  console.log(JSON.stringify({
433332
433156
  total_tokens: total,
433333
433157
  files
@@ -433368,7 +433192,7 @@ async function runMemoryTokensAction(options) {
433368
433192
  }
433369
433193
  const { total, files } = estimate;
433370
433194
  if (format5 === "json") {
433371
- printJson3(total, files);
433195
+ printJson2(total, files);
433372
433196
  } else {
433373
433197
  printText(total, files, top, options.quiet);
433374
433198
  }
@@ -433383,8 +433207,8 @@ var init_memory_tokens = __esm(() => {
433383
433207
  import { cpSync, existsSync as existsSync57, mkdirSync as mkdirSync39, rmSync as rmSync12, statSync as statSync19 } from "node:fs";
433384
433208
  import { readdir as readdir12 } from "node:fs/promises";
433385
433209
  import { dirname as dirname31, join as join72 } from "node:path";
433386
- import { parseArgs as parseArgs12 } from "node:util";
433387
- function printUsage9() {
433210
+ import { parseArgs as parseArgs11 } from "node:util";
433211
+ function printUsage8() {
433388
433212
  console.log(`
433389
433213
  Usage:
433390
433214
  letta memory status [--agent <id>]
@@ -433417,7 +433241,7 @@ function getAgentId3(agentFromArgs, agentIdFromArgs) {
433417
433241
  return agentFromArgs || agentIdFromArgs || process.env.LETTA_AGENT_ID || "";
433418
433242
  }
433419
433243
  function parseMemoryArgs(argv) {
433420
- return parseArgs12({
433244
+ return parseArgs11({
433421
433245
  args: argv,
433422
433246
  options: MEMORY_OPTIONS,
433423
433247
  strict: true,
@@ -433478,12 +433302,12 @@ async function runMemorySubcommand(argv) {
433478
433302
  } catch (error5) {
433479
433303
  const message = error5 instanceof Error ? error5.message : String(error5);
433480
433304
  console.error(`Error: ${message}`);
433481
- printUsage9();
433305
+ printUsage8();
433482
433306
  return 1;
433483
433307
  }
433484
433308
  const [action3] = parsed.positionals;
433485
433309
  if (parsed.values.help || !action3 || action3 === "help") {
433486
- printUsage9();
433310
+ printUsage8();
433487
433311
  return 0;
433488
433312
  }
433489
433313
  const agentId = getAgentId3(parsed.values.agent, parsed.values["agent-id"]);
@@ -433627,7 +433451,7 @@ async function runMemorySubcommand(argv) {
433627
433451
  return 1;
433628
433452
  }
433629
433453
  console.error(`Unknown action: ${action3}`);
433630
- printUsage9();
433454
+ printUsage8();
433631
433455
  return 1;
433632
433456
  }
433633
433457
  var MEMORY_OPTIONS;
@@ -433986,8 +433810,8 @@ var init_message_search = __esm(() => {
433986
433810
  // src/cli/subcommands/messages.ts
433987
433811
  import { writeFile as writeFile16 } from "node:fs/promises";
433988
433812
  import { resolve as resolve35 } from "node:path";
433989
- import { parseArgs as parseArgs13 } from "node:util";
433990
- function printUsage10() {
433813
+ import { parseArgs as parseArgs12 } from "node:util";
433814
+ function printUsage9() {
433991
433815
  console.log(`
433992
433816
  Usage:
433993
433817
  letta messages search --query <text> [options]
@@ -434072,7 +433896,7 @@ function pageItems4(page) {
434072
433896
  return [];
434073
433897
  }
434074
433898
  function parseMessagesArgs(argv) {
434075
- return parseArgs13({
433899
+ return parseArgs12({
434076
433900
  args: argv,
434077
433901
  options: MESSAGES_OPTIONS,
434078
433902
  strict: true,
@@ -434086,12 +433910,12 @@ async function runMessagesSubcommand(argv, deps = {}) {
434086
433910
  } catch (error5) {
434087
433911
  const message = error5 instanceof Error ? error5.message : String(error5);
434088
433912
  console.error(`Error: ${message}`);
434089
- printUsage10();
433913
+ printUsage9();
434090
433914
  return 1;
434091
433915
  }
434092
433916
  const [action3] = parsed.positionals;
434093
433917
  if (parsed.values.help || !action3 || action3 === "help") {
434094
- printUsage10();
433918
+ printUsage9();
434095
433919
  return 0;
434096
433920
  }
434097
433921
  try {
@@ -434333,7 +434157,7 @@ async function runMessagesSubcommand(argv, deps = {}) {
434333
434157
  return 1;
434334
434158
  }
434335
434159
  console.error(`Unknown action: ${action3}`);
434336
- printUsage10();
434160
+ printUsage9();
434337
434161
  return 1;
434338
434162
  }
434339
434163
  var MESSAGES_OPTIONS;
@@ -434378,7 +434202,7 @@ import {
434378
434202
  } from "node:fs";
434379
434203
  import { tmpdir as tmpdir10 } from "node:os";
434380
434204
  import path46 from "node:path";
434381
- function isRecord18(value) {
434205
+ function isRecord17(value) {
434382
434206
  return typeof value === "object" && value !== null && !Array.isArray(value);
434383
434207
  }
434384
434208
  function isPathInsideOrEqual2(childPath, parentPath) {
@@ -434394,7 +434218,7 @@ function readPackageJson(packageJsonPath) {
434394
434218
  } catch (error5) {
434395
434219
  throw new Error(`Could not read package.json: ${error5 instanceof Error ? error5.message : String(error5)}`);
434396
434220
  }
434397
- if (!isRecord18(parsed)) {
434221
+ if (!isRecord17(parsed)) {
434398
434222
  throw new Error("package.json must be an object");
434399
434223
  }
434400
434224
  return parsed;
@@ -434404,7 +434228,7 @@ function formatRepository(repository) {
434404
434228
  const trimmed2 = repository.trim();
434405
434229
  return trimmed2 || undefined;
434406
434230
  }
434407
- if (!isRecord18(repository))
434231
+ if (!isRecord17(repository))
434408
434232
  return;
434409
434233
  const url2 = repository.url;
434410
434234
  if (typeof url2 !== "string")
@@ -434934,7 +434758,7 @@ function hasRuntimeDependencies(packageJson) {
434934
434758
  if (!packageJson)
434935
434759
  return false;
434936
434760
  const dependencies4 = packageJson.dependencies;
434937
- return isRecord18(dependencies4) && Object.keys(dependencies4).length > 0;
434761
+ return isRecord17(dependencies4) && Object.keys(dependencies4).length > 0;
434938
434762
  }
434939
434763
  function readPackageJsonIfExists(packageDirectory) {
434940
434764
  const packageJsonPath = path46.join(packageDirectory, "package.json");
@@ -435363,8 +435187,8 @@ var init_package_scaffolder = __esm(() => {
435363
435187
 
435364
435188
  // src/cli/subcommands/mods.ts
435365
435189
  import { dirname as dirname32, join as join74 } from "node:path";
435366
- import { parseArgs as parseArgs14 } from "node:util";
435367
- function printUsage11() {
435190
+ import { parseArgs as parseArgs13 } from "node:util";
435191
+ function printUsage10() {
435368
435192
  console.log(`
435369
435193
  Usage:
435370
435194
  letta mods list [--agent <id>]
@@ -435381,7 +435205,7 @@ Options:
435381
435205
  `.trim());
435382
435206
  }
435383
435207
  function parseModsArgs(argv) {
435384
- return parseArgs14({
435208
+ return parseArgs13({
435385
435209
  args: argv,
435386
435210
  options: MODS_OPTIONS,
435387
435211
  strict: true,
@@ -435389,7 +435213,7 @@ function parseModsArgs(argv) {
435389
435213
  });
435390
435214
  }
435391
435215
  function parseModsPackageArgs(argv) {
435392
- return parseArgs14({
435216
+ return parseArgs13({
435393
435217
  args: argv,
435394
435218
  options: MODS_PACKAGE_OPTIONS,
435395
435219
  strict: true,
@@ -435487,16 +435311,16 @@ async function runList2(argv, options = {}) {
435487
435311
  parsed = parseModsArgs(argv);
435488
435312
  } catch (error5) {
435489
435313
  console.error(`Error: ${error5 instanceof Error ? error5.message : String(error5)}`);
435490
- printUsage11();
435314
+ printUsage10();
435491
435315
  return 1;
435492
435316
  }
435493
435317
  if (parsed.values.help) {
435494
- printUsage11();
435318
+ printUsage10();
435495
435319
  return 0;
435496
435320
  }
435497
435321
  if (parsed.positionals.length > 0) {
435498
435322
  console.error(`Unexpected argument: ${parsed.positionals[0]}`);
435499
- printUsage11();
435323
+ printUsage10();
435500
435324
  return 1;
435501
435325
  }
435502
435326
  const agentId = getExplicitAgentId(parsed.values);
@@ -435513,27 +435337,27 @@ async function runPackageMutation(action3, argv, options = {}) {
435513
435337
  parsed = parseModsArgs(argv);
435514
435338
  } catch (error5) {
435515
435339
  console.error(`Error: ${error5 instanceof Error ? error5.message : String(error5)}`);
435516
- printUsage11();
435340
+ printUsage10();
435517
435341
  return 1;
435518
435342
  }
435519
435343
  if (parsed.values.help) {
435520
- printUsage11();
435344
+ printUsage10();
435521
435345
  return 0;
435522
435346
  }
435523
435347
  if (getExplicitAgentId(parsed.values)) {
435524
435348
  console.error(`--agent is only supported for 'letta mods list'.`);
435525
- printUsage11();
435349
+ printUsage10();
435526
435350
  return 1;
435527
435351
  }
435528
435352
  const [specifier, extra] = parsed.positionals;
435529
435353
  if (!specifier) {
435530
435354
  console.error(`Missing package specifier.`);
435531
- printUsage11();
435355
+ printUsage10();
435532
435356
  return 1;
435533
435357
  }
435534
435358
  if (extra) {
435535
435359
  console.error(`Unexpected argument: ${extra}`);
435536
- printUsage11();
435360
+ printUsage10();
435537
435361
  return 1;
435538
435362
  }
435539
435363
  try {
@@ -435559,27 +435383,27 @@ async function runPackageUpdate(argv, options = {}) {
435559
435383
  parsed = parseModsArgs(argv);
435560
435384
  } catch (error5) {
435561
435385
  console.error(`Error: ${error5 instanceof Error ? error5.message : String(error5)}`);
435562
- printUsage11();
435386
+ printUsage10();
435563
435387
  return 1;
435564
435388
  }
435565
435389
  if (parsed.values.help) {
435566
- printUsage11();
435390
+ printUsage10();
435567
435391
  return 0;
435568
435392
  }
435569
435393
  if (getExplicitAgentId(parsed.values)) {
435570
435394
  console.error(`--agent is not supported for 'letta mods update'.`);
435571
- printUsage11();
435395
+ printUsage10();
435572
435396
  return 1;
435573
435397
  }
435574
435398
  const [specifier, extra] = parsed.positionals;
435575
435399
  if (!specifier) {
435576
435400
  console.error(`Missing package specifier.`);
435577
- printUsage11();
435401
+ printUsage10();
435578
435402
  return 1;
435579
435403
  }
435580
435404
  if (extra) {
435581
435405
  console.error(`Unexpected argument: ${extra}`);
435582
- printUsage11();
435406
+ printUsage10();
435583
435407
  return 1;
435584
435408
  }
435585
435409
  try {
@@ -435601,33 +435425,33 @@ async function runPackageScaffold(argv) {
435601
435425
  parsed = parseModsPackageArgs(argv);
435602
435426
  } catch (error5) {
435603
435427
  console.error(`Error: ${error5 instanceof Error ? error5.message : String(error5)}`);
435604
- printUsage11();
435428
+ printUsage10();
435605
435429
  return 1;
435606
435430
  }
435607
435431
  if (parsed.values.help) {
435608
- printUsage11();
435432
+ printUsage10();
435609
435433
  return 0;
435610
435434
  }
435611
435435
  if (getExplicitAgentId(parsed.values)) {
435612
435436
  console.error(`--agent is not supported for 'letta mods package'.`);
435613
- printUsage11();
435437
+ printUsage10();
435614
435438
  return 1;
435615
435439
  }
435616
435440
  const [sourceFile, extra] = parsed.positionals;
435617
435441
  if (!sourceFile) {
435618
435442
  console.error(`Missing mod file.`);
435619
- printUsage11();
435443
+ printUsage10();
435620
435444
  return 1;
435621
435445
  }
435622
435446
  if (extra) {
435623
435447
  console.error(`Unexpected argument: ${extra}`);
435624
- printUsage11();
435448
+ printUsage10();
435625
435449
  return 1;
435626
435450
  }
435627
435451
  const packageName = parsed.values.name;
435628
435452
  if (typeof packageName !== "string" || !packageName.trim()) {
435629
435453
  console.error(`Missing required --name <package-name>.`);
435630
- printUsage11();
435454
+ printUsage10();
435631
435455
  return 1;
435632
435456
  }
435633
435457
  try {
@@ -435649,7 +435473,7 @@ async function runPackageScaffold(argv) {
435649
435473
  async function runModsSubcommand(argv, options = {}) {
435650
435474
  const [action3, ...rest4] = argv;
435651
435475
  if (!action3 || action3 === "help" || action3 === "--help" || action3 === "-h") {
435652
- printUsage11();
435476
+ printUsage10();
435653
435477
  return 0;
435654
435478
  }
435655
435479
  switch (action3) {
@@ -435665,7 +435489,7 @@ async function runModsSubcommand(argv, options = {}) {
435665
435489
  return runPackageMutation(action3, rest4, options);
435666
435490
  default:
435667
435491
  console.error(`Unknown mods action: ${action3}`);
435668
- printUsage11();
435492
+ printUsage10();
435669
435493
  return 1;
435670
435494
  }
435671
435495
  }
@@ -435745,8 +435569,8 @@ var init_sandbox_files = __esm(() => {
435745
435569
  // src/cli/subcommands/sandbox.ts
435746
435570
  import { readFile as readFile24, stat as stat16, writeFile as writeFile17 } from "node:fs/promises";
435747
435571
  import { basename as basename26, resolve as resolve36 } from "node:path";
435748
- import { parseArgs as parseArgs15 } from "node:util";
435749
- function printUsage12() {
435572
+ import { parseArgs as parseArgs14 } from "node:util";
435573
+ function printUsage11() {
435750
435574
  console.log(`
435751
435575
  Usage:
435752
435576
  letta sandbox upload <local-path>
@@ -435760,7 +435584,7 @@ Notes:
435760
435584
  `.trim());
435761
435585
  }
435762
435586
  function parseSandboxArgs(argv) {
435763
- return parseArgs15({
435587
+ return parseArgs14({
435764
435588
  args: argv,
435765
435589
  options: SANDBOX_OPTIONS,
435766
435590
  strict: true,
@@ -435800,17 +435624,17 @@ async function runSandboxSubcommand(argv, deps = {}) {
435800
435624
  parsed = parseSandboxArgs(argv);
435801
435625
  } catch (error5) {
435802
435626
  console.error(`Error: ${error5 instanceof Error ? error5.message : error5}`);
435803
- printUsage12();
435627
+ printUsage11();
435804
435628
  return 1;
435805
435629
  }
435806
435630
  const [action3, path48] = parsed.positionals;
435807
435631
  if (parsed.values.help || !action3 || action3 === "help") {
435808
- printUsage12();
435632
+ printUsage11();
435809
435633
  return 0;
435810
435634
  }
435811
435635
  if (action3 !== "upload" && action3 !== "download" || !path48) {
435812
435636
  console.error("Error: expected upload or download with a file path");
435813
- printUsage12();
435637
+ printUsage11();
435814
435638
  return 1;
435815
435639
  }
435816
435640
  try {
@@ -435854,8 +435678,8 @@ var init_sandbox2 = __esm(() => {
435854
435678
  });
435855
435679
 
435856
435680
  // src/cli/subcommands/secret.ts
435857
- import { parseArgs as parseArgs16 } from "node:util";
435858
- function printUsage13() {
435681
+ import { parseArgs as parseArgs15 } from "node:util";
435682
+ function printUsage12() {
435859
435683
  console.log(`
435860
435684
  Usage:
435861
435685
  letta secret set KEY --env SOURCE_VAR Set KEY from environment variable SOURCE_VAR
@@ -435880,7 +435704,7 @@ Notes:
435880
435704
  `.trim());
435881
435705
  }
435882
435706
  function parseSecretArgs(argv) {
435883
- return parseArgs16({
435707
+ return parseArgs15({
435884
435708
  args: argv,
435885
435709
  options: SECRET_OPTIONS,
435886
435710
  strict: true,
@@ -435915,11 +435739,11 @@ async function runSecretSubcommand(argv, deps = {}) {
435915
435739
  parsed = parseSecretArgs(argv);
435916
435740
  } catch (error5) {
435917
435741
  printError(error5);
435918
- printUsage13();
435742
+ printUsage12();
435919
435743
  return 1;
435920
435744
  }
435921
435745
  if (parsed.values.help || parsed.positionals.length === 0) {
435922
- printUsage13();
435746
+ printUsage12();
435923
435747
  return parsed.values.help ? 0 : 1;
435924
435748
  }
435925
435749
  const [verb, rawKey, rawValue] = parsed.positionals;
@@ -435929,7 +435753,7 @@ async function runSecretSubcommand(argv, deps = {}) {
435929
435753
  }
435930
435754
  switch (verb) {
435931
435755
  case "help": {
435932
- printUsage13();
435756
+ printUsage12();
435933
435757
  return 0;
435934
435758
  }
435935
435759
  case "list": {
@@ -436037,7 +435861,7 @@ async function runSecretSubcommand(argv, deps = {}) {
436037
435861
  }
436038
435862
  default: {
436039
435863
  console.error(`Unknown subcommand '${verb ?? ""}'.`);
436040
- printUsage13();
435864
+ printUsage12();
436041
435865
  return 1;
436042
435866
  }
436043
435867
  }
@@ -436055,7 +435879,7 @@ var init_secret = __esm(() => {
436055
435879
  });
436056
435880
 
436057
435881
  // src/cli/subcommands/app-server.ts
436058
- import { parseArgs as parseArgs17 } from "node:util";
435882
+ import { parseArgs as parseArgs16 } from "node:util";
436059
435883
  function printAppServerHelp() {
436060
435884
  console.log(`Usage: letta server --listen [url]
436061
435885
 
@@ -436103,7 +435927,7 @@ Stopped App Server (${signal}).`);
436103
435927
  async function runAppServerSubcommand(argv) {
436104
435928
  let parsed;
436105
435929
  try {
436106
- parsed = parseArgs17({
435930
+ parsed = parseArgs16({
436107
435931
  args: argv,
436108
435932
  allowPositionals: false,
436109
435933
  options: {
@@ -436172,10 +435996,10 @@ function printServerHelp() {
436172
435996
  letta server [remote options]
436173
435997
  letta server --listen [url] [App Server options]
436174
435998
 
436175
- 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.
436176
436000
 
436177
- Remote environment options:
436178
- --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)
436179
436003
  --channels <list> Comma-separated channel names to enable (e.g. telegram)
436180
436004
  --install-channel-runtimes Install missing runtime dependencies for selected channels
436181
436005
  --debug Log WebSocket events instead of showing the interactive status UI
@@ -436196,7 +436020,7 @@ Common options:
436196
436020
 
436197
436021
  Examples:
436198
436022
  letta server
436199
- letta server --env-name "work-laptop"
436023
+ letta server --computer-name "work-laptop"
436200
436024
  letta server --channels telegram
436201
436025
  letta server --listen
436202
436026
  letta server --listen ws://127.0.0.1:4500
@@ -436235,7 +436059,7 @@ function resolveServerCommand(argv) {
436235
436059
  }
436236
436060
  }
436237
436061
  if (foundListen) {
436238
- 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="));
436239
436063
  if (conflictingOption) {
436240
436064
  throw new Error(`${conflictingOption.split("=")[0]} cannot be used with --listen`);
436241
436065
  }
@@ -436688,7 +436512,7 @@ var init_setup6 = __esm(async () => {
436688
436512
  });
436689
436513
 
436690
436514
  // src/cli/subcommands/setup.ts
436691
- function printUsage14() {
436515
+ function printUsage13() {
436692
436516
  console.log(`
436693
436517
  Usage:
436694
436518
  letta setup
@@ -436699,12 +436523,12 @@ Re-run the interactive setup menu to choose local mode or sign in with Letta.
436699
436523
  async function runSetupSubcommand(argv) {
436700
436524
  const [arg, ...rest4] = argv;
436701
436525
  if (arg === "help" || arg === "--help" || arg === "-h") {
436702
- printUsage14();
436526
+ printUsage13();
436703
436527
  return 0;
436704
436528
  }
436705
436529
  if (arg || rest4.length > 0) {
436706
436530
  console.error(`Unexpected arguments: ${[arg, ...rest4].filter(Boolean).join(" ")}`);
436707
- printUsage14();
436531
+ printUsage13();
436708
436532
  return 1;
436709
436533
  }
436710
436534
  await settingsManager.initialize();
@@ -436719,8 +436543,8 @@ var init_setup7 = __esm(async () => {
436719
436543
  // src/cli/subcommands/shared-memory.ts
436720
436544
  import { existsSync as existsSync61 } from "node:fs";
436721
436545
  import { join as join75 } from "node:path";
436722
- import { parseArgs as parseArgs18 } from "node:util";
436723
- function printUsage15() {
436546
+ import { parseArgs as parseArgs17 } from "node:util";
436547
+ function printUsage14() {
436724
436548
  console.log(`
436725
436549
  Usage:
436726
436550
  letta shared-memory list [--agent <id>]
@@ -436755,7 +436579,7 @@ Examples:
436755
436579
  `.trim());
436756
436580
  }
436757
436581
  function parseSharedMemoryArgs(argv) {
436758
- return parseArgs18({
436582
+ return parseArgs17({
436759
436583
  args: argv,
436760
436584
  options: SHARED_MEMORY_OPTIONS,
436761
436585
  strict: true,
@@ -436831,12 +436655,12 @@ async function runSharedMemorySubcommand(argv, deps = {}) {
436831
436655
  parsed = parseSharedMemoryArgs(argv);
436832
436656
  } catch (error5) {
436833
436657
  console.error(error5 instanceof Error ? error5.message : String(error5));
436834
- printUsage15();
436658
+ printUsage14();
436835
436659
  return 1;
436836
436660
  }
436837
436661
  const [action3, reference] = parsed.positionals;
436838
436662
  if (parsed.values.help || !action3 || action3 === "help") {
436839
- printUsage15();
436663
+ printUsage14();
436840
436664
  return 0;
436841
436665
  }
436842
436666
  if (isLocalBackendEnvEnabled()) {
@@ -436941,7 +436765,7 @@ async function runSharedMemorySubcommand(argv, deps = {}) {
436941
436765
  return result2.failed > 0 ? 1 : 0;
436942
436766
  }
436943
436767
  console.error(`Unknown action: ${action3}`);
436944
- printUsage15();
436768
+ printUsage14();
436945
436769
  return 1;
436946
436770
  } catch (error5) {
436947
436771
  console.error(error5 instanceof Error ? error5.message : String(error5));
@@ -438449,8 +438273,8 @@ import {
438449
438273
  import { mkdir as mkdir14, readdir as readdir13 } from "node:fs/promises";
438450
438274
  import { tmpdir as tmpdir11 } from "node:os";
438451
438275
  import { basename as basename27, dirname as dirname33, join as join76, normalize as normalize5, resolve as resolve37, sep as sep8 } from "node:path";
438452
- import { parseArgs as parseArgs19, TextDecoder as TextDecoder2, TextEncoder as TextEncoder2 } from "node:util";
438453
- function printUsage16() {
438276
+ import { parseArgs as parseArgs18, TextDecoder as TextDecoder2, TextEncoder as TextEncoder2 } from "node:util";
438277
+ function printUsage15() {
438454
438278
  console.log(`
438455
438279
  Usage:
438456
438280
  letta install <thing> [--agent <id> | -n <agent name>] [--force]
@@ -438477,7 +438301,7 @@ Options:
438477
438301
  `.trim());
438478
438302
  }
438479
438303
  function parseSkillsArgs(argv) {
438480
- return parseArgs19({
438304
+ return parseArgs18({
438481
438305
  args: argv,
438482
438306
  options: SKILLS_OPTIONS,
438483
438307
  strict: true,
@@ -439125,17 +438949,17 @@ async function runInstall(argv, options = {}) {
439125
438949
  parsed = parseSkillsArgs(argv);
439126
438950
  } catch (error5) {
439127
438951
  console.error(`Error: ${error5 instanceof Error ? error5.message : String(error5)}`);
439128
- printUsage16();
438952
+ printUsage15();
439129
438953
  return 1;
439130
438954
  }
439131
438955
  const [specifier] = parsed.positionals;
439132
438956
  if (parsed.values.help || !specifier || specifier === "help") {
439133
- printUsage16();
438957
+ printUsage15();
439134
438958
  return 0;
439135
438959
  }
439136
438960
  if (parsed.positionals.length > 1) {
439137
438961
  console.error(`Unexpected argument: ${parsed.positionals[1]}`);
439138
- printUsage16();
438962
+ printUsage15();
439139
438963
  return 1;
439140
438964
  }
439141
438965
  if (specifier.startsWith("npm:")) {
@@ -439226,16 +439050,16 @@ async function runList3(argv) {
439226
439050
  parsed = parseSkillsArgs(argv);
439227
439051
  } catch (error5) {
439228
439052
  console.error(`Error: ${error5 instanceof Error ? error5.message : String(error5)}`);
439229
- printUsage16();
439053
+ printUsage15();
439230
439054
  return 1;
439231
439055
  }
439232
439056
  if (parsed.values.help) {
439233
- printUsage16();
439057
+ printUsage15();
439234
439058
  return 0;
439235
439059
  }
439236
439060
  if (parsed.positionals.length > 0) {
439237
439061
  console.error(`Unexpected argument: ${parsed.positionals[0]}`);
439238
- printUsage16();
439062
+ printUsage15();
439239
439063
  return 1;
439240
439064
  }
439241
439065
  try {
@@ -439256,17 +439080,17 @@ async function runDelete(argv) {
439256
439080
  parsed = parseSkillsArgs(argv);
439257
439081
  } catch (error5) {
439258
439082
  console.error(`Error: ${error5 instanceof Error ? error5.message : String(error5)}`);
439259
- printUsage16();
439083
+ printUsage15();
439260
439084
  return 1;
439261
439085
  }
439262
439086
  const [skillName] = parsed.positionals;
439263
439087
  if (parsed.values.help || !skillName || skillName === "help") {
439264
- printUsage16();
439088
+ printUsage15();
439265
439089
  return 0;
439266
439090
  }
439267
439091
  if (parsed.positionals.length > 1) {
439268
439092
  console.error(`Unexpected argument: ${parsed.positionals[1]}`);
439269
- printUsage16();
439093
+ printUsage15();
439270
439094
  return 1;
439271
439095
  }
439272
439096
  const agentId = getExplicitAgentId2(parsed.values);
@@ -439306,11 +439130,11 @@ async function runSkillsSubcommand(argv) {
439306
439130
  case "help":
439307
439131
  case "--help":
439308
439132
  case "-h":
439309
- printUsage16();
439133
+ printUsage15();
439310
439134
  return 0;
439311
439135
  default:
439312
439136
  console.error(`Unknown action: ${action3}`);
439313
- printUsage16();
439137
+ printUsage15();
439314
439138
  return 1;
439315
439139
  }
439316
439140
  }
@@ -439329,31 +439153,31 @@ var init_skills4 = __esm(() => {
439329
439153
  });
439330
439154
 
439331
439155
  // src/cli/subcommands/teleport.ts
439332
- import { parseArgs as parseArgs20 } from "node:util";
439333
- function printUsage17() {
439156
+ import { parseArgs as parseArgs19 } from "node:util";
439157
+ function printUsage16() {
439334
439158
  console.log(`
439335
439159
  Usage:
439336
439160
  letta teleport list
439337
439161
  letta teleport cloud
439338
439162
  letta teleport local
439339
- letta teleport <environment>
439163
+ letta teleport <computer>
439340
439164
 
439341
439165
  Notes:
439342
439166
  - Operates on the current agent/conversation from LETTA_AGENT_ID /
439343
439167
  LETTA_CONVERSATION_ID (or AGENT_ID / CONVERSATION_ID), falling back to the
439344
439168
  last active session.
439345
439169
  - Requires a Letta Cloud agent and an active conversation.
439346
- - list: prints accessible online remote environments as JSON.
439170
+ - list: prints accessible online remote computers as JSON.
439347
439171
  - cloud: teleports to the agent's Cloud sandbox.
439348
- - local: teleports to the one online Desktop environment. Desktop Remote
439172
+ - local: teleports to the one online Desktop computer. Desktop Remote
439349
439173
  Access must be enabled; if several are online, choose one explicitly.
439350
- - <environment>: teleports to a specific remote environment by name,
439351
- 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.
439352
439176
  - Output is JSON only.
439353
439177
  `.trim());
439354
439178
  }
439355
439179
  function parseTeleportArgs(argv) {
439356
- return parseArgs20({
439180
+ return parseArgs19({
439357
439181
  args: argv,
439358
439182
  options: TELEPORT_OPTIONS,
439359
439183
  strict: true,
@@ -439413,7 +439237,7 @@ function isTeleportableRemoteEnvironment(environment2) {
439413
439237
  }
439414
439238
  function assertTeleportableRemoteEnvironment(environment2) {
439415
439239
  if (!isTeleportableRemoteEnvironment(environment2)) {
439416
- 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.");
439417
439241
  }
439418
439242
  }
439419
439243
  async function initializeTeleportSettings() {
@@ -439426,12 +439250,12 @@ async function runTeleportSubcommand(argv, deps = {}) {
439426
439250
  parsed = parseTeleportArgs(argv);
439427
439251
  } catch (error5) {
439428
439252
  console.error(`Error: ${error5 instanceof Error ? error5.message : error5}`);
439429
- printUsage17();
439253
+ printUsage16();
439430
439254
  return 1;
439431
439255
  }
439432
439256
  const [action3] = parsed.positionals;
439433
439257
  if (parsed.values.help || !action3 || action3 === "help") {
439434
- printUsage17();
439258
+ printUsage16();
439435
439259
  return 0;
439436
439260
  }
439437
439261
  try {
@@ -439456,7 +439280,7 @@ async function runTeleportSubcommand(argv, deps = {}) {
439456
439280
  const result3 = await resolve38();
439457
439281
  targetConnectionId = result3.connectionId;
439458
439282
  } else if (action3 === "back") {
439459
- 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.");
439460
439284
  } else {
439461
439285
  const resolve38 = deps.resolveEnvironmentConnectionId ?? resolveEnvironmentConnectionId;
439462
439286
  const resolved = await resolve38(action3);
@@ -439867,8 +439691,8 @@ var init_review = () => {};
439867
439691
 
439868
439692
  // src/cli/subcommands/trajectories.ts
439869
439693
  import { readFile as readFile28 } from "node:fs/promises";
439870
- import { parseArgs as parseArgs21 } from "node:util";
439871
- function printUsage18() {
439694
+ import { parseArgs as parseArgs20 } from "node:util";
439695
+ function printUsage17() {
439872
439696
  console.log(`
439873
439697
  Usage:
439874
439698
  letta trajectories export [options]
@@ -440006,7 +439830,7 @@ ${results.length} session(s) matched "${keyword}"`);
440006
439830
  return 0;
440007
439831
  }
440008
439832
  function parseTrajectoriesArgs(argv) {
440009
- return parseArgs21({
439833
+ return parseArgs20({
440010
439834
  args: argv,
440011
439835
  options: TRAJECTORIES_OPTIONS,
440012
439836
  strict: true,
@@ -440019,12 +439843,12 @@ async function runTrajectoriesSubcommand(argv) {
440019
439843
  parsed = parseTrajectoriesArgs(argv);
440020
439844
  } catch (error5) {
440021
439845
  console.error(`Error: ${error5 instanceof Error ? error5.message : String(error5)}`);
440022
- printUsage18();
439846
+ printUsage17();
440023
439847
  return 1;
440024
439848
  }
440025
439849
  const [action3] = parsed.positionals;
440026
439850
  if (parsed.values.help || action3 === "help" || !action3) {
440027
- printUsage18();
439851
+ printUsage17();
440028
439852
  return parsed.values.help || action3 === "help" ? 0 : 1;
440029
439853
  }
440030
439854
  const asJson = Boolean(parsed.values.json);
@@ -440056,7 +439880,7 @@ async function runTrajectoriesSubcommand(argv) {
440056
439880
  }
440057
439881
  if (action3 !== "export") {
440058
439882
  console.error(`Unknown command: ${action3}`);
440059
- printUsage18();
439883
+ printUsage17();
440060
439884
  return 1;
440061
439885
  }
440062
439886
  const options = {
@@ -441605,9 +441429,9 @@ class ChannelRichDraftStreamerImpl {
441605
441429
  return;
441606
441430
  }
441607
441431
  const record5 = asRecord10(chunk2);
441608
- const messageType = stringValue6(record5?.message_type);
441432
+ const messageType = stringValue5(record5?.message_type);
441609
441433
  if (messageType === "tool_return_message") {
441610
- const toolCallId = stringValue6(record5?.tool_call_id);
441434
+ const toolCallId = stringValue5(record5?.tool_call_id);
441611
441435
  if (toolCallId) {
441612
441436
  this.finishCall(toolCallId);
441613
441437
  }
@@ -441900,14 +441724,14 @@ function extractToolCallFragments2(record5) {
441900
441724
  const fragments = [];
441901
441725
  for (const rawToolCall of rawToolCalls) {
441902
441726
  const toolCall = asRecord10(rawToolCall);
441903
- const toolCallId = stringValue6(toolCall?.tool_call_id);
441727
+ const toolCallId = stringValue5(toolCall?.tool_call_id);
441904
441728
  if (!toolCallId) {
441905
441729
  continue;
441906
441730
  }
441907
441731
  fragments.push({
441908
441732
  toolCallId,
441909
- name: stringValue6(toolCall?.name),
441910
- argumentsDelta: stringValue6(toolCall?.arguments)
441733
+ name: stringValue5(toolCall?.name),
441734
+ argumentsDelta: stringValue5(toolCall?.arguments)
441911
441735
  });
441912
441736
  }
441913
441737
  return fragments;
@@ -442027,7 +441851,7 @@ function buildDraftId(seed) {
442027
441851
  function asRecord10(value) {
442028
441852
  return value && typeof value === "object" ? value : null;
442029
441853
  }
442030
- function stringValue6(value) {
441854
+ function stringValue5(value) {
442031
441855
  return typeof value === "string" ? value : undefined;
442032
441856
  }
442033
441857
  var MESSAGE_CHANNEL_TOOL_NAMES, DEFAULT_DRAFT_DEBOUNCE_MS = 1000, MIN_DRAFT_TEXT_LENGTH = 1;
@@ -444895,14 +444719,14 @@ var exports_channel_gateway = {};
444895
444719
  __export(exports_channel_gateway, {
444896
444720
  runChannelGatewaySubcommand: () => runChannelGatewaySubcommand
444897
444721
  });
444898
- import { parseArgs as parseArgs22 } from "node:util";
444722
+ import { parseArgs as parseArgs21 } from "node:util";
444899
444723
  function isGatewayCommandEnvelope(value) {
444900
444724
  return Boolean(value && typeof value === "object" && "type" in value && value.type === "command" && "requestId" in value && typeof value.requestId === "string" && "command" in value && value.command && typeof value.command === "object");
444901
444725
  }
444902
444726
  async function runChannelGatewaySubcommand(argv) {
444903
444727
  let values3;
444904
444728
  try {
444905
- ({ values: values3 } = parseArgs22({
444729
+ ({ values: values3 } = parseArgs21({
444906
444730
  args: argv,
444907
444731
  strict: true,
444908
444732
  allowPositionals: false,
@@ -445029,6 +444853,7 @@ function subcommandNeedsEarlyBackendMode(command) {
445029
444853
  case "channel-gateway":
445030
444854
  case "agents":
445031
444855
  case "connect":
444856
+ case "computers":
445032
444857
  case "environments":
445033
444858
  case "envs":
445034
444859
  case "feedback":
@@ -445042,7 +444867,6 @@ function subcommandNeedsEarlyBackendMode(command) {
445042
444867
  case "sandbox":
445043
444868
  case "secret":
445044
444869
  case "server":
445045
- case "cloud-mcp":
445046
444870
  case "shared-memory":
445047
444871
  case "skills":
445048
444872
  case "teleport":
@@ -445074,6 +444898,7 @@ async function runSubcommand(argv) {
445074
444898
  return runMessagesSubcommand(rest4);
445075
444899
  case "mcp":
445076
444900
  return runMcpSubcommand(rest4);
444901
+ case "computers":
445077
444902
  case "environments":
445078
444903
  case "envs":
445079
444904
  return runEnvironmentsSubcommand(rest4);
@@ -445087,8 +444912,6 @@ async function runSubcommand(argv) {
445087
444912
  return runTeleportSubcommand(rest4);
445088
444913
  case "server":
445089
444914
  return runServerSubcommand(rest4);
445090
- case "cloud-mcp":
445091
- return runCloudMcpSubcommand(rest4);
445092
444915
  case "feedback":
445093
444916
  return runFeedbackSubcommand(rest4);
445094
444917
  case "remote":
@@ -445126,11 +444949,11 @@ var init_router = __esm(async () => {
445126
444949
  init_agents6();
445127
444950
  init_backend3();
445128
444951
  init_channels();
445129
- init_cloud_mcp();
445130
444952
  init_connect();
445131
444953
  init_environments3();
445132
444954
  init_feedback3();
445133
444955
  init_local_backend2();
444956
+ init_mcp();
445134
444957
  init_memory7();
445135
444958
  init_messages10();
445136
444959
  init_sandbox2();
@@ -445142,7 +444965,6 @@ var init_router = __esm(async () => {
445142
444965
  await __promiseAll([
445143
444966
  init_cron2(),
445144
444967
  init_listen(),
445145
- init_mcp(),
445146
444968
  init_mods(),
445147
444969
  init_server(),
445148
444970
  init_setup7()
@@ -447304,7 +447126,7 @@ function getEnvironmentRoutedMessagingUnsupportedReason(environment2) {
447304
447126
  if (environment2.metadata?.environmentMessageProtocol === "v2-input") {
447305
447127
  return null;
447306
447128
  }
447307
- 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.`;
447308
447130
  }
447309
447131
  async function handleHeadlessCommand(parsedArgs, model, skillsDirectoryOverride, skillSourcesOverride, systemInfoReminderEnabledOverride, startupOptions = {}) {
447310
447132
  const { values: values3, positionals } = parsedArgs;
@@ -447377,7 +447199,7 @@ In headless mode, use:
447377
447199
  }
447378
447200
  let forceNewConversation = values3.new ?? false;
447379
447201
  const fromAgentId = values3["from-agent"];
447380
- const explicitEnvironmentSelector = values3.environment || values3.env;
447202
+ const explicitEnvironmentSelector = values3.computer ?? values3.environment ?? values3.env;
447381
447203
  const usesRemoteEnvironment = typeof explicitEnvironmentSelector === "string" && explicitEnvironmentSelector.trim().length > 0;
447382
447204
  let agent = null;
447383
447205
  let ephemeralConversationId = null;
@@ -447745,9 +447567,6 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
447745
447567
  markMilestone("HEADLESS_AGENT_RESOLVED");
447746
447568
  const publicAgentId = ephemeralFlag ? null : agent.id;
447747
447569
  telemetry.setCurrentAgent(publicAgentId, agent.tags);
447748
- if (!ephemeralFlag) {
447749
- await replaceClientMcpServers(agent.id, settingsManager.getMcpServers(agent.id), { stderr: "pipe" });
447750
- }
447751
447570
  const isResumingAgent = !ephemeralFlag && !!(specifiedAgentId || !forceNew && !fromAfFile);
447752
447571
  if (isResumingAgent) {
447753
447572
  if (model) {
@@ -447936,7 +447755,7 @@ Current session AGENT_ID=${process.env.AGENT_ID}; --backend local switches to a
447936
447755
  process.exit(1);
447937
447756
  }
447938
447757
  if (usesRemoteEnvironment && isBidirectionalMode) {
447939
- 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");
447940
447759
  process.exit(1);
447941
447760
  }
447942
447761
  const sessionStats = new SessionStats;
@@ -448373,6 +448192,7 @@ ${loadedContents.join(`
448373
448192
  let emptyResponseRetries = 0;
448374
448193
  let conversationBusyRetries = 0;
448375
448194
  let chatgptPlanSwaps = 0;
448195
+ const chatgptExhaustedProviders = new Set;
448376
448196
  markMilestone("HEADLESS_FIRST_STREAM_START");
448377
448197
  measureSinceMilestone("headless-setup-total", "HEADLESS_CLIENT_READY");
448378
448198
  const checkMaxTurns = async () => {
@@ -448640,6 +448460,7 @@ ${loadedContents.join(`
448640
448460
  emptyResponseRetries = 0;
448641
448461
  conversationBusyRetries = 0;
448642
448462
  chatgptPlanSwaps = 0;
448463
+ chatgptExhaustedProviders.clear();
448643
448464
  const continueMessage = await emitHeadlessTurnEnd({
448644
448465
  agent,
448645
448466
  conversationId,
@@ -448743,8 +448564,10 @@ ${loadedContents.join(`
448743
448564
  if (chatgptPlanSwaps < CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN) {
448744
448565
  const rotation = await rotateChatGPTPlanOnQuotaLimit({
448745
448566
  agentId: agent.id,
448567
+ conversationId,
448746
448568
  currentHandle: null,
448747
- error: runErrorInfo2 ?? detailFromRun ?? latestErrorText
448569
+ error: runErrorInfo2 ?? detailFromRun ?? latestErrorText,
448570
+ exhaustedProviders: chatgptExhaustedProviders
448748
448571
  });
448749
448572
  if (rotation) {
448750
448573
  chatgptPlanSwaps += 1;
@@ -450160,6 +449983,7 @@ var init_headless = __esm(async () => {
450160
449983
  init_headless_environment_response();
450161
449984
  init_headless_reflection_settings();
450162
449985
  init_diff_preview();
449986
+ init_mcp_runtime();
450163
449987
  init_format_denial();
450164
449988
  init_startup();
450165
449989
  init_queue_runtime();
@@ -450178,7 +450002,6 @@ var init_headless = __esm(async () => {
450178
450002
  init_headless_ephemeral_startup(),
450179
450003
  init_headless_mod_adapter(),
450180
450004
  init_headless_tool_events(),
450181
- init_mcp_runtime(),
450182
450005
  init_manager4(),
450183
450006
  init_toolset()
450184
450007
  ]);
@@ -465838,6 +465661,110 @@ var init_LettaLoginOverlay = __esm(async () => {
465838
465661
  jsx_dev_runtime63 = __toESM(require_jsx_dev_runtime(), 1);
465839
465662
  });
465840
465663
 
465664
+ // src/backend/api/mcp-servers.ts
465665
+ function withTimeout3(promise2, timeoutMs, label) {
465666
+ let timer;
465667
+ const timeout = new Promise((_4, reject2) => {
465668
+ timer = setTimeout(() => reject2(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs);
465669
+ });
465670
+ return Promise.race([promise2, timeout]).finally(() => {
465671
+ if (timer !== undefined)
465672
+ clearTimeout(timer);
465673
+ });
465674
+ }
465675
+ function listServerMcpServers(client, timeoutMs = 1e4) {
465676
+ return withTimeout3(client.mcpServers.list(), timeoutMs, "Listing server-side MCP servers");
465677
+ }
465678
+ async function listLiveServerMcpTools(client, serverName2, timeoutMs = 15000) {
465679
+ const result2 = await withTimeout3(client.get(`/v1/tools/mcp/servers/${encodeURIComponent(serverName2)}/tools`), timeoutMs, `Listing tools for MCP server "${serverName2}"`);
465680
+ if (!Array.isArray(result2))
465681
+ return [];
465682
+ return result2.filter((tool) => typeof tool === "object" && tool !== null && typeof tool.name === "string");
465683
+ }
465684
+ async function loadServerMcpEntries(client, timeoutMs = 15000) {
465685
+ const servers = await listServerMcpServers(client, timeoutMs);
465686
+ return Promise.all(servers.map(async (server2) => {
465687
+ try {
465688
+ const tools = await listLiveServerMcpTools(client, server2.server_name, timeoutMs);
465689
+ return { server: server2, tools };
465690
+ } catch (cause) {
465691
+ return {
465692
+ server: server2,
465693
+ tools: [],
465694
+ toolsError: cause instanceof Error ? cause.message : String(cause)
465695
+ };
465696
+ }
465697
+ }));
465698
+ }
465699
+ function parseMcpMetadata(tool) {
465700
+ const metadata = tool.metadata_;
465701
+ const mcp = metadata?.mcp;
465702
+ if (typeof mcp !== "object" || mcp === null)
465703
+ return null;
465704
+ const { server_id, server_name } = mcp;
465705
+ return {
465706
+ ...typeof server_id === "string" && { serverId: server_id },
465707
+ ...typeof server_name === "string" && { serverName: server_name }
465708
+ };
465709
+ }
465710
+ async function listAgentMcpAttachments(client, agentId) {
465711
+ const attachments = [];
465712
+ for await (const tool of client.agents.tools.list(agentId, { limit: 100 })) {
465713
+ if (tool.tool_type !== "external_mcp" || !tool.id || !tool.name)
465714
+ continue;
465715
+ attachments.push({
465716
+ toolId: tool.id,
465717
+ toolName: tool.name,
465718
+ ...parseMcpMetadata(tool)
465719
+ });
465720
+ }
465721
+ return attachments;
465722
+ }
465723
+ function attachmentsForEntry(entry, attachments) {
465724
+ return attachments.filter((attachment) => attachment.serverId && entry.server.id ? attachment.serverId === entry.server.id : attachment.serverName === entry.server.server_name);
465725
+ }
465726
+ function attachedToolNamesForEntry(entry, attachments) {
465727
+ return new Set(attachmentsForEntry(entry, attachments).map((attachment) => attachment.toolName));
465728
+ }
465729
+ async function registerServerMcpTool(client, serverName2, toolName) {
465730
+ const result2 = await client.post(`/v1/tools/mcp/servers/${encodeURIComponent(serverName2)}/${encodeURIComponent(toolName)}`);
465731
+ if (typeof result2?.id !== "string") {
465732
+ throw new Error(`Registering MCP tool "${toolName}" on server "${serverName2}" returned no tool id`);
465733
+ }
465734
+ return { id: result2.id };
465735
+ }
465736
+ async function attachServerMcpTools(client, agentId, serverName2, toolNames) {
465737
+ await Promise.all(toolNames.map(async (toolName) => {
465738
+ const { id: id2 } = await registerServerMcpTool(client, serverName2, toolName);
465739
+ await client.agents.tools.attach(id2, { agent_id: agentId });
465740
+ }));
465741
+ }
465742
+ async function detachServerMcpTools(client, agentId, toolIds) {
465743
+ await Promise.all(toolIds.map((toolId) => client.agents.tools.detach(toolId, { agent_id: agentId })));
465744
+ }
465745
+ function refreshServerMcpServer(client, mcpServerId, agentId) {
465746
+ return client.mcpServers.refresh(mcpServerId, { agent_id: agentId });
465747
+ }
465748
+ function planServerMcpToggle(entry, attachments) {
465749
+ const attached = attachmentsForEntry(entry, attachments);
465750
+ if (attached.length > 0) {
465751
+ return {
465752
+ action: "detach",
465753
+ toolIds: attached.map((attachment) => attachment.toolId)
465754
+ };
465755
+ }
465756
+ return { action: "attach", toolNames: entry.tools.map((tool) => tool.name) };
465757
+ }
465758
+ function describeServerMcpTarget(server2) {
465759
+ if ("server_url" in server2 && server2.server_url) {
465760
+ return server2.server_url;
465761
+ }
465762
+ if ("command" in server2 && server2.command) {
465763
+ return [server2.command, ...server2.args ?? []].join(" ");
465764
+ }
465765
+ return "";
465766
+ }
465767
+
465841
465768
  // src/cli/components/McpSelector.tsx
465842
465769
  function buildMcpRows(localStates, serverEntries) {
465843
465770
  return [
@@ -465954,15 +465881,14 @@ var import_react87, jsx_dev_runtime64, SOLID_LINE12 = "─", DISPLAY_PAGE_SIZE2
465954
465881
  var init_McpSelector = __esm(async () => {
465955
465882
  init_backend2();
465956
465883
  init_client2();
465957
- init_mcp_servers2();
465958
465884
  init_truncate_text();
465959
465885
  init_use_terminal_width();
465960
465886
  init_mcp_oauth();
465887
+ init_mcp_runtime();
465961
465888
  init_settings_manager();
465962
465889
  init_colors();
465963
465890
  await __promiseAll([
465964
465891
  init_build4(),
465965
- init_mcp_runtime(),
465966
465892
  init_Text2()
465967
465893
  ]);
465968
465894
  import_react87 = __toESM(require_react(), 1);
@@ -466264,7 +466190,7 @@ var init_McpSelector = __esm(async () => {
466264
466190
  flexDirection: "column",
466265
466191
  children: [
466266
466192
  /* @__PURE__ */ jsx_dev_runtime64.jsxDEV(Text2, {
466267
- children: tool.label ?? tool.name
466193
+ children: tool.title ?? tool.name
466268
466194
  }, undefined, false, undefined, this),
466269
466195
  /* @__PURE__ */ jsx_dev_runtime64.jsxDEV(Text2, {
466270
466196
  dimColor: true,
@@ -466274,7 +466200,7 @@ var init_McpSelector = __esm(async () => {
466274
466200
  ]
466275
466201
  }, undefined, true, undefined, this)
466276
466202
  ]
466277
- }, tool.registrationKey ?? tool.name, true, undefined, this)),
466203
+ }, tool.name, true, undefined, this)),
466278
466204
  /* @__PURE__ */ jsx_dev_runtime64.jsxDEV(Box_default, {
466279
466205
  marginTop: 1,
466280
466206
  children: /* @__PURE__ */ jsx_dev_runtime64.jsxDEV(Text2, {
@@ -475585,7 +475511,7 @@ var init_ToolCallMessageRich = __esm(async () => {
475585
475511
  let shellSemanticKind = null;
475586
475512
  let hasShellDescription = false;
475587
475513
  if (!isQuestionTool(rawName)) {
475588
- const parseArgs23 = () => {
475514
+ const parseArgs22 = () => {
475589
475515
  if (!argsText.trim()) {
475590
475516
  return { formatted: null, parseable: true };
475591
475517
  }
@@ -475599,7 +475525,7 @@ var init_ToolCallMessageRich = __esm(async () => {
475599
475525
  return { formatted: null, parseable: false };
475600
475526
  }
475601
475527
  };
475602
- const { formatted, parseable } = parseArgs23();
475528
+ const { formatted, parseable } = parseArgs22();
475603
475529
  const argsComplete = parseable || line.phase === "running" || line.phase === "finished" || !isStreaming;
475604
475530
  if (!argsComplete) {
475605
475531
  args = "(…)";
@@ -477815,7 +477741,7 @@ function updateCommandResult(buffersRef, refreshDerived, cmdId, input, output, s
477815
477741
  buffersRef.current.byId.set(cmdId, line);
477816
477742
  refreshDerived();
477817
477743
  }
477818
- function parseArgs23(msg) {
477744
+ function parseArgs22(msg) {
477819
477745
  return msg.trim().split(/\s+/).filter(Boolean);
477820
477746
  }
477821
477747
  function formatConnectUsage() {
@@ -478197,7 +478123,7 @@ ${formatBedrockUsage2()}`, false);
478197
478123
  }
478198
478124
  }
478199
478125
  async function handleConnect(ctx, msg) {
478200
- const parts = parseArgs23(msg);
478126
+ const parts = parseArgs22(msg);
478201
478127
  const providerToken = parts[1];
478202
478128
  if (!providerToken) {
478203
478129
  addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, formatConnectUsage(), false);
@@ -493905,20 +493831,20 @@ var init_session3 = __esm(() => {
493905
493831
  });
493906
493832
 
493907
493833
  // src/cli/app/use-agent-mcp-servers.ts
493908
- function useAgentMcpServers(agentId) {
493834
+ function useMcpCleanup(agentId) {
493835
+ const previousAgentId = import_react110.useRef(agentId);
493909
493836
  import_react110.useEffect(() => {
493910
- const refresh = agentId ? replaceClientMcpServers(agentId, settingsManager.getMcpServers(agentId)) : closeClientMcpServers();
493911
- 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)}`));
493912
493841
  }, [agentId]);
493913
493842
  }
493914
493843
  var import_react110;
493915
- var init_use_agent_mcp_servers = __esm(async () => {
493916
- init_settings_manager();
493844
+ var init_use_agent_mcp_servers = __esm(() => {
493845
+ init_mcp_runtime();
493846
+ init_mcp_runtime();
493917
493847
  init_debug();
493918
- await __promiseAll([
493919
- init_mcp_runtime(),
493920
- init_mcp_runtime()
493921
- ]);
493922
493848
  import_react110 = __toESM(require_react(), 1);
493923
493849
  });
493924
493850
 
@@ -495908,6 +495834,7 @@ function useConversationLoop(ctx) {
495908
495834
  clearApprovalToolContext,
495909
495835
  closeTrajectorySegment,
495910
495836
  chatgptPlanSwapsRef,
495837
+ chatgptExhaustedProvidersRef,
495911
495838
  consumeQueuedMessages,
495912
495839
  queueModeRef,
495913
495840
  contextTrackerRef,
@@ -496140,6 +496067,7 @@ function useConversationLoop(ctx) {
496140
496067
  conversationBusyRetriesRef.current = 0;
496141
496068
  quotaAutoSwapAttemptedRef.current = false;
496142
496069
  chatgptPlanSwapsRef.current = 0;
496070
+ chatgptExhaustedProvidersRef.current.clear();
496143
496071
  }
496144
496072
  let currentRunId;
496145
496073
  let preserveTranscriptStartForApproval = false;
@@ -497107,8 +497035,10 @@ ${feedback}
497107
497035
  if (chatgptPlanSwapsRef.current < CHATGPT_PLAN_ROTATION_MAX_SWAPS_PER_TURN) {
497108
497036
  const rotation = await rotateChatGPTPlanOnQuotaLimit({
497109
497037
  agentId: agentIdRef.current,
497038
+ conversationId: conversationIdRef.current,
497110
497039
  currentHandle: currentModelId,
497111
- error: runErrorInfo2 ?? detailFromRun ?? fallbackError
497040
+ error: runErrorInfo2 ?? detailFromRun ?? fallbackError,
497041
+ exhaustedProviders: chatgptExhaustedProvidersRef.current
497112
497042
  });
497113
497043
  if (rotation) {
497114
497044
  chatgptPlanSwapsRef.current += 1;
@@ -498026,6 +497956,8 @@ function useFeedbackHandler(ctx) {
498026
497956
  await submitFeedbackMetadata(apiKey, settingsManager.getOrCreateDeviceId(), {
498027
497957
  message: resolvedMessage,
498028
497958
  feature: "letta-code",
497959
+ submission_source: "slash_command",
497960
+ client_type: getFeedbackClientType(),
498029
497961
  agent_id: agentId,
498030
497962
  session_id: telemetry.getSessionId(),
498031
497963
  run_id: lastRunIdRef.current ?? undefined,
@@ -501442,10 +501374,10 @@ function mcpHelpText() {
501442
501374
  `);
501443
501375
  }
501444
501376
  var activeCommandId2 = null;
501445
- var init_mcp2 = __esm(async () => {
501377
+ var init_mcp2 = __esm(() => {
501446
501378
  init_error_formatter();
501379
+ init_mcp_runtime();
501447
501380
  init_settings_manager();
501448
- await init_mcp_runtime();
501449
501381
  });
501450
501382
 
501451
501383
  // src/cli/commands/listen.ts
@@ -501508,24 +501440,24 @@ Listener disconnected from Letta Cloud.`, true);
501508
501440
  return;
501509
501441
  }
501510
501442
  if (msg.includes("--help") || msg.includes("-h")) {
501511
- addCommandResult3(ctx.buffersRef, ctx.refreshDerived, msg, `Usage: /server [--env-name <name>]
501443
+ addCommandResult3(ctx.buffersRef, ctx.refreshDerived, msg, `Usage: /server [--computer-name <name>]
501512
501444
  /server off
501513
501445
 
501514
- Register this letta-code instance to receive messages from Letta Cloud.
501446
+ Register this computer to receive messages from Letta Cloud.
501515
501447
  Alias: /remote
501516
501448
 
501517
501449
  Options:
501518
- --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)
501519
501451
  off Stop the active listener connection
501520
501452
  -h, --help Show this help message
501521
501453
 
501522
501454
  Examples:
501523
501455
  /server # Start listener with hostname
501524
- /server --env-name "work-laptop" # Start with custom name
501456
+ /server --computer-name "work-laptop" # Start with custom name
501525
501457
  /server off # Stop listening
501526
501458
 
501527
501459
  Once connected, this instance will listen for incoming messages from cloud agents.
501528
- Messages will be executed locally using your letta-code environment.`, true);
501460
+ Messages will be executed locally on this computer.`, true);
501529
501461
  return;
501530
501462
  }
501531
501463
  let connectionName;
@@ -501575,7 +501507,7 @@ Retry ${attempt2} in ${Math.round(delayMs / 1000)}s: ${error5.message}`, true, "
501575
501507
  updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `✓ Registered successfully!
501576
501508
 
501577
501509
  ` + `Connection ID: ${connectionId}
501578
- Environment: "${connectionName}"
501510
+ Computer: "${connectionName}"
501579
501511
  WebSocket: ${wsUrl}
501580
501512
 
501581
501513
  Starting WebSocket connection...`, true, "running");
@@ -501593,18 +501525,18 @@ Starting WebSocket connection...`, true, "running");
501593
501525
  const url2 = buildConnectionUrl(id2);
501594
501526
  const urlText = url2 ? `
501595
501527
 
501596
- Connect to this environment:
501528
+ Connect to this computer:
501597
501529
  ${url2}` : "";
501598
- updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment initialized: ${connectionName}
501530
+ updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Computer initialized: ${connectionName}
501599
501531
  ${statusText}${urlText}`, true, "finished");
501600
501532
  },
501601
501533
  onRetrying: (attempt2, _maxAttempts, nextRetryIn, id2) => {
501602
501534
  const url2 = buildConnectionUrl(id2);
501603
501535
  const urlText = url2 ? `
501604
501536
 
501605
- Connect to this environment:
501537
+ Connect to this computer:
501606
501538
  ${url2}` : "";
501607
- updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment initialized: ${connectionName}
501539
+ updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Computer initialized: ${connectionName}
501608
501540
  Reconnecting to Letta Cloud...
501609
501541
  Attempt ${attempt2}, retrying in ${Math.round(nextRetryIn / 1000)}s${urlText}`, true, "running");
501610
501542
  },
@@ -501612,14 +501544,14 @@ Attempt ${attempt2}, retrying in ${Math.round(nextRetryIn / 1000)}s${urlText}`,
501612
501544
  const url2 = buildConnectionUrl(id2);
501613
501545
  const urlText = url2 ? `
501614
501546
 
501615
- Connect to this environment:
501547
+ Connect to this computer:
501616
501548
  ${url2}` : "";
501617
- updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Environment initialized: ${connectionName}
501549
+ updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Computer initialized: ${connectionName}
501618
501550
  Awaiting instructions${urlText}`, true, "finished");
501619
501551
  ctx.setCommandRunning(false);
501620
501552
  },
501621
501553
  onNeedsReregister: async () => {
501622
- 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");
501623
501555
  try {
501624
501556
  const nextRegisterOptions = await resolveRegisterOptions();
501625
501557
  const reregisterResult = await registerWithCloudRetry(nextRegisterOptions, {
@@ -501745,7 +501677,7 @@ async function handleConnectionCommand(msg, trimmed, ctx) {
501745
501677
  for (let i4 = 1;i4 < parts.length; i4++) {
501746
501678
  const part = parts[i4];
501747
501679
  const nextPart = parts[i4 + 1];
501748
- if (part === "--env-name" && nextPart) {
501680
+ if ((part === "--computer-name" || part === "--env-name") && nextPart) {
501749
501681
  name = nextPart;
501750
501682
  i4++;
501751
501683
  }
@@ -501768,8 +501700,8 @@ async function handleConnectionCommand(msg, trimmed, ctx) {
501768
501700
  }
501769
501701
  return null;
501770
501702
  }
501771
- var init_submit_connection_commands = __esm(async () => {
501772
- await init_mcp2();
501703
+ var init_submit_connection_commands = __esm(() => {
501704
+ init_mcp2();
501773
501705
  });
501774
501706
 
501775
501707
  // src/cli/helpers/context-chart.ts
@@ -505551,6 +505483,7 @@ var init_use_submit_handler = __esm(async () => {
505551
505483
  init_command_routing();
505552
505484
  init_ids();
505553
505485
  init_session3();
505486
+ init_submit_connection_commands();
505554
505487
  init_submit_diagnostics_commands();
505555
505488
  init_submit_profile_commands();
505556
505489
  await __promiseAll([
@@ -505558,7 +505491,6 @@ var init_use_submit_handler = __esm(async () => {
505558
505491
  init_mods2(),
505559
505492
  init_PinDialog(),
505560
505493
  init_accumulator(),
505561
- init_submit_connection_commands(),
505562
505494
  init_submit_navigation_commands()
505563
505495
  ]);
505564
505496
  import_react120 = __toESM(require_react(), 1);
@@ -506254,6 +506186,7 @@ function App2({
506254
506186
  const quotaAutoSwapAttemptedRef = import_react121.useRef(false);
506255
506187
  const emptyResponseRetriesRef = import_react121.useRef(0);
506256
506188
  const chatgptPlanSwapsRef = import_react121.useRef(0);
506189
+ const chatgptExhaustedProvidersRef = import_react121.useRef(new Set);
506257
506190
  const conversationBusyRetriesRef = import_react121.useRef(0);
506258
506191
  const [queueDisplay, setQueueDisplay] = import_react121.useState([]);
506259
506192
  const tuiQueueRef = import_react121.useRef(null);
@@ -506910,7 +506843,7 @@ function App2({
506910
506843
  import_react121.useEffect(() => {
506911
506844
  buffersRef.current.agentId = agentState?.id;
506912
506845
  }, [agentState?.id]);
506913
- useAgentMcpServers(agentState?.id);
506846
+ useMcpCleanup(agentState?.id);
506914
506847
  const precomputedDiffsRef = import_react121.useRef(new Map);
506915
506848
  const eagerCommittedPreviewsRef = import_react121.useRef(new Set);
506916
506849
  const estimateApprovalPreviewLines = import_react121.useCallback((approval) => {
@@ -507743,6 +507676,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
507743
507676
  buffersRef,
507744
507677
  clearApprovalToolContext,
507745
507678
  chatgptPlanSwapsRef,
507679
+ chatgptExhaustedProvidersRef,
507746
507680
  closeTrajectorySegment,
507747
507681
  consumeQueuedMessages,
507748
507682
  queueModeRef,
@@ -508904,6 +508838,7 @@ var init_AppCoordinator = __esm(async () => {
508904
508838
  init_ids();
508905
508839
  init_model_config();
508906
508840
  init_session3();
508841
+ init_use_agent_mcp_servers();
508907
508842
  init_use_feedback_handler();
508908
508843
  init_use_queued_approval_submit();
508909
508844
  init_use_reasoning_cycle();
@@ -508919,7 +508854,6 @@ var init_AppCoordinator = __esm(async () => {
508919
508854
  init_manager4(),
508920
508855
  init_toolset(),
508921
508856
  init_AppView(),
508922
- init_use_agent_mcp_servers(),
508923
508857
  init_use_approval_flow(),
508924
508858
  init_use_bash_handlers(),
508925
508859
  init_use_configuration_handlers(),
@@ -509136,14 +509070,13 @@ USAGE
509136
509070
  letta update Check for updates and install (aliases: upgrade, --update, --upgrade)
509137
509071
  letta memory ... Memory filesystem subcommands
509138
509072
  letta agents ... Agents subcommands (JSON-only)
509139
- letta environments ... List available remote environments (JSON-only)
509140
- 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
509141
509075
  letta messages ... Messages subcommands (JSON-only)
509142
509076
  letta mcp ... List, search, and call MCP servers available to an agent
509143
- letta cloud-mcp ... Legacy server-side MCP commands (JSON-only)
509144
509077
  letta mods ... List and manage local mods
509145
509078
  letta sandbox ... Transfer files to or from the current Cloud sandbox
509146
- letta server ... Run a remote environment, channels, or the App Server
509079
+ letta server ... Run a remote computer, channels, or the App Server
509147
509080
  letta connect ... Connect providers from terminal
509148
509081
  letta backend ... Show or set the default backend
509149
509082
  letta setup Re-run first-run setup
@@ -509162,20 +509095,19 @@ SUBCOMMANDS
509162
509095
  letta memory pull --agent <id>
509163
509096
  letta memory tokens [--memory-dir <path>] [--agent <id>] [--format text|json]
509164
509097
  letta agents list [--query <text> | --name <name> | --tags <tags>]
509165
- letta environments list [--online-only]
509166
- letta environments current
509167
- letta teleport list|cloud|local|<environment>
509098
+ letta computers list [--online-only]
509099
+ letta computers current
509100
+ letta teleport list|cloud|local|<computer>
509168
509101
  letta messages search --query <text> [--all-agents]
509169
509102
  letta messages list [--agent <id>]
509170
509103
  letta messages transcript --conversation <id> [--out <path>]
509171
- letta cloud-mcp list|tools|run ... [--agent <id>]
509172
509104
  letta mods list [--agent <id>]
509173
509105
  letta mods package <mod-file> --name <package-name> [--out <dir>]
509174
509106
  letta mods enable <package-spec>
509175
509107
  letta mods disable <package-spec>
509176
509108
  letta mods remove <package-spec>
509177
509109
  letta mcp list|get|tools|search|call ... [--agent <id>]
509178
- letta server [--env-name <name> | --listen [url]] [options]
509110
+ letta server [--computer-name <name> | --listen [url]] [options]
509179
509111
  letta connect <provider> [options]
509180
509112
  letta install <thing> [--agent <id> | -n <name>]
509181
509113
  letta skills list [--agent <id> | -n <name>]
@@ -509936,7 +509868,7 @@ Error: ${message}`);
509936
509868
  markMilestone("REACT_IMPORT_DONE");
509937
509869
  await terminalPreflightPromise;
509938
509870
  markMilestone("TERMINAL_PREFLIGHT_DONE");
509939
- const { useState: useState56, useEffect: useEffect50, useRef: useRef20 } = React14;
509871
+ const { useState: useState56, useEffect: useEffect50, useRef: useRef21 } = React14;
509940
509872
  const App3 = AppModule.App;
509941
509873
  function LoadingApp({
509942
509874
  forceNew: forceNew2,
@@ -509960,7 +509892,7 @@ Error: ${message}`);
509960
509892
  const [resumedExistingConversation, setResumedExistingConversation] = useState56(false);
509961
509893
  const [agentProvenance, setAgentProvenance] = useState56(null);
509962
509894
  const [selectedGlobalAgentId, setSelectedGlobalAgentId] = useState56(null);
509963
- const startupCreatedAgentRef = useRef20(null);
509895
+ const startupCreatedAgentRef = useRef21(null);
509964
509896
  const [startupHasCloudCredentials, setStartupHasCloudCredentials] = useState56(Boolean(settings3.refreshToken || apiKey));
509965
509897
  const [fileAutocompleteFdPath, setFileAutocompleteFdPath] = useState56(() => resolveFdPath());
509966
509898
  const [startupHasAvailableLocalModels, setStartupHasAvailableLocalModels] = useState56(true);
@@ -512995,4 +512927,4 @@ function registerBunOAuthFlows() {
512995
512927
  registerBunOAuthFlows();
512996
512928
  await init_src5().then(() => exports_src2);
512997
512929
 
512998
- //# debugId=39DF2EA197BB152964756E2164756E21
512930
+ //# debugId=D6C12B8170F7A1C664756E2164756E21