@letta-ai/letta-code 0.33.3 → 0.33.5

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 (40) hide show
  1. package/dist/mcp-client.js +2 -2
  2. package/dist/mcp-client.js.map +1 -1
  3. package/dist/types/agent/subagent-state.d.ts +5 -1
  4. package/dist/types/agent/subagent-state.d.ts.map +1 -1
  5. package/dist/types/agent/subagents/child-send-tracking.d.ts +1 -1
  6. package/dist/types/agent/subagents/child-send-tracking.d.ts.map +1 -1
  7. package/dist/types/agent/subagents/names.d.ts +1 -1
  8. package/dist/types/agent/subagents/names.d.ts.map +1 -1
  9. package/dist/types/agent/subagents/remote-turn-wait.d.ts.map +1 -1
  10. package/dist/types/backend/api/conversation-enqueue.d.ts +10 -0
  11. package/dist/types/backend/api/conversation-enqueue.d.ts.map +1 -1
  12. package/dist/types/headless-super-run-wait.d.ts +7 -11
  13. package/dist/types/headless-super-run-wait.d.ts.map +1 -1
  14. package/dist/types/tools/impl/workflow.d.ts.map +1 -1
  15. package/dist/types/tools/workflow/decide.d.ts +32 -0
  16. package/dist/types/tools/workflow/decide.d.ts.map +1 -0
  17. package/dist/types/tools/workflow/execution-registry.d.ts.map +1 -1
  18. package/dist/types/tools/workflow/journal.d.ts +15 -2
  19. package/dist/types/tools/workflow/journal.d.ts.map +1 -1
  20. package/dist/types/tools/workflow/sdk-loader.d.ts +3 -0
  21. package/dist/types/tools/workflow/sdk-loader.d.ts.map +1 -1
  22. package/dist/types/tools/workflow/sdk-spawner.d.ts +17 -0
  23. package/dist/types/tools/workflow/sdk-spawner.d.ts.map +1 -1
  24. package/dist/types/tools/workflow/types.d.ts +13 -3
  25. package/dist/types/tools/workflow/types.d.ts.map +1 -1
  26. package/dist/types/tools/workflow/workflow-engine.d.ts +1 -1
  27. package/dist/types/tools/workflow/workflow-engine.d.ts.map +1 -1
  28. package/dist/types/types/loop-status-protocol.d.ts +31 -0
  29. package/dist/types/types/loop-status-protocol.d.ts.map +1 -1
  30. package/dist/types/types/protocol_v2.d.ts +3 -29
  31. package/dist/types/types/protocol_v2.d.ts.map +1 -1
  32. package/dist/types/websocket/listener/outbound-wire.d.ts.map +1 -1
  33. package/dist/types/websocket/listener/protocol-outbound.d.ts +0 -10
  34. package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
  35. package/dist/types/websocket/listener/turn-correlation.d.ts +1 -0
  36. package/dist/types/websocket/listener/turn-correlation.d.ts.map +1 -1
  37. package/letta.js +630 -389
  38. package/package.json +2 -2
  39. package/scripts/source-file-size-baseline.json +3 -4
  40. package/skills/workflow-authoring/SKILL.md +31 -4
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.5",
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",
@@ -5785,7 +5785,7 @@ var init_package = __esm(() => {
5785
5785
  dependencies: {
5786
5786
  "@earendil-works/pi-ai": "^0.87.1",
5787
5787
  "@janhapke/sharp-electron": "0.35.3-electron.1",
5788
- "@letta-ai/letta-agent-sdk": "^0.8.17",
5788
+ "@letta-ai/letta-agent-sdk": "0.8.21",
5789
5789
  "@letta-ai/letta-client": "^1.10.2",
5790
5790
  "@letta-ai/trajectory": "0.2.0",
5791
5791
  "@modelcontextprotocol/sdk": "1.30.0",
@@ -111416,7 +111416,6 @@ var init_names = __esm(() => {
111416
111416
  "Songbird",
111417
111417
  "Slider",
111418
111418
  "Aguilar",
111419
- "Dogmeat",
111420
111419
  "Codsworth",
111421
111420
  "Nick Valentine",
111422
111421
  "Yes Man",
@@ -187644,7 +187643,7 @@ function getSubagentByToolCallId(toolCallId) {
187644
187643
  }
187645
187644
  return;
187646
187645
  }
187647
- function registerSubagent(id2, type3, description, toolCallId, isBackground, silent, parentScope, prompt) {
187646
+ function registerSubagent(id2, type3, description, toolCallId, isBackground, silent, parentScope, prompt, claimsParentRuntime) {
187648
187647
  const displayType = type3.charAt(0).toUpperCase() + type3.slice(1);
187649
187648
  const agent = {
187650
187649
  id: id2,
@@ -187661,6 +187660,7 @@ function registerSubagent(id2, type3, description, toolCallId, isBackground, sil
187661
187660
  startTime: Date.now(),
187662
187661
  toolCallId,
187663
187662
  isBackground,
187663
+ claimsParentRuntime,
187664
187664
  silent,
187665
187665
  parentAgentId: parentScope?.agentId ?? undefined,
187666
187666
  parentConversationId: parentScope?.conversationId && parentScope.conversationId.length > 0 ? parentScope.conversationId : undefined
@@ -188768,9 +188768,7 @@ function enqueueOutboundFrame(transport, frame) {
188768
188768
  if (frame.frameClass === "status" && frame.coalesceKey) {
188769
188769
  const index = state.frames.findIndex((f4) => f4.frameClass === "status" && f4.coalesceKey === frame.coalesceKey);
188770
188770
  if (index !== -1) {
188771
- state.frames[index] = frame;
188772
- drainOutboundQueue(transport, state);
188773
- return;
188771
+ state.frames.splice(index, 1);
188774
188772
  }
188775
188773
  }
188776
188774
  state.frames.push(frame);
@@ -189196,6 +189194,9 @@ function createTurnCorrelation(runtime, message, batchId) {
189196
189194
  }
189197
189195
  }
189198
189196
  return {
189197
+ get clientMessageIds() {
189198
+ return [...clientMessageIds];
189199
+ },
189199
189200
  appendDequeuedBatch(nextBatchId) {
189200
189201
  for (const clientMessageId of takeDequeuedClientMessageIds(runtime, nextBatchId)) {
189201
189202
  clientMessageIds.add(clientMessageId);
@@ -189241,7 +189242,6 @@ __export(exports_protocol_outbound, {
189241
189242
  emitProtocolV2Message: () => emitProtocolV2Message,
189242
189243
  emitLoopStatusUpdate: () => emitLoopStatusUpdate,
189243
189244
  emitLoopStatusIfOpen: () => emitLoopStatusIfOpen,
189244
- emitLoopErrorDelta: () => emitLoopErrorDelta,
189245
189245
  emitInterruptedStatusDelta: () => emitInterruptedStatusDelta,
189246
189246
  emitDeviceStatusUpdateIfChanged: () => emitDeviceStatusUpdateIfChanged,
189247
189247
  emitDeviceStatusUpdate: () => emitDeviceStatusUpdate,
@@ -189688,8 +189688,10 @@ function buildSubagentSnapshot(runtime, scope) {
189688
189688
  status: a2.status,
189689
189689
  agent_url: a2.agentURL,
189690
189690
  conversation_id: a2.conversationId ?? null,
189691
+ super_run_id: a2.superRunId,
189691
189692
  model: a2.model,
189692
189693
  is_background: a2.isBackground,
189694
+ claims_parent_runtime: a2.claimsParentRuntime,
189693
189695
  silent: a2.silent,
189694
189696
  tool_call_id: a2.toolCallId,
189695
189697
  parent_agent_id: a2.parentAgentId,
@@ -189726,18 +189728,6 @@ function createLifecycleMessageBase(messageType, runId) {
189726
189728
  function emitCanonicalMessageDelta(socket, runtime, delta2, scope) {
189727
189729
  emitStreamDelta(socket, runtime, delta2, scope);
189728
189730
  }
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
189731
  function emitRetryDelta(socket, runtime, params) {
189742
189732
  const delta2 = {
189743
189733
  ...createLifecycleMessageBase("retry", params.runId),
@@ -203027,40 +203017,31 @@ Pass a URL ending at the PR number, such as \`https://github.com/owner/repo/pull
203027
203017
  var init_WatchPR = () => {};
203028
203018
 
203029
203019
  // src/tools/descriptions/Workflow.md
203030
- var Workflow_default = `Execute a workflow script that orchestrates multiple subagents deterministically. Use for multi-step orchestration where control flow should be deterministic (loops, conditionals, fan-out) rather than model-driven.
203031
-
203032
- Workflows run in the background — this tool validates the script and returns immediately with a task ID (\`workflow_N\`) and output file path; a <task-notification> arrives when the workflow completes, carrying the script's return value. Do not poll or sleep for it: keep working or end your turn, and never fabricate the result before the notification arrives. Read the output file only when you need interim progress; TaskStop aborts the run.
203020
+ var Workflow_default = `Execute a workflow script that orchestrates multiple subagents deterministically (loops, conditionals, fan-out) rather than model-driven.
203033
203021
 
203034
- ONLY call this tool when the user has explicitly opted into multi-agent orchestration. Workflows can spawn dozens of subagent sessions and cost real money; the user must request that scale, not have it inferred. Explicit opt-in means: the user directly asked for a workflow or multi-agent orchestration in their own words ("use a workflow", "fan out agents", "orchestrate this with subagents"), asked for a comprehensive audit/sweep at a scale that plainly requires it, or invoked a skill whose instructions call this tool. For any other task — even one that would benefit from parallelism — describe what a workflow could do and ask first.
203022
+ Workflows run in the background: this tool returns immediately with a task ID, and a <task-notification> carrying the script's return value arrives when the workflow completes. Do not poll or sleep for it, and never fabricate the result before it arrives. TaskStop aborts the run.
203035
203023
 
203036
- Every script must begin with \`export const meta = {...}\`: a PURE LITERAL (no variables, calls, or interpolation) giving the workflow's \`name\` (kebab-case), a one-line \`description\`, and optionally \`phases\` — one \`{ title, detail? }\` per phase() call. Scripts are plain JavaScript, not TypeScript. The script runs in the CLI process with the CLI's privileges and the user approves it by reading it, so keep it to orchestration (deciding what runs, combining results); reading, searching, and writing belong in subagents, where the tool allowlist applies.
203024
+ ONLY call this tool when the user has explicitly opted into multi-agent orchestration — they asked for a workflow or multi-agent orchestration in their own words ("use a workflow", "fan out agents"), or invoked a skill whose instructions call this tool. Workflows can spawn many subagents and cost real money. For any other task, even one that would benefit from parallelism, describe what a workflow could do and ask first.
203037
203025
 
203038
- The canonical multi-stage pattern — pipeline by default, each item verifies as soon as its review completes:
203026
+ Scripts are plain JavaScript and must begin with \`export const meta = {...}\`, a pure literal (no variables, calls, or interpolation). Pass the work list via \`args\`. Prefer \`pipeline()\` so each item moves to its next stage as soon as it is ready; \`agent()\` resolves to \`null\` on failure, so guard and filter:
203039
203027
 
203040
203028
  export const meta = {
203041
- name: 'review-changes',
203042
- description: 'Review changed files across dimensions, verify each finding',
203029
+ name: 'review-files',
203030
+ description: 'Review each file for bugs, verify each finding',
203043
203031
  phases: [{ title: 'Review' }, { title: 'Verify' }],
203044
203032
  }
203045
- const DIMENSIONS = [{key: 'bugs', prompt: '...'}, {key: 'perf', prompt: '...'}]
203046
- const findingsSchema = {type: 'object', properties: {findings: {type: 'array', items: {type: 'object', properties: {file: {type: 'string'}, summary: {type: 'string'}}, required: ['file', 'summary']}}}, required: ['findings']}
203047
- const verdictSchema = {type: 'object', properties: {real: {type: 'boolean'}, why: {type: 'string'}}, required: ['real', 'why']}
203033
+ const findings = {type: 'object', properties: {bugs: {type: 'array', items: {type: 'string'}}}, required: ['bugs']}
203034
+ const verdict = {type: 'object', properties: {real: {type: 'boolean'}}, required: ['real']}
203048
203035
  const results = await pipeline(
203049
- DIMENSIONS,
203050
- d => agent(d.prompt, {label: \`review:\${d.key}\`, phase: 'Review', schema: findingsSchema}),
203051
- review => review ? parallel(review.findings.map(f => () =>
203052
- agent(\`Adversarially verify: \${f.summary}\`, {label: \`verify:\${f.file}\`, phase: 'Verify', schema: verdictSchema})
203053
- .then(v => ({...f, verdict: v})))) : []
203036
+ args.files,
203037
+ f => agent(\`Review \${f} for bugs.\`, { phase: 'Review', schema: findings }),
203038
+ (review, f) => parallel((review?.bugs ?? []).map(bug => () =>
203039
+ agent(\`Is this a real bug in \${f}? \${bug}\`, { phase: 'Verify', schema: verdict })
203040
+ .then(v => v?.real ? { file: f, bug } : null))),
203054
203041
  )
203055
- return { confirmed: results.filter(Boolean).flat().filter(Boolean).filter(f => f.verdict?.real) }
203056
-
203057
- Script hooks: agent(prompt, opts?) spawns one subagent and resolves to final text. Prefer opts.schema (JSON Schema) for a validated object; invalid/missing results retry and then resolve to null with the validation error in the journal. opts.json still parses without validating; schema wins if both are supplied. Options: label, phase, schema, json, model, effort, allowedTools, systemPrompt, timeoutMs, maxToolCalls. pipeline(items, ...stages) runs each item through all stages independently with NO barrier between stages; each stage receives (prevResult, originalItem, index); a throwing stage drops that item to null. parallel(thunks) runs zero-arg functions concurrently and IS a barrier — use only when a stage genuinely needs all prior results together. phase(title) groups subsequent agents in progress output (inside concurrent stages use opts.phase instead — the global phase races). log(message) emits a progress line. args is the invocation's args input, verbatim.
203042
+ return results.filter(Boolean).flat().filter(Boolean)
203058
203043
 
203059
- Subagents run in isolated agent-free ephemeral conversations with read-only tools by default (Read, Grep, Glob) and no access to your memory or conversation — put ALL context they need in the prompt. Their model defaults to the invoking conversation's model; opts.model or the tool's model input accept any handle or alias from \`letta model list\`. They are told their final text IS the return value, so they return raw data. Concurrency is capped (excess agent() calls queue); a lifetime cap of 1000 agents per run is the runaway-loop backstop. Each subagent is also guarded: a 10-minute default timeout (override with opts.timeoutMs), at most 1000 unique tool calls by default (override with the positive safe integer opts.maxToolCalls), and a stop after three identical consecutive tool calls — a guarded call resolves to null and the journal records which guard fired.
203060
-
203061
- Every run persists its script and a journal of each subagent's outcome under ~/.letta/workflows/executions/<id>/ (the paths are in the tool result). Before diagnosing an empty or unexpected result, read that run's journal.jsonl; it records each agent's actual return value. Workflow subagents require the API backend.
203062
-
203063
- Before authoring a script, load the \`workflow-authoring\` skill — the workflow authoring reference: script API and gotchas, pipeline-vs-barrier rules, quality patterns (adversarial verify, judge panel, loop-until-dry), and worked examples.
203044
+ Before authoring a script, load the \`workflow-authoring\` skill — the script API, pipeline-vs-barrier rules, quality patterns, worked examples, and how to diagnose a run.
203064
203045
  `;
203065
203046
  var init_Workflow = () => {};
203066
203047
 
@@ -212179,6 +212160,9 @@ async function listEnqueuedRunMessages(runId, signal) {
212179
212160
  }
212180
212161
  return result2;
212181
212162
  }
212163
+ async function getExactSuperRun(agentId, superRunId, signal, request = apiRequest) {
212164
+ return request("GET", `/v1/agents/${encodeURIComponent(agentId)}/super-runs/${encodeURIComponent(superRunId)}`, undefined, { signal });
212165
+ }
212182
212166
  async function getLatestConversationSuperRun(conversationId, signal) {
212183
212167
  return apiRequest("GET", `/v1/conversations/${encodeURIComponent(conversationId)}/super-run`, undefined, { signal });
212184
212168
  }
@@ -212189,212 +212173,93 @@ var init_conversation_enqueue = __esm(() => {
212189
212173
  init_request();
212190
212174
  });
212191
212175
 
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;
212176
+ // src/headless-super-run-wait.ts
212177
+ import { setTimeout as delay3 } from "node:timers/promises";
212178
+ function isTransientReadError(error4) {
212179
+ if (error4 instanceof ApiRequestError || error4 instanceof APIError) {
212180
+ return error4.status === 408 || error4.status === 429 || error4.status >= 500;
212199
212181
  }
212200
- return event.conversation_id === conversationId ? event.status : undefined;
212182
+ return error4 instanceof TypeError || error4 instanceof Error && error4.name === "TimeoutError";
212201
212183
  }
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
- };
212184
+ async function retryRead(read2, signal, sleep11, failureLabel) {
212185
+ let failures = 0;
212186
+ while (true) {
212187
+ signal.throwIfAborted();
212188
+ try {
212189
+ return await read2();
212190
+ } catch (error4) {
212191
+ signal.throwIfAborted();
212192
+ if (!isTransientReadError(error4)) {
212193
+ throw new RemoteExecutionFailed(`${failureLabel}: ${error4 instanceof Error ? error4.message : String(error4)}`);
212256
212194
  }
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"})`);
212195
+ await sleep11(Math.min(30000, 1000 * 2 ** Math.min(failures++, 5)), signal);
212262
212196
  }
212263
- } catch (error4) {
212264
- throw new EnqueuedWaitError(error4, [...runIds]);
212265
212197
  }
212266
212198
  }
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)
212199
+ function throwIfSuperRunFailed(run) {
212200
+ if (run.errored_at) {
212201
+ const detail = run.error ? ` during ${run.error.code}: ${run.error.message}` : "";
212202
+ throw new RemoteExecutionFailed(`Remote Super Run ${run.id} failed${detail}`);
212203
+ }
212204
+ if (run.status === "CAN" || run.cancelled_at) {
212285
212205
  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;
212206
+ }
212207
+ }
212208
+ function assistantText(messages) {
212209
+ const assistant = messages.filter((message) => message.message_type === "assistant_message").sort((left, right) => (right.seq_id ?? 0) - (left.seq_id ?? 0))[0];
212210
+ if (assistant?.message_type !== "assistant_message")
212211
+ return null;
212212
+ const text2 = typeof assistant.content === "string" ? assistant.content : assistant.content.filter((part) => part.type === "text").map((part) => part.text).join(`
212213
+ `);
212214
+ return text2.trim() ? text2 : null;
212215
+ }
212216
+ function noReplyMessage(receipt) {
212217
+ 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
212218
  }
212292
212219
  async function waitForAcceptedSuperRun(receipt, signal, deps) {
212293
- const runIds = new Set;
212294
- let finished2 = false;
212295
- let failures = 0;
212296
- while (!finished2) {
212220
+ const pollMs = deps.pollMs ?? 1000;
212221
+ const sleep11 = deps.sleep ?? ((ms, waitSignal) => delay3(ms, undefined, { signal: waitSignal }));
212222
+ while (true) {
212297
212223
  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();
212224
+ 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`);
212225
+ if (exact.id !== receipt.super_run_id) {
212226
+ throw new RemoteExecutionFailed(`Exact Super Run read returned ${exact.id} for ${receipt.super_run_id}.`);
212227
+ }
212228
+ throwIfSuperRunFailed(exact);
212229
+ const terminal = exact.status === "COM" || exact.completed_at !== null;
212230
+ if (!terminal) {
212231
+ await sleep11(pollMs, signal);
212232
+ continue;
212360
212233
  }
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;
212234
+ const runId = exact.run_ids[0];
212235
+ if (!runId) {
212236
+ throw new RemoteExecutionFailed(`Remote Super Run ${exact.id} completed without a correlated child run.`);
212371
212237
  }
212372
- }
212373
- const runId = [...runIds].at(-1);
212374
- if (runId) {
212238
+ const run = await retryRead(() => deps.run(runId, AbortSignal.any([signal, AbortSignal.timeout(30000)])), signal, sleep11, `Remote child run read for ${runId} failed`);
212239
+ if (run.status === "failed" || run.status === "cancelled") {
212240
+ throw new RemoteExecutionFailed(`Remote child run ${runId} ${run.status}${run.stop_reason ? ` (${run.stop_reason})` : ""}.`);
212241
+ }
212242
+ if (run.status !== "completed" || run.stop_reason === "requires_approval") {
212243
+ await sleep11(pollMs, signal);
212244
+ continue;
212245
+ }
212246
+ let messages = [];
212375
212247
  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
- }
212248
+ messages = await deps.messages(runId, AbortSignal.any([signal, AbortSignal.timeout(1e4)]));
212384
212249
  } catch {
212385
212250
  signal.throwIfAborted();
212386
212251
  }
212252
+ return {
212253
+ text: assistantText(messages) ?? noReplyMessage(receipt),
212254
+ runIds: exact.run_ids,
212255
+ stopReason: run.stop_reason ?? null
212256
+ };
212387
212257
  }
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
212258
  }
212394
212259
  var RemoteExecutionFailed;
212395
212260
  var init_headless_super_run_wait = __esm(() => {
212261
+ init_letta_client();
212396
212262
  init_request();
212397
- init_headless_enqueue_wait();
212398
212263
  RemoteExecutionFailed = class RemoteExecutionFailed extends Error {
212399
212264
  };
212400
212265
  });
@@ -212426,19 +212291,21 @@ async function resolveChildSubagent(backend3, agentId, parentAgentId) {
212426
212291
  }
212427
212292
  }
212428
212293
  function waitForChildRun(receipt, signal) {
212294
+ const backend3 = getBackend();
212429
212295
  return waitForAcceptedSuperRun(receipt, signal, {
212430
- open: openConversationStatusStream,
212431
- latest: getLatestConversationSuperRun,
212296
+ exact: getExactSuperRun,
212297
+ run: (runId, readSignal) => backend3.retrieveRun(runId, { signal: readSignal }),
212432
212298
  messages: async () => []
212433
212299
  });
212434
212300
  }
212435
212301
  function trackChildSend(input) {
212436
212302
  const { receipt, child, parentScope } = input;
212437
212303
  const subagentId = generateSubagentId();
212438
- registerSubagent(subagentId, child.type, child.name, undefined, true, false, parentScope, input.prompt);
212304
+ registerSubagent(subagentId, child.type, child.name, undefined, true, false, parentScope, input.prompt, false);
212439
212305
  updateSubagent(subagentId, {
212440
212306
  agentId: receipt.agent_id,
212441
212307
  conversationId: receipt.conversation_id,
212308
+ superRunId: receipt.super_run_id,
212442
212309
  agentURL: buildAgentReference(receipt.agent_id, {
212443
212310
  conversationId: receipt.conversation_id
212444
212311
  })
@@ -212451,6 +212318,7 @@ function trackChildSend(input) {
212451
212318
  }
212452
212319
  var init_child_send_tracking = __esm(() => {
212453
212320
  init_subagent_state();
212321
+ init_backend2();
212454
212322
  init_conversation_enqueue();
212455
212323
  init_app_urls();
212456
212324
  init_headless_super_run_wait();
@@ -213151,7 +213019,7 @@ class CodexAppServerClient {
213151
213019
  await this.request("initialize", {
213152
213020
  clientInfo: {
213153
213021
  name: "letta-code",
213154
- version: "0.33.3"
213022
+ version: "0.33.5"
213155
213023
  },
213156
213024
  capabilities: null
213157
213025
  });
@@ -216509,9 +216377,10 @@ async function collectRemoteTurnResult(receipt, state, subagentId, signal = new
216509
216377
  })
216510
216378
  });
216511
216379
  try {
216380
+ const backend3 = getBackend();
216512
216381
  const reply = await waitForAcceptedSuperRun(receipt, signal, {
216513
- open: openConversationStatusStream,
216514
- latest: getLatestConversationSuperRun,
216382
+ exact: getExactSuperRun,
216383
+ run: (runId, readSignal) => backend3.retrieveRun(runId, { signal: readSignal }),
216515
216384
  messages: async (runId, readSignal) => {
216516
216385
  const messages = await listEnqueuedRunMessages(runId, readSignal);
216517
216386
  for (const message of messages) {
@@ -216547,6 +216416,7 @@ async function collectRemoteTurnResult(receipt, state, subagentId, signal = new
216547
216416
  }
216548
216417
  var init_remote_turn_wait = __esm(() => {
216549
216418
  init_subagent_state();
216419
+ init_backend2();
216550
216420
  init_conversation_enqueue();
216551
216421
  init_app_urls();
216552
216422
  init_constants2();
@@ -220477,6 +220347,7 @@ function registerWorkflowExecution(params) {
220477
220347
  startedAt: params.startedAt ?? Date.now(),
220478
220348
  phases: (params.meta.phases ?? []).map((p2) => p2.title),
220479
220349
  agents: new Map,
220350
+ decisionTokens: 0,
220480
220351
  logs: []
220481
220352
  });
220482
220353
  notify();
@@ -220495,6 +220366,9 @@ function recordWorkflowProgress(taskId, event) {
220495
220366
  if (record4.logs.length > MAX_LOG_LINES)
220496
220367
  record4.logs.shift();
220497
220368
  break;
220369
+ case "decision_usage":
220370
+ record4.decisionTokens += event.totalTokens;
220371
+ break;
220498
220372
  case "agent": {
220499
220373
  const previous = record4.agents.get(event.callIndex);
220500
220374
  const phase = event.phase ?? previous?.phase ?? null;
@@ -220566,7 +220440,7 @@ function snapshot(record4, now2) {
220566
220440
  agentsDone: agents.filter((a2) => a2.status === "done").length,
220567
220441
  agentsFailed: agents.filter((a2) => a2.status === "error").length,
220568
220442
  agentsRunning: agents.filter((a2) => a2.status === "running").length,
220569
- totalTokens: agents.reduce((sum2, a2) => sum2 + (a2.totalTokens ?? 0), 0),
220443
+ totalTokens: record4.decisionTokens + agents.reduce((sum2, a2) => sum2 + (a2.totalTokens ?? 0), 0),
220570
220444
  phases: phaseOrder.map((title) => ({
220571
220445
  title,
220572
220446
  agents: byPhase.get(title) ?? []
@@ -220767,6 +220641,22 @@ import { existsSync as existsSync45, readFileSync as readFileSync35 } from "node
220767
220641
  import { createRequire as createRequire6 } from "node:module";
220768
220642
  import { dirname as dirname26, join as join64 } from "node:path";
220769
220643
  import { fileURLToPath as fileURLToPath7, pathToFileURL as pathToFileURL3 } from "node:url";
220644
+ function supportsPublishedResume(version2) {
220645
+ if (!version2 || !MIN_RESUME_SDK_VERSION)
220646
+ return false;
220647
+ const match2 = /^(\d+)\.(\d+)\.(\d+)$/.exec(version2);
220648
+ const minimum3 = MIN_RESUME_SDK_VERSION.split(".").map(Number);
220649
+ if (!match2)
220650
+ return false;
220651
+ const parts = match2.slice(1).map(Number);
220652
+ for (let index = 0;index < parts.length; index++) {
220653
+ const part = parts[index];
220654
+ const required5 = minimum3[index];
220655
+ if (part !== required5)
220656
+ return (part ?? 0) > (required5 ?? 0);
220657
+ }
220658
+ return true;
220659
+ }
220770
220660
  function preferRunningCliForSubagents() {
220771
220661
  if (process.env.LETTA_CLI_PATH)
220772
220662
  return;
@@ -220775,6 +220665,17 @@ function preferRunningCliForSubagents() {
220775
220665
  process.env.LETTA_CLI_PATH = entry;
220776
220666
  }
220777
220667
  }
220668
+ function packageVersion(entry) {
220669
+ for (let dir = dirname26(entry);; dir = dirname26(dir)) {
220670
+ try {
220671
+ const manifest = JSON.parse(readFileSync35(join64(dir, "package.json"), "utf8"));
220672
+ if (manifest.name === SDK_PACKAGE)
220673
+ return manifest.version;
220674
+ } catch {}
220675
+ if (dir === dirname26(dir))
220676
+ return;
220677
+ }
220678
+ }
220778
220679
  function packageEntry(packageDir) {
220779
220680
  try {
220780
220681
  const manifest = JSON.parse(readFileSync35(join64(packageDir, "package.json"), "utf8"));
@@ -220842,6 +220743,7 @@ async function loadAgentSdk() {
220842
220743
  continue;
220843
220744
  }
220844
220745
  return {
220746
+ supportsAgentFreeResume: process.env.LETTA_WORKFLOW_AGENT_FREE_RESUME === "1" && Boolean(envPath) && specifier === specifiers[0] || specifier.startsWith("file:") && supportsPublishedResume(packageVersion(fileURLToPath7(specifier))),
220845
220747
  createLocalClient: () => {
220846
220748
  const client = new sdk.LettaAgentClient({
220847
220749
  backend: "local",
@@ -220871,12 +220773,26 @@ async function loadAgentSdk() {
220871
220773
  ${attempts.map((a2) => ` tried ${a2}`).join(`
220872
220774
  `)}`);
220873
220775
  }
220874
- var SDK_PACKAGE;
220776
+ var SDK_PACKAGE, MIN_RESUME_SDK_VERSION = "0.8.20";
220875
220777
  var init_sdk_loader = __esm(() => {
220876
220778
  SDK_PACKAGE = ["@letta-ai", "letta-agent-sdk"].join("/");
220877
220779
  });
220878
220780
 
220879
220781
  // src/tools/workflow/sdk-spawner.ts
220782
+ async function latestWorkerRun(conversationId) {
220783
+ const client = await getClient();
220784
+ const messages = await client.conversations.messages.list(conversationId, {
220785
+ limit: 100,
220786
+ order: "desc"
220787
+ });
220788
+ const runId = messages.getPaginatedItems().map((message) => message.run_id).find((id2) => typeof id2 === "string" && id2.startsWith("run-"));
220789
+ if (!runId)
220790
+ return null;
220791
+ return client.runs.retrieve(runId);
220792
+ }
220793
+ async function retrieveWorkerConversation(id2) {
220794
+ return apiRequest("GET", `/v1/conversations/${encodeURIComponent(id2)}`);
220795
+ }
220880
220796
  function parseJsonReply(text2) {
220881
220797
  const trimmed = text2.trim();
220882
220798
  const fenced = /^```(?:json)?\s*([\s\S]*?)\s*```$/.exec(trimmed);
@@ -220962,16 +220878,22 @@ function usageTokensFromEvent(event) {
220962
220878
  const total = event.total_tokens;
220963
220879
  return typeof total === "number" && Number.isFinite(total) ? total : undefined;
220964
220880
  }
220965
- async function drainTurn(query3, usage, stop, maxToolCalls, onUsage) {
220966
- let assistantText = "";
220881
+ async function drainTurn(query3, usage, stop, maxToolCalls, onUsage, onStarted) {
220882
+ let assistantText2 = "";
220967
220883
  let resultText;
220968
220884
  let success = false;
220969
220885
  let error4;
220970
220886
  let structuredOutput;
220887
+ let startedNotified = false;
220971
220888
  const guard = createToolCallGuard(maxToolCalls);
220972
220889
  for await (const message of query3) {
220890
+ const id2 = query3.conversationId ?? message.conversationId;
220891
+ if (!startedNotified && id2) {
220892
+ startedNotified = true;
220893
+ onStarted?.(id2);
220894
+ }
220973
220895
  if (message.type === "assistant")
220974
- assistantText += message.content ?? "";
220896
+ assistantText2 += message.content ?? "";
220975
220897
  if (message.type === "stream_event") {
220976
220898
  const tokens = usageTokensFromEvent(message.event);
220977
220899
  if (tokens !== undefined) {
@@ -220997,7 +220919,7 @@ async function drainTurn(query3, usage, stop, maxToolCalls, onUsage) {
220997
220919
  }
220998
220920
  }
220999
220921
  return {
221000
- finalText: (resultText ?? assistantText).trim(),
220922
+ finalText: (resultText ?? assistantText2).trim(),
221001
220923
  success,
221002
220924
  error: error4,
221003
220925
  structuredOutput,
@@ -221020,16 +220942,44 @@ function buildQueryOptions(options, model, config, callIndex) {
221020
220942
  name: options.label ?? `Workflow worker ${callIndex + 1}`,
221021
220943
  system: system2,
221022
220944
  permissionMode: "unrestricted",
221023
- allowedTools: options.allowedTools ?? config.allowedTools ?? DEFAULT_ALLOWED_TOOLS,
220945
+ allowedTools: options.allowedTools ?? (options.conversationId ? [] : config.allowedTools ?? DEFAULT_ALLOWED_TOOLS),
221024
220946
  skillSources: [],
221025
220947
  ...config.cwd ? { cwd: config.cwd } : {},
220948
+ disableMemoryGuard: true,
221026
220949
  ...options.effort ? { modelSettings: { reasoning_effort: options.effort } } : {}
221027
220950
  };
221028
220951
  }
221029
220952
  function createSdkSpawner(client, config) {
221030
220953
  return async (request, signal, hooks) => {
221031
220954
  const { prompt, options } = request;
221032
- const model = options.model ? config.resolveModel?.(options.model) ?? null : config.model;
220955
+ const resumeId = options.conversationId;
220956
+ if (resumeId !== undefined && !/^conv-[A-Za-z0-9_-]+$/.test(resumeId)) {
220957
+ throw new Error("agent() conversationId must be a conv-... ID.");
220958
+ }
220959
+ if (resumeId && !config.supportsAgentFreeResume) {
220960
+ throw new Error("Workflow worker continuation requires an Agent SDK release with agent-free query() resume support.");
220961
+ }
220962
+ const persisted = resumeId ? await (config.retrieveConversation ?? retrieveWorkerConversation)(resumeId) : null;
220963
+ if (persisted && (persisted.agent_id !== null || persisted.parent_agent_id !== config.parentAgentId)) {
220964
+ throw new Error("Worker conversation is not agent-free or belongs to another parent agent.");
220965
+ }
220966
+ if (persisted && resumeId) {
220967
+ const latest = await (config.latestRun ?? latestWorkerRun)(resumeId);
220968
+ if (!latest || latest.conversation_id !== resumeId || !["completed", "failed", "cancelled"].includes(latest.status ?? "")) {
220969
+ throw new Error("Cannot confirm worker's latest run is terminal; reconcile it before continuing.");
220970
+ }
220971
+ }
220972
+ if (persisted && (!persisted.model || typeof persisted.model !== "string")) {
220973
+ throw new Error("Worker conversation has no persisted model; cannot continue safely.");
220974
+ }
220975
+ const selectedModel = options.model ? config.resolveModel?.(options.model) ?? null : config.model;
220976
+ if (persisted && options.systemPrompt !== undefined) {
220977
+ throw new Error("agent() continuation cannot override the worker system prompt.");
220978
+ }
220979
+ if (persisted && options.model && selectedModel !== persisted.model) {
220980
+ throw new Error("agent() continuation model must match the persisted worker model.");
220981
+ }
220982
+ const model = persisted ? persisted.model : selectedModel;
221033
220983
  if (!model) {
221034
220984
  return {
221035
220985
  value: null,
@@ -221048,8 +220998,15 @@ function createSdkSpawner(client, config) {
221048
220998
  const usage = {};
221049
220999
  const query3 = client.query({
221050
221000
  prompt,
221051
- options: buildQueryOptions(options, model, config, request.callIndex)
221001
+ options: {
221002
+ ...buildQueryOptions(options, model, config, request.callIndex),
221003
+ ...resumeId ? { conversationId: resumeId } : {}
221004
+ }
221052
221005
  });
221006
+ if (resumeId && query3.conversationId && query3.conversationId !== resumeId) {
221007
+ query3.close();
221008
+ throw new Error("SDK resumed an unexpected worker conversation; refusing continuation.");
221009
+ }
221053
221010
  let settleStopped;
221054
221011
  const stopped = new Promise((resolve30) => {
221055
221012
  settleStopped = resolve30;
@@ -221079,44 +221036,68 @@ function createSdkSpawner(client, config) {
221079
221036
  drainTurn(query3, usage, stop, options.maxToolCalls ?? DEFAULT_MAX_SUBAGENT_TOOL_CALLS, (totalTokens) => {
221080
221037
  if (!finished2)
221081
221038
  hooks?.onUsage?.(totalTokens);
221039
+ }, (id2) => {
221040
+ if (resumeId && id2 !== resumeId) {
221041
+ stop("SDK resumed an unexpected worker conversation");
221042
+ } else if (!finished2) {
221043
+ hooks?.onStarted?.(id2);
221044
+ }
221082
221045
  }),
221083
221046
  stopped
221084
221047
  ]);
221048
+ if (resumeId && query3.conversationId !== resumeId) {
221049
+ throw new Error("SDK did not resume the requested worker conversation.");
221050
+ }
221085
221051
  const stats = {
221086
221052
  durationMs: Date.now() - startedAt,
221087
221053
  ...turn.totalTokens !== undefined ? { totalTokens: turn.totalTokens } : {},
221088
221054
  ...query3.conversationId ? { conversationId: query3.conversationId } : {}
221089
221055
  };
221090
221056
  if (!turn.success) {
221091
- return {
221057
+ const outcome2 = {
221092
221058
  value: null,
221093
221059
  failed: true,
221094
221060
  error: turn.error ?? "subagent turn failed",
221095
221061
  ...stats
221096
221062
  };
221063
+ return outcome2;
221097
221064
  }
221098
221065
  if (options.schema) {
221099
- return { value: turn.structuredOutput, failed: false, ...stats };
221066
+ const outcome2 = {
221067
+ value: turn.structuredOutput,
221068
+ failed: false,
221069
+ ...stats
221070
+ };
221071
+ return outcome2;
221100
221072
  }
221101
221073
  if (options.json) {
221102
221074
  try {
221103
- return {
221075
+ const outcome2 = {
221104
221076
  value: parseJsonReply(turn.finalText),
221105
221077
  failed: false,
221106
221078
  ...stats
221107
221079
  };
221080
+ return outcome2;
221108
221081
  } catch {
221109
- return {
221082
+ const outcome2 = {
221110
221083
  value: null,
221111
221084
  failed: true,
221112
221085
  error: `Subagent reply was not valid JSON: ${turn.finalText.slice(0, 200)}`,
221113
221086
  ...stats
221114
221087
  };
221088
+ return outcome2;
221115
221089
  }
221116
221090
  }
221117
- return { value: turn.finalText, failed: false, ...stats };
221091
+ const outcome = { value: turn.finalText, failed: false, ...stats };
221092
+ return outcome;
221118
221093
  } catch (error4) {
221119
- return { value: null, failed: true, error: String(error4) };
221094
+ const outcome = {
221095
+ value: null,
221096
+ failed: true,
221097
+ error: String(error4),
221098
+ ...query3.conversationId || resumeId ? { conversationId: query3.conversationId ?? resumeId } : {}
221099
+ };
221100
+ return outcome;
221120
221101
  } finally {
221121
221102
  finished2 = true;
221122
221103
  clearTimeout(timeout);
@@ -221127,10 +221108,140 @@ function createSdkSpawner(client, config) {
221127
221108
  }
221128
221109
  var DEFAULT_ALLOWED_TOOLS, DEFAULT_SUBAGENT_TIMEOUT_MS, DEFAULT_MAX_SUBAGENT_TOOL_CALLS = 1000, MAX_IDENTICAL_TOOL_CALLS = 3, SUBAGENT_PREAMBLE = `You are a subagent inside a deterministic workflow. You are not talking to a human: your final output is consumed by a script. Return raw data with no preamble, no markdown framing, and no questions.`, JSON_PREAMBLE = `Your final message must be a single JSON value and nothing else: no prose, no markdown code fence.`;
221129
221110
  var init_sdk_spawner = __esm(() => {
221111
+ init_client4();
221112
+ init_request();
221130
221113
  DEFAULT_ALLOWED_TOOLS = ["Read", "Grep", "Glob"];
221131
221114
  DEFAULT_SUBAGENT_TIMEOUT_MS = 10 * 60 * 1000;
221132
221115
  });
221133
221116
 
221117
+ // src/tools/workflow/decide.ts
221118
+ function isRecord9(value) {
221119
+ return value !== null && typeof value === "object" && !Array.isArray(value);
221120
+ }
221121
+ function isFiniteNumber2(value) {
221122
+ return typeof value === "number" && Number.isFinite(value);
221123
+ }
221124
+ function validateRequest(input) {
221125
+ if (!isRecord9(input))
221126
+ throw new Error("decide() requires a request object.");
221127
+ const { state, questions, provider, session_id, trace, user } = input;
221128
+ if (Object.hasOwn(input, "model"))
221129
+ throw new Error("decide() does not accept a model option.");
221130
+ if (!(typeof state === "string" || isRecord9(state) || Array.isArray(state))) {
221131
+ throw new Error("decide() state must be a string, object, or array.");
221132
+ }
221133
+ if (!isRecord9(questions) || Object.keys(questions).length === 0) {
221134
+ throw new Error("decide() questions must be a non-empty object.");
221135
+ }
221136
+ for (const [id2, question] of Object.entries(questions)) {
221137
+ if (!isRecord9(question) || typeof question.instructions !== "string" || !question.instructions.trim()) {
221138
+ throw new Error(`decide() question ${id2} requires instructions.`);
221139
+ }
221140
+ if (question.type === "choice") {
221141
+ if (!isRecord9(question.criteria) || Object.keys(question.criteria).length === 0 || Object.keys(question.criteria).length > 255 || !Object.values(question.criteria).every((value) => typeof value === "string")) {
221142
+ throw new Error(`decide() choice ${id2} requires a non-empty criteria map (at most 255 options).`);
221143
+ }
221144
+ } else if (question.type === "score") {
221145
+ if (!Array.isArray(question.criteria) || question.criteria.length === 0 || !question.criteria.every((value) => typeof value === "string")) {
221146
+ throw new Error(`decide() score ${id2} requires a non-empty criteria array.`);
221147
+ }
221148
+ } else if (question.type !== "noul") {
221149
+ throw new Error(`decide() question ${id2} has an unsupported type.`);
221150
+ }
221151
+ }
221152
+ if (provider !== undefined && !isRecord9(provider))
221153
+ throw new Error("decide() provider must be an object.");
221154
+ if (isRecord9(provider) && provider.allow_fallbacks === true) {
221155
+ throw new Error("decide() does not allow model/provider fallbacks.");
221156
+ }
221157
+ if (session_id !== undefined && (typeof session_id !== "string" || session_id.length > 256)) {
221158
+ throw new Error("decide() session_id must be a string of at most 256 characters.");
221159
+ }
221160
+ if (trace !== undefined && !isRecord9(trace))
221161
+ throw new Error("decide() trace must be an object.");
221162
+ if (user !== undefined && typeof user !== "string")
221163
+ throw new Error("decide() user must be a string.");
221164
+ return input;
221165
+ }
221166
+ function validProbabilityMap(value) {
221167
+ return isRecord9(value) && Object.values(value).every(isFiniteNumber2);
221168
+ }
221169
+ function validAnswer(answer, question) {
221170
+ if (!isRecord9(answer) || answer.type !== question.type)
221171
+ return false;
221172
+ if (answer.type === "choice") {
221173
+ return typeof answer.choice === "string" && isRecord9(question.criteria) && Object.hasOwn(question.criteria, answer.choice) && (answer.probabilities === undefined || validProbabilityMap(answer.probabilities)) && (answer.confidence === undefined || isFiniteNumber2(answer.confidence));
221174
+ }
221175
+ if (answer.type === "score") {
221176
+ return isFiniteNumber2(answer.score) && isRecord9(answer.legend) && Object.values(answer.legend).every((value) => typeof value === "string") && (answer.probabilities === undefined || validProbabilityMap(answer.probabilities)) && (answer.confidence === undefined || isFiniteNumber2(answer.confidence));
221177
+ }
221178
+ return answer.type === "noul" && isFiniteNumber2(answer.noul) && answer.noul >= 0 && answer.noul <= 1;
221179
+ }
221180
+ function validateResponse(response, request) {
221181
+ if (!isRecord9(response) || typeof response.model !== "string" || typeof response.id !== "string" || typeof response.provider !== "string" || !isRecord9(response.usage) || !isFiniteNumber2(response.usage.input_tokens) || !isFiniteNumber2(response.usage.output_tokens) || !isFiniteNumber2(response.usage.cost) || !isRecord9(response.answers)) {
221182
+ throw new Error("decide() received a malformed response.");
221183
+ }
221184
+ const answers = response.answers;
221185
+ const questionIds = Object.keys(request.questions);
221186
+ if (Object.keys(answers).length !== questionIds.length || questionIds.some((id2) => !validAnswer(answers[id2], request.questions[id2]))) {
221187
+ throw new InvalidDecisionAnswerError;
221188
+ }
221189
+ return {
221190
+ ...response,
221191
+ answers: Object.fromEntries(questionIds.map((id2) => [
221192
+ id2,
221193
+ { ...answers[id2], calibrated: true }
221194
+ ]))
221195
+ };
221196
+ }
221197
+ async function submitWorkflowDecision(input, signal, onResult) {
221198
+ const request = validateRequest(input);
221199
+ const body3 = {
221200
+ ...request,
221201
+ model: DEFAULT_JEV_MODEL,
221202
+ provider: { ...request.provider, allow_fallbacks: false }
221203
+ };
221204
+ for (let attempt2 = 0;attempt2 < 2; attempt2++) {
221205
+ if (signal.aborted)
221206
+ throw new Error("Workflow aborted.");
221207
+ const response = await apiRequest("POST", "/v1/alpha/decisions", body3, { signal: AbortSignal.any([signal, AbortSignal.timeout(35000)]) });
221208
+ try {
221209
+ const result3 = validateResponse(response, request);
221210
+ onResult?.({
221211
+ model: result3.model,
221212
+ cost: result3.usage.cost,
221213
+ calibrated: true,
221214
+ valid: true,
221215
+ totalTokens: result3.usage.input_tokens + result3.usage.output_tokens
221216
+ });
221217
+ return result3;
221218
+ } catch (error4) {
221219
+ if (!(error4 instanceof InvalidDecisionAnswerError))
221220
+ throw error4;
221221
+ const usage = response.usage;
221222
+ onResult?.({
221223
+ model: response.model,
221224
+ cost: usage.cost,
221225
+ calibrated: false,
221226
+ valid: false,
221227
+ totalTokens: usage.input_tokens + usage.output_tokens
221228
+ });
221229
+ if (attempt2 === 1)
221230
+ return null;
221231
+ }
221232
+ }
221233
+ return null;
221234
+ }
221235
+ var DEFAULT_JEV_MODEL = "~typesafe/jev-latest", InvalidDecisionAnswerError;
221236
+ var init_decide = __esm(() => {
221237
+ init_request();
221238
+ InvalidDecisionAnswerError = class InvalidDecisionAnswerError extends Error {
221239
+ constructor() {
221240
+ super("decide() received invalid answers for the requested questions.");
221241
+ }
221242
+ };
221243
+ });
221244
+
221134
221245
  // src/tools/workflow/workflow-engine.ts
221135
221246
  import vm2 from "node:vm";
221136
221247
 
@@ -221169,18 +221280,57 @@ async function executeWorkflow(spawner, options) {
221169
221280
  };
221170
221281
  const inFlight = new Set;
221171
221282
  const maxTotalAgents = options.maxTotalAgents ?? DEFAULT_MAX_TOTAL_AGENTS;
221283
+ const maxTotalDecisions = options.maxTotalDecisions ?? DEFAULT_MAX_TOTAL_DECISIONS;
221172
221284
  const semaphore = new Semaphore(options.maxConcurrent ?? DEFAULT_MAX_CONCURRENT);
221173
221285
  let currentPhase = null;
221174
221286
  let callCounter = 0;
221287
+ let decisionCounter = 0;
221175
221288
  let agentsSpawned = 0;
221176
221289
  let totalTokens = 0;
221177
- function agent(prompt, callOptions) {
221178
- const pending2 = callAgent(prompt, callOptions);
221290
+ function trackCall(pending2) {
221179
221291
  pending2.catch(() => {});
221180
221292
  inFlight.add(pending2);
221181
221293
  pending2.finally(() => inFlight.delete(pending2)).catch(() => {});
221182
221294
  return pending2;
221183
221295
  }
221296
+ function agent(prompt, callOptions) {
221297
+ return trackCall(callAgent(prompt, callOptions));
221298
+ }
221299
+ function decide(state, questions, callOptions) {
221300
+ return trackCall(callDecision(state, questions, callOptions));
221301
+ }
221302
+ async function callDecision(state, questions, callOptions) {
221303
+ if (signal.aborted)
221304
+ throw new Error("Workflow aborted.");
221305
+ if (decisionCounter >= maxTotalDecisions) {
221306
+ throw new Error(`Lifetime decision cap of ${maxTotalDecisions} reached.`);
221307
+ }
221308
+ if (callOptions !== undefined && (!callOptions || typeof callOptions !== "object" || Array.isArray(callOptions))) {
221309
+ throw new Error("decide() options must be an object.");
221310
+ }
221311
+ decisionCounter++;
221312
+ await semaphore.acquire();
221313
+ try {
221314
+ if (signal.aborted)
221315
+ throw new Error("Workflow aborted.");
221316
+ return await submitWorkflowDecision({
221317
+ ...callOptions,
221318
+ state,
221319
+ questions
221320
+ }, signal, (result3) => {
221321
+ totalTokens += result3.totalTokens;
221322
+ emit({ kind: "decision_usage", totalTokens: result3.totalTokens });
221323
+ if (options.journalPath) {
221324
+ appendJournalEntry(options.journalPath, {
221325
+ kind: "decision",
221326
+ ...result3
221327
+ });
221328
+ }
221329
+ });
221330
+ } finally {
221331
+ semaphore.release();
221332
+ }
221333
+ }
221184
221334
  async function callAgent(prompt, callOptions) {
221185
221335
  if (typeof prompt !== "string" || !prompt.trim()) {
221186
221336
  throw new Error("agent() requires a non-empty prompt string.");
@@ -221194,6 +221344,9 @@ async function executeWorkflow(spawner, options) {
221194
221344
  throw new Error("agent() options must be an object.");
221195
221345
  }
221196
221346
  const opts = { ...callOptions };
221347
+ if (opts.conversationId !== undefined && (typeof opts.conversationId !== "string" || !/^conv-[A-Za-z0-9_-]+$/.test(opts.conversationId))) {
221348
+ throw new Error("agent() conversationId must be a conv-... ID.");
221349
+ }
221197
221350
  if (opts.maxToolCalls !== undefined && (!Number.isSafeInteger(opts.maxToolCalls) || opts.maxToolCalls <= 0)) {
221198
221351
  throw new Error("agent() maxToolCalls must be a positive safe integer.");
221199
221352
  }
@@ -221208,6 +221361,15 @@ async function executeWorkflow(spawner, options) {
221208
221361
  emit({ kind: "agent", callIndex, label, phase: phase2, status: "running" });
221209
221362
  agentsSpawned++;
221210
221363
  const outcome = await spawner({ prompt, options: opts, callIndex }, signal, {
221364
+ onStarted: (conversationId) => {
221365
+ if (options.journalPath) {
221366
+ appendJournalEntry(options.journalPath, {
221367
+ kind: "agent_started",
221368
+ callIndex,
221369
+ conversationId
221370
+ });
221371
+ }
221372
+ },
221211
221373
  onUsage: (totalTokens2) => emit({
221212
221374
  kind: "agent",
221213
221375
  callIndex,
@@ -221223,6 +221385,7 @@ async function executeWorkflow(spawner, options) {
221223
221385
  callIndex,
221224
221386
  label,
221225
221387
  prompt,
221388
+ ...opts.conversationId ? { resumedConversationId: opts.conversationId } : {},
221226
221389
  outcome
221227
221390
  });
221228
221391
  }
@@ -221292,6 +221455,7 @@ async function executeWorkflow(spawner, options) {
221292
221455
  }
221293
221456
  const context3 = vm2.createContext({
221294
221457
  agent,
221458
+ decide,
221295
221459
  parallel,
221296
221460
  pipeline: pipeline6,
221297
221461
  phase,
@@ -221339,8 +221503,9 @@ ${stripMetaExport(options.script)}
221339
221503
  settled = true;
221340
221504
  }
221341
221505
  }
221342
- var DEFAULT_MAX_CONCURRENT = 16, DEFAULT_MAX_TOTAL_AGENTS = 1000, MAX_ITEMS_PER_HELPER = 4096;
221506
+ var DEFAULT_MAX_CONCURRENT = 16, DEFAULT_MAX_TOTAL_AGENTS = 1000, DEFAULT_MAX_TOTAL_DECISIONS = 1000, MAX_ITEMS_PER_HELPER = 4096;
221343
221507
  var init_workflow_engine = __esm(() => {
221508
+ init_decide();
221344
221509
  init_journal();
221345
221510
  init_meta3();
221346
221511
  });
@@ -221394,7 +221559,8 @@ async function createSdkSpawnerHandle(args, setStage = () => {}) {
221394
221559
  model,
221395
221560
  resolveModel,
221396
221561
  allowedTools: args.allowedTools ?? [...DEFAULT_ALLOWED_TOOLS],
221397
- cwd: getCurrentWorkingDirectory()
221562
+ cwd: getCurrentWorkingDirectory(),
221563
+ supportsAgentFreeResume: sdk.supportsAgentFreeResume
221398
221564
  });
221399
221565
  } catch (error4) {
221400
221566
  client[Symbol.asyncDispose]?.().catch(() => {
@@ -221417,6 +221583,8 @@ function formatWorkflowProgressLine(event) {
221417
221583
  return `── ${event.title} ──`;
221418
221584
  case "log":
221419
221585
  return `» ${event.message}`;
221586
+ case "decision_usage":
221587
+ return null;
221420
221588
  case "agent": {
221421
221589
  if (event.status === "queued")
221422
221590
  return null;
@@ -221462,7 +221630,7 @@ function formatCompletionResult(run, executionDir) {
221462
221630
  return [
221463
221631
  payload,
221464
221632
  "",
221465
- `Per-agent results: ${join65(executionDir, "journal.jsonl")} — one line per completed agent with its full return value.`,
221633
+ `Per-call results: ${join65(executionDir, "journal.jsonl")} — one line per completed agent call with its full return value, plus one per decide() API attempt (retries included) with its model, cost, calibration, and tokens.`,
221466
221634
  "If the result above is empty or unexpected, read that file BEFORE diagnosing — do not assume agents returned non-empty results."
221467
221635
  ].join(`
221468
221636
  `);
@@ -221681,7 +221849,7 @@ ${result3}
221681
221849
  `Workflow launched in background. Task ID: ${taskId}`,
221682
221850
  `Summary: ${meta.description}`,
221683
221851
  `Script file: ${scriptPath}`,
221684
- `Journal: ${journalPath} (one line per completed agent)`,
221852
+ `Journal: ${journalPath} (one line per completed agent, and per decide() API attempt including retries)`,
221685
221853
  `Output file: ${outputFile}`,
221686
221854
  "",
221687
221855
  "You will be notified when it completes. Do not poll or sleep — keep working or end your turn. Read the output file only when you need interim progress; TaskStop aborts the run; the user can watch live status with /workflows."
@@ -398948,7 +399116,7 @@ function createModChangeBatcher(onChange) {
398948
399116
  // src/mods/package-manifest.ts
398949
399117
  import { readFileSync as readFileSync37 } from "node:fs";
398950
399118
  import path35 from "node:path";
398951
- function isRecord9(value) {
399119
+ function isRecord10(value) {
398952
399120
  return typeof value === "object" && value !== null && !Array.isArray(value);
398953
399121
  }
398954
399122
  function addError(errors4, errorPath, message) {
@@ -399087,7 +399255,7 @@ function validateCapabilities(value, errors4) {
399087
399255
  function validateEngines(value, errors4) {
399088
399256
  if (value === undefined)
399089
399257
  return;
399090
- if (!isRecord9(value)) {
399258
+ if (!isRecord10(value)) {
399091
399259
  addError(errors4, "letta.engines", "engines must be an object");
399092
399260
  return;
399093
399261
  }
@@ -399112,7 +399280,7 @@ function validateEngines(value, errors4) {
399112
399280
  return Object.keys(engines).length > 0 ? engines : undefined;
399113
399281
  }
399114
399282
  function parseLettaPackageManifest(packageJson) {
399115
- if (!isRecord9(packageJson)) {
399283
+ if (!isRecord10(packageJson)) {
399116
399284
  return {
399117
399285
  errors: [{ message: "package.json must be an object", path: "package" }],
399118
399286
  manifest: null,
@@ -399123,7 +399291,7 @@ function parseLettaPackageManifest(packageJson) {
399123
399291
  if (rawManifest === undefined) {
399124
399292
  return { errors: [], manifest: null, ok: true };
399125
399293
  }
399126
- if (!isRecord9(rawManifest)) {
399294
+ if (!isRecord10(rawManifest)) {
399127
399295
  return {
399128
399296
  errors: [{ message: "letta manifest must be an object", path: "letta" }],
399129
399297
  manifest: null,
@@ -399193,7 +399361,7 @@ import {
399193
399361
  writeFileSync as writeFileSync28
399194
399362
  } from "node:fs";
399195
399363
  import path36 from "node:path";
399196
- function isRecord10(value) {
399364
+ function isRecord11(value) {
399197
399365
  return typeof value === "object" && value !== null && !Array.isArray(value);
399198
399366
  }
399199
399367
  function createDiagnostic(diagnosticPath, message) {
@@ -399270,7 +399438,7 @@ function readRegistryObject(modsRoot) {
399270
399438
  registryPath
399271
399439
  };
399272
399440
  }
399273
- if (!isRecord10(registryResult.value)) {
399441
+ if (!isRecord11(registryResult.value)) {
399274
399442
  return {
399275
399443
  diagnostics: [
399276
399444
  createDiagnostic(registryPath, "packages.json must be an object")
@@ -399347,7 +399515,7 @@ function resolvePackageEntry(packageRoot, entry) {
399347
399515
  }
399348
399516
  function validatePackageMetadata(modsRoot, rawEntry, index) {
399349
399517
  const diagnosticPath = `packages[${index}]`;
399350
- if (!isRecord10(rawEntry)) {
399518
+ if (!isRecord11(rawEntry)) {
399351
399519
  return {
399352
399520
  diagnostics: [
399353
399521
  createDiagnostic(diagnosticPath, "package registry entry must be an object")
@@ -399714,7 +399882,7 @@ function setManagedModPackageEnabled(params) {
399714
399882
  const registry3 = readMutablePackageRegistry(params.modsRoot);
399715
399883
  const match3 = findPackageIndex(params.modsRoot, registry3.packagesValue, params.specifier);
399716
399884
  const rawEntry = registry3.packagesValue[match3.index];
399717
- if (!isRecord10(rawEntry)) {
399885
+ if (!isRecord11(rawEntry)) {
399718
399886
  throw new Error("Invalid package entry");
399719
399887
  }
399720
399888
  rawEntry.enabled = params.enabled;
@@ -399760,7 +399928,7 @@ function upsertManagedModPackage(params) {
399760
399928
  let removedDuplicates = 0;
399761
399929
  let replaced = false;
399762
399930
  registry3.packagesValue.forEach((rawEntry) => {
399763
- if (isRecord10(rawEntry) && rawEntry.source === params.source) {
399931
+ if (isRecord11(rawEntry) && rawEntry.source === params.source) {
399764
399932
  if (!replaced) {
399765
399933
  insertionIndex = nextPackages.length;
399766
399934
  nextPackages.push(entry);
@@ -399924,7 +400092,7 @@ var init_runtime_dependencies = __esm(() => {
399924
400092
  });
399925
400093
 
399926
400094
  // src/mods/turn-start-cancel.ts
399927
- function isRecord11(value) {
400095
+ function isRecord12(value) {
399928
400096
  return typeof value === "object" && value !== null;
399929
400097
  }
399930
400098
  function normalizeTurnStartCancelReason(value) {
@@ -399936,7 +400104,7 @@ function normalizeTurnStartCancelReason(value) {
399936
400104
  return trimmed.length > MAX_TURN_START_CANCEL_REASON_LENGTH ? trimmed.slice(0, MAX_TURN_START_CANCEL_REASON_LENGTH) : trimmed;
399937
400105
  }
399938
400106
  function getTurnStartCancel(event) {
399939
- if (!isRecord11(event) || !isRecord11(event.cancel))
400107
+ if (!isRecord12(event) || !isRecord12(event.cancel))
399940
400108
  return null;
399941
400109
  const reason = normalizeTurnStartCancelReason(event.cancel.reason);
399942
400110
  return reason ? { reason } : null;
@@ -402562,14 +402730,16 @@ function emitLoopErrorNotice(socket, runtime, params) {
402562
402730
  mirrorRecoverableNoticeToDesktopDebugPanel(params.message);
402563
402731
  return null;
402564
402732
  }
402565
- emitLoopErrorDelta(socket, runtime, {
402733
+ emitCanonicalMessageDelta(socket, runtime, {
402734
+ ...createLifecycleMessageBase("loop_error", params.runId),
402566
402735
  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
402736
+ stop_reason: params.stopReason,
402737
+ is_terminal: params.isTerminal,
402738
+ ...params.clientMessageIds?.length ? { client_message_ids: params.clientMessageIds } : {},
402739
+ ...decision.apiError ? { api_error: decision.apiError } : {}
402740
+ }, {
402741
+ agent_id: params.agentId,
402742
+ conversation_id: params.conversationId
402573
402743
  });
402574
402744
  return decision.message;
402575
402745
  }
@@ -406579,14 +406749,14 @@ var init_approval_suggestions = __esm(async () => {
406579
406749
  });
406580
406750
 
406581
406751
  // src/websocket/listener/cloud-retry-message.ts
406582
- function isRecord12(value) {
406752
+ function isRecord13(value) {
406583
406753
  return typeof value === "object" && value !== null && !Array.isArray(value);
406584
406754
  }
406585
406755
  function optionalString4(value) {
406586
406756
  return typeof value === "string" && value.length > 0 ? value : null;
406587
406757
  }
406588
406758
  function parseCloudRetryMessage(value) {
406589
- if (!isRecord12(value) || value.message_type !== "retry_message") {
406759
+ if (!isRecord13(value) || value.message_type !== "retry_message") {
406590
406760
  return null;
406591
406761
  }
406592
406762
  const attempt2 = value.attempt;
@@ -406841,6 +407011,19 @@ function finishListenerTurn(runtime, lease, options) {
406841
407011
  if (options.stopReason === "end_turn" || options.stopReason === "cancelled") {
406842
407012
  forgetListenerWork(runtime);
406843
407013
  }
407014
+ if (options.socket && options.errorNotice) {
407015
+ const runId = options.errorNotice.runId ?? options.runId ?? transition2.runId;
407016
+ const message = emitLoopErrorNotice(options.socket, runtime, {
407017
+ ...options.errorNotice,
407018
+ stopReason: options.stopReason,
407019
+ isTerminal: true,
407020
+ runId,
407021
+ agentId: options.agentId,
407022
+ conversationId: options.conversationId
407023
+ });
407024
+ runtime.lastTerminalLoopErrorMessage = message ?? options.errorNotice.message;
407025
+ runtime.lastTerminalLoopErrorRunId = runId ?? null;
407026
+ }
406844
407027
  if (options.stopReason === "cancelled" && transition2.previousKind === "active" && options.socket) {
406845
407028
  emitInterruptedStatusDelta(options.socket, runtime, {
406846
407029
  runId: options.runId ?? transition2.runId,
@@ -406873,6 +407056,7 @@ var init_turn_terminal = __esm(() => {
406873
407056
  init_connection();
406874
407057
  init_interrupted_turn_record();
406875
407058
  init_protocol_outbound();
407059
+ init_recoverable_notices();
406876
407060
  });
406877
407061
 
406878
407062
  // src/websocket/listener/recovery.ts
@@ -417121,6 +417305,12 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
417121
417305
  ...options,
417122
417306
  socket: options.socket ?? socket,
417123
417307
  turnId: activeDequeuedBatchId,
417308
+ ...options.errorNotice ? {
417309
+ errorNotice: {
417310
+ ...options.errorNotice,
417311
+ clientMessageIds: turnCorrelation.clientMessageIds
417312
+ }
417313
+ } : {},
417124
417314
  ...runtime.executionSettings ? { usage: buildTurnUsage(buffers.usage) } : {}
417125
417315
  }));
417126
417316
  const finishIfInterrupted = (runId) => {
@@ -417175,24 +417365,16 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
417175
417365
  return;
417176
417366
  }
417177
417367
  if (setup.kind === "cancelled") {
417178
- const transition2 = finishTurn({
417368
+ finishTurn({
417179
417369
  stopReason: "cancelled",
417180
417370
  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
417371
  conversationId,
417192
- cancelRequested: turnAbortSignal.aborted,
417193
- abortSignal: turnAbortSignal
417372
+ errorNotice: {
417373
+ message: setup.reason,
417374
+ cancelRequested: turnAbortSignal.aborted,
417375
+ abortSignal: turnAbortSignal
417376
+ }
417194
417377
  });
417195
- runtime.lastTerminalLoopErrorMessage = formattedError ?? setup.reason;
417196
417378
  return;
417197
417379
  }
417198
417380
  let turnInput = setup.turnInput;
@@ -417262,19 +417444,15 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
417262
417444
  lastApprovalContinuationAccepted = false;
417263
417445
  const maxTurns = runtime.executionSettings?.max_turns;
417264
417446
  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
417447
  finishTurn({
417274
417448
  stopReason: "max_steps",
417275
417449
  socket,
417276
417450
  agentId,
417277
- conversationId
417451
+ conversationId,
417452
+ errorNotice: {
417453
+ message: `Maximum turns limit reached (${buffers.usage.stepCount}/${maxTurns} steps)`,
417454
+ runId: runId || runtime.activeRunId
417455
+ }
417278
417456
  });
417279
417457
  break;
417280
417458
  }
@@ -417560,23 +417738,13 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
417560
417738
  abortSignal: turnAbortSignal
417561
417739
  };
417562
417740
  const terminalError = getConsumerLoopErrorMessage(noticeParams);
417563
- const transition2 = finishTurn({
417741
+ finishTurn({
417564
417742
  stopReason: effectiveStopReason,
417565
417743
  agentId,
417566
417744
  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
417745
+ error: terminalError,
417746
+ errorNotice: { ...noticeParams, runId: terminalRunId }
417577
417747
  });
417578
- runtime.lastTerminalLoopErrorMessage = formattedError ?? errorMessage5;
417579
- runtime.lastTerminalLoopErrorRunId = terminalRunId ?? null;
417580
417748
  break;
417581
417749
  }
417582
417750
  const approvalResult = await handleApprovalStop({
@@ -417600,25 +417768,16 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
417600
417768
  });
417601
417769
  if (approvalResult.kind === "error") {
417602
417770
  const terminalRunId = runId || runtime.activeRunId;
417603
- const transition2 = finishTurn({
417771
+ finishTurn({
417604
417772
  stopReason: "error",
417605
417773
  agentId,
417606
417774
  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
417775
+ error: getTranscriptLoopErrorMessage({ message: approvalResult.message }),
417776
+ errorNotice: {
417777
+ message: approvalResult.message,
417778
+ runId: terminalRunId
417779
+ }
417619
417780
  });
417620
- runtime.lastTerminalLoopErrorMessage = formattedError ?? approvalResult.message;
417621
- runtime.lastTerminalLoopErrorRunId = terminalRunId ?? null;
417622
417781
  return;
417623
417782
  }
417624
417783
  turnInput = approvalResult.turnInput;
@@ -417720,19 +417879,12 @@ async function handleIncomingMessageInner(msg, socket, runtime, onStatusChange,
417720
417879
  stopReason: "error",
417721
417880
  agentId: agentId || null,
417722
417881
  conversationId,
417723
- error: terminalError
417882
+ error: terminalError,
417883
+ errorNotice: { ...noticeParams, runId: terminalRunId }
417724
417884
  });
417725
417885
  if (!transition2.finished) {
417726
417886
  return;
417727
417887
  }
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
417888
  if (isDebugEnabled()) {
417737
417889
  console.error("[Listen] Error handling message:", error4);
417738
417890
  }
@@ -418206,8 +418358,8 @@ function spawnBun(shell, cwd2, cols, rows, terminal_id, connectionId, socket) {
418206
418358
  data: (_t, chunk2) => handleData(new TextDecoder().decode(chunk2))
418207
418359
  }
418208
418360
  });
418209
- const terminal2 = proc.terminal;
418210
- if (!terminal2) {
418361
+ const terminal = proc.terminal;
418362
+ if (!terminal) {
418211
418363
  throw new Error("Bun.spawn terminal object missing — API unavailable");
418212
418364
  }
418213
418365
  proc.exited.then((exitCode) => {
@@ -418224,17 +418376,17 @@ function spawnBun(shell, cwd2, cols, rows, terminal_id, connectionId, socket) {
418224
418376
  return {
418225
418377
  write: (d2) => {
418226
418378
  try {
418227
- terminal2.write(d2);
418379
+ terminal.write(d2);
418228
418380
  } catch {}
418229
418381
  },
418230
418382
  resize: (c, r5) => {
418231
418383
  try {
418232
- terminal2.resize(c, r5);
418384
+ terminal.resize(c, r5);
418233
418385
  } catch {}
418234
418386
  },
418235
418387
  kill: () => {
418236
418388
  try {
418237
- terminal2.close();
418389
+ terminal.close();
418238
418390
  } catch {}
418239
418391
  try {
418240
418392
  proc.kill();
@@ -421601,7 +421753,7 @@ var init_inbound_dispatch = __esm(async () => {
421601
421753
  });
421602
421754
 
421603
421755
  // src/websocket/listener/protocol-logging.ts
421604
- function isRecord13(value) {
421756
+ function isRecord14(value) {
421605
421757
  return typeof value === "object" && value !== null && !Array.isArray(value);
421606
421758
  }
421607
421759
  function formatLogValue(value) {
@@ -421625,14 +421777,14 @@ function pushField(fields, key2, value, label = key2) {
421625
421777
  fields.push(`${label}=${formatted}`);
421626
421778
  }
421627
421779
  function summarizeInputPayload(payload) {
421628
- if (!isRecord13(payload))
421780
+ if (!isRecord14(payload))
421629
421781
  return [];
421630
421782
  const fields = [];
421631
421783
  pushField(fields, "kind", payload.kind);
421632
421784
  if (payload.kind === "create_message") {
421633
421785
  pushField(fields, "messages", payload.messages);
421634
421786
  pushField(fields, "client_tool_allowlist", payload.client_tool_allowlist);
421635
- if (isRecord13(payload.client_toolset)) {
421787
+ if (isRecord14(payload.client_toolset)) {
421636
421788
  pushField(fields, "client_toolset.base", payload.client_toolset.base);
421637
421789
  pushField(fields, "client_toolset.include", payload.client_toolset.include);
421638
421790
  }
@@ -421649,9 +421801,9 @@ function summarizeRuntimeStartCommand(command) {
421649
421801
  const fields = [];
421650
421802
  pushField(fields, "agent_id", command.agent_id, "agent");
421651
421803
  pushField(fields, "conversation_id", command.conversation_id, "conversation");
421652
- if (isRecord13(command.create_agent))
421804
+ if (isRecord14(command.create_agent))
421653
421805
  fields.push("create_agent=true");
421654
- if (isRecord13(command.create_conversation)) {
421806
+ if (isRecord14(command.create_conversation)) {
421655
421807
  fields.push("create_conversation=true");
421656
421808
  }
421657
421809
  pushField(fields, "cwd", command.cwd);
@@ -421660,17 +421812,17 @@ function summarizeRuntimeStartCommand(command) {
421660
421812
  return fields;
421661
421813
  }
421662
421814
  function summarizeV2Command(parsed) {
421663
- if (!isRecord13(parsed) || typeof parsed.type !== "string")
421815
+ if (!isRecord14(parsed) || typeof parsed.type !== "string")
421664
421816
  return "unknown";
421665
421817
  const fields = [];
421666
- const runtime = isRecord13(parsed.runtime) ? parsed.runtime : null;
421818
+ const runtime = isRecord14(parsed.runtime) ? parsed.runtime : null;
421667
421819
  if (runtime) {
421668
421820
  fields.push(`runtime=${runtime.agent_id ?? "<unknown>"}/${runtime.conversation_id ?? "<unknown>"}`);
421669
421821
  }
421670
421822
  pushField(fields, "request_id", parsed.request_id);
421671
421823
  if (parsed.type === "input") {
421672
421824
  fields.push(...summarizeInputPayload(parsed.payload));
421673
- } else if (parsed.type === "change_device_state" && isRecord13(parsed.payload)) {
421825
+ } else if (parsed.type === "change_device_state" && isRecord14(parsed.payload)) {
421674
421826
  pushField(fields, "mode", parsed.payload.mode);
421675
421827
  pushField(fields, "cwd", parsed.payload.cwd);
421676
421828
  pushField(fields, "agent_id", parsed.payload.agent_id);
@@ -421680,7 +421832,7 @@ function summarizeV2Command(parsed) {
421680
421832
  } else if (parsed.type === "runtime_external_tools_update" && Array.isArray(parsed.updates)) {
421681
421833
  fields.push(`updates=${parsed.updates.length}`);
421682
421834
  fields.push(`runtimes=${parsed.updates.reduce((count, update3) => {
421683
- return count + (isRecord13(update3) && Array.isArray(update3.runtimes) ? update3.runtimes.length : 0);
421835
+ return count + (isRecord14(update3) && Array.isArray(update3.runtimes) ? update3.runtimes.length : 0);
421684
421836
  }, 0)}`);
421685
421837
  } else {
421686
421838
  for (const key2 of [
@@ -424539,7 +424691,7 @@ function decodeJwtClaims(token2, sharedSecret) {
424539
424691
  } catch {
424540
424692
  return { error: unauthorized("invalid websocket jwt") };
424541
424693
  }
424542
- if (!isRecord14(header) || header.alg !== "HS256") {
424694
+ if (!isRecord15(header) || header.alg !== "HS256") {
424543
424695
  return { error: unauthorized("invalid websocket jwt") };
424544
424696
  }
424545
424697
  const expectedSignature = createHmac("sha256", sharedSecret).update(`${encodedHeader}.${encodedClaims}`).digest();
@@ -424577,7 +424729,7 @@ function audienceMatches(actual, expectedAudience) {
424577
424729
  return false;
424578
424730
  }
424579
424731
  function isJwtClaims(value) {
424580
- if (!isRecord14(value) || !Number.isSafeInteger(value.exp)) {
424732
+ if (!isRecord15(value) || !Number.isSafeInteger(value.exp)) {
424581
424733
  return false;
424582
424734
  }
424583
424735
  if (value.nbf !== undefined && !Number.isSafeInteger(value.nbf)) {
@@ -424597,7 +424749,7 @@ function isJwtClaims(value) {
424597
424749
  }
424598
424750
  return true;
424599
424751
  }
424600
- function isRecord14(value) {
424752
+ function isRecord15(value) {
424601
424753
  return typeof value === "object" && value !== null && !Array.isArray(value);
424602
424754
  }
424603
424755
  function base64UrlDecode(value) {
@@ -428790,8 +428942,8 @@ function formatError(error4, mapper = (issue2) => issue2.message) {
428790
428942
  let i4 = 0;
428791
428943
  while (i4 < fullpath.length) {
428792
428944
  const el = fullpath[i4];
428793
- const terminal2 = i4 === fullpath.length - 1;
428794
- if (!terminal2) {
428945
+ const terminal = i4 === fullpath.length - 1;
428946
+ if (!terminal) {
428795
428947
  curr[el] = curr[el] || { _errors: [] };
428796
428948
  } else {
428797
428949
  curr[el] = curr[el] || { _errors: [] };
@@ -444692,8 +444844,8 @@ async function connectMcpServer(config2, options = {}) {
444692
444844
  return {
444693
444845
  content: Array.isArray(result3.content) ? result3.content : [],
444694
444846
  ...typeof result3.isError === "boolean" ? { isError: result3.isError } : {},
444695
- ...isRecord15(result3.structuredContent) ? { structuredContent: result3.structuredContent } : {},
444696
- ...isRecord15(result3._meta) ? { _meta: result3._meta } : {}
444847
+ ...isRecord16(result3.structuredContent) ? { structuredContent: result3.structuredContent } : {},
444848
+ ...isRecord16(result3._meta) ? { _meta: result3._meta } : {}
444697
444849
  };
444698
444850
  },
444699
444851
  close: async () => {
@@ -444766,11 +444918,11 @@ function mergeHeaders4(init, headers) {
444766
444918
  };
444767
444919
  }
444768
444920
  function normalizeInputSchema(value) {
444769
- if (isRecord15(value) && value.type === "object")
444921
+ if (isRecord16(value) && value.type === "object")
444770
444922
  return value;
444771
444923
  return { type: "object", properties: {} };
444772
444924
  }
444773
- function isRecord15(value) {
444925
+ function isRecord16(value) {
444774
444926
  return typeof value === "object" && value !== null && !Array.isArray(value);
444775
444927
  }
444776
444928
  var DEFAULT_CLIENT_INFO;
@@ -444782,7 +444934,7 @@ var init_mcp_client = __esm(() => {
444782
444934
  init_streamableHttp();
444783
444935
  DEFAULT_CLIENT_INFO = {
444784
444936
  name: "letta-code",
444785
- version: "0.33.3"
444937
+ version: "0.33.5"
444786
444938
  };
444787
444939
  });
444788
444940
 
@@ -447450,7 +447602,7 @@ import {
447450
447602
  } from "node:fs";
447451
447603
  import { tmpdir as tmpdir12 } from "node:os";
447452
447604
  import path45 from "node:path";
447453
- function isRecord16(value) {
447605
+ function isRecord17(value) {
447454
447606
  return typeof value === "object" && value !== null && !Array.isArray(value);
447455
447607
  }
447456
447608
  function isPathInsideOrEqual2(childPath, parentPath) {
@@ -447466,7 +447618,7 @@ function readPackageJson(packageJsonPath) {
447466
447618
  } catch (error5) {
447467
447619
  throw new Error(`Could not read package.json: ${error5 instanceof Error ? error5.message : String(error5)}`);
447468
447620
  }
447469
- if (!isRecord16(parsed)) {
447621
+ if (!isRecord17(parsed)) {
447470
447622
  throw new Error("package.json must be an object");
447471
447623
  }
447472
447624
  return parsed;
@@ -447476,7 +447628,7 @@ function formatRepository(repository) {
447476
447628
  const trimmed2 = repository.trim();
447477
447629
  return trimmed2 || undefined;
447478
447630
  }
447479
- if (!isRecord16(repository))
447631
+ if (!isRecord17(repository))
447480
447632
  return;
447481
447633
  const url2 = repository.url;
447482
447634
  if (typeof url2 !== "string")
@@ -448006,7 +448158,7 @@ function hasRuntimeDependencies(packageJson) {
448006
448158
  if (!packageJson)
448007
448159
  return false;
448008
448160
  const dependencies4 = packageJson.dependencies;
448009
- return isRecord16(dependencies4) && Object.keys(dependencies4).length > 0;
448161
+ return isRecord17(dependencies4) && Object.keys(dependencies4).length > 0;
448010
448162
  }
448011
448163
  function readPackageJsonIfExists(packageDirectory) {
448012
448164
  const packageJsonPath = path45.join(packageDirectory, "package.json");
@@ -456140,23 +456292,23 @@ class ChannelGateway {
456140
456292
  active.richDraft?.flushPending();
456141
456293
  }
456142
456294
  }
456143
- handleTurnFinished(runtime, terminal2) {
456295
+ handleTurnFinished(runtime, terminal) {
456144
456296
  const state = this.getState(runtime);
456145
456297
  const active = state.active;
456146
456298
  if (!active)
456147
456299
  return;
456148
456300
  state.active = null;
456149
456301
  active.richDraft?.dispose();
456150
- const remainingSources = lifecycleOutcome(terminal2.stopReason) === "completed" ? this.remainingSources(state) : [];
456302
+ const remainingSources = lifecycleOutcome(terminal.stopReason) === "completed" ? this.remainingSources(state) : [];
456151
456303
  this.enqueueHook(state, () => this.hooks.onLifecycle({
456152
456304
  type: "finished",
456153
456305
  batchId: active.batchId,
456154
456306
  sources: active.lifecycleSources,
456155
- outcome: lifecycleOutcome(terminal2.stopReason),
456156
- stopReason: terminal2.stopReason,
456307
+ outcome: lifecycleOutcome(terminal.stopReason),
456308
+ stopReason: terminal.stopReason,
456157
456309
  ...remainingSources.length ? { remainingSources } : {},
456158
- ...terminal2.runId ?? active.runId ? { runId: terminal2.runId ?? active.runId } : {},
456159
- ...terminal2.error ? { error: terminal2.error } : {}
456310
+ ...terminal.runId ?? active.runId ? { runId: terminal.runId ?? active.runId } : {},
456311
+ ...terminal.error ? { error: terminal.error } : {}
456160
456312
  }));
456161
456313
  }
456162
456314
  handleControlRequest(message) {
@@ -458967,6 +459119,95 @@ var init_local_backend_mod_events = __esm(() => {
458967
459119
  init_local_backend();
458968
459120
  });
458969
459121
 
459122
+ // src/headless-enqueue-wait.ts
459123
+ function getSendRunIds(status, clientMessageId) {
459124
+ return Object.entries(status?.runtime_status?.loop_state?.client_message_ids_by_run_id ?? {}).filter(([, ids]) => ids.includes(clientMessageId)).map(([runId]) => runId);
459125
+ }
459126
+ function getConversationStatus(event, conversationId) {
459127
+ if (event.type === "conversation_super_run_snapshot") {
459128
+ return event.statuses.find((status) => status.conversation_id === conversationId) ?? null;
459129
+ }
459130
+ return event.conversation_id === conversationId ? event.status : undefined;
459131
+ }
459132
+ async function waitForEnqueuedReply(params) {
459133
+ const runIds = new Set;
459134
+ const now2 = params.now ?? Date.now;
459135
+ let completedWithoutText;
459136
+ let next = Promise.resolve({
459137
+ done: false,
459138
+ value: params.firstEvent
459139
+ });
459140
+ try {
459141
+ while (true) {
459142
+ params.signal.throwIfAborted();
459143
+ let timer;
459144
+ const event = await Promise.race([
459145
+ next,
459146
+ new Promise((resolve42) => {
459147
+ timer = setTimeout(() => resolve42(null), params.pollMs ?? 1000);
459148
+ })
459149
+ ]).finally(() => clearTimeout(timer));
459150
+ if (event) {
459151
+ if (event.done)
459152
+ throw new Error("Conversation status connection closed; remote execution may still be running.");
459153
+ const status = getConversationStatus(event.value, params.receipt.conversation_id);
459154
+ if (status !== undefined) {
459155
+ for (const runId2 of getSendRunIds(status, params.receipt.client_message_id))
459156
+ runIds.add(runId2);
459157
+ }
459158
+ next = params.events.next();
459159
+ next.catch(() => {});
459160
+ }
459161
+ const runId = [...runIds].at(-1);
459162
+ if (!runId) {
459163
+ const latest = await params.latestSuperRun();
459164
+ if (latest?.id === params.receipt.super_run_id && (latest.errored_at || latest.cancelled_at)) {
459165
+ throw new Error(`Accepted send ${latest.id} ${latest.errored_at ? "failed" : "was cancelled"} before a run was observed.`);
459166
+ }
459167
+ continue;
459168
+ }
459169
+ const run = await params.retrieveRun(runId);
459170
+ if (run.status === "failed" || run.status === "cancelled") {
459171
+ throw new Error(`Remote run ${runId} ${run.status}${run.stop_reason ? ` (${run.stop_reason})` : ""}`);
459172
+ }
459173
+ if (run.status !== "completed" || run.stop_reason === "requires_approval")
459174
+ continue;
459175
+ const messages = await params.listRunMessages(runId);
459176
+ const assistant = messages.filter((message) => message.message_type === "assistant_message").sort((a2, b3) => (b3.seq_id ?? 0) - (a2.seq_id ?? 0))[0];
459177
+ if (assistant?.message_type === "assistant_message") {
459178
+ const text2 = typeof assistant.content === "string" ? assistant.content : assistant.content.filter((part) => part.type === "text").map((part) => part.text).join(`
459179
+ `);
459180
+ if (text2.trim())
459181
+ return {
459182
+ text: text2,
459183
+ runIds: [...runIds],
459184
+ stopReason: run.stop_reason ?? null
459185
+ };
459186
+ }
459187
+ if (completedWithoutText?.runId !== runId)
459188
+ completedWithoutText = { runId, at: now2() };
459189
+ if (now2() - completedWithoutText.at < 15000)
459190
+ continue;
459191
+ throw new Error(`Remote run ${runId} completed without an assistant reply (${run.stop_reason ?? "unknown stop reason"})`);
459192
+ }
459193
+ } catch (error5) {
459194
+ throw new EnqueuedWaitError(error5, [...runIds]);
459195
+ }
459196
+ }
459197
+ var EnqueuedWaitError;
459198
+ var init_headless_enqueue_wait = __esm(() => {
459199
+ EnqueuedWaitError = class EnqueuedWaitError extends Error {
459200
+ runIds;
459201
+ constructor(error5, runIds) {
459202
+ super(error5 instanceof Error ? error5.message : String(error5), {
459203
+ cause: error5
459204
+ });
459205
+ this.runIds = runIds;
459206
+ this.name = "EnqueuedWaitError";
459207
+ }
459208
+ };
459209
+ });
459210
+
458970
459211
  // src/headless-cloud-send.ts
458971
459212
  import { randomUUID as randomUUID48 } from "node:crypto";
458972
459213
  function shouldEnqueueCloudSend(values4, cloud, isAgentLaunch) {
@@ -465672,14 +465913,14 @@ function detectTerminalType() {
465672
465913
  function isVSCodeLikeTerminal() {
465673
465914
  return detectTerminalType() !== null;
465674
465915
  }
465675
- function getKeybindingsPath(terminal2) {
465676
- if (!terminal2)
465916
+ function getKeybindingsPath(terminal) {
465917
+ if (!terminal)
465677
465918
  return null;
465678
465919
  const appName = {
465679
465920
  vscode: "Code",
465680
465921
  cursor: "Cursor",
465681
465922
  windsurf: "Windsurf"
465682
- }[terminal2];
465923
+ }[terminal];
465683
465924
  const os9 = platform10();
465684
465925
  if (os9 === "darwin") {
465685
465926
  return join96(homedir52(), "Library", "Application Support", appName, "User", "keybindings.json");
@@ -465802,35 +466043,35 @@ function removeKeybinding(keybindingsPath) {
465802
466043
  }
465803
466044
  }
465804
466045
  function installKeybindingForCurrentTerminal() {
465805
- const terminal2 = detectTerminalType();
465806
- if (!terminal2) {
466046
+ const terminal = detectTerminalType();
466047
+ if (!terminal) {
465807
466048
  return {
465808
466049
  success: false,
465809
466050
  error: "Not running in a VS Code-like terminal"
465810
466051
  };
465811
466052
  }
465812
- const path48 = getKeybindingsPath(terminal2);
466053
+ const path48 = getKeybindingsPath(terminal);
465813
466054
  if (!path48) {
465814
466055
  return {
465815
466056
  success: false,
465816
- error: `Could not determine keybindings.json path for ${terminal2}`
466057
+ error: `Could not determine keybindings.json path for ${terminal}`
465817
466058
  };
465818
466059
  }
465819
466060
  return installKeybinding(path48);
465820
466061
  }
465821
466062
  function removeKeybindingForCurrentTerminal() {
465822
- const terminal2 = detectTerminalType();
465823
- if (!terminal2) {
466063
+ const terminal = detectTerminalType();
466064
+ if (!terminal) {
465824
466065
  return {
465825
466066
  success: false,
465826
466067
  error: "Not running in a VS Code-like terminal"
465827
466068
  };
465828
466069
  }
465829
- const path48 = getKeybindingsPath(terminal2);
466070
+ const path48 = getKeybindingsPath(terminal);
465830
466071
  if (!path48) {
465831
466072
  return {
465832
466073
  success: false,
465833
- error: `Could not determine keybindings.json path for ${terminal2}`
466074
+ error: `Could not determine keybindings.json path for ${terminal}`
465834
466075
  };
465835
466076
  }
465836
466077
  return removeKeybinding(path48);
@@ -466582,16 +466823,16 @@ var init_registry2 = __esm(() => {
466582
466823
  } = await Promise.resolve().then(() => (init_terminal_keybinding_installer(), exports_terminal_keybinding_installer));
466583
466824
  const { updateSettings: updateSettings2 } = await Promise.resolve().then(() => (init_settings4(), exports_settings2));
466584
466825
  const isRevert = args.includes("--revert") || args.includes("--remove");
466585
- const terminal2 = detectTerminalType2();
466586
- if (!terminal2) {
466826
+ const terminal = detectTerminalType2();
466827
+ if (!terminal) {
466587
466828
  return "Not running in a VS Code-like terminal. Shift+Enter keybinding is not needed.";
466588
466829
  }
466589
466830
  const terminalName = {
466590
466831
  vscode: "VS Code",
466591
466832
  cursor: "Cursor",
466592
466833
  windsurf: "Windsurf"
466593
- }[terminal2];
466594
- const keybindingsPath = getKeybindingsPath2(terminal2);
466834
+ }[terminal];
466835
+ const keybindingsPath = getKeybindingsPath2(terminal);
466595
466836
  if (!keybindingsPath) {
466596
466837
  return `Could not determine keybindings.json path for ${terminalName}`;
466597
466838
  }
@@ -508893,13 +509134,13 @@ Error: ${message}`);
508893
509134
  installKeybinding: installKeybinding2
508894
509135
  } = await Promise.resolve().then(() => (init_terminal_keybinding_installer(), exports_terminal_keybinding_installer));
508895
509136
  const { loadSettings: loadSettings2, updateSettings: updateSettings2 } = await Promise.resolve().then(() => (init_settings4(), exports_settings2));
508896
- const terminal2 = detectTerminalType2();
508897
- if (!terminal2) {
509137
+ const terminal = detectTerminalType2();
509138
+ if (!terminal) {
508898
509139
  setShowKeybindingSetup(false);
508899
509140
  return;
508900
509141
  }
508901
509142
  const settings4 = await loadSettings2();
508902
- const keybindingsPath = getKeybindingsPath2(terminal2);
509143
+ const keybindingsPath = getKeybindingsPath2(terminal);
508903
509144
  if (!keybindingsPath || settings4.shiftEnterKeybindingInstalled) {
508904
509145
  setShowKeybindingSetup(false);
508905
509146
  return;
@@ -512015,4 +512256,4 @@ function registerBunOAuthFlows() {
512015
512256
  registerBunOAuthFlows();
512016
512257
  await init_src5().then(() => exports_src2);
512017
512258
 
512018
- //# debugId=F0EE3697E822655164756E2164756E21
512259
+ //# debugId=4BF692CA3D7D262964756E2164756E21