@letta-ai/letta-code 0.13.10 → 0.13.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +3 -1
  2. package/letta.js +183 -28
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -15,8 +15,10 @@ npm install -g @letta-ai/letta-code
15
15
  ```
16
16
  Navigate to your project directory and run `letta` (see various command-line options [on the docs](https://docs.letta.com/letta-code/commands)).
17
17
 
18
+ Run `/connect` to configure your own LLM API keys (OpenAI, Anthropic, etc.), and use `/model` to swap models.
19
+
18
20
  > [!NOTE]
19
- > By default, Letta Code will to connect to the [Letta API](https://app.letta.com/). Use `/connect` to use your own LLM API keys and coding plans (Codex, Z.ai) for free. You can also connect to a [Docker server](https://docs.letta.com/letta-code/configuration#docker) by setting `LETTA_BASE_URL`.
21
+ > By default, Letta Code will to connect to the [Letta API](https://app.letta.com/). Use `/connect` to use your own LLM API keys and coding plans (Codex, zAI, Minimax) for free. Set `LETTA_BASE_URL` to connect to an external [Docker server](https://docs.letta.com/letta-code/docker).
20
22
 
21
23
  ## Philosophy
22
24
  Letta Code is built around long-lived agents that persist across sessions and improve with use. Rather than working in independent sessions, each session is tied to a persisted agent that learns.
package/letta.js CHANGED
@@ -3108,7 +3108,7 @@ var package_default;
3108
3108
  var init_package = __esm(() => {
3109
3109
  package_default = {
3110
3110
  name: "@letta-ai/letta-code",
3111
- version: "0.13.10",
3111
+ version: "0.13.11",
3112
3112
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
3113
3113
  type: "module",
3114
3114
  bin: {
@@ -61185,6 +61185,19 @@ function getResourceLimitMessage(e) {
61185
61185
  }
61186
61186
  return;
61187
61187
  }
61188
+ function isAgentLimitError(e) {
61189
+ if (e.status !== 429)
61190
+ return false;
61191
+ const errorBody = e.error;
61192
+ if (errorBody && typeof errorBody === "object") {
61193
+ if ("reasons" in errorBody && Array.isArray(errorBody.reasons)) {
61194
+ if (errorBody.reasons.includes("agents-limit-exceeded")) {
61195
+ return true;
61196
+ }
61197
+ }
61198
+ }
61199
+ return false;
61200
+ }
61188
61201
  function isCreditExhaustedError(e) {
61189
61202
  if (e.status !== 402)
61190
61203
  return false;
@@ -61217,6 +61230,15 @@ function formatErrorDetails(e, agentId, conversationId) {
61217
61230
  const resetInfo = rateLimitResetMs > 0 ? formatResetTime(rateLimitResetMs) : "Try again later";
61218
61231
  return `You've hit your usage limit. ${resetInfo}. View usage: ${LETTA_USAGE_URL}`;
61219
61232
  }
61233
+ if (isAgentLimitError(e)) {
61234
+ const { billingTier } = getErrorContext();
61235
+ if (billingTier?.toLowerCase() === "free") {
61236
+ return `You've reached the agent limit (3) for the Free Plan. Delete agents at: ${LETTA_AGENTS_URL}
61237
+ Or upgrade to Pro for unlimited agents at: ${LETTA_USAGE_URL}`;
61238
+ }
61239
+ return `You've reached your agent limit. Delete agents at: ${LETTA_AGENTS_URL}
61240
+ Or check your plan at: ${LETTA_USAGE_URL}`;
61241
+ }
61220
61242
  const resourceLimitMsg = getResourceLimitMessage(e);
61221
61243
  if (resourceLimitMsg) {
61222
61244
  const match3 = resourceLimitMsg.match(/limit for (\w+)/);
@@ -62285,15 +62307,10 @@ In headless mode, use:
62285
62307
  console.error(`Error: Invalid model "${model}"`);
62286
62308
  process.exit(1);
62287
62309
  }
