@letta-ai/letta-code 0.24.3 → 0.24.4

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 +80 -21
  2. package/package.json +1 -1
package/letta.js CHANGED
@@ -3269,7 +3269,7 @@ var package_default;
3269
3269
  var init_package = __esm(() => {
3270
3270
  package_default = {
3271
3271
  name: "@letta-ai/letta-code",
3272
- version: "0.24.3",
3272
+ version: "0.24.4",
3273
3273
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
3274
3274
  type: "module",
3275
3275
  bin: {
@@ -87563,6 +87563,60 @@ class StreamProcessor {
87563
87563
  }
87564
87564
 
87565
87565
  // src/cli/helpers/stream.ts
87566
+ function summarizeStreamForDebug(stream2) {
87567
+ if (!stream2 || typeof stream2 !== "object") {
87568
+ return `type=${typeof stream2}`;
87569
+ }
87570
+ const record = stream2;
87571
+ const ctor = stream2.constructor?.name;
87572
+ const controller = record.controller && typeof record.controller === "object" ? record.controller : null;
87573
+ const keys = Object.keys(record).slice(0, 8);
87574
+ return [
87575
+ `ctor=${ctor ?? "unknown"}`,
87576
+ `asyncIterator=${typeof record[Symbol.asyncIterator]}`,
87577
+ `controller=${typeof record.controller}`,
87578
+ `controllerAbort=${typeof controller?.abort}`,
87579
+ `controllerSignal=${typeof controller?.signal}`,
87580
+ keys.length > 0 ? `keys=${keys.join(",")}` : "keys=(none)"
87581
+ ].join(" ");
87582
+ }
87583
+ function summarizeChunkForDebug(chunk) {
87584
+ if (!chunk) {
87585
+ return "none";
87586
+ }
87587
+ const record = chunk;
87588
+ const parts = [`message_type=${chunk.message_type ?? "unknown"}`];
87589
+ for (const key of ["run_id", "seq_id", "id", "otid", "tool_call_id"]) {
87590
+ const value = record[key];
87591
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
87592
+ parts.push(`${key}=${value}`);
87593
+ }
87594
+ }
87595
+ if (chunk.message_type === "stop_reason") {
87596
+ parts.push(`stop_reason=${String(record.stop_reason ?? "unknown")}`);
87597
+ }
87598
+ const toolCalls = record.tool_calls;
87599
+ if (Array.isArray(toolCalls)) {
87600
+ parts.push(`tool_calls=${toolCalls.length}`);
87601
+ }
87602
+ return parts.join(" ");
87603
+ }
87604
+ function abortStreamController(stream2, reason) {
87605
+ const controller = stream2.controller;
87606
+ if (!controller || typeof controller !== "object") {
87607
+ debugWarn("drainStream", "stream.controller is unavailable during %s - cannot abort HTTP request (%s)", reason, summarizeStreamForDebug(stream2));
87608
+ return;
87609
+ }
87610
+ const controllerRecord = controller;
87611
+ if (controllerRecord.signal?.aborted) {
87612
+ return;
87613
+ }
87614
+ if (typeof controllerRecord.abort !== "function") {
87615
+ debugWarn("drainStream", "stream.controller.abort is unavailable during %s - cannot abort HTTP request (%s)", reason, summarizeStreamForDebug(stream2));
87616
+ return;
87617
+ }
87618
+ controllerRecord.abort();
87619
+ }
87566
87620
  function hasPaginatedItems(response) {
87567
87621
  return !Array.isArray(response) && typeof response.getPaginatedItems === "function";
87568
87622
  }
@@ -87640,28 +87694,26 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
87640
87694
  let stopReason = null;
87641
87695
  let hasCalledFirstMessage = false;
87642
87696
  let fallbackError = null;
87697
+ let lastChunkDebugSummary = "none";
87643
87698
  let abortedViaListener = false;
87644
87699
  const startAbortGen = buffers.abortGeneration || 0;
87645
87700
  const abortHandler = () => {
87646
87701
  abortedViaListener = true;
87647
- if (!stream2.controller) {
87648
- debugWarn("drainStream", "stream.controller is undefined - cannot abort HTTP request");
87649
- return;
87650
- }
87651
- if (!stream2.controller.signal.aborted) {
87652
- stream2.controller.abort();
87653
- }
87702
+ abortStreamController(stream2, "abort_signal");
87654
87703
  };
87655
87704
  if (abortSignal && !abortSignal.aborted) {
87656
87705
  abortSignal.addEventListener("abort", abortHandler, { once: true });
87657
87706
  } else if (abortSignal?.aborted) {
87658
87707
  abortedViaListener = true;
87659
- if (stream2.controller && !stream2.controller.signal.aborted) {
87660
- stream2.controller.abort();
87661
- }
87708
+ abortStreamController(stream2, "pre_aborted_signal");
87662
87709
  }
87663
87710
  try {
87711
+ const asyncIterator = stream2[Symbol.asyncIterator];
87712
+ if (typeof asyncIterator !== "function") {
87713
+ throw new TypeError(`Stream is not async iterable (${summarizeStreamForDebug(stream2)})`);
87714
+ }
87664
87715
  for await (const chunk of stream2) {
87716
+ lastChunkDebugSummary = summarizeChunkForDebug(chunk);
87665
87717
  recordTuiJsonPayload(`stream_chunk:${chunk.message_type ?? "unknown"}`, chunk);
87666
87718
  if ((buffers.abortGeneration || 0) !== startAbortGen) {
87667
87719
  stopReason = "cancelled";
@@ -87730,7 +87782,10 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
87730
87782
  const errorMessage = e instanceof Error ? e.message : String(e);
87731
87783
  const sdkDiagnostic = consumeLastSDKDiagnostic();
87732
87784
  const errorMessageWithDiagnostic = sdkDiagnostic ? `${errorMessage} [${sdkDiagnostic}]` : errorMessage;
87733
- debugWarn("drainStream", "Stream error caught:", errorMessage);
87785
+ debugWarn("drainStream", "Stream error caught: %s last_chunk=%s stream=%s", errorMessageWithDiagnostic, lastChunkDebugSummary, summarizeStreamForDebug(stream2));
87786
+ if (e instanceof Error && e.stack) {
87787
+ debugWarn("drainStream", "Stream error stack: %s", e.stack);
87788
+ }
87734
87789
  if (!streamProcessor.lastRunId && e instanceof APIError2 && e.error) {
87735
87790
  const errorObj = e.error;
87736
87791
  if ("run_id" in errorObj && typeof errorObj.run_id === "string") {
@@ -95763,7 +95818,7 @@ function isSyncCommand(value) {
95763
95818
  return false;
95764
95819
  }
95765
95820
  const candidate = value;
95766
- return candidate.type === "sync" && isRuntimeScope(candidate.runtime);
95821
+ return candidate.type === "sync" && isRuntimeScope(candidate.runtime) && (candidate.recover_approvals === undefined || typeof candidate.recover_approvals === "boolean");
95767
95822
  }
95768
95823
  function isTerminalSpawnCommand(value) {
95769
95824
  if (!value || typeof value !== "object")
@@ -96444,12 +96499,14 @@ function runDetachedListenerTask(commandName, task2) {
96444
96499
  async function replaySyncStateForRuntime(listenerRuntime, socket, scope, opts) {
96445
96500
  const syncScopedRuntime = getOrCreateScopedRuntime(listenerRuntime, scope.agent_id, scope.conversation_id);
96446
96501
  const recoverFn = opts?.recoverApprovalStateForSync ?? recoverApprovalStateForSync;
96447
- try {
96448
- await recoverFn(syncScopedRuntime, scope);
96449
- } catch (error) {
96450
- trackListenerError("listener_sync_recovery_failed", error, "listener_sync_recovery");
96451
- if (isDebugEnabled()) {
96452
- console.warn("[Listen] Sync approval recovery failed:", error);
96502
+ if (opts?.recoverApprovals ?? true) {
96503
+ try {
96504
+ await recoverFn(syncScopedRuntime, scope);
96505
+ } catch (error) {
96506
+ trackListenerError("listener_sync_recovery_failed", error, "listener_sync_recovery");
96507
+ if (isDebugEnabled()) {
96508
+ console.warn("[Listen] Sync approval recovery failed:", error);
96509
+ }
96453
96510
  }
96454
96511
  }
96455
96512
  emitStateSync(socket, listenerRuntime, scope);
@@ -98796,7 +98853,9 @@ async function connectWithRetry(runtime, opts, attempt = 0, startTime = Date.now
98796
98853
  console.log(`[Listen V2] Dropping sync: runtime mismatch or closed`);
98797
98854
  return;
98798
98855
  }
98799
- await replaySyncStateForRuntime(runtime, socket, parsed.runtime);
98856
+ await replaySyncStateForRuntime(runtime, socket, parsed.runtime, {
98857
+ recoverApprovals: parsed.recover_approvals !== false
98858
+ });
98800
98859
  return;
98801
98860
  }
98802
98861
  if (parsed.type === "input") {
@@ -168653,4 +168712,4 @@ Error during initialization: ${message}`);
168653
168712
  }
168654
168713
  main();
168655
168714
 
168656
- //# debugId=22CE2EBE31776A7764756E2164756E21
168715
+ //# debugId=A2D8C37B0089C68564756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letta-ai/letta-code",
3
- "version": "0.24.3",
3
+ "version": "0.24.4",
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": {