@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.
- package/dist/mcp-client.js +2 -2
- package/dist/mcp-client.js.map +1 -1
- package/dist/types/agent/subagent-state.d.ts +5 -1
- package/dist/types/agent/subagent-state.d.ts.map +1 -1
- package/dist/types/agent/subagents/child-send-tracking.d.ts +1 -1
- package/dist/types/agent/subagents/child-send-tracking.d.ts.map +1 -1
- package/dist/types/agent/subagents/names.d.ts +1 -1
- package/dist/types/agent/subagents/names.d.ts.map +1 -1
- package/dist/types/agent/subagents/remote-turn-wait.d.ts.map +1 -1
- package/dist/types/backend/api/conversation-enqueue.d.ts +10 -0
- package/dist/types/backend/api/conversation-enqueue.d.ts.map +1 -1
- package/dist/types/headless-super-run-wait.d.ts +7 -11
- package/dist/types/headless-super-run-wait.d.ts.map +1 -1
- package/dist/types/tools/impl/workflow.d.ts.map +1 -1
- package/dist/types/tools/workflow/decide.d.ts +32 -0
- package/dist/types/tools/workflow/decide.d.ts.map +1 -0
- package/dist/types/tools/workflow/execution-registry.d.ts.map +1 -1
- package/dist/types/tools/workflow/journal.d.ts +15 -2
- package/dist/types/tools/workflow/journal.d.ts.map +1 -1
- package/dist/types/tools/workflow/sdk-loader.d.ts +3 -0
- package/dist/types/tools/workflow/sdk-loader.d.ts.map +1 -1
- package/dist/types/tools/workflow/sdk-spawner.d.ts +17 -0
- package/dist/types/tools/workflow/sdk-spawner.d.ts.map +1 -1
- package/dist/types/tools/workflow/types.d.ts +13 -3
- package/dist/types/tools/workflow/types.d.ts.map +1 -1
- package/dist/types/tools/workflow/workflow-engine.d.ts +1 -1
- package/dist/types/tools/workflow/workflow-engine.d.ts.map +1 -1
- package/dist/types/types/loop-status-protocol.d.ts +31 -0
- package/dist/types/types/loop-status-protocol.d.ts.map +1 -1
- package/dist/types/types/protocol_v2.d.ts +3 -29
- package/dist/types/types/protocol_v2.d.ts.map +1 -1
- package/dist/types/websocket/listener/outbound-wire.d.ts.map +1 -1
- package/dist/types/websocket/listener/protocol-outbound.d.ts +0 -10
- package/dist/types/websocket/listener/protocol-outbound.d.ts.map +1 -1
- package/dist/types/websocket/listener/turn-correlation.d.ts +1 -0
- package/dist/types/websocket/listener/turn-correlation.d.ts.map +1 -1
- package/letta.js +630 -389
- package/package.json +2 -2
- package/scripts/source-file-size-baseline.json +3 -4
- 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.
|
|
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": "
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
203042
|
-
description: 'Review
|
|
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
|
|
203046
|
-
const
|
|
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
|
-
|
|
203050
|
-
|
|
203051
|
-
review => review
|
|
203052
|
-
agent(\`
|
|
203053
|
-
.then(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
|
|
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
|
-
|
|
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-
|
|
212193
|
-
|
|
212194
|
-
|
|
212195
|
-
|
|
212196
|
-
|
|
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
|
|
212182
|
+
return error4 instanceof TypeError || error4 instanceof Error && error4.name === "TimeoutError";
|
|
212201
212183
|
}
|
|
212202
|
-
async function
|
|
212203
|
-
|
|
212204
|
-
|
|
212205
|
-
|
|
212206
|
-
|
|
212207
|
-
|
|
212208
|
-
|
|
212209
|
-
|
|
212210
|
-
|
|
212211
|
-
|
|
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
|
-
|
|
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
|
-
|
|
212268
|
-
|
|
212269
|
-
|
|
212270
|
-
|
|
212271
|
-
|
|
212272
|
-
|
|
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
|
-
|
|
212287
|
-
|
|
212288
|
-
|
|
212289
|
-
|
|
212290
|
-
|
|
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
|
|
212294
|
-
|
|
212295
|
-
|
|
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
|
|
212299
|
-
|
|
212300
|
-
|
|
212301
|
-
|
|
212302
|
-
|
|
212303
|
-
|
|
212304
|
-
|
|
212305
|
-
|
|
212306
|
-
|
|
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
|
-
|
|
212363
|
-
|
|
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
|
-
|
|
212374
|
-
|
|
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
|
-
|
|
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
|
-
|
|
212431
|
-
|
|
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.
|
|
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
|
-
|
|
216514
|
-
|
|
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
|
|
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
|
-
|
|
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 ??
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
221091
|
+
const outcome = { value: turn.finalText, failed: false, ...stats };
|
|
221092
|
+
return outcome;
|
|
221118
221093
|
} catch (error4) {
|
|
221119
|
-
|
|
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
|
|
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-
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (
|
|
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
|
|
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 (!
|
|
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
|
-
|
|
402733
|
+
emitCanonicalMessageDelta(socket, runtime, {
|
|
402734
|
+
...createLifecycleMessageBase("loop_error", params.runId),
|
|
402566
402735
|
message: decision.message,
|
|
402567
|
-
|
|
402568
|
-
|
|
402569
|
-
|
|
402570
|
-
|
|
402571
|
-
|
|
402572
|
-
|
|
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
|
|
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 (!
|
|
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
|
-
|
|
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
|
-
|
|
417193
|
-
|
|
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
|
-
|
|
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
|
-
|
|
417771
|
+
finishTurn({
|
|
417604
417772
|
stopReason: "error",
|
|
417605
417773
|
agentId,
|
|
417606
417774
|
conversationId,
|
|
417607
|
-
error: getTranscriptLoopErrorMessage({ message: approvalResult.message })
|
|
417608
|
-
|
|
417609
|
-
|
|
417610
|
-
|
|
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
|
|
418210
|
-
if (!
|
|
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
|
-
|
|
418379
|
+
terminal.write(d2);
|
|
418228
418380
|
} catch {}
|
|
418229
418381
|
},
|
|
418230
418382
|
resize: (c, r5) => {
|
|
418231
418383
|
try {
|
|
418232
|
-
|
|
418384
|
+
terminal.resize(c, r5);
|
|
418233
418385
|
} catch {}
|
|
418234
418386
|
},
|
|
418235
418387
|
kill: () => {
|
|
418236
418388
|
try {
|
|
418237
|
-
|
|
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
|
|
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 (!
|
|
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 (
|
|
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 (
|
|
421804
|
+
if (isRecord14(command.create_agent))
|
|
421653
421805
|
fields.push("create_agent=true");
|
|
421654
|
-
if (
|
|
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 (!
|
|
421815
|
+
if (!isRecord14(parsed) || typeof parsed.type !== "string")
|
|
421664
421816
|
return "unknown";
|
|
421665
421817
|
const fields = [];
|
|
421666
|
-
const runtime =
|
|
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" &&
|
|
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 + (
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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
|
|
428794
|
-
if (!
|
|
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
|
-
...
|
|
444696
|
-
...
|
|
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 (
|
|
444921
|
+
if (isRecord16(value) && value.type === "object")
|
|
444770
444922
|
return value;
|
|
444771
444923
|
return { type: "object", properties: {} };
|
|
444772
444924
|
}
|
|
444773
|
-
function
|
|
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.
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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,
|
|
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(
|
|
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(
|
|
456156
|
-
stopReason:
|
|
456307
|
+
outcome: lifecycleOutcome(terminal.stopReason),
|
|
456308
|
+
stopReason: terminal.stopReason,
|
|
456157
456309
|
...remainingSources.length ? { remainingSources } : {},
|
|
456158
|
-
...
|
|
456159
|
-
...
|
|
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(
|
|
465676
|
-
if (!
|
|
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
|
-
}[
|
|
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
|
|
465806
|
-
if (!
|
|
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(
|
|
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 ${
|
|
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
|
|
465823
|
-
if (!
|
|
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(
|
|
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 ${
|
|
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
|
|
466586
|
-
if (!
|
|
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
|
-
}[
|
|
466594
|
-
const keybindingsPath = getKeybindingsPath2(
|
|
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
|
|
508897
|
-
if (!
|
|
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(
|
|
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=
|
|
512259
|
+
//# debugId=4BF692CA3D7D262964756E2164756E21
|