@letta-ai/letta-code 0.33.3 → 0.33.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.
package/letta.js CHANGED
@@ -5653,7 +5653,7 @@ var package_default;
5653
5653
  var init_package = __esm(() => {
5654
5654
  package_default = {
5655
5655
  name: "@letta-ai/letta-code",
5656
- version: "0.33.3",
5656
+ version: "0.33.4",
5657
5657
  lettaStartupLogProtocol: 1,
5658
5658
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5659
5659
  type: "module",
@@ -187644,7 +187644,7 @@ function getSubagentByToolCallId(toolCallId) {
187644
187644
  }
187645
187645
  return;
187646
187646
  }
187647
- function registerSubagent(id2, type3, description, toolCallId, isBackground, silent, parentScope, prompt) {
187647
+ function registerSubagent(id2, type3, description, toolCallId, isBackground, silent, parentScope, prompt, claimsParentRuntime) {
187648
187648
  const displayType = type3.charAt(0).toUpperCase() + type3.slice(1);
187649
187649
  const agent = {
187650
187650
  id: id2,
@@ -187661,6 +187661,7 @@ function registerSubagent(id2, type3, description, toolCallId, isBackground, sil
187661
187661
  startTime: Date.now(),
187662
187662
  toolCallId,
187663
187663
  isBackground,
187664
+ claimsParentRuntime,
187664
187665
  silent,
187665
187666
  parentAgentId: parentScope?.agentId ?? undefined,
187666
187667
  parentConversationId: parentScope?.conversationId && parentScope.conversationId.length > 0 ? parentScope.conversationId : undefined
@@ -188768,9 +188769,7 @@ function enqueueOutboundFrame(transport, frame) {
188768
188769
  if (frame.frameClass === "status" && frame.coalesceKey) {
188769
188770
  const index = state.frames.findIndex((f4) => f4.frameClass === "status" && f4.coalesceKey === frame.coalesceKey);
188770
188771
  if (index !== -1) {
188771
- state.frames[index] = frame;
188772
- drainOutboundQueue(transport, state);
188773
- return;
188772
+ state.frames.splice(index, 1);
188774
188773
  }
188775
188774
  }
188776
188775
  state.frames.push(frame);
@@ -189196,6 +189195,9 @@ function createTurnCorrelation(runtime, message, batchId) {
189196
189195
  }
189197
189196
  }
189198
189197
  return {
189198
+ get clientMessageIds() {
189199
+ return [...clientMessageIds];
189200
+ },
189199
189201
  appendDequeuedBatch(nextBatchId) {
189200
189202
  for (const clientMessageId of takeDequeuedClientMessageIds(runtime, nextBatchId)) {
189201
189203
  clientMessageIds.add(clientMessageId);
@@ -189241,7 +189243,6 @@ __export(exports_protocol_outbound, {
189241
189243
  emitProtocolV2Message: () => emitProtocolV2Message,
189242
189244
  emitLoopStatusUpdate: () => emitLoopStatusUpdate,
189243
189245
  emitLoopStatusIfOpen: () => emitLoopStatusIfOpen,
189244
- emitLoopErrorDelta: () => emitLoopErrorDelta,
189245
189246
  emitInterruptedStatusDelta: () => emitInterruptedStatusDelta,
189246
189247
  emitDeviceStatusUpdateIfChanged: () => emitDeviceStatusUpdateIfChanged,
189247
189248
  emitDeviceStatusUpdate: () => emitDeviceStatusUpdate,
@@ -189688,8 +189689,10 @@ function buildSubagentSnapshot(runtime, scope) {
189688
189689
  status: a2.status,
189689
189690
  agent_url: a2.agentURL,
189690
189691
  conversation_id: a2.conversationId ?? null,
189692
+ super_run_id: a2.superRunId,
189691
189693
  model: a2.model,
189692
189694
  is_background: a2.isBackground,
189695
+ claims_parent_runtime: a2.claimsParentRuntime,
189693
189696
  silent: a2.silent,
189694
189697
  tool_call_id: a2.toolCallId,
189695
189698
  parent_agent_id: a2.parentAgentId,
@@ -189726,18 +189729,6 @@ function createLifecycleMessageBase(messageType, runId) {
189726
189729
  function emitCanonicalMessageDelta(socket, runtime, delta2, scope) {
189727
189730
  emitStreamDelta(socket, runtime, delta2, scope);
189728
189731
  }
189729
- function emitLoopErrorDelta(socket, runtime, params) {
189730
- emitCanonicalMessageDelta(socket, runtime, {
189731
- ...createLifecycleMessageBase("loop_error", params.runId),
189732
- message: params.message,
189733
- stop_reason: params.stopReason,
189734
- is_terminal: params.isTerminal,
189735
- ...params.apiError ? { api_error: params.apiError } : {}
189736
- }, {
189737
- agent_id: params.agentId,
189738
- conversation_id: params.conversationId
189739
- });
189740
- }
189741
189732
  function emitRetryDelta(socket, runtime, params) {
189742
189733
  const delta2 = {
189743
189734
  ...createLifecycleMessageBase("retry", params.runId),
@@ -212179,6 +212170,9 @@ async function listEnqueuedRunMessages(runId, signal) {
212179
212170
  }
212180
212171
  return result2;
212181
212172
  }
212173
+ async function getExactSuperRun(agentId, superRunId, signal, request = apiRequest) {
212174
+ return request("GET", `/v1/agents/${encodeURIComponent(agentId)}/super-runs/${encodeURIComponent(superRunId)}`, undefined, { signal });
212175
+ }
212182
212176
  async function getLatestConversationSuperRun(conversationId, signal) {
212183
212177
  return apiRequest("GET", `/v1/conversations/${encodeURIComponent(conversationId)}/super-run`, undefined, { signal });
212184
212178
  }
@@ -212189,212 +212183,93 @@ var init_conversation_enqueue = __esm(() => {
212189
212183
  init_request();
212190
212184
  });
212191
212185
 
212192
- // src/headless-enqueue-wait.ts
212193
- function getSendRunIds(status, clientMessageId) {
212194
- return Object.entries(status?.runtime_status?.loop_state?.client_message_ids_by_run_id ?? {}).filter(([, ids]) => ids.includes(clientMessageId)).map(([runId]) => runId);
212195
- }
212196
- function getConversationStatus(event, conversationId) {
212197
- if (event.type === "conversation_super_run_snapshot") {
212198
- return event.statuses.find((status) => status.conversation_id === conversationId) ?? null;
212186
+ // src/headless-super-run-wait.ts
212187
+ import { setTimeout as delay3 } from "node:timers/promises";
212188
+ function isTransientReadError(error4) {
212189
+ if (error4 instanceof ApiRequestError || error4 instanceof APIError) {
212190
+ return error4.status === 408 || error4.status === 429 || error4.status >= 500;
212199
212191
  }
212200
- return event.conversation_id === conversationId ? event.status : undefined;
212192
+ return error4 instanceof TypeError || error4 instanceof Error && error4.name === "TimeoutError";
212201
212193
  }
212202
- async function waitForEnqueuedReply(params) {
212203
- const runIds = new Set;
212204
- const now2 = params.now ?? Date.now;
212205
- let completedWithoutText;
212206
- let next = Promise.resolve({
212207
- done: false,
212208
- value: params.firstEvent
212209
- });
212210
- try {
212211
- while (true) {
212212
- params.signal.throwIfAborted();
212213
- let timer;
212214
- const event = await Promise.race([
212215
- next,
212216
- new Promise((resolve29) => {
212217
- timer = setTimeout(() => resolve29(null), params.pollMs ?? 1000);
212218
- })
212219
- ]).finally(() => clearTimeout(timer));
212220
- if (event) {
212221
- if (event.done)
212222
- throw new Error("Conversation status connection closed; remote execution may still be running.");
212223
- const status = getConversationStatus(event.value, params.receipt.conversation_id);
212224
- if (status !== undefined) {
212225
- for (const runId2 of getSendRunIds(status, params.receipt.client_message_id))
212226
- runIds.add(runId2);
212227
- }
212228
- next = params.events.next();
212229
- next.catch(() => {});
212230
- }
212231
- const runId = [...runIds].at(-1);
212232
- if (!runId) {
212233
- const latest = await params.latestSuperRun();
212234
- if (latest?.id === params.receipt.super_run_id && (latest.errored_at || latest.cancelled_at)) {
212235
- throw new Error(`Accepted send ${latest.id} ${latest.errored_at ? "failed" : "was cancelled"} before a run was observed.`);
212236
- }
212237
- continue;
212238
- }
212239
- const run = await params.retrieveRun(runId);
212240
- if (run.status === "failed" || run.status === "cancelled") {
212241
- throw new Error(`Remote run ${runId} ${run.status}${run.stop_reason ? ` (${run.stop_reason})` : ""}`);
212242
- }
212243
- if (run.status !== "completed" || run.stop_reason === "requires_approval")
212244
- continue;
212245
- const messages = await params.listRunMessages(runId);
212246
- const assistant = messages.filter((message) => message.message_type === "assistant_message").sort((a2, b3) => (b3.seq_id ?? 0) - (a2.seq_id ?? 0))[0];
212247
- if (assistant?.message_type === "assistant_message") {
212248
- const text2 = typeof assistant.content === "string" ? assistant.content : assistant.content.filter((part) => part.type === "text").map((part) => part.text).join(`
212249
- `);
212250
- if (text2.trim())
212251
- return {
212252
- text: text2,
212253
- runIds: [...runIds],
212254
- stopReason: run.stop_reason ?? null
212255
- };
212194
+ async function retryRead(read2, signal, sleep11, failureLabel) {
212195
+ let failures = 0;
212196
+ while (true) {
212197
+ signal.throwIfAborted();
212198
+ try {
212199
+ return await read2();
212200
+ } catch (error4) {
212201
+ signal.throwIfAborted();
212202
+ if (!isTransientReadError(error4)) {
212203
+ throw new RemoteExecutionFailed(`${failureLabel}: ${error4 instanceof Error ? error4.message : String(error4)}`);
212256
212204
  }
212257
- if (completedWithoutText?.runId !== runId)
212258
- completedWithoutText = { runId, at: now2() };
212259
- if (now2() - completedWithoutText.at < 15000)
212260
- continue;
212261
- throw new Error(`Remote run ${runId} completed without an assistant reply (${run.stop_reason ?? "unknown stop reason"})`);
212205
+ await sleep11(Math.min(30000, 1000 * 2 ** Math.min(failures++, 5)), signal);
212262
212206
  }
212263
- } catch (error4) {
212264
- throw new EnqueuedWaitError(error4, [...runIds]);
212265
212207
  }
212266
212208
  }
212267
- var EnqueuedWaitError;
212268
- var init_headless_enqueue_wait = __esm(() => {
212269
- EnqueuedWaitError = class EnqueuedWaitError extends Error {
212270
- runIds;
212271
- constructor(error4, runIds) {
212272
- super(error4 instanceof Error ? error4.message : String(error4), {
212273
- cause: error4
212274
- });
212275
- this.runIds = runIds;
212276
- this.name = "EnqueuedWaitError";
212277
- }
212278
- };
212279
- });
212280
-
212281
- // src/headless-super-run-wait.ts
212282
- import { setTimeout as delay3 } from "node:timers/promises";
212283
- function terminal(run) {
212284
- if (run.status === "CAN" || run.cancelled_at)
212209
+ function throwIfSuperRunFailed(run) {
212210
+ if (run.errored_at) {
212211
+ const detail = run.error ? ` during ${run.error.code}: ${run.error.message}` : "";
212212
+ throw new RemoteExecutionFailed(`Remote Super Run ${run.id} failed${detail}`);
212213
+ }
212214
+ if (run.status === "CAN" || run.cancelled_at) {
212285
212215
  throw new RemoteExecutionFailed(`Remote Super Run ${run.id} was cancelled.`);
212286
- if (run.status !== "COM" && !run.completed_at)
212287
- return false;
212288
- if (run.errored_at)
212289
- throw new RemoteExecutionFailed(`Remote Super Run ${run.id} finished with an error.`);
212290
- return true;
212216
+ }
212217
+ }
212218
+ function assistantText(messages) {
212219
+ const assistant = messages.filter((message) => message.message_type === "assistant_message").sort((left, right) => (right.seq_id ?? 0) - (left.seq_id ?? 0))[0];
212220
+ if (assistant?.message_type !== "assistant_message")
212221
+ return null;
212222
+ const text2 = typeof assistant.content === "string" ? assistant.content : assistant.content.filter((part) => part.type === "text").map((part) => part.text).join(`
212223
+ `);
212224
+ return text2.trim() ? text2 : null;
212225
+ }
212226
+ function noReplyMessage(receipt) {
212227
+ return `Remote task finished. Its reply was not collected. Read the conversation with: letta messages list --agent ${receipt.agent_id} --conversation ${receipt.conversation_id}. Do not launch the task again to retrieve its result.`;
212291
212228
  }
212292
212229
  async function waitForAcceptedSuperRun(receipt, signal, deps) {
212293
- const runIds = new Set;
212294
- let finished2 = false;
212295
- let failures = 0;
212296
- while (!finished2) {
212230
+ const pollMs = deps.pollMs ?? 1000;
212231
+ const sleep11 = deps.sleep ?? ((ms, waitSignal) => delay3(ms, undefined, { signal: waitSignal }));
212232
+ while (true) {
212297
212233
  signal.throwIfAborted();
212298
- const controller = new AbortController;
212299
- const abort = () => controller.abort();
212300
- signal.addEventListener("abort", abort, { once: true });
212301
- try {
212302
- if (receipt.conversation_id !== "default") {
212303
- try {
212304
- const latest = await deps.latest(receipt.conversation_id, AbortSignal.any([signal, AbortSignal.timeout(30000)]));
212305
- if (latest.id === receipt.super_run_id)
212306
- finished2 = terminal(latest);
212307
- } catch (error4) {
212308
- if (!(error4 instanceof ApiRequestError && error4.status === 404))
212309
- throw error4;
212310
- }
212311
- }
212312
- if (finished2)
212313
- break;
212314
- const openTimeout = setTimeout(() => controller.abort(), 30000);
212315
- const stream11 = await deps.open(receipt.agent_id, controller).finally(() => clearTimeout(openTimeout));
212316
- const events = stream11[Symbol.asyncIterator]();
212317
- let next = events.next();
212318
- next.catch(() => {});
212319
- while (!finished2) {
212320
- signal.throwIfAborted();
212321
- let timer;
212322
- const event = await Promise.race([
212323
- next,
212324
- new Promise((resolve29) => {
212325
- timer = setTimeout(() => resolve29(null), deps.pollMs ?? 30000);
212326
- })
212327
- ]).finally(() => clearTimeout(timer));
212328
- if (!event)
212329
- break;
212330
- if (event.done)
212331
- throw new Error("Cloud status stream disconnected");
212332
- failures = 0;
212333
- const value = event.value;
212334
- if (value.type === "super_run_update") {
212335
- if (value.data.id === receipt.super_run_id)
212336
- finished2 = terminal(value.data);
212337
- } else {
212338
- const status = getConversationStatus(value, receipt.conversation_id);
212339
- if (status !== undefined) {
212340
- for (const id2 of getSendRunIds(status, receipt.client_message_id))
212341
- runIds.add(id2);
212342
- finished2 = !status?.active_super_runs.some((run) => run.id === receipt.super_run_id);
212343
- }
212344
- }
212345
- if (!finished2) {
212346
- next = events.next();
212347
- next.catch(() => {});
212348
- }
212349
- }
212350
- } catch (error4) {
212351
- signal.throwIfAborted();
212352
- if (error4 instanceof RemoteExecutionFailed)
212353
- throw error4;
212354
- if (error4 instanceof ApiRequestError && [401, 403].includes(error4.status))
212355
- throw error4;
212356
- await delay3(Math.min(30000, (deps.pollMs ?? 1000) * 2 ** Math.min(failures++, 5)), undefined, { signal });
212357
- } finally {
212358
- signal.removeEventListener("abort", abort);
212359
- controller.abort();
212234
+ const exact = await retryRead(() => deps.exact(receipt.agent_id, receipt.super_run_id, AbortSignal.any([signal, AbortSignal.timeout(30000)])), signal, sleep11, `Cloud status read for accepted Super Run ${receipt.super_run_id} failed`);
212235
+ if (exact.id !== receipt.super_run_id) {
212236
+ throw new RemoteExecutionFailed(`Exact Super Run read returned ${exact.id} for ${receipt.super_run_id}.`);
212237
+ }
212238
+ throwIfSuperRunFailed(exact);
212239
+ const terminal = exact.status === "COM" || exact.completed_at !== null;
212240
+ if (!terminal) {
212241
+ await sleep11(pollMs, signal);
212242
+ continue;
212360
212243
  }
212361
- }
212362
- if (receipt.conversation_id !== "default") {
212363
- try {
212364
- const latest = await deps.latest(receipt.conversation_id, AbortSignal.any([signal, AbortSignal.timeout(1e4)]));
212365
- if (latest.id === receipt.super_run_id)
212366
- terminal(latest);
212367
- } catch (error4) {
212368
- signal.throwIfAborted();
212369
- if (error4 instanceof RemoteExecutionFailed)
212370
- throw error4;
212244
+ const runId = exact.run_ids[0];
212245
+ if (!runId) {
212246
+ throw new RemoteExecutionFailed(`Remote Super Run ${exact.id} completed without a correlated child run.`);
212371
212247
  }
212372
- }
212373
- const runId = [...runIds].at(-1);
212374
- if (runId) {
212248
+ const run = await retryRead(() => deps.run(runId, AbortSignal.any([signal, AbortSignal.timeout(30000)])), signal, sleep11, `Remote child run read for ${runId} failed`);
212249
+ if (run.status === "failed" || run.status === "cancelled") {
212250
+ throw new RemoteExecutionFailed(`Remote child run ${runId} ${run.status}${run.stop_reason ? ` (${run.stop_reason})` : ""}.`);
212251
+ }
212252
+ if (run.status !== "completed" || run.stop_reason === "requires_approval") {
212253
+ await sleep11(pollMs, signal);
212254
+ continue;
212255
+ }
212256
+ let messages = [];
212375
212257
  try {
212376
- const messages = await deps.messages(runId, AbortSignal.any([signal, AbortSignal.timeout(1e4)]));
212377
- const last2 = messages.filter((m4) => m4.message_type === "assistant_message").sort((a2, b3) => (b3.seq_id ?? 0) - (a2.seq_id ?? 0))[0];
212378
- if (last2?.message_type === "assistant_message") {
212379
- const text2 = typeof last2.content === "string" ? last2.content : last2.content.filter((p2) => p2.type === "text").map((p2) => p2.text).join(`
212380
- `);
212381
- if (text2.trim())
212382
- return { text: text2, runIds: [...runIds], stopReason: null };
212383
- }
212258
+ messages = await deps.messages(runId, AbortSignal.any([signal, AbortSignal.timeout(1e4)]));
212384
212259
  } catch {
212385
212260
  signal.throwIfAborted();
212386
212261
  }
212262
+ return {
212263
+ text: assistantText(messages) ?? noReplyMessage(receipt),
212264
+ runIds: exact.run_ids,
212265
+ stopReason: run.stop_reason ?? null
212266
+ };
212387
212267
  }
212388
- return {
212389
- text: `Remote task finished. Its reply was not collected. Read the conversation with: letta messages list --agent ${receipt.agent_id} --conversation ${receipt.conversation_id}. Do not launch the task again to retrieve its result.`,
212390
- runIds: [...runIds],
212391
- stopReason: null
212392
- };
212393
212268
  }
212394
212269
  var RemoteExecutionFailed;
212395
212270
  var init_headless_super_run_wait = __esm(() => {
212271
+ init_letta_client();
212396
212272
  init_request();
212397
- init_headless_enqueue_wait();
212398
212273
  RemoteExecutionFailed = class RemoteExecutionFailed extends Error {
212399
212274
  };
212400
212275
  });
@@ -212426,19 +212301,21 @@ async function resolveChildSubagent(backend3, agentId, parentAgentId) {
212426
212301
  }
212427
212302
  }
212428
212303
  function waitForChildRun(receipt, signal) {
212304
+ const backend3 = getBackend();
212429
212305
  return waitForAcceptedSuperRun(receipt, signal, {
212430
- open: openConversationStatusStream,
212431
- latest: getLatestConversationSuperRun,
212306
+ exact: getExactSuperRun,
212307
+ run: (runId, readSignal) => backend3.retrieveRun(runId, { signal: readSignal }),
212432
212308
  messages: async () => []
212433
212309
  });
212434
212310
  }
212435
212311
  function trackChildSend(input) {
212436
212312
  const { receipt, child, parentScope } = input;
212437
212313
  const subagentId = generateSubagentId();
212438
- registerSubagent(subagentId, child.type, child.name, undefined, true, false, parentScope, input.prompt);
212314
+ registerSubagent(subagentId, child.type, child.name, undefined, true, false, parentScope, input.prompt, false);
212439
212315
  updateSubagent(subagentId, {
212440
212316
  agentId: receipt.agent_id,
212441
212317
  conversationId: receipt.conversation_id,
212318
+ superRunId: receipt.super_run_id,
212442
212319
  agentURL: buildAgentReference(receipt.agent_id, {
212443
212320
  conversationId: receipt.conversation_id
212444
212321
  })
@@ -212451,6 +212328,7 @@ function trackChildSend(input) {
212451
212328
  }
212452
212329
  var init_child_send_tracking = __esm(() => {
212453
212330
  init_subagent_state();
212331
+ init_backend2();
212454
212332
  init_conversation_enqueue();
212455
212333
  init_app_urls();
212456
212334
  init_headless_super_run_wait();
@@ -213151,7 +213029,7 @@ class CodexAppServerClient {
213151
213029
  await this.request("initialize", {
213152
213030
  clientInfo: {
213153
213031
  name: "letta-code",
213154
- version: "0.33.3"
213032
+ version: "0.33.4"
213155
213033
  },
213156
213034
  capabilities: null
213157
213035
  });
@@ -216509,9 +216387,10 @@ async function collectRemoteTurnResult(receipt, state, subagentId, signal = new
216509
216387
  })
216510
216388
  });
216511
216389
  try {
216390
+ const backend3 = getBackend();
216512
216391
  const reply = await waitForAcceptedSuperRun(receipt, signal, {
216513
- open: openConversationStatusStream,
216514
- latest: getLatestConversationSuperRun,
216392
+ exact: getExactSuperRun,
216393
+ run: (runId, readSignal) => backend3.retrieveRun(runId, { signal: readSignal }),
216515
216394
  messages: async (runId, readSignal) => {
216516
216395
  const messages = await listEnqueuedRunMessages(runId, readSignal);
216517
216396
  for (const message of messages) {
@@ -216547,6 +216426,7 @@ async function collectRemoteTurnResult(receipt, state, subagentId, signal = new
216547
216426
  }
216548
216427
  var init_remote_turn_wait = __esm(() => {
216549
216428
  init_subagent_state();
216429
+ init_backend2();
216550
216430
  init_conversation_enqueue();
216551
216431
  init_app_urls();
216552
216432
  init_constants2();
@@ -220963,7 +220843,7 @@ function usageTokensFromEvent(event) {
220963
220843
  return typeof total === "number" && Number.isFinite(total) ? total : undefined;
220964
220844
  }
220965
220845
  async function drainTurn(query3, usage, stop, maxToolCalls, onUsage) {
220966
- let assistantText = "";
220846
+ let assistantText2 = "";
220967
220847
  let resultText;
220968
220848
  let success = false;
220969
220849
  let error4;
@@ -220971,7 +220851,7 @@ async function drainTurn(query3, usage, stop, maxToolCalls, onUsage) {
220971
220851
  const guard = createToolCallGuard(maxToolCalls);
220972
220852
  for await (const message of query3) {
220973
220853
  if (message.type === "assistant")
220974
- assistantText += message.content ?? "";
220854
+ assistantText2 += message.content ?? "";
220975
220855
  if (message.type === "stream_event") {
220976
220856
  const tokens = usageTokensFromEvent(message.event);
220977
220857
  if (tokens !== undefined) {
@@ -220997,7 +220877,7 @@ async function drainTurn(query3, usage, stop, maxToolCalls, onUsage) {
220997
220877
  }
220998
220878
  }
220999
220879
  return {
221000
- finalText: (resultText ?? assistantText).trim(),
220880
+ finalText: (resultText ?? assistantText2).trim(),
221001
220881
  success,
221002
220882
  error: error4,
221003
220883
  structuredOutput,
@@ -402562,14 +402442,16 @@ function emitLoopErrorNotice(socket, runtime, params) {
402562
402442
  mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
402563
402443
  return null;
402564
402444
  }
402565
- emitLoopErrorDelta(socket, runtime, {
402445
+ emitCanonicalMessageDelta(socket, runtime, {
402446
+ ...createLifecycleMessageBase("loop_error", params.runId),
402566
402447
  message: decision.message,
402567
- stopReason: params.stopReason,
402568
- isTerminal: params.isTerminal,
402569
- runId: params.runId,
402570
- agentId: params.agentId,
402571
- conversationId: params.conversationId,
402572
- apiError: decision.apiError
402448
+ stop_reason: params.stopReason,
402449
+ is_terminal: params.isTerminal,
402450
+ ...params.clientMessageIds?.length ? { client_message_ids: params.clientMessageIds } : {},
402451
+ ...decision.apiError ? { api_error: decision.apiError } : {}
402452
+ }, {
402453
+ agent_id: params.agentId,
402454
+ conversation_id: params.conversationId
402573
402455
  });
402574
402456
  return decision.message;
402575
402457
  }
@@ -406841,6 +406723,19 @@ function finishListenerTurn(runtime, lease, options) {
406841
406723
  if (options.stopReason === "end_turn" || options.stopReason === "cancelled") {
406842
406724
  forgetListenerWork(runtime);
406843
406725
  }
406726
+ if (options.socket && options.errorNotice) {
406727
+ const runId = options.errorNotice.runId ?? options.runId ?? transition2.runId;
406728
+ const message = emitLoopErrorNotice(options.socket, runtime, {
406729
+ ...options.errorNotice,
406730
+ stopReason: options.stopReason,
406731
+ isTerminal: true,
406732
+ runId,
406733
+ agentId: options.agentId,
406734
+ conversationId: options.conversationId
406735
+ });
406736
+ runtime.lastTerminalLoopErrorMessage = message ?? options.errorNotice.message;
406737
+ runtime.lastTerminalLoopErrorRunId = runId ?? null;
406738
+ }
406844
406739
  if (options.stopReason === "cancelled" && transition2.previousKind === "active" && options.socket) {
406845
406740
  emitInterruptedStatusDelta(options.socket, runtime, {
406846
406741
  runId: options.runId ?? transition2.runId,
@@ -406873,6 +406768,7 @@ var init_turn_terminal = __esm(() => {
406873
406768
  init_connection();
406874
406769
  init_interrupted_turn_record();
406875
406770
  init_protocol_outbound();
406771
+ init_recoverable_notices();
406876
406772
  });
406877
406773
 
406878
406774
  // src/websocket/listener/recovery.ts
@@ -417121,6 +417017,12 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
417121
417017
  ...options,
417122
417018
  socket: options.socket ?? socket,
417123
417019
  turnId: activeDequeuedBatchId,
417020
+ ...options.errorNotice ? {
417021
+ errorNotice: {
417022
+ ...options.errorNotice,
417023
+ clientMessageIds: turnCorrelation.clientMessageIds
417024
+ }
417025
+ } : {},
417124
417026
  ...runtime.executionSettings ? { usage: buildTurnUsage(buffers.usage) } : {}
417125
417027
  }));
417126
417028
  const finishIfInterrupted = (runId) => {
@@ -417175,24 +417077,16 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
417175
417077
  return;
417176
417078
  }
417177
417079
  if (setup.kind === "cancelled") {
417178
- const transition2 = finishTurn({
417080
+ finishTurn({
417179
417081
  stopReason: "cancelled",
417180
417082
  agentId: agentId || null,
417181
- conversationId
417182
- });
417183
- if (!transition2.finished) {
417184
- return;
417185
- }
417186
- const formattedError = emitLoopErrorNotice(socket, runtime, {
417187
- message: setup.reason,
417188
- stopReason: "cancelled",
417189
- isTerminal: true,
417190
- agentId,
417191
417083
  conversationId,
417192
- cancelRequested: turnAbortSignal.aborted,
417193
- abortSignal: turnAbortSignal
417084
+ errorNotice: {
417085
+ message: setup.reason,
417086
+ cancelRequested: turnAbortSignal.aborted,
417087
+ abortSignal: turnAbortSignal
417088
+ }
417194
417089
  });
417195
- runtime.lastTerminalLoopErrorMessage = formattedError ?? setup.reason;
417196
417090
  return;
417197
417091
  }
417198
417092
  let turnInput = setup.turnInput;
@@ -417262,19 +417156,15 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
417262
417156
  lastApprovalContinuationAccepted = false;
417263
417157
  const maxTurns = runtime.executionSettings?.max_turns;
417264
417158
  if (maxTurns !== undefined && buffers.usage.stepCount >= maxTurns && stopReason !== "requires_approval" && !(stopReason === "error" && fallbackError)) {
417265
- emitLoopErrorNotice(socket, runtime, {
417266
- message: `Maximum turns limit reached (${buffers.usage.stepCount}/${maxTurns} steps)`,
417267
- stopReason: "max_steps",
417268
- isTerminal: true,
417269
- runId: runId || runtime.activeRunId,
417270
- agentId,
417271
- conversationId
417272
- });
417273
417159
  finishTurn({
417274
417160
  stopReason: "max_steps",
417275
417161
  socket,
417276
417162
  agentId,
417277
- conversationId
417163
+ conversationId,
417164
+ errorNotice: {
417165
+ message: `Maximum turns limit reached (${buffers.usage.stepCount}/${maxTurns} steps)`,
417166
+ runId: runId || runtime.activeRunId
417167
+ }
417278
417168
  });
417279
417169
  break;
417280
417170
  }
@@ -417560,23 +417450,13 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
417560
417450
  abortSignal: turnAbortSignal
417561
417451
  };
417562
417452
  const terminalError = getConsumerLoopErrorMessage(noticeParams);
417563
- const transition2 = finishTurn({
417453
+ finishTurn({
417564
417454
  stopReason: effectiveStopReason,
417565
417455
  agentId,
417566
417456
  conversationId,
417567
- error: terminalError
417568
- });
417569
- if (!transition2.finished) {
417570
- break;
417571
- }
417572
- const formattedError = emitLoopErrorNotice(socket, runtime, {
417573
- ...noticeParams,
417574
- stopReason: effectiveStopReason,
417575
- isTerminal: true,
417576
- runId: terminalRunId
417457
+ error: terminalError,
417458
+ errorNotice: { ...noticeParams, runId: terminalRunId }
417577
417459
  });
417578
- runtime.lastTerminalLoopErrorMessage = formattedError ?? errorMessage5;
417579
- runtime.lastTerminalLoopErrorRunId = terminalRunId ?? null;
417580
417460
  break;
417581
417461
  }
417582
417462
  const approvalResult = await handleApprovalStop({
@@ -417600,25 +417480,16 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
417600
417480
  });
417601
417481
  if (approvalResult.kind === "error") {
417602
417482
  const terminalRunId = runId || runtime.activeRunId;
417603
- const transition2 = finishTurn({
417483
+ finishTurn({
417604
417484
  stopReason: "error",
417605
417485
  agentId,
417606
417486
  conversationId,
417607
- error: getTranscriptLoopErrorMessage({ message: approvalResult.message })
417608
- });
417609
- if (!transition2.finished) {
417610
- return;
417611
- }
417612
- const formattedError = emitLoopErrorNotice(socket, runtime, {
417613
- message: approvalResult.message,
417614
- stopReason: "error",
417615
- isTerminal: true,
417616
- runId: terminalRunId,
417617
- agentId,
417618
- conversationId
417487
+ error: getTranscriptLoopErrorMessage({ message: approvalResult.message }),
417488
+ errorNotice: {
417489
+ message: approvalResult.message,
417490
+ runId: terminalRunId
417491
+ }
417619
417492
  });
417620
- runtime.lastTerminalLoopErrorMessage = formattedError ?? approvalResult.message;
417621
- runtime.lastTerminalLoopErrorRunId = terminalRunId ?? null;
417622
417493
  return;
417623
417494
  }
417624
417495
  turnInput = approvalResult.turnInput;
@@ -417720,19 +417591,12 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
417720
417591
  stopReason: "error",
417721
417592
  agentId: agentId || null,
417722
417593
  conversationId,
417723
- error: terminalError
417594
+ error: terminalError,
417595
+ errorNotice: { ...noticeParams, runId: terminalRunId }
417724
417596
  });
417725
417597
  if (!transition2.finished) {
417726
417598
  return;
417727
417599
  }
417728
- const formattedError = emitLoopErrorNotice(socket, runtime, {
417729
- ...noticeParams,
417730
- stopReason: "error",
417731
- isTerminal: true,
417732
- runId: terminalRunId
417733
- });
417734
- runtime.lastTerminalLoopErrorMessage = formattedError ?? errorMessage5;
417735
- runtime.lastTerminalLoopErrorRunId = terminalRunId ?? null;
417736
417600
  if (isDebugEnabled()) {
417737
417601
  console.error("[Listen] Error handling message:", error4);
417738
417602
  }
@@ -418206,8 +418070,8 @@ function spawnBun(shell, cwd2, cols, rows, terminal_id, connectionId, socket) {
418206
418070
  data: (_t, chunk2) => handleData(new TextDecoder().decode(chunk2))
418207
418071
  }
418208
418072
  });
418209
- const terminal2 = proc.terminal;
418210
- if (!terminal2) {
418073
+ const terminal = proc.terminal;
418074
+ if (!terminal) {
418211
418075
  throw new Error("Bun.spawn terminal object missing — API unavailable");
418212
418076
  }
418213
418077
  proc.exited.then((exitCode) => {
@@ -418224,17 +418088,17 @@ function spawnBun(shell, cwd2, cols, rows, terminal_id, connectionId, socket) {
418224
418088
  return {
418225
418089
  write: (d2) => {
418226
418090
  try {
418227
- terminal2.write(d2);
418091
+ terminal.write(d2);
418228
418092
  } catch {}
418229
418093
  },
418230
418094
  resize: (c, r5) => {
418231
418095
  try {
418232
- terminal2.resize(c, r5);
418096
+ terminal.resize(c, r5);
418233
418097
  } catch {}
418234
418098
  },
418235
418099
  kill: () => {
418236
418100
  try {
418237
- terminal2.close();
418101
+ terminal.close();
418238
418102
  } catch {}
418239
418103
  try {
418240
418104
  proc.kill();
@@ -428790,8 +428654,8 @@ function formatError(error4, mapper = (issue2) => issue2.message) {
428790
428654
  let i4 = 0;
428791
428655
  while (i4 < fullpath.length) {
428792
428656
  const el = fullpath[i4];
428793
- const terminal2 = i4 === fullpath.length - 1;
428794
- if (!terminal2) {
428657
+ const terminal = i4 === fullpath.length - 1;
428658
+ if (!terminal) {
428795
428659
  curr[el] = curr[el] || { _errors: [] };
428796
428660
  } else {
428797
428661
  curr[el] = curr[el] || { _errors: [] };
@@ -444782,7 +444646,7 @@ var init_mcp_client = __esm(() => {
444782
444646
  init_streamableHttp();
444783
444647
  DEFAULT_CLIENT_INFO = {
444784
444648
  name: "letta-code",
444785
- version: "0.33.3"
444649
+ version: "0.33.4"
444786
444650
  };
444787
444651
  });
444788
444652
 
@@ -456140,23 +456004,23 @@ class ChannelGateway {
456140
456004
  active.richDraft?.flushPending();
456141
456005
  }
456142
456006
  }
456143
- handleTurnFinished(runtime, terminal2) {
456007
+ handleTurnFinished(runtime, terminal) {
456144
456008
  const state = this.getState(runtime);
456145
456009
  const active = state.active;
456146
456010
  if (!active)
456147
456011
  return;
456148
456012
  state.active = null;
456149
456013
  active.richDraft?.dispose();
456150
- const remainingSources = lifecycleOutcome(terminal2.stopReason) === "completed" ? this.remainingSources(state) : [];
456014
+ const remainingSources = lifecycleOutcome(terminal.stopReason) === "completed" ? this.remainingSources(state) : [];
456151
456015
  this.enqueueHook(state, () => this.hooks.onLifecycle({
456152
456016
  type: "finished",
456153
456017
  batchId: active.batchId,
456154
456018
  sources: active.lifecycleSources,
456155
- outcome: lifecycleOutcome(terminal2.stopReason),
456156
- stopReason: terminal2.stopReason,
456019
+ outcome: lifecycleOutcome(terminal.stopReason),
456020
+ stopReason: terminal.stopReason,
456157
456021
  ...remainingSources.length ? { remainingSources } : {},
456158
- ...terminal2.runId ?? active.runId ? { runId: terminal2.runId ?? active.runId } : {},
456159
- ...terminal2.error ? { error: terminal2.error } : {}
456022
+ ...terminal.runId ?? active.runId ? { runId: terminal.runId ?? active.runId } : {},
456023
+ ...terminal.error ? { error: terminal.error } : {}
456160
456024
  }));
456161
456025
  }
456162
456026
  handleControlRequest(message) {
@@ -458967,6 +458831,95 @@ var init_local_backend_mod_events = __esm(() => {
458967
458831
  init_local_backend();
458968
458832
  });
458969
458833
 
458834
+ // src/headless-enqueue-wait.ts
458835
+ function getSendRunIds(status, clientMessageId) {
458836
+ return Object.entries(status?.runtime_status?.loop_state?.client_message_ids_by_run_id ?? {}).filter(([, ids]) => ids.includes(clientMessageId)).map(([runId]) => runId);
458837
+ }
458838
+ function getConversationStatus(event, conversationId) {
458839
+ if (event.type === "conversation_super_run_snapshot") {
458840
+ return event.statuses.find((status) => status.conversation_id === conversationId) ?? null;
458841
+ }
458842
+ return event.conversation_id === conversationId ? event.status : undefined;
458843
+ }
458844
+ async function waitForEnqueuedReply(params) {
458845
+ const runIds = new Set;
458846
+ const now2 = params.now ?? Date.now;
458847
+ let completedWithoutText;
458848
+ let next = Promise.resolve({
458849
+ done: false,
458850
+ value: params.firstEvent
458851
+ });
458852
+ try {
458853
+ while (true) {
458854
+ params.signal.throwIfAborted();
458855
+ let timer;
458856
+ const event = await Promise.race([
458857
+ next,
458858
+ new Promise((resolve42) => {
458859
+ timer = setTimeout(() => resolve42(null), params.pollMs ?? 1000);
458860
+ })
458861
+ ]).finally(() => clearTimeout(timer));
458862
+ if (event) {
458863
+ if (event.done)
458864
+ throw new Error("Conversation status connection closed; remote execution may still be running.");
458865
+ const status = getConversationStatus(event.value, params.receipt.conversation_id);
458866
+ if (status !== undefined) {
458867
+ for (const runId2 of getSendRunIds(status, params.receipt.client_message_id))
458868
+ runIds.add(runId2);
458869
+ }
458870
+ next = params.events.next();
458871
+ next.catch(() => {});
458872
+ }
458873
+ const runId = [...runIds].at(-1);
458874
+ if (!runId) {
458875
+ const latest = await params.latestSuperRun();
458876
+ if (latest?.id === params.receipt.super_run_id && (latest.errored_at || latest.cancelled_at)) {
458877
+ throw new Error(`Accepted send ${latest.id} ${latest.errored_at ? "failed" : "was cancelled"} before a run was observed.`);
458878
+ }
458879
+ continue;
458880
+ }
458881
+ const run = await params.retrieveRun(runId);
458882
+ if (run.status === "failed" || run.status === "cancelled") {
458883
+ throw new Error(`Remote run ${runId} ${run.status}${run.stop_reason ? ` (${run.stop_reason})` : ""}`);
458884
+ }
458885
+ if (run.status !== "completed" || run.stop_reason === "requires_approval")
458886
+ continue;
458887
+ const messages = await params.listRunMessages(runId);
458888
+ const assistant = messages.filter((message) => message.message_type === "assistant_message").sort((a2, b3) => (b3.seq_id ?? 0) - (a2.seq_id ?? 0))[0];
458889
+ if (assistant?.message_type === "assistant_message") {
458890
+ const text2 = typeof assistant.content === "string" ? assistant.content : assistant.content.filter((part) => part.type === "text").map((part) => part.text).join(`
458891
+ `);
458892
+ if (text2.trim())
458893
+ return {
458894
+ text: text2,
458895
+ runIds: [...runIds],
458896
+ stopReason: run.stop_reason ?? null
458897
+ };
458898
+ }
458899
+ if (completedWithoutText?.runId !== runId)
458900
+ completedWithoutText = { runId, at: now2() };
458901
+ if (now2() - completedWithoutText.at < 15000)
458902
+ continue;
458903
+ throw new Error(`Remote run ${runId} completed without an assistant reply (${run.stop_reason ?? "unknown stop reason"})`);
458904
+ }
458905
+ } catch (error5) {
458906
+ throw new EnqueuedWaitError(error5, [...runIds]);
458907
+ }
458908
+ }
458909
+ var EnqueuedWaitError;
458910
+ var init_headless_enqueue_wait = __esm(() => {
458911
+ EnqueuedWaitError = class EnqueuedWaitError extends Error {
458912
+ runIds;
458913
+ constructor(error5, runIds) {
458914
+ super(error5 instanceof Error ? error5.message : String(error5), {
458915
+ cause: error5
458916
+ });
458917
+ this.runIds = runIds;
458918
+ this.name = "EnqueuedWaitError";
458919
+ }
458920
+ };
458921
+ });
458922
+
458970
458923
  // src/headless-cloud-send.ts
458971
458924
  import { randomUUID as randomUUID48 } from "node:crypto";
458972
458925
  function shouldEnqueueCloudSend(values4, cloud, isAgentLaunch) {
@@ -465672,14 +465625,14 @@ function detectTerminalType() {
465672
465625
  function isVSCodeLikeTerminal() {
465673
465626
  return detectTerminalType() !== null;
465674
465627
  }
465675
- function getKeybindingsPath(terminal2) {
465676
- if (!terminal2)
465628
+ function getKeybindingsPath(terminal) {
465629
+ if (!terminal)
465677
465630
  return null;
465678
465631
  const appName = {
465679
465632
  vscode: "Code",
465680
465633
  cursor: "Cursor",
465681
465634
  windsurf: "Windsurf"
465682
- }[terminal2];
465635
+ }[terminal];
465683
465636
  const os9 = platform10();
465684
465637
  if (os9 === "darwin") {
465685
465638
  return join96(homedir52(), "Library", "Application Support", appName, "User", "keybindings.json");
@@ -465802,35 +465755,35 @@ function removeKeybinding(keybindingsPath) {
465802
465755
  }
465803
465756
  }
465804
465757
  function installKeybindingForCurrentTerminal() {
465805
- const terminal2 = detectTerminalType();
465806
- if (!terminal2) {
465758
+ const terminal = detectTerminalType();
465759
+ if (!terminal) {
465807
465760
  return {
465808
465761
  success: false,
465809
465762
  error: "Not running in a VS Code-like terminal"
465810
465763
  };
465811
465764
  }
465812
- const path48 = getKeybindingsPath(terminal2);
465765
+ const path48 = getKeybindingsPath(terminal);
465813
465766
  if (!path48) {
465814
465767
  return {
465815
465768
  success: false,
465816
- error: `Could not determine keybindings.json path for ${terminal2}`
465769
+ error: `Could not determine keybindings.json path for ${terminal}`
465817
465770
  };
465818
465771
  }
465819
465772
  return installKeybinding(path48);
465820
465773
  }
465821
465774
  function removeKeybindingForCurrentTerminal() {
465822
- const terminal2 = detectTerminalType();
465823
- if (!terminal2) {
465775
+ const terminal = detectTerminalType();
465776
+ if (!terminal) {
465824
465777
  return {
465825
465778
  success: false,
465826
465779
  error: "Not running in a VS Code-like terminal"
465827
465780
  };
465828
465781
  }
465829
- const path48 = getKeybindingsPath(terminal2);
465782
+ const path48 = getKeybindingsPath(terminal);
465830
465783
  if (!path48) {
465831
465784
  return {
465832
465785
  success: false,
465833
- error: `Could not determine keybindings.json path for ${terminal2}`
465786
+ error: `Could not determine keybindings.json path for ${terminal}`
465834
465787
  };
465835
465788
  }
465836
465789
  return removeKeybinding(path48);
@@ -466582,16 +466535,16 @@ var init_registry2 = __esm(() => {
466582
466535
  } = await Promise.resolve().then(() => (init_terminal_keybinding_installer(), exports_terminal_keybinding_installer));
466583
466536
  const { updateSettings: updateSettings2 } = await Promise.resolve().then(() => (init_settings4(), exports_settings2));
466584
466537
  const isRevert = args.includes("--revert") || args.includes("--remove");
466585
- const terminal2 = detectTerminalType2();
466586
- if (!terminal2) {
466538
+ const terminal = detectTerminalType2();
466539
+ if (!terminal) {
466587
466540
  return "Not running in a VS Code-like terminal. Shift+Enter keybinding is not needed.";
466588
466541
  }
466589
466542
  const terminalName = {
466590
466543
  vscode: "VS Code",
466591
466544
  cursor: "Cursor",
466592
466545
  windsurf: "Windsurf"
466593
- }[terminal2];
466594
- const keybindingsPath = getKeybindingsPath2(terminal2);
466546
+ }[terminal];
466547
+ const keybindingsPath = getKeybindingsPath2(terminal);
466595
466548
  if (!keybindingsPath) {
466596
466549
  return `Could not determine keybindings.json path for ${terminalName}`;
466597
466550
  }
@@ -508893,13 +508846,13 @@ Error: ${message}`);
508893
508846
  installKeybinding: installKeybinding2
508894
508847
  } = await Promise.resolve().then(() => (init_terminal_keybinding_installer(), exports_terminal_keybinding_installer));
508895
508848
  const { loadSettings: loadSettings2, updateSettings: updateSettings2 } = await Promise.resolve().then(() => (init_settings4(), exports_settings2));
508896
- const terminal2 = detectTerminalType2();
508897
- if (!terminal2) {
508849
+ const terminal = detectTerminalType2();
508850
+ if (!terminal) {
508898
508851
  setShowKeybindingSetup(false);
508899
508852
  return;
508900
508853
  }
508901
508854
  const settings4 = await loadSettings2();
508902
- const keybindingsPath = getKeybindingsPath2(terminal2);
508855
+ const keybindingsPath = getKeybindingsPath2(terminal);
508903
508856
  if (!keybindingsPath || settings4.shiftEnterKeybindingInstalled) {
508904
508857
  setShowKeybindingSetup(false);
508905
508858
  return;
@@ -512015,4 +511968,4 @@ function registerBunOAuthFlows() {
512015
511968
  registerBunOAuthFlows();
512016
511969
  await init_src5().then(() => exports_src2);
512017
511970
 
512018
- //# debugId=F0EE3697E822655164756E2164756E21
511971
+ //# debugId=E297E0391CF07BFB64756E2164756E21