62288
- const currentModel = agent.llm_config?.model;
62289
- const currentEndpointType = agent.llm_config?.model_endpoint_type;
62290
- const currentHandle = `${currentEndpointType}/${currentModel}`;
62291
- if (currentHandle !== modelHandle) {
62292
- const { updateAgentLLMConfig: updateAgentLLMConfig2 } = await init_modify().then(() => exports_modify);
62293
- const updateArgs = getModelUpdateArgs(model);
62294
- await updateAgentLLMConfig2(agent.id, modelHandle, updateArgs);
62295
- agent = await client.agents.retrieve(agent.id);
62296
- }
62310
+ const { updateAgentLLMConfig: updateAgentLLMConfig2 } = await init_modify().then(() => exports_modify);
62311
+ const updateArgs = getModelUpdateArgs(model);
62312
+ await updateAgentLLMConfig2(agent.id, modelHandle, updateArgs);
62313
+ agent = await client.agents.retrieve(agent.id);
62297
62314
  }
62298
62315
  if (systemPromptPreset) {
62299
62316
  const { updateAgentSystemPrompt: updateAgentSystemPrompt2 } = await init_modify().then(() => exports_modify);
@@ -64296,6 +64313,9 @@ function AgentSelector({
64296
64313
  const [allQuery, setAllQuery] = import_react29.useState("");
64297
64314
  const [searchInput, setSearchInput] = import_react29.useState("");
64298
64315
  const [activeQuery, setActiveQuery] = import_react29.useState("");
64316
+ const [viewState, setViewState] = import_react29.useState({ type: "list" });
64317
+ const [deleteConfirmInput, setDeleteConfirmInput] = import_react29.useState("");
64318
+ const [deleteLoading, setDeleteLoading] = import_react29.useState(false);
64299
64319
  const loadPinnedAgents = import_react29.useCallback(async () => {
64300
64320
  setPinnedLoading(true);
64301
64321
  try {
@@ -64439,9 +64459,10 @@ function AgentSelector({
64439
64459
  setAllLoadingMore(false);
64440
64460
  }
64441
64461
  }, [allLoadingMore, allHasMore, allCursor, fetchListAgents, activeQuery]);
64442
- const pinnedTotalPages = Math.ceil(pinnedAgents.length / DISPLAY_PAGE_SIZE2);
64462
+ const validPinnedAgents = pinnedAgents.filter((p) => p.agent !== null);
64463
+ const pinnedTotalPages = Math.ceil(validPinnedAgents.length / DISPLAY_PAGE_SIZE2);
64443
64464
  const pinnedStartIndex = pinnedPage * DISPLAY_PAGE_SIZE2;
64444
- const pinnedPageAgents = pinnedAgents.slice(pinnedStartIndex, pinnedStartIndex + DISPLAY_PAGE_SIZE2);
64465
+ const pinnedPageAgents = validPinnedAgents.slice(pinnedStartIndex, pinnedStartIndex + DISPLAY_PAGE_SIZE2);
64445
64466
  const lettaCodeTotalPages = Math.ceil(lettaCodeAgents.length / DISPLAY_PAGE_SIZE2);
64446
64467
  const lettaCodeStartIndex = lettaCodePage * DISPLAY_PAGE_SIZE2;
64447
64468
  const lettaCodePageAgents = lettaCodeAgents.slice(lettaCodeStartIndex, lettaCodeStartIndex + DISPLAY_PAGE_SIZE2);
@@ -64465,11 +64486,49 @@ function AgentSelector({
64465
64486
  setActiveQuery("");
64466
64487
  }
64467
64488
  }, [activeQuery]);
64489
+ const handleDeleteAgent = import_react29.useCallback(async () => {
64490
+ if (viewState.type !== "deleteConfirm")
64491
+ return;
64492
+ const { agent, agentId } = viewState;
64493
+ const expectedName = agent.name || agentId.slice(0, 12);
64494
+ if (deleteConfirmInput !== expectedName)
64495
+ return;
64496
+ setDeleteLoading(true);
64497
+ try {
64498
+ const client = clientRef.current || await getClient2();
64499
+ clientRef.current = client;
64500
+ await client.agents.delete(agentId);
64501
+ setViewState({ type: "list" });
64502
+ setDeleteConfirmInput("");
64503
+ loadPinnedAgents();
64504
+ setLettaCodeLoaded(false);
64505
+ setAllLoaded(false);
64506
+ } catch {} finally {
64507
+ setDeleteLoading(false);
64508
+ }
64509
+ }, [viewState, deleteConfirmInput, loadPinnedAgents]);
64468
64510
  use_input_default((input, key) => {
64469
64511
  if (key.ctrl && input === "c") {
64470
64512
  onCancel();
64471
64513
  return;
64472
64514
  }
64515
+ if (viewState.type === "deleteConfirm") {
64516
+ if (key.escape) {
64517
+ setViewState({ type: "list" });
64518
+ setDeleteConfirmInput("");
64519
+ return;
64520
+ }
64521
+ if (deleteLoading)
64522
+ return;
64523
+ if (key.return) {
64524
+ handleDeleteAgent();
64525
+ } else if (key.backspace || key.delete) {
64526
+ setDeleteConfirmInput((prev) => prev.slice(0, -1));
64527
+ } else if (input && !key.ctrl && !key.meta) {
64528
+ setDeleteConfirmInput((prev) => prev + input);
64529
+ }
64530
+ return;
64531
+ }
64473
64532
  if (key.tab) {
64474
64533
  const currentIndex = TABS.findIndex((t) => t.id === activeTab);
64475
64534
  const nextIndex = (currentIndex + 1) % TABS.length;
@@ -64568,6 +64627,30 @@ function AgentSelector({
64568
64627
  }
64569
64628
  loadPinnedAgents();
64570
64629
  }
64630
+ } else if (input === "d" || input === "D") {
64631
+ let selectedAgent = null;
64632
+ let selectedAgentId = null;
64633
+ if (activeTab === "pinned") {
64634
+ const selected = pinnedPageAgents[pinnedSelectedIndex];
64635
+ if (selected?.agent) {
64636
+ selectedAgent = selected.agent;
64637
+ selectedAgentId = selected.agentId;
64638
+ }
64639
+ } else if (activeTab === "letta-code") {
64640
+ selectedAgent = lettaCodePageAgents[lettaCodeSelectedIndex] ?? null;
64641
+ selectedAgentId = selectedAgent?.id ?? null;
64642
+ } else {
64643
+ selectedAgent = allPageAgents[allSelectedIndex] ?? null;
64644
+ selectedAgentId = selectedAgent?.id ?? null;
64645
+ }
64646
+ if (selectedAgent && selectedAgentId) {
64647
+ setViewState({
64648
+ type: "deleteConfirm",
64649
+ agent: selectedAgent,
64650
+ agentId: selectedAgentId
64651
+ });
64652
+ setDeleteConfirmInput("");
64653
+ }
64571
64654
  } else if (input === "n" || input === "N") {
64572
64655
  onCreateNewAgent?.();
64573
64656
  } else if (activeTab !== "pinned" && input && !key.ctrl && !key.meta) {
@@ -64703,7 +64786,85 @@ function AgentSelector({
64703
64786
  ]
64704
64787
  }, data.agentId, true, undefined, this);
64705
64788
  };
64789
+ const renderDeleteConfirm = () => {
64790
+ if (viewState.type !== "deleteConfirm")
64791
+ return null;
64792
+ const { agent, agentId } = viewState;
64793
+ const displayName = agent.name || agentId.slice(0, 12);
64794
+ const inputMatches = deleteConfirmInput === displayName;
64795
+ return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(jsx_dev_runtime8.Fragment, {
64796
+ children: [
64797
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
64798
+ flexDirection: "column",
64799
+ marginBottom: 1,
64800
+ children: [
64801
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
64802
+ children: [
64803
+ " ",
64804
+ "Are you sure you want to delete",
64805
+ " ",
64806
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
64807
+ bold: true,
64808
+ children: displayName
64809
+ }, undefined, false, undefined, this),
64810
+ "?"
64811
+ ]
64812
+ }, undefined, true, undefined, this),
64813
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
64814
+ color: "red",
64815
+ children: [
64816
+ " ",
64817
+ "This action can not be undone."
64818
+ ]
64819
+ }, undefined, true, undefined, this)
64820
+ ]
64821
+ }, undefined, true, undefined, this),
64822
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
64823
+ flexDirection: "row",
64824
+ children: [
64825
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
64826
+ color: colors.selector.itemHighlighted,
64827
+ children: "> "
64828
+ }, undefined, false, undefined, this),
64829
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
64830
+ dimColor: !deleteConfirmInput,
64831
+ children: deleteConfirmInput || "(type the agent's name)"
64832
+ }, undefined, false, undefined, this)
64833
+ ]
64834
+ }, undefined, true, undefined, this),
64835
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
64836
+ marginTop: 1,
64837
+ children: /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
64838
+ dimColor: true,
64839
+ children: [
64840
+ " ",
64841
+ deleteLoading ? "Deleting... · Esc cancel" : inputMatches ? "Enter to delete · Esc cancel" : "Esc cancel"
64842
+ ]
64843
+ }, undefined, true, undefined, this)
64844
+ }, undefined, false, undefined, this)
64845
+ ]
64846
+ }, undefined, true, undefined, this);
64847
+ };
64706
64848
  const solidLine = SOLID_LINE2.repeat(Math.max(terminalWidth, 10));
