@letta-ai/letta-code 0.12.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/letta.js +279 -37
  2. package/package.json +1 -1
package/letta.js CHANGED
@@ -3237,7 +3237,7 @@ var package_default;
3237
3237
  var init_package = __esm(() => {
3238
3238
  package_default = {
3239
3239
  name: "@letta-ai/letta-code",
3240
- version: "0.12.0",
3240
+ version: "0.12.1",
3241
3241
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
3242
3242
  type: "module",
3243
3243
  bin: {
@@ -29951,6 +29951,10 @@ var init_WelcomeScreen = __esm(async () => {
29951
29951
  });
29952
29952
 
29953
29953
  // src/permissions/readOnlyShell.ts
29954
+ function isReadOnlySkillScript(scriptPath) {
29955
+ const normalized = scriptPath.replace(/\\/g, "/");
29956
+ return BUNDLED_READ_ONLY_SCRIPTS.some((pattern) => normalized.endsWith(pattern));
29957
+ }
29954
29958
  function isReadOnlyShellCommand(command) {
29955
29959
  if (!command) {
29956
29960
  return false;
@@ -30018,6 +30022,13 @@ function isSafeSegment(segment) {
30018
30022
  if (command === "sort") {
30019
30023
  return !/\s-o\b/.test(segment);
30020
30024
  }
30025
+ if (command === "npx" && tokens[1] === "tsx") {
30026
+ const scriptPath = tokens[2];
30027
+ if (scriptPath && isReadOnlySkillScript(scriptPath)) {
30028
+ return true;
30029
+ }
30030
+ return false;
30031
+ }
30021
30032
  return false;
30022
30033
  }
30023
30034
  return true;
@@ -30050,7 +30061,7 @@ function extractDashCArgument(tokens) {
30050
30061
  }
30051
30062
  return;
30052
30063
  }
30053
- var ALWAYS_SAFE_COMMANDS, SAFE_GIT_SUBCOMMANDS, DANGEROUS_OPERATOR_PATTERN;
30064
+ var ALWAYS_SAFE_COMMANDS, SAFE_GIT_SUBCOMMANDS, BUNDLED_READ_ONLY_SCRIPTS, DANGEROUS_OPERATOR_PATTERN;
30054
30065
  var init_readOnlyShell = __esm(() => {
30055
30066
  ALWAYS_SAFE_COMMANDS = new Set([
30056
30067
  "cat",
@@ -30113,6 +30124,12 @@ var init_readOnlyShell = __esm(() => {
30113
30124
  "tag",
30114
30125
  "remote"
30115
30126
  ]);
30127
+ BUNDLED_READ_ONLY_SCRIPTS = [
30128
+ "/skills/searching-messages/scripts/search-messages.ts",
30129
+ "/skills/searching-messages/scripts/get-messages.ts",
30130
+ "/skills/builtin/searching-messages/scripts/search-messages.ts",
30131
+ "/skills/builtin/searching-messages/scripts/get-messages.ts"
30132
+ ];
30116
30133
  DANGEROUS_OPERATOR_PATTERN = /(>>|>|\$\(|`)/;
30117
30134
  });
30118
30135
 
@@ -31629,6 +31646,46 @@ Remember: You're planning, not implementing. Don't make changes, just create a r
31629
31646
  `;
31630
31647
  var init_plan = () => {};
31631
31648
 
31649
+ // src/agent/subagents/builtin/recall.md
31650
+ var recall_default = `---
31651
+ name: recall
31652
+ description: Search conversation history to recall past discussions, decisions, and context
31653
+ tools: Skill, Bash, Read, BashOutput
31654
+ model: haiku
31655
+ memoryBlocks: human, persona
31656
+ mode: stateless
31657
+ ---
31658
+
31659
+ You are a subagent launched via the Task tool to search conversation history. You run autonomously and return a single final report when done. You CANNOT ask questions mid-execution.
31660
+
31661
+ ## Instructions
31662
+
31663
+ ### Step 1: Load the searching-messages skill
31664
+ \`\`\`
31665
+ Skill({ command: "load", skills: ["searching-messages"] })
31666
+ \`\`\`
31667
+
31668
+ The skill content will appear in your loaded_skills block with script paths and search strategies.
31669
+
31670
+ ### Step 2: Search the parent agent's history
31671
+
31672
+ **CRITICAL - Two rules:**
31673
+
31674
+ 1. **DO NOT use \`conversation_search\`** - That tool only searches YOUR history (empty). You MUST use the Bash scripts from the skill.
31675
+
31676
+ 2. **ALWAYS add \`--agent-id $LETTA_PARENT_AGENT_ID\`** - This searches the parent agent's history. The only exception is \`--all-agents\` searches.
31677
+
31678
+ Follow the strategies documented in the loaded skill.
31679
+
31680
+ ## Output Format
31681
+
31682
+ 1. **Direct answer** - What the user asked about
31683
+ 2. **Key findings** - Relevant quotes or summaries from past conversations
31684
+ 3. **When discussed** - Timestamps of relevant discussions
31685
+ 4. **Outcome/Decision** - What was decided or concluded (if applicable)
31686
+ `;
31687
+ var init_recall = () => {};
31688
+
31632
31689
  // src/agent/subagents/index.ts
31633
31690
  var exports_subagents = {};
31634
31691
  __export(exports_subagents, {
@@ -31793,7 +31850,13 @@ var init_subagents = __esm(() => {
31793
31850
  init_explore();
31794
31851
  init_general_purpose();
31795
31852
  init_plan();
31796
- BUILTIN_SOURCES = [explore_default, general_purpose_default, plan_default];
31853
+ init_recall();
31854
+ BUILTIN_SOURCES = [
31855
+ explore_default,
31856
+ general_purpose_default,
31857
+ plan_default,
31858
+ recall_default
31859
+ ];
31797
31860
  GLOBAL_AGENTS_DIR = join3(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents");
31798
31861
  VALID_MEMORY_BLOCKS = new Set(MEMORY_BLOCK_LABELS);
31799
31862
  cache3 = {
@@ -43281,11 +43344,16 @@ async function executeSubagent(type, config, model, userPrompt, baseURL, subagen
43281
43344
  try {
43282
43345
  const cliArgs = buildSubagentArgs(type, config, model, userPrompt);
43283
43346
  const lettaCmd = process.env.LETTA_CODE_BIN || "letta";
43347
+ let parentAgentId;
43348
+ try {
43349
+ parentAgentId = getCurrentAgentId();
43350
+ } catch {}
43284
43351
  const proc2 = spawn3(lettaCmd, cliArgs, {
43285
43352
  cwd: process.cwd(),
43286
43353
  env: {
43287
43354
  ...process.env,
43288
- LETTA_CODE_AGENT_ROLE: "subagent"
43355
+ LETTA_CODE_AGENT_ROLE: "subagent",
43356
+ ...parentAgentId && { LETTA_PARENT_AGENT_ID: parentAgentId }
43289
43357
  }
43290
43358
  });
43291
43359
  let wasAborted = false;
@@ -45644,7 +45712,13 @@ var init_subagents2 = __esm(() => {
45644
45712
  init_explore();
45645
45713
  init_general_purpose();
45646
45714
  init_plan();
45647
- BUILTIN_SOURCES2 = [explore_default, general_purpose_default, plan_default];
45715
+ init_recall();
45716
+ BUILTIN_SOURCES2 = [
45717
+ explore_default,
45718
+ general_purpose_default,
45719
+ plan_default,
45720
+ recall_default
45721
+ ];
45648
45722
  GLOBAL_AGENTS_DIR2 = join10(process.env.HOME || process.env.USERPROFILE || "~", ".letta/agents");
45649
45723
  VALID_MEMORY_BLOCKS2 = new Set(MEMORY_BLOCK_LABELS);
45650
45724
  cache4 = {
@@ -48326,7 +48400,9 @@ var init_checker = __esm(() => {
48326
48400
  "explore",
48327
48401
  "Explore",
48328
48402
  "plan",
48329
- "Plan"
48403
+ "Plan",
48404
+ "recall",
48405
+ "Recall"
48330
48406
  ]);
48331
48407
  });
48332
48408
 
@@ -49510,7 +49586,7 @@ var init_create = __esm(async () => {
49510
49586
  });
49511
49587
 
49512
49588
  // src/agent/message.ts
49513
- async function sendMessageStream(agentId, messages, opts = { streamTokens: true, background: true }) {
49589
+ async function sendMessageStream(agentId, messages, opts = { streamTokens: true, background: true }, requestOptions = { maxRetries: 0 }) {
49514
49590
  const client = await getClient2();
49515
49591
  return client.agents.messages.create(agentId, {
49516
49592
  messages,
@@ -49518,7 +49594,7 @@ async function sendMessageStream(agentId, messages, opts = { streamTokens: true,
49518
49594
  stream_tokens: opts.streamTokens ?? true,
49519
49595
  background: opts.background ?? true,
49520
49596
  client_tools: getClientToolsFromRegistry()
49521
- });
49597
+ }, requestOptions);
49522
49598
  }
49523
49599
  var init_message = __esm(async () => {
49524
49600
  await __promiseAll([
@@ -49636,8 +49712,10 @@ function markCurrentLineAsFinished(b) {
49636
49712
  markAsFinished(b, b.lastOtid);
49637
49713
  } else {}
49638
49714
  }
49639
- function markIncompleteToolsAsCancelled(b) {
49640
- b.interrupted = true;
49715
+ function markIncompleteToolsAsCancelled(b, setInterruptedFlag = true) {
49716
+ if (setInterruptedFlag) {
49717
+ b.interrupted = true;
49718
+ }
49641
49719
  let anyToolsCancelled = false;
49642
49720
  for (const [id, line] of b.byId.entries()) {
49643
49721
  if (line.kind === "tool_call" && line.phase !== "finished") {
@@ -50032,6 +50110,10 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
50032
50110
  queueMicrotask(refresh);
50033
50111
  break;
50034
50112
  }
50113
+ const errObj = chunk.error;
50114
+ if (errObj?.detail?.includes("No tool call is currently awaiting approval")) {
50115
+ continue;
50116
+ }
50035
50117
  onChunk(buffers, chunk);
50036
50118
  queueMicrotask(refresh);
50037
50119
  if (chunk.message_type === "stop_reason") {
@@ -50113,7 +50195,7 @@ async function drainStreamWithResume(stream2, buffers, refresh, abortSignal, onF
50113
50195
  const resumeStream = await client.runs.messages.stream(result.lastRunId, {
50114
50196
  starting_after: result.lastSeqId,
50115
50197
  batch_size: 1000
50116
- });
50198
+ }, { maxRetries: 0 });
50117
50199
  const resumeResult = await drainStream(resumeStream, buffers, refresh, abortSignal);
50118
50200
  result = resumeResult;
50119
50201
  } catch (_e) {
@@ -70528,6 +70610,7 @@ function App2({
70528
70610
  }, [agentId]);
70529
70611
  const [streaming, setStreaming, streamingRef] = useSyncedState(false);
70530
70612
  const processingConversationRef = import_react76.useRef(0);
70613
+ const conversationGenerationRef = import_react76.useRef(0);
70531
70614
  const [interruptRequested, setInterruptRequested] = import_react76.useState(false);
70532
70615
  const [commandRunning, setCommandRunning, commandRunningRef] = useSyncedState(false);
70533
70616
  const [profileConfirmPending, setProfileConfirmPending] = import_react76.useState(null);
@@ -70917,6 +71000,10 @@ function App2({
70917
71000
  const processConversation = import_react76.useCallback(async (initialInput, options) => {
70918
71001
  const currentInput = [...initialInput];
70919
71002
  const allowReentry = options?.allowReentry ?? false;
71003
+ const myGeneration = options?.submissionGeneration ?? conversationGenerationRef.current;
71004
+ if (myGeneration !== conversationGenerationRef.current) {
71005
+ return;
71006
+ }
70920
71007
  if (processingConversationRef.current > 0 && !allowReentry) {
70921
71008
  return;
70922
71009
  }
@@ -70930,20 +71017,29 @@ function App2({
70930
71017
  userCancelledRef.current = false;
70931
71018
  return;
70932
71019
  }
71020
+ if (myGeneration !== conversationGenerationRef.current) {
71021
+ return;
71022
+ }
70933
71023
  setStreaming(true);
70934
71024
  abortControllerRef.current = new AbortController;
70935
- markIncompleteToolsAsCancelled(buffersRef.current);
71025
+ markIncompleteToolsAsCancelled(buffersRef.current, false);
70936
71026
  buffersRef.current.interrupted = false;
70937
71027
  clearCompletedSubagents();
70938
71028
  while (true) {
70939
71029
  const signal = abortControllerRef.current?.signal;
70940
71030
  if (signal?.aborted) {
70941
- setStreaming(false);
71031
+ const isStaleAtAbort = myGeneration !== conversationGenerationRef.current;
71032
+ if (!isStaleAtAbort) {
71033
+ setStreaming(false);
71034
+ }
70942
71035
  return;
70943
71036
  }
70944
71037
  const stream2 = await sendMessageStream(agentIdRef.current, currentInput);
70945
71038
  if (signal?.aborted) {
70946
- setStreaming(false);
71039
+ const isStaleAtAbort = myGeneration !== conversationGenerationRef.current;
71040
+ if (!isStaleAtAbort) {
71041
+ setStreaming(false);
71042
+ }
70947
71043
  return;
70948
71044
  }
70949
71045
  const syncAgentState = async () => {
@@ -70987,6 +71083,10 @@ function App2({
70987
71083
  const wasInterrupted = !!buffersRef.current.interrupted;
70988
71084
  const wasAborted = !!signal?.aborted;
70989
71085
  let stopReasonToHandle = wasAborted ? "cancelled" : stopReason;
71086
+ const isStaleAfterDrain = myGeneration !== conversationGenerationRef.current;
71087
+ if (isStaleAfterDrain) {
71088
+ return;
71089
+ }
70990
71090
  if (!wasInterrupted) {
70991
71091
  refreshDerived();
70992
71092
  }
@@ -71306,7 +71406,8 @@ function App2({
71306
71406
  sendDesktopNotification();
71307
71407
  return;
71308
71408
  }
71309
- const isApprovalPayload = currentInput.length === 1 && currentInput[0]?.type === "approval";
71409
+ const hasApprovalInPayload = currentInput.some((item) => item?.type === "approval");
71410
+ const isApprovalOnlyPayload = hasApprovalInPayload && currentInput.length === 1;
71310
71411
  let latestErrorText = null;
71311
71412
  for (let i = buffersRef.current.order.length - 1;i >= 0; i -= 1) {
71312
71413
  const id = buffersRef.current.order[i];
@@ -71321,7 +71422,7 @@ function App2({
71321
71422
  const detailFromRun = await fetchRunErrorDetail(lastRunId);
71322
71423
  const desyncDetected = isApprovalStateDesyncError(detailFromRun) || isApprovalStateDesyncError(latestErrorText);
71323
71424
  const lastFailureMessage = latestErrorText || detailFromRun || null;
71324
- if (isApprovalPayload && desyncDetected) {
71425
+ if (hasApprovalInPayload && desyncDetected) {
71325
71426
  if (llmApiErrorRetriesRef.current < LLM_API_ERROR_MAX_RETRIES2) {
71326
71427
  llmApiErrorRetriesRef.current += 1;
71327
71428
  const statusId = uid4("status");
@@ -71334,7 +71435,16 @@ function App2({
71334
71435
  });
71335
71436
  buffersRef.current.order.push(statusId);
71336
71437
  refreshDerived();
71337
- currentInput.splice(0, currentInput.length, buildApprovalRecoveryMessage());
71438
+ if (isApprovalOnlyPayload) {
71439
+ currentInput.splice(0, currentInput.length, buildApprovalRecoveryMessage());
71440
+ } else {
71441
+ const messageItems = currentInput.filter((item) => item?.type !== "approval");
71442
+ if (messageItems.length > 0) {
71443
+ currentInput.splice(0, currentInput.length, ...messageItems);
71444
+ } else {
71445
+ currentInput.splice(0, currentInput.length, buildApprovalRecoveryMessage());
71446
+ }
71447
+ }
71338
71448
  buffersRef.current.byId.delete(statusId);
71339
71449
  buffersRef.current.order = buffersRef.current.order.filter((id) => id !== statusId);
71340
71450
  refreshDerived();
@@ -71451,8 +71561,11 @@ function App2({
71451
71561
  sendDesktopNotification();
71452
71562
  refreshDerived();
71453
71563
  } finally {
71564
+ const isStale = myGeneration !== conversationGenerationRef.current;
71454
71565
  abortControllerRef.current = null;
71455
- processingConversationRef.current = Math.max(0, processingConversationRef.current - 1);
71566
+ if (!isStale) {
71567
+ processingConversationRef.current = Math.max(0, processingConversationRef.current - 1);
71568
+ }
71456
71569
  }
71457
71570
  }, [
71458
71571
  appendError,
@@ -71495,8 +71608,9 @@ function App2({
71495
71608
  }, 50);
71496
71609
  return;
71497
71610
  }
71498
- if (!streaming || interruptRequested)
71611
+ if (!streaming || interruptRequested) {
71499
71612
  return;
71613
+ }
71500
71614
  if (waitingForQueueCancelRef.current) {
71501
71615
  setRestoreQueueOnCancel(true);
71502
71616
  }
@@ -71509,11 +71623,22 @@ function App2({
71509
71623
  abortControllerRef.current = null;
71510
71624
  }
71511
71625
  userCancelledRef.current = true;
71626
+ conversationGenerationRef.current += 1;
71627
+ processingConversationRef.current = 0;
71512
71628
  setStreaming(false);
71513
71629
  if (!toolsCancelled) {
71514
71630
  appendError(INTERRUPT_MESSAGE, true);
71515
71631
  }
71516
71632
  refreshDerived();
71633
+ if (pendingApprovals.length > 0) {
71634
+ const denialResults = pendingApprovals.map((approval) => ({
71635
+ type: "approval",
71636
+ tool_call_id: approval.toolCallId,
71637
+ approve: false,
71638
+ reason: "User interrupted the stream"
71639
+ }));
71640
+ setQueuedApprovalResults(denialResults);
71641
+ }
71517
71642
  setPendingApprovals([]);
71518
71643
  setApprovalContexts([]);
71519
71644
  setApprovalResults([]);
@@ -71546,7 +71671,8 @@ function App2({
71546
71671
  appendError,
71547
71672
  isExecutingTool,
71548
71673
  refreshDerived,
71549
- setStreaming
71674
+ setStreaming,
71675
+ pendingApprovals
71550
71676
  ]);
71551
71677
  const processConversationRef = import_react76.useRef(processConversation);
71552
71678
  import_react76.useEffect(() => {
@@ -71761,6 +71887,96 @@ function App2({
71761
71887
  }
71762
71888
  refreshDerived();
71763
71889
  }, [refreshDerived]);
71890
+ const checkPendingApprovalsForSlashCommand = import_react76.useCallback(async () => {
71891
+ if (!CHECK_PENDING_APPROVALS_BEFORE_SEND) {
71892
+ return { blocked: false };
71893
+ }
71894
+ try {
71895
+ const client = await getClient2();
71896
+ const agent = await client.agents.retrieve(agentId);
71897
+ const { pendingApprovals: existingApprovals } = await getResumeData2(client, agent);
71898
+ if (!existingApprovals || existingApprovals.length === 0) {
71899
+ return { blocked: false };
71900
+ }
71901
+ const approvalResults2 = await Promise.all(existingApprovals.map(async (approvalItem) => {
71902
+ if (!approvalItem.toolName) {
71903
+ return {
71904
+ approval: approvalItem,
71905
+ permission: {
71906
+ decision: "deny",
71907
+ reason: "Tool call incomplete - missing name"
71908
+ },
71909
+ context: null
71910
+ };
71911
+ }
71912
+ const parsedArgs = safeJsonParseOr(approvalItem.toolArgs, {});
71913
+ const permission = await checkToolPermission(approvalItem.toolName, parsedArgs);
71914
+ const context3 = await analyzeToolApproval(approvalItem.toolName, parsedArgs);
71915
+ return { approval: approvalItem, permission, context: context3 };
71916
+ }));
71917
+ const needsUserInput = [];
71918
+ const autoAllowed = [];
71919
+ const autoDenied = [];
71920
+ for (const ac of approvalResults2) {
71921
+ const { approval, permission } = ac;
71922
+ let decision = permission.decision;
71923
+ if (alwaysRequiresUserInput(approval.toolName) && decision === "allow") {
71924
+ decision = "ask";
71925
+ }
71926
+ if (decision === "ask") {
71927
+ needsUserInput.push(ac);
71928
+ } else if (decision === "deny") {
71929
+ autoDenied.push(ac);
71930
+ } else {
71931
+ autoAllowed.push(ac);
71932
+ }
71933
+ }
71934
+ if (needsUserInput.length > 0) {
71935
+ setPendingApprovals(needsUserInput.map((ac) => ac.approval));
71936
+ setApprovalContexts(needsUserInput.map((ac) => ac.context).filter((ctx) => ctx !== null));
71937
+ return { blocked: true };
71938
+ }
71939
+ const allResults = [];
71940
+ if (autoAllowed.length > 0) {
71941
+ const autoAllowedResults = await executeAutoAllowedTools(autoAllowed, (chunk) => onChunk(buffersRef.current, chunk));
71942
+ allResults.push(...autoAllowedResults.map((ar) => ({
71943
+ type: "tool",
71944
+ tool_call_id: ar.toolCallId,
71945
+ tool_return: ar.result.toolReturn,
71946
+ status: ar.result.status,
71947
+ stdout: ar.result.stdout,
71948
+ stderr: ar.result.stderr
71949
+ })));
71950
+ }
71951
+ for (const ac of autoDenied) {
71952
+ const reason = ac.permission.reason || "Permission denied";
71953
+ onChunk(buffersRef.current, {
71954
+ message_type: "tool_return_message",
71955
+ id: "dummy",
71956
+ date: new Date().toISOString(),
71957
+ tool_call_id: ac.approval.toolCallId,
71958
+ tool_return: `Error: request to call tool denied. User reason: ${reason}`,
71959
+ status: "error",
71960
+ stdout: null,
71961
+ stderr: null
71962
+ });
71963
+ allResults.push({
71964
+ type: "approval",
71965
+ tool_call_id: ac.approval.toolCallId,
71966
+ approve: false,
71967
+ reason
71968
+ });
71969
+ }
71970
+ if (allResults.length > 0) {
71971
+ await processConversation([
71972
+ { type: "approval", approvals: allResults }
71973
+ ]);
71974
+ }
71975
+ return { blocked: false };
71976
+ } catch {
71977
+ return { blocked: false };
71978
+ }
71979
+ }, [agentId, processConversation]);
71764
71980
  const onSubmit = import_react76.useCallback(async (message) => {
71765
71981
  const msg = message?.trim() ?? "";
71766
71982
  if (profileConfirmPending && !msg) {
@@ -71789,6 +72005,7 @@ function App2({
71789
72005
  }
71790
72006
  if (!msg)
71791
72007
  return { submitted: false };
72008
+ const submissionGeneration = conversationGenerationRef.current;
71792
72009
  telemetry2.trackUserInput(msg, "user", currentModelId || "unknown");
71793
72010
  if (pendingApprovals.length > 0) {
71794
72011
  return { submitted: false };
@@ -71801,6 +72018,9 @@ function App2({
71801
72018
  if (!isSlashCommand && streamingRef.current && !waitingForQueueCancelRef.current) {
71802
72019
  waitingForQueueCancelRef.current = true;
71803
72020
  queueSnapshotRef.current = [...newQueue];
72021
+ if (toolAbortControllerRef.current) {
72022
+ toolAbortControllerRef.current.abort();
72023
+ }
71804
72024
  getClient2().then((client) => client.agents.messages.cancel(agentId)).then(() => {}).catch(() => {
71805
72025
  waitingForQueueCancelRef.current = false;
71806
72026
  });
@@ -72479,6 +72699,10 @@ Press Enter to continue, or type anything to cancel.`, false, "running");
72479
72699
  return { submitted: true };
72480
72700
  }
72481
72701
  if (trimmed.startsWith("/skill")) {
72702
+ const approvalCheck = await checkPendingApprovalsForSlashCommand();
72703
+ if (approvalCheck.blocked) {
72704
+ return { submitted: false };
72705
+ }
72482
72706
  const cmdId2 = uid4("cmd");
72483
72707
  const [, ...rest] = trimmed.split(/\s+/);
72484
72708
  const description = rest.join(" ").trim();
@@ -72537,6 +72761,10 @@ ${SKILL_CREATOR_PROMPT3}${userDescriptionLine}
72537
72761
  return { submitted: true };
72538
72762
  }
72539
72763
  if (trimmed.startsWith("/remember")) {
72764
+ const approvalCheck = await checkPendingApprovalsForSlashCommand();
72765
+ if (approvalCheck.blocked) {
72766
+ return { submitted: false };
72767
+ }
72540
72768
  const cmdId2 = uid4("cmd");
72541
72769
  const [, ...rest] = trimmed.split(/\s+/);
72542
72770
  const userText = rest.join(" ").trim();
@@ -72593,6 +72821,10 @@ The user did not specify what to remember. Look at the recent conversation conte
72593
72821
  return { submitted: true };
72594
72822
  }
72595
72823
  if (trimmed === "/init") {
72824
+ const approvalCheck = await checkPendingApprovalsForSlashCommand();
72825
+ if (approvalCheck.blocked) {
72826
+ return { submitted: false };
72827
+ }
72596
72828
  const cmdId2 = uid4("cmd");
72597
72829
  buffersRef.current.byId.set(cmdId2, {
72598
72830
  kind: "command",
@@ -72709,6 +72941,10 @@ ${gitContext}
72709
72941
  const commandName = trimmed.split(/\s+/)[0]?.slice(1) || "";
72710
72942
  const matchedCustom = await findCustomCommand2(commandName);
72711
72943
  if (matchedCustom) {
72944
+ const approvalCheck = await checkPendingApprovalsForSlashCommand();
72945
+ if (approvalCheck.blocked) {
72946
+ return { submitted: false };
72947
+ }
72712
72948
  const cmdId2 = uid4("cmd");
72713
72949
  const args = trimmed.slice(`/${matchedCustom.id}`.length).trim();
72714
72950
  let prompt = substituteArguments2(matchedCustom.content, args);
@@ -73108,7 +73344,7 @@ DO NOT respond to these messages or otherwise consider them in your response unl
73108
73344
  role: "user",
73109
73345
  content: messageContent
73110
73346
  });
73111
- await processConversation(initialInput);
73347
+ await processConversation(initialInput, { submissionGeneration });
73112
73348
  clearPlaceholdersInText(msg);
73113
73349
  return { submitted: true };
73114
73350
  }, [
@@ -73230,6 +73466,8 @@ DO NOT respond to these messages or otherwise consider them in your response unl
73230
73466
  setQueuedApprovalResults(allResults);
73231
73467
  }
73232
73468
  setStreaming(false);
73469
+ waitingForQueueCancelRef.current = false;
73470
+ queueSnapshotRef.current = [];
73233
73471
  } else {
73234
73472
  await processConversation([
73235
73473
  {
@@ -74001,7 +74239,6 @@ Plan file path: ${planFilePath}`;
74001
74239
  ]);
74002
74240
  return /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Box_default, {
74003
74241
  flexDirection: "column",
74004
- gap: 1,
74005
74242
  children: [
74006
74243
  /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Static, {
74007
74244
  items: staticItems,
@@ -74047,7 +74284,6 @@ Plan file path: ${planFilePath}`;
74047
74284
  }, staticRenderEpoch, false, undefined, this),
74048
74285
  /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Box_default, {
74049
74286
  flexDirection: "column",
74050
- gap: 1,
74051
74287
  children: [
74052
74288
  loadingState !== "ready" && /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(WelcomeScreen, {
74053
74289
  loadingState,
@@ -74242,7 +74478,7 @@ Plan file path: ${planFilePath}`;
74242
74478
  ]
74243
74479
  }, undefined, true, undefined, this),
74244
74480
  /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Box_default, {
74245
- marginTop: liveItems.length > 0 ? 0 : 1,
74481
+ marginTop: 1,
74246
74482
  children: /* @__PURE__ */ jsx_dev_runtime56.jsxDEV(Input, {
74247
74483
  visible: !showExitStats && pendingApprovals.length === 0 && !anySelectorOpen,
74248
74484
  streaming: streaming && !abortControllerRef.current?.signal.aborted,
@@ -77556,13 +77792,19 @@ Error: ${message}`);
77556
77792
  try {
77557
77793
  await client.agents.retrieve(localProjectSettings.lastAgent);
77558
77794
  resumingAgentId = localProjectSettings.lastAgent;
77559
- } catch {}
77795
+ } catch {
77796
+ setLoadingState("selecting_global");
77797
+ return;
77798
+ }
77560
77799
  }
77561
77800
  if (!resumingAgentId && continueSession && settings.lastAgent) {
77562
77801
  try {
77563
77802
  await client.agents.retrieve(settings.lastAgent);
77564
77803
  resumingAgentId = settings.lastAgent;
77565
- } catch {}
77804
+ } catch {
77805
+ setLoadingState("selecting_global");
77806
+ return;
77807
+ }
77566
77808
  }
77567
77809
  if (!resumingAgentId && selectedGlobalAgentId) {
77568
77810
  try {
@@ -77617,22 +77859,22 @@ Error: ${message}`);
77617
77859
  agent = result.agent;
77618
77860
  setAgentProvenance(result.provenance);
77619
77861
  }
77620
- if (!agent) {
77621
- await settingsManager2.loadLocalProjectSettings();
77622
- const localProjectSettings = settingsManager2.getLocalProjectSettings();
77623
- if (localProjectSettings?.lastAgent) {
77624
- try {
77625
- agent = await client.agents.retrieve(localProjectSettings.lastAgent);
77626
- } catch (error) {
77627
- console.error(`Project agent ${localProjectSettings.lastAgent} not found (error: ${JSON.stringify(error)}), creating new one...`);
77628
- }
77862
+ if (!agent && resumingAgentId) {
77863
+ try {
77864
+ agent = await client.agents.retrieve(resumingAgentId);
77865
+ } catch (error) {
77866
+ console.error(`Agent ${resumingAgentId} not found (error: ${JSON.stringify(error)})`);
77867
+ setLoadingState("selecting_global");
77868
+ return;
77629
77869
  }
77630
77870
  }
77631
77871
  if (!agent && continueSession && settings.lastAgent) {
77632
77872
  try {
77633
77873
  agent = await client.agents.retrieve(settings.lastAgent);
77634
77874
  } catch (error) {
77635
- console.error(`Previous agent ${settings.lastAgent} not found (error: ${JSON.stringify(error)}), creating new one...`);
77875
+ console.error(`Previous agent ${settings.lastAgent} not found (error: ${JSON.stringify(error)})`);
77876
+ setLoadingState("selecting_global");
77877
+ return;
77636
77878
  }
77637
77879
  }
77638
77880
  if (!agent) {
@@ -77795,4 +78037,4 @@ Error during initialization: ${message}`);
77795
78037
  }
77796
78038
  main();
77797
78039
 
77798
- //# debugId=6EE8B666F8368EAC64756E2164756E21
78040
+ //# debugId=D2E37E4C34BABD1E64756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letta-ai/letta-code",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
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": {