64849
+ if (viewState.type === "deleteConfirm") {
64850
+ return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
64851
+ flexDirection: "column",
64852
+ children: [
64853
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
64854
+ dimColor: true,
64855
+ children: `> ${command}`
64856
+ }, undefined, false, undefined, this),
64857
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
64858
+ dimColor: true,
64859
+ children: solidLine
64860
+ }, undefined, false, undefined, this),
64861
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
64862
+ height: 1
64863
+ }, undefined, false, undefined, this),
64864
+ renderDeleteConfirm()
64865
+ ]
64866
+ }, undefined, true, undefined, this);
64867
+ }
64707
64868
  return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
64708
64869
  flexDirection: "column",
64709
64870
  children: [
@@ -64789,7 +64950,7 @@ function AgentSelector({
64789
64950
  ]
64790
64951
  }, undefined, true, undefined, this)
64791
64952
  }, undefined, false, undefined, this),
64792
- !currentLoading && (activeTab === "pinned" && pinnedAgents.length === 0 || activeTab === "letta-code" && !lettaCodeError && lettaCodeAgents.length === 0 || activeTab === "all" && !allError && allAgents.length === 0) && /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
64953
+ !currentLoading && (activeTab === "pinned" && validPinnedAgents.length === 0 || activeTab === "letta-code" && !lettaCodeError && lettaCodeAgents.length === 0 || activeTab === "all" && !allError && allAgents.length === 0) && /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
64793
64954
  flexDirection: "column",
64794
64955
  children: [
64795
64956
  /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
@@ -64802,7 +64963,7 @@ function AgentSelector({
64802
64963
  }, undefined, false, undefined, this)
64803
64964
  ]
64804
64965
  }, undefined, true, undefined, this),
64805
- activeTab === "pinned" && !pinnedLoading && pinnedAgents.length > 0 && /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
64966
+ activeTab === "pinned" && !pinnedLoading && validPinnedAgents.length > 0 && /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
64806
64967
  flexDirection: "column",
64807
64968
  children: pinnedPageAgents.map((data, index) => renderPinnedItem(data, index, index === pinnedSelectedIndex))
64808
64969
  }, undefined, false, undefined, this),
@@ -64814,10 +64975,10 @@ function AgentSelector({
64814
64975
  flexDirection: "column",
64815
64976
  children: allPageAgents.map((agent, index) => renderAgentItem(agent, index, index === allSelectedIndex))
64816
64977
  }, undefined, false, undefined, this),
64817
- !currentLoading && (activeTab === "pinned" && pinnedAgents.length > 0 || activeTab === "letta-code" && !lettaCodeError && lettaCodeAgents.length > 0 || activeTab === "all" && !allError && allAgents.length > 0) && (() => {
64978
+ !currentLoading && (activeTab === "pinned" && validPinnedAgents.length > 0 || activeTab === "letta-code" && !lettaCodeError && lettaCodeAgents.length > 0 || activeTab === "all" && !allError && allAgents.length > 0) && (() => {
64818
64979
  const footerWidth = Math.max(0, terminalWidth - 2);
64819
64980
  const pageText = activeTab === "pinned" ? `Page ${pinnedPage + 1}/${pinnedTotalPages || 1}` : activeTab === "letta-code" ? `Page ${lettaCodePage + 1}${lettaCodeHasMore ? "+" : `/${lettaCodeTotalPages || 1}`}${lettaCodeLoadingMore ? " (loading...)" : ""}` : `Page ${allPage + 1}${allHasMore ? "+" : `/${allTotalPages || 1}`}${allLoadingMore ? " (loading...)" : ""}`;
64820
- const hintsText = `Enter select · ↑↓ navigate · ←→ page · Tab switch${activeTab === "pinned" ? " · P unpin" : " · Type to search"}${onCreateNewAgent ? " · N new" : ""} · Esc cancel`;
64981
+ const hintsText = `Enter select · ↑↓ ←→ navigate · Tab switch · D delete${activeTab === "pinned" ? " · P unpin" : ""}${onCreateNewAgent ? " · N new" : ""} · Esc cancel`;
64821
64982
  return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
64822
64983
  flexDirection: "column",
64823
64984
  children: [
@@ -97015,22 +97176,16 @@ Error: ${message}`);
97015
97176
  setIsResumingSession(resuming);
97016
97177
  if (resuming && (model || systemPromptPreset2)) {
97017
97178
  if (model) {
97018
- const { resolveModel: resolveModel3 } = await Promise.resolve().then(() => (init_model2(), exports_model2));
97179
+ const { resolveModel: resolveModel3, getModelUpdateArgs: getModelUpdateArgs4 } = await Promise.resolve().then(() => (init_model2(), exports_model2));
97019
97180
  const modelHandle = resolveModel3(model);
97020
97181
  if (!modelHandle) {
97021
97182
  console.error(`Error: Invalid model "${model}"`);
97022
97183
  process.exit(1);
97023
97184
  }
97024
- const currentModel = agent.llm_config?.model;
97025
- const currentEndpointType = agent.llm_config?.model_endpoint_type;
97026
- const currentHandle = `${currentEndpointType}/${currentModel}`;
97027
- if (currentHandle !== modelHandle) {
97028
- const { updateAgentLLMConfig: updateAgentLLMConfig3 } = await init_modify2().then(() => exports_modify2);
97029
- const { getModelUpdateArgs: getModelUpdateArgs4 } = await Promise.resolve().then(() => (init_model2(), exports_model2));
97030
- const updateArgs = getModelUpdateArgs4(model);
97031
- await updateAgentLLMConfig3(agent.id, modelHandle, updateArgs);
97032
- agent = await client.agents.retrieve(agent.id);
97033
- }
97185
+ const { updateAgentLLMConfig: updateAgentLLMConfig3 } = await init_modify2().then(() => exports_modify2);
97186
+ const updateArgs = getModelUpdateArgs4(model);
97187
+ await updateAgentLLMConfig3(agent.id, modelHandle, updateArgs);
97188
+ agent = await client.agents.retrieve(agent.id);
97034
97189
  }
97035
97190
  if (systemPromptPreset2) {
97036
97191
  const { updateAgentSystemPrompt: updateAgentSystemPrompt3 } = await init_modify2().then(() => exports_modify2);
@@ -97264,4 +97419,4 @@ Error during initialization: ${message}`);
97264
97419
  }
97265
97420
  main();
97266
97421
 
97267
- //# debugId=421C79302D2709D564756E2164756E21
97422
+ //# debugId=8E63B855C90D4DD564756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letta-ai/letta-code",
3
- "version": "0.13.10",
3
+ "version": "0.13.11",
4
4
  "description": "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {