openfox 2.0.113 → 2.0.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/CHANGELOG.md +43 -0
  3. package/dist/agent-defaults/builder.agent.md +1 -0
  4. package/dist/agent-defaults/planner.agent.md +1 -0
  5. package/dist/{backend-P3GHHLHJ.js → backend-LVYHLGQJ.js} +2 -2
  6. package/dist/{chat-handler-PEK5JDHO.js → chat-handler-5SP265CR.js} +32 -26
  7. package/dist/{chunk-HKD4IMOE.js → chunk-27NABDXB.js} +2 -2
  8. package/dist/{chunk-FF2EKUQO.js → chunk-2FCLCUVR.js} +6 -6
  9. package/dist/{chunk-ONONXV3N.js → chunk-37QLXLML.js} +4 -4
  10. package/dist/{chunk-YB6WYVNY.js → chunk-3KBRMBTP.js} +2 -2
  11. package/dist/{chunk-YGPPFVLJ.js → chunk-3NPLERPQ.js} +17 -17
  12. package/dist/{chunk-XQR76MQ5.js → chunk-3PG65AXG.js} +18 -3
  13. package/dist/chunk-3QQAIUZI.js +957 -0
  14. package/dist/{chunk-PWXBIUEY.js → chunk-5PT4UMRR.js} +89 -1
  15. package/dist/chunk-5V3BF67X.js +7 -0
  16. package/dist/{chunk-6UPBZ2ZR.js → chunk-6KPJLELC.js} +4 -4
  17. package/dist/chunk-6RGACY4E.js +1081 -0
  18. package/dist/{chunk-BNFGDTEU.js → chunk-AESOGRFK.js} +2 -2
  19. package/dist/{chunk-YHEQTVFV.js → chunk-AZHWLLPP.js} +1 -1
  20. package/dist/{chunk-TCGWZBTS.js → chunk-BVVCRIVM.js} +4 -4
  21. package/dist/{chunk-EMI3YYLP.js → chunk-BWVO5WFK.js} +4 -4
  22. package/dist/{chunk-CP44U7BT.js → chunk-ERNWAKUB.js} +7 -7
  23. package/dist/{chunk-WWTYWLDM.js → chunk-HD6Y77RO.js} +2 -2
  24. package/dist/{chunk-4NMGX5F2.js → chunk-I7FY2LTR.js} +2 -2
  25. package/dist/{chunk-5VYSKVZT.js → chunk-JFK4GKQD.js} +321 -54
  26. package/dist/{chunk-43M7QZMX.js → chunk-JGWHRYWG.js} +4 -4
  27. package/dist/{chunk-Y64PEWKP.js → chunk-JLAR2CMV.js} +2 -2
  28. package/dist/{chunk-BYSUSSSC.js → chunk-LNNBLB6G.js} +48 -151
  29. package/dist/{chunk-V4664YKR.js → chunk-LTYL6ZGH.js} +2 -2
  30. package/dist/{chunk-R2MTWC7C.js → chunk-M6X6AIEG.js} +6 -4
  31. package/dist/{chunk-VGRVPYZ5.js → chunk-O6DU226D.js} +2 -2
  32. package/dist/{chunk-TEQEDOWI.js → chunk-OCBBAEMT.js} +288 -316
  33. package/dist/{chunk-SNLLOXCM.js → chunk-OCSTEGK7.js} +3 -3
  34. package/dist/{chunk-HGOTZWON.js → chunk-OKVHMKE2.js} +60 -1064
  35. package/dist/chunk-OSXPQSLW.js +128 -0
  36. package/dist/{chunk-O2YSYW2F.js → chunk-TFF5T3K3.js} +10 -10
  37. package/dist/{chunk-3R43CMLS.js → chunk-TGLVWAFC.js} +11 -11
  38. package/dist/{chunk-L737Y63F.js → chunk-TOKQ2UVG.js} +2 -2
  39. package/dist/{chunk-AZFZE36I.js → chunk-VWEATA7R.js} +18 -8
  40. package/dist/{chunk-BKCW3JLL.js → chunk-X25Q6RAV.js} +1 -1
  41. package/dist/{chunk-JR54MDZI.js → chunk-YX3OQBNX.js} +3 -3
  42. package/dist/{chunk-EC5T5A6O.js → chunk-ZTOG6LJD.js} +3 -3
  43. package/dist/cli/dev.js +1 -1
  44. package/dist/cli/index.js +1 -1
  45. package/dist/client-KE7EDI2D.js +16 -0
  46. package/dist/{client-pure-VFZIIK4S.js → client-pure-66Z6FWS6.js} +2 -2
  47. package/dist/command-defaults/mark-done.command.md +14 -0
  48. package/dist/compactor-SKVC2VNL.js +32 -0
  49. package/dist/{dynamic-context-F2XTQJR5.js → dynamic-context-QNB4ELLP.js} +10 -9
  50. package/dist/{events-224IO5NJ.js → events-5PLO4QJU.js} +9 -7
  51. package/dist/{folding-YTTTVS56.js → folding-CJWYFUKD.js} +7 -5
  52. package/dist/http-client-KLODRQC2.js +11 -0
  53. package/dist/{inspect-proxy-B7LGGTM7.js → inspect-proxy-K6QKEYDT.js} +4 -4
  54. package/dist/launch-EOXVWLOP.js +52 -0
  55. package/dist/{manager-4QGXI6WZ.js → manager-LZ3JQ443.js} +5 -5
  56. package/dist/{model-overrides-OY2YKUNV.js → model-overrides-5UVW3KTE.js} +4 -4
  57. package/dist/orchestrator-ED3KFPXO.js +63 -0
  58. package/dist/package.json +3 -3
  59. package/dist/{path-security-PFMZY7IA.js → path-security-B6EZC63L.js} +13 -11
  60. package/dist/{platform-QNGCKX4L.js → platform-6RPPBHKH.js} +4 -4
  61. package/dist/{processor-NYPJ5PFA.js → processor-226ZOTRI.js} +31 -25
  62. package/dist/{project-creator-AWP2JUFS.js → project-creator-VBFE35NI.js} +3 -3
  63. package/dist/{projects-C4353IQK.js → projects-AXHZOBR2.js} +5 -3
  64. package/dist/{protocol-CBT1d98i.d.ts → protocol-JdxRpPxM.d.ts} +21 -3
  65. package/dist/{protocol-LZZ7C4VQ.js → protocol-RKSWKNXI.js} +3 -3
  66. package/dist/provider/index.d.ts +4 -4
  67. package/dist/{provider-PIRPN2CC.js → provider-DL4ZWQY7.js} +8 -8
  68. package/dist/{provider-manager-GNEPR6UN.js → provider-manager-6CLRMGDE.js} +8 -8
  69. package/dist/{registry-VCKDSVKA.js → registry-5XI5NDBF.js} +6 -4
  70. package/dist/{serve-6DRHQLCG.js → serve-DARV4NJG.js} +36 -33
  71. package/dist/server/index.d.ts +13 -6
  72. package/dist/server/index.js +35 -32
  73. package/dist/server-LQJ7MBDS.js +55 -0
  74. package/dist/service-4JKTGPRG.js +25 -0
  75. package/dist/{session-overrides-RNKV35MU.js → session-overrides-AZKV6BRD.js} +8 -6
  76. package/dist/{sessions-D5CEPQGU.js → sessions-752IZIIK.js} +7 -5
  77. package/dist/{settings-BNRNX6IW.js → settings-2AHDKCD7.js} +3 -3
  78. package/dist/shared/index.d.ts +3 -3
  79. package/dist/shared/index.js +1 -1
  80. package/dist/skill-defaults/workflows/SKILL.md +24 -6
  81. package/dist/tasks-XJXHU623.js +217 -0
  82. package/dist/{tools-2B363F7L.js → tools-QYYNFMGU.js} +31 -23
  83. package/dist/{types-cVfqOj6M.d.ts → types-CIVhQMvD.d.ts} +1 -1
  84. package/dist/{types-BAxh20ZL.d.ts → types-Df7NM9b5.d.ts} +76 -1
  85. package/dist/{update-IQMRYN7J.js → update-2REP2WB6.js} +2 -2
  86. package/dist/web/assets/{index-CjWC6EQ4.css → index-BmILAZrT.css} +1 -1
  87. package/dist/web/assets/index-M7ToECa4.js +324 -0
  88. package/dist/web/index.html +2 -2
  89. package/dist/web/sw.js +1 -1
  90. package/dist/workflow-defaults/default.workflow.json +5 -3
  91. package/dist/{workspace-YUNHV4WS.js → workspace-RMZVTFJD.js} +4 -4
  92. package/package.json +3 -3
  93. package/dist/chunk-B2PHPBFU.js +0 -7
  94. package/dist/client-3LJGD6KY.js +0 -16
  95. package/dist/compactor-ZBNKANHV.js +0 -30
  96. package/dist/http-client-YC3UA5OZ.js +0 -11
  97. package/dist/orchestrator-JKBY7B3P.js +0 -57
  98. package/dist/server-HUHFJW7U.js +0 -48
  99. package/dist/web/assets/index-DBUtUSHK.js +0 -323
@@ -0,0 +1,957 @@
1
+ import {
2
+ runAgentTurn
3
+ } from "./chunk-3NPLERPQ.js";
4
+ import {
5
+ executeSubAgent,
6
+ getToolRegistryForAgent
7
+ } from "./chunk-JFK4GKQD.js";
8
+ import {
9
+ TurnMetrics,
10
+ createMessageStartEvent
11
+ } from "./chunk-YX3OQBNX.js";
12
+ import {
13
+ checkAborted,
14
+ decodeUtf8,
15
+ spawnShellProcess
16
+ } from "./chunk-ZTOG6LJD.js";
17
+ import {
18
+ terminateProcessTree
19
+ } from "./chunk-I72ACQ6R.js";
20
+ import {
21
+ gitSpawnEnv
22
+ } from "./chunk-J7GAZGZT.js";
23
+ import {
24
+ findWorkflowById,
25
+ loadAllWorkflows,
26
+ loadDefaultWorkflows,
27
+ loadProjectWorkflows,
28
+ loadUserWorkflows,
29
+ normalizeWorkflowScope
30
+ } from "./chunk-6RGACY4E.js";
31
+ import {
32
+ getCurrentContextWindowId,
33
+ getEventStore
34
+ } from "./chunk-ERNWAKUB.js";
35
+ import {
36
+ createChatMessageMessage,
37
+ createSessionRunningMessage
38
+ } from "./chunk-I7FY2LTR.js";
39
+ import {
40
+ findAgentById,
41
+ getRuntimeConfig,
42
+ loadAllAgentsDefault,
43
+ resolveDefaultAgentId
44
+ } from "./chunk-LNNBLB6G.js";
45
+ import {
46
+ logger
47
+ } from "./chunk-K44MW7JJ.js";
48
+ import {
49
+ computeSessionStats
50
+ } from "./chunk-VUQCQXXJ.js";
51
+ import {
52
+ createServerMessage
53
+ } from "./chunk-X25Q6RAV.js";
54
+ import {
55
+ getGlobalConfigDir
56
+ } from "./chunk-CQGTEGKL.js";
57
+
58
+ // src/server/workflows/types.ts
59
+ var TERMINAL_DONE = "$done";
60
+ var TERMINAL_BLOCKED = "$blocked";
61
+
62
+ // src/server/git/diff.ts
63
+ import { spawn } from "child_process";
64
+ function getGitDiffFiles(cwd) {
65
+ return new Promise((resolve) => {
66
+ const env = gitSpawnEnv();
67
+ const diffProc = spawn("git", ["diff", "--name-status", "HEAD"], {
68
+ cwd,
69
+ env,
70
+ stdio: ["ignore", "pipe", "pipe"],
71
+ windowsHide: true
72
+ });
73
+ const statusProc = spawn("git", ["status", "--porcelain"], {
74
+ cwd,
75
+ env,
76
+ stdio: ["ignore", "pipe", "pipe"],
77
+ windowsHide: true
78
+ });
79
+ let diffStdout = "";
80
+ let statusStdout = "";
81
+ let diffExited = false;
82
+ let statusExited = false;
83
+ let diffCode = null;
84
+ let statusCode = null;
85
+ const collect = () => {
86
+ if (!diffExited || !statusExited) return;
87
+ const files = [];
88
+ if (diffCode === 0) {
89
+ for (const line of diffStdout.split("\n")) {
90
+ if (!line.trim()) continue;
91
+ const [statusChar, ...pathParts] = line.split(" ");
92
+ const path = pathParts.join(" ") || statusChar || "";
93
+ if (!path) continue;
94
+ const status = statusChar === "A" ? "added" : statusChar === "D" ? "deleted" : "modified";
95
+ files.push({ path, status, additions: 0, deletions: 0 });
96
+ }
97
+ }
98
+ if (statusCode === 0) {
99
+ for (const line of statusStdout.split("\n")) {
100
+ if (!line.startsWith("?? ")) continue;
101
+ const path = line.slice(3).trim();
102
+ if (!path) continue;
103
+ files.push({ path, status: "added", additions: 0, deletions: 0 });
104
+ }
105
+ }
106
+ resolve(files);
107
+ };
108
+ diffProc.stdout.on("data", (data) => {
109
+ diffStdout += data.toString();
110
+ });
111
+ statusProc.stdout.on("data", (data) => {
112
+ statusStdout += data.toString();
113
+ });
114
+ diffProc.on("close", (code) => {
115
+ diffExited = true;
116
+ diffCode = code;
117
+ collect();
118
+ });
119
+ statusProc.on("close", (code) => {
120
+ statusExited = true;
121
+ statusCode = code;
122
+ collect();
123
+ });
124
+ diffProc.on("error", () => {
125
+ diffExited = true;
126
+ diffCode = 1;
127
+ collect();
128
+ });
129
+ statusProc.on("error", () => {
130
+ statusExited = true;
131
+ statusCode = 1;
132
+ collect();
133
+ });
134
+ });
135
+ }
136
+ async function formatGitDiffFiles(cwd) {
137
+ const files = await getGitDiffFiles(cwd);
138
+ if (files.length === 0) return "(none)";
139
+ return files.map((f) => `- ${f.path} (${f.status})`).join("\n");
140
+ }
141
+
142
+ // src/server/workflows/shell.ts
143
+ function executeShellCommand(command, cwd, timeout, signal) {
144
+ return new Promise((resolve, reject) => {
145
+ if (checkAborted(signal)) {
146
+ reject(new Error("Aborted"));
147
+ return;
148
+ }
149
+ const proc = spawnShellProcess(command, cwd, signal);
150
+ const stdoutChunks = [];
151
+ const stderrChunks = [];
152
+ let killed = false;
153
+ const timer = setTimeout(() => {
154
+ killed = true;
155
+ void terminateProcessTree(proc);
156
+ resolve({
157
+ exitCode: 1,
158
+ stdout: decodeUtf8(stdoutChunks),
159
+ stderr: decodeUtf8(stderrChunks) + "\nCommand timed out",
160
+ success: false
161
+ });
162
+ }, timeout);
163
+ const onAbort = () => {
164
+ if (!killed) {
165
+ killed = true;
166
+ void terminateProcessTree(proc, { immediate: true });
167
+ clearTimeout(timer);
168
+ reject(new Error("Aborted"));
169
+ }
170
+ };
171
+ signal?.addEventListener("abort", onAbort);
172
+ proc.stdout?.on("data", (data) => {
173
+ stdoutChunks.push(data);
174
+ });
175
+ proc.stderr?.on("data", (data) => {
176
+ stderrChunks.push(data);
177
+ });
178
+ proc.on("close", (code) => {
179
+ clearTimeout(timer);
180
+ signal?.removeEventListener("abort", onAbort);
181
+ if (killed) return;
182
+ const exitCode = code ?? 1;
183
+ resolve({
184
+ exitCode,
185
+ stdout: decodeUtf8(stdoutChunks),
186
+ stderr: decodeUtf8(stderrChunks),
187
+ success: exitCode === 0
188
+ });
189
+ });
190
+ proc.on("error", (err) => {
191
+ clearTimeout(timer);
192
+ signal?.removeEventListener("abort", onAbort);
193
+ if (killed) return;
194
+ resolve({ exitCode: 1, stdout: decodeUtf8(stdoutChunks), stderr: err.message, success: false });
195
+ });
196
+ });
197
+ }
198
+
199
+ // src/server/workflows/executor.ts
200
+ var TEMPLATE_VARIABLES = [
201
+ { name: "workdir", description: "Working directory of the session" },
202
+ { name: "reason", description: 'Human-readable reason (e.g. "2 criteria remaining")' },
203
+ {
204
+ name: "stepOutput",
205
+ description: "Structured output from the previous step (content, stdout, stderr, exitCode, etc.)"
206
+ },
207
+ {
208
+ name: "verifierFindings",
209
+ description: "@deprecated Use stepOutput.content instead. Output from the last sub-agent step"
210
+ },
211
+ {
212
+ name: "previousStepOutput",
213
+ description: "@deprecated Use stepOutput.stdout instead. Output from the last shell step"
214
+ },
215
+ { name: "criteriaCount", description: "Total number of criteria" },
216
+ { name: "pendingCount", description: "Number of pending/failed criteria" },
217
+ { name: "criteriaList", description: "Formatted list of all criteria with status" },
218
+ { name: "modifiedFiles", description: "List of modified files" }
219
+ ];
220
+ function formatCriteriaList(entries) {
221
+ if (entries.length === 0) return "(none)";
222
+ return entries.map((e) => {
223
+ const status = e.status === "passed" ? "[PASSED]" : e.status === "completed" ? "[NEEDS VERIFICATION]" : e.status === "failed" ? "[FAILED]" : "[NOT COMPLETED]";
224
+ return `- **${e.id}** ${status}: ${e.description}`;
225
+ }).join("\n");
226
+ }
227
+ async function formatModifiedFiles(workdir) {
228
+ return formatGitDiffFiles(workdir);
229
+ }
230
+ function resolveTemplate(template, ctx) {
231
+ let result = template;
232
+ for (const { name } of TEMPLATE_VARIABLES) {
233
+ if (name === "stepOutput" || name === "verifierFindings" || name === "previousStepOutput") continue;
234
+ const value = String(ctx[name]);
235
+ result = result.replace(new RegExp(`\\{\\{${name}\\}\\}`, "g"), value);
236
+ }
237
+ result = result.replace(/\{\{stepOutput\.(\w+)\}\}/g, (_, key) => ctx.stepOutput[key] ?? "");
238
+ result = result.replace(/\{\{verifierFindings\}\}/g, ctx.stepOutput["content"] ?? "");
239
+ result = result.replace(/\{\{previousStepOutput\}\}/g, ctx.stepOutput["stdout"] ?? "");
240
+ for (const [key, value] of Object.entries(ctx.params)) {
241
+ result = result.replaceAll(`{{${key}}}`, value);
242
+ }
243
+ return result;
244
+ }
245
+ function evaluateCondition(condition, stepOutcome, metadataEntries) {
246
+ switch (condition.type) {
247
+ case "step_result":
248
+ if (!stepOutcome) return false;
249
+ return stepOutcome.result === condition.result;
250
+ case "metadata_all_match": {
251
+ if (!metadataEntries) return false;
252
+ const entries = metadataEntries[condition.key];
253
+ if (!entries || entries.length === 0) return true;
254
+ return entries.every((e) => e[condition.field] === condition.value);
255
+ }
256
+ case "metadata_all_in": {
257
+ if (!metadataEntries) return false;
258
+ const entries = metadataEntries[condition.key];
259
+ if (!entries || entries.length === 0) return true;
260
+ return entries.every((e) => condition.values.includes(e[condition.field]));
261
+ }
262
+ case "always":
263
+ return true;
264
+ }
265
+ }
266
+ function findMatchingTransition(transitions, stepOutcome, metadataEntries) {
267
+ for (const transition of transitions) {
268
+ if (evaluateCondition(transition.when, stepOutcome, metadataEntries)) {
269
+ return transition;
270
+ }
271
+ }
272
+ return null;
273
+ }
274
+ var DEFAULT_USER_RESULT = "continue";
275
+ var CONTINUE_CHOICE_ID = "continue";
276
+ function userStepChoices(step) {
277
+ const seen = /* @__PURE__ */ new Set();
278
+ const choices = [];
279
+ for (const t of step.transitions) {
280
+ if (t.when.type === "step_result") {
281
+ const id = t.when.result;
282
+ if (seen.has(id)) continue;
283
+ seen.add(id);
284
+ choices.push({ id, label: id, goto: t.goto });
285
+ } else if (t.when.type === "always") {
286
+ if (seen.has(CONTINUE_CHOICE_ID)) continue;
287
+ seen.add(CONTINUE_CHOICE_ID);
288
+ choices.push({ id: CONTINUE_CHOICE_ID, label: "Continue", goto: t.goto });
289
+ }
290
+ }
291
+ return choices;
292
+ }
293
+ function emitWorkflowMessage(eventStore, sessionId, content, windowOptions, onMessage) {
294
+ const msgId = crypto.randomUUID();
295
+ eventStore.append(
296
+ sessionId,
297
+ createMessageStartEvent(msgId, "user", content, {
298
+ ...windowOptions ?? {},
299
+ isSystemGenerated: true,
300
+ messageKind: "correction",
301
+ metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
302
+ })
303
+ );
304
+ eventStore.append(sessionId, { type: "message.done", data: { messageId: msgId } });
305
+ if (onMessage) {
306
+ onMessage(
307
+ createChatMessageMessage({
308
+ id: msgId,
309
+ role: "user",
310
+ content,
311
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
312
+ isSystemGenerated: true,
313
+ messageKind: "correction",
314
+ metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
315
+ })
316
+ );
317
+ }
318
+ return msgId;
319
+ }
320
+ function injectGenericKickoff(sessionId) {
321
+ const eventStore = getEventStore();
322
+ const windowOpts = getCurrentWindowMessageOptions(sessionId);
323
+ const msgId = crypto.randomUUID();
324
+ eventStore.append(
325
+ sessionId,
326
+ createMessageStartEvent(msgId, "user", "Proceed with the current step.", {
327
+ ...windowOpts ?? {},
328
+ isSystemGenerated: true,
329
+ messageKind: "auto-prompt",
330
+ metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
331
+ })
332
+ );
333
+ eventStore.append(sessionId, { type: "message.done", data: { messageId: msgId } });
334
+ }
335
+ function getCurrentWindowMessageOptions(sessionId) {
336
+ const contextWindowId = getCurrentContextWindowId(sessionId);
337
+ return contextWindowId ? { contextWindowId } : void 0;
338
+ }
339
+ function buildReason(metadataEntries) {
340
+ const entries = metadataEntries?.["criteria"] ?? [];
341
+ const remaining = entries.filter((e) => e.status !== "passed");
342
+ return `${remaining.length} criteria remaining`;
343
+ }
344
+ async function executeWorkflow(workflow, options, subGroup) {
345
+ const { sessionManager, sessionId, llmClient, signal, onMessage } = options;
346
+ const eventStore = getEventStore();
347
+ const startTime = performance.now();
348
+ let iterations = 0;
349
+ const activeSteps = subGroup ? workflow.steps.filter((s) => s.subGroup === subGroup) : workflow.steps;
350
+ const resumeFromStep = options.resumeFromStep;
351
+ const isResume = !!resumeFromStep;
352
+ let resumeConsumed = false;
353
+ let currentStepId = isResume ? resumeFromStep : subGroup ? activeSteps[0]?.id ?? workflow.entryStep : workflow.entryStep;
354
+ let lastStepOutput = options.initialStepOutput ?? {};
355
+ const firstEntryForStep = /* @__PURE__ */ new Set();
356
+ const messagesBeforeWorkflow = sessionManager.requireSession(sessionId).messages.length;
357
+ const activeStepIds = new Set(activeSteps.map((s) => s.id));
358
+ const activeSubGroups = /* @__PURE__ */ new Set();
359
+ if (subGroup) {
360
+ activeSubGroups.add(subGroup);
361
+ }
362
+ const stepsById = /* @__PURE__ */ new Map();
363
+ for (const step of workflow.steps) {
364
+ stepsById.set(step.id, step);
365
+ }
366
+ if (resumeFromStep) {
367
+ const targetStep = stepsById.get(resumeFromStep);
368
+ if (!targetStep) {
369
+ return {
370
+ finalAction: {
371
+ type: "BLOCKED",
372
+ reason: `Resume target step "${resumeFromStep}" not found in workflow "${workflow.metadata.id}"`,
373
+ blockedCriteria: []
374
+ },
375
+ iterations: 0,
376
+ totalTime: (performance.now() - startTime) / 1e3
377
+ };
378
+ }
379
+ }
380
+ logger.debug("Workflow executor starting", { sessionId, workflow: workflow.metadata.id });
381
+ let executionId;
382
+ if (isResume) {
383
+ const activeExec = sessionManager.getActiveWorkflowExecution(sessionId);
384
+ if (activeExec) {
385
+ executionId = activeExec.id;
386
+ }
387
+ }
388
+ if (workflow.startCondition && workflow.startCondition.type !== "always") {
389
+ const session = sessionManager.requireSession(sessionId);
390
+ const conditionMet = evaluateCondition(
391
+ workflow.startCondition,
392
+ null,
393
+ session.metadataEntries
394
+ );
395
+ if (!conditionMet) {
396
+ logger.debug("Workflow start condition not met", { sessionId, condition: workflow.startCondition.type });
397
+ return {
398
+ finalAction: {
399
+ type: "BLOCKED",
400
+ reason: `Start condition not met: ${workflow.startCondition.type}`,
401
+ blockedCriteria: []
402
+ },
403
+ iterations: 0,
404
+ totalTime: (performance.now() - startTime) / 1e3
405
+ };
406
+ }
407
+ }
408
+ if (!isResume) {
409
+ const startMsgId = crypto.randomUUID();
410
+ const startWindowOpts = getCurrentWindowMessageOptions(sessionId);
411
+ eventStore.append(
412
+ sessionId,
413
+ createMessageStartEvent(
414
+ startMsgId,
415
+ "user",
416
+ JSON.stringify({
417
+ workflowName: workflow.metadata.name,
418
+ workflowId: workflow.metadata.id,
419
+ workflowColor: workflow.metadata.color
420
+ }),
421
+ { ...startWindowOpts ?? {}, isSystemGenerated: true, messageKind: "workflow-started" }
422
+ )
423
+ );
424
+ eventStore.append(sessionId, { type: "message.done", data: { messageId: startMsgId } });
425
+ executionId = crypto.randomUUID();
426
+ sessionManager.startWorkflow(
427
+ sessionId,
428
+ executionId,
429
+ workflow.metadata.id,
430
+ workflow.metadata.name,
431
+ workflow.metadata.color,
432
+ options.params ?? {},
433
+ subGroup
434
+ );
435
+ }
436
+ if (options.userMessage) {
437
+ sessionManager.addMessage(sessionId, {
438
+ role: "user",
439
+ content: options.userMessage.content,
440
+ ...options.userMessage.attachments ? { attachments: options.userMessage.attachments } : {}
441
+ });
442
+ }
443
+ while (iterations < workflow.settings.maxIterations) {
444
+ if (signal?.aborted) {
445
+ logger.debug("Workflow executor aborted \u2014 preserving execution", { sessionId, iterations });
446
+ return {
447
+ finalAction: { type: "RUN_BUILDER", reason: "Aborted" },
448
+ iterations,
449
+ totalTime: (performance.now() - startTime) / 1e3
450
+ };
451
+ }
452
+ iterations++;
453
+ const step = stepsById.get(currentStepId);
454
+ if (!step) {
455
+ logger.error("Workflow step not found", { sessionId, stepId: currentStepId });
456
+ return {
457
+ finalAction: { type: "BLOCKED", reason: `Step "${currentStepId}" not found in workflow`, blockedCriteria: [] },
458
+ iterations,
459
+ totalTime: (performance.now() - startTime) / 1e3
460
+ };
461
+ }
462
+ const session = sessionManager.requireSession(sessionId);
463
+ const currentWindowMessageOptions = getCurrentWindowMessageOptions(sessionId);
464
+ const criteriaEntries = session.metadataEntries["criteria"] ?? [];
465
+ const templateCtx = {
466
+ workdir: sessionManager.getEffectiveWorkdir(sessionId),
467
+ reason: buildReason(session.metadataEntries),
468
+ verifierFindings: lastStepOutput["content"] ?? "",
469
+ previousStepOutput: lastStepOutput["stdout"] ?? "",
470
+ criteriaCount: criteriaEntries.length,
471
+ pendingCount: criteriaEntries.filter((e) => e.status !== "passed").length,
472
+ criteriaList: formatCriteriaList(criteriaEntries),
473
+ modifiedFiles: await formatModifiedFiles(sessionManager.getEffectiveWorkdir(sessionId)),
474
+ stepOutput: lastStepOutput,
475
+ params: options.params ?? {}
476
+ };
477
+ sessionManager.setPhase(sessionId, step.phase);
478
+ if (executionId) {
479
+ sessionManager.updateWorkflowStep(
480
+ sessionId,
481
+ executionId,
482
+ step.id,
483
+ step.name,
484
+ workflow.metadata.id,
485
+ workflow.metadata.name,
486
+ workflow.metadata.color
487
+ );
488
+ }
489
+ if (step.type === "agent") {
490
+ const agentStep = step;
491
+ sessionManager.setMode(sessionId, agentStep.agentId ?? resolveDefaultAgentId());
492
+ }
493
+ logger.debug("Workflow step executing", { sessionId, iteration: iterations, stepId: step.id, stepType: step.type });
494
+ let stepOutcome = null;
495
+ switch (step.type) {
496
+ case "agent": {
497
+ const agentStep = step;
498
+ const STEP_DONE_PROMPT = "\n\nOnce you're done, call step_done()";
499
+ const STEP_DONE_NUDGE = "You haven't called step_done(). If you haven't finished the task, continue and when you're finished call step_done()";
500
+ let promptContent;
501
+ let nudgeContent;
502
+ const isResumingCurrentStep = isResume && step.id === resumeFromStep && !resumeConsumed;
503
+ if (!firstEntryForStep.has(step.id) && agentStep.prompt && !isResumingCurrentStep) {
504
+ const resolvedPrompt = resolveTemplate(agentStep.prompt, templateCtx);
505
+ promptContent = resolvedPrompt + STEP_DONE_PROMPT;
506
+ const promptMsgId = crypto.randomUUID();
507
+ const msgMetadata = { type: "workflow", name: "Workflow", color: "#f59e0b" };
508
+ eventStore.append(
509
+ sessionId,
510
+ createMessageStartEvent(promptMsgId, "user", promptContent, {
511
+ ...currentWindowMessageOptions ?? {},
512
+ isSystemGenerated: true,
513
+ messageKind: "auto-prompt",
514
+ metadata: msgMetadata
515
+ })
516
+ );
517
+ eventStore.append(sessionId, { type: "message.done", data: { messageId: promptMsgId } });
518
+ if (onMessage) {
519
+ onMessage(
520
+ createChatMessageMessage({
521
+ id: promptMsgId,
522
+ role: "user",
523
+ content: promptContent,
524
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
525
+ isSystemGenerated: true,
526
+ messageKind: "auto-prompt",
527
+ metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
528
+ })
529
+ );
530
+ }
531
+ } else if (firstEntryForStep.has(step.id) && !isResumingCurrentStep) {
532
+ const parts = [];
533
+ if (agentStep.nudgePrompt) {
534
+ const resolvedNudge = resolveTemplate(agentStep.nudgePrompt, templateCtx);
535
+ parts.push(resolvedNudge);
536
+ }
537
+ parts.push(STEP_DONE_NUDGE);
538
+ nudgeContent = parts.join("\n\n");
539
+ emitWorkflowMessage(eventStore, sessionId, nudgeContent, currentWindowMessageOptions, onMessage);
540
+ }
541
+ const turnMetrics = new TurnMetrics();
542
+ const es = getEventStore();
543
+ const append = (event) => es.append(sessionId, event);
544
+ let stepDoneCalled = false;
545
+ const agentResult = await runAgentTurn(
546
+ {
547
+ sessionManager,
548
+ sessionId,
549
+ llmClient,
550
+ ...options.statsIdentity ? { statsIdentity: options.statsIdentity } : {},
551
+ ...signal ? { signal } : {},
552
+ ...onMessage ? { onMessage } : {}
553
+ },
554
+ turnMetrics,
555
+ agentStep.agentId ?? resolveDefaultAgentId(),
556
+ append,
557
+ {
558
+ ...!firstEntryForStep.has(step.id) && !agentStep.prompt && !isResumingCurrentStep ? { injectKickoff: () => injectGenericKickoff(sessionId) } : {},
559
+ onToolExecuted: (toolCall, toolResult) => {
560
+ if (toolCall.name === "step_done" && toolResult.success) {
561
+ stepDoneCalled = true;
562
+ }
563
+ }
564
+ }
565
+ );
566
+ firstEntryForStep.add(step.id);
567
+ resumeConsumed = true;
568
+ const agentReturnValue = agentResult.returnValueResult ?? "completed";
569
+ lastStepOutput = {
570
+ ...agentResult.returnValueContent ? { content: agentResult.returnValueContent } : {},
571
+ ...agentResult.returnValueResult ? { result: agentResult.returnValueResult } : {},
572
+ stepDoneCalled: String(stepDoneCalled)
573
+ };
574
+ stepOutcome = { result: agentReturnValue, output: lastStepOutput };
575
+ if (!stepDoneCalled) {
576
+ logger.debug("step_done not called, looping agent step", {
577
+ sessionId,
578
+ stepId: step.id,
579
+ iteration: iterations
580
+ });
581
+ continue;
582
+ }
583
+ break;
584
+ }
585
+ case "sub_agent": {
586
+ const subStep = step;
587
+ const turnMetrics = new TurnMetrics();
588
+ const promptTemplate = subStep.prompt ?? "Perform your task.";
589
+ const resolvedPrompt = resolveTemplate(promptTemplate, templateCtx);
590
+ const allAgents = await loadAllAgentsDefault(sessionManager.getProjectWorkdir(sessionId));
591
+ const agentDef = findAgentById(subStep.subAgentType, allAgents);
592
+ if (!agentDef) {
593
+ logger.error("Sub-agent definition not found", { subAgentType: subStep.subAgentType });
594
+ stepOutcome = { result: "error", output: {} };
595
+ break;
596
+ }
597
+ const toolRegistry = getToolRegistryForAgent(agentDef);
598
+ const filteredToolRegistry = {
599
+ tools: toolRegistry.tools.filter((t) => t.name !== "step_done"),
600
+ definitions: toolRegistry.definitions.filter((d) => d.type === "function" && d.function.name !== "step_done"),
601
+ execute: toolRegistry.execute
602
+ };
603
+ const result = await executeSubAgent({
604
+ subAgentType: subStep.subAgentType,
605
+ prompt: resolvedPrompt,
606
+ sessionManager,
607
+ sessionId,
608
+ llmClient,
609
+ toolRegistry: filteredToolRegistry,
610
+ turnMetrics,
611
+ statsIdentity: options.statsIdentity ?? {
612
+ providerId: "",
613
+ providerName: "",
614
+ backend: "unknown",
615
+ model: llmClient.getModel()
616
+ },
617
+ ...signal ? { signal } : {},
618
+ ...onMessage ? { onMessage } : {}
619
+ });
620
+ lastStepOutput = { content: result.content ?? "", ...result.result ? { result: result.result } : {} };
621
+ stepOutcome = { result: result.result ?? "success", output: lastStepOutput };
622
+ break;
623
+ }
624
+ case "shell": {
625
+ const shellStep = step;
626
+ const command = resolveTemplate(shellStep.command, templateCtx);
627
+ const timeout = shellStep.timeout ?? 6e4;
628
+ const successCodes = shellStep.successExitCodes ?? [0];
629
+ const shellMsgId = crypto.randomUUID();
630
+ eventStore.append(
631
+ sessionId,
632
+ createMessageStartEvent(shellMsgId, "user", `Running: \`${command}\``, {
633
+ ...currentWindowMessageOptions ?? {},
634
+ isSystemGenerated: true,
635
+ messageKind: "auto-prompt",
636
+ metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
637
+ })
638
+ );
639
+ if (onMessage) {
640
+ onMessage(
641
+ createChatMessageMessage({
642
+ id: shellMsgId,
643
+ role: "user",
644
+ content: `Running: \`${command}\``,
645
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
646
+ isSystemGenerated: true,
647
+ messageKind: "auto-prompt",
648
+ metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
649
+ })
650
+ );
651
+ }
652
+ const result = await executeShellCommand(
653
+ command,
654
+ sessionManager.getEffectiveWorkdir(sessionId),
655
+ timeout,
656
+ signal
657
+ );
658
+ const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
659
+ lastStepOutput = { stdout: result.stdout ?? "", stderr: result.stderr ?? "", exitCode: String(result.exitCode) };
660
+ const outputContent = output ? `Exit code: ${result.exitCode}
661
+ \`\`\`
662
+ ${output.slice(0, 1e4)}
663
+ \`\`\`` : `Exit code: ${result.exitCode}`;
664
+ eventStore.append(sessionId, { type: "message.done", data: { messageId: shellMsgId } });
665
+ const outputMsgId = crypto.randomUUID();
666
+ eventStore.append(
667
+ sessionId,
668
+ createMessageStartEvent(outputMsgId, "user", outputContent, {
669
+ ...currentWindowMessageOptions ?? {},
670
+ isSystemGenerated: true,
671
+ messageKind: "correction"
672
+ })
673
+ );
674
+ eventStore.append(sessionId, { type: "message.done", data: { messageId: outputMsgId } });
675
+ if (onMessage) {
676
+ onMessage(
677
+ createChatMessageMessage({
678
+ id: outputMsgId,
679
+ role: "user",
680
+ content: outputContent,
681
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
682
+ isSystemGenerated: true,
683
+ messageKind: "correction"
684
+ })
685
+ );
686
+ }
687
+ stepOutcome = { result: successCodes.includes(result.exitCode) ? "success" : "failure", output: lastStepOutput };
688
+ break;
689
+ }
690
+ case "user": {
691
+ if (resumeFromStep === step.id) {
692
+ const choice = options.userChoice;
693
+ const result = choice === void 0 || choice === CONTINUE_CHOICE_ID ? DEFAULT_USER_RESULT : choice;
694
+ stepOutcome = { result, output: lastStepOutput };
695
+ break;
696
+ }
697
+ if (executionId) {
698
+ const choices = userStepChoices(step).map((choice) => {
699
+ const target = choice.goto ? stepsById.get(choice.goto) : void 0;
700
+ return target ? { ...choice, nextStepName: target.name } : choice;
701
+ });
702
+ sessionManager.waitAtStep(
703
+ sessionId,
704
+ executionId,
705
+ step.id,
706
+ step.name,
707
+ lastStepOutput,
708
+ workflow.metadata.id,
709
+ workflow.metadata.name,
710
+ workflow.metadata.color,
711
+ choices
712
+ );
713
+ }
714
+ logger.debug("Workflow paused at user step", { sessionId, stepId: step.id, stepName: step.name });
715
+ return {
716
+ finalAction: {
717
+ type: "WAITING",
718
+ reason: `Paused at user step: ${step.name}`,
719
+ workflowId: workflow.metadata.id,
720
+ stepId: step.id,
721
+ stepOutput: lastStepOutput
722
+ },
723
+ iterations,
724
+ totalTime: (performance.now() - startTime) / 1e3
725
+ };
726
+ }
727
+ }
728
+ const refreshedSession = sessionManager.requireSession(sessionId);
729
+ const candidates = subGroup ? step.transitions.filter((t) => !t.subGroup || activeSubGroups.has(t.subGroup)) : step.transitions;
730
+ const fired = findMatchingTransition(candidates, stepOutcome, refreshedSession.metadataEntries);
731
+ let nextStepId = fired ? fired.goto : TERMINAL_BLOCKED;
732
+ if (subGroup && nextStepId !== TERMINAL_DONE && nextStepId !== TERMINAL_BLOCKED && !activeStepIds.has(nextStepId)) {
733
+ if (fired && fired.subGroup && activeSubGroups.has(fired.subGroup)) {
734
+ activeStepIds.add(nextStepId);
735
+ const targetStep = stepsById.get(nextStepId);
736
+ if (targetStep?.subGroup) {
737
+ activeSubGroups.add(targetStep.subGroup);
738
+ }
739
+ } else {
740
+ nextStepId = TERMINAL_DONE;
741
+ }
742
+ }
743
+ if (nextStepId === TERMINAL_DONE) {
744
+ sessionManager.setPhase(sessionId, "done");
745
+ if (executionId) {
746
+ sessionManager.completeWorkflow(
747
+ sessionId,
748
+ executionId,
749
+ workflow.metadata.id,
750
+ workflow.metadata.name,
751
+ workflow.metadata.color
752
+ );
753
+ }
754
+ const totalTimeSeconds = Math.round((performance.now() - startTime) / 100) / 10;
755
+ const completedSession = sessionManager.requireSession(sessionId);
756
+ const workflowMessages = completedSession.messages.slice(messagesBeforeWorkflow);
757
+ const workflowStats = computeSessionStats(workflowMessages);
758
+ const totalToolCalls = workflowMessages.reduce((sum, m) => sum + (m.toolCalls?.length ?? 0), 0);
759
+ const taskCompletedData = {
760
+ summary: null,
761
+ iterations,
762
+ totalTimeSeconds,
763
+ totalToolCalls,
764
+ totalTokensGenerated: workflowStats?.generationTokens ?? 0,
765
+ avgGenerationSpeed: workflowStats?.avgGenerationSpeed ?? 0,
766
+ responseCount: workflowStats?.responseCount ?? 0,
767
+ llmCallCount: workflowStats?.llmCallCount ?? 0,
768
+ criteria: [],
769
+ workflowName: workflow.metadata.name,
770
+ workflowId: workflow.metadata.id,
771
+ ...workflow.metadata.color ? { workflowColor: workflow.metadata.color } : {}
772
+ };
773
+ eventStore.append(sessionId, { type: "task.completed", data: taskCompletedData });
774
+ const markerMsgId = crypto.randomUUID();
775
+ eventStore.append(
776
+ sessionId,
777
+ createMessageStartEvent(markerMsgId, "user", JSON.stringify(taskCompletedData), {
778
+ ...currentWindowMessageOptions ?? {},
779
+ isSystemGenerated: true,
780
+ messageKind: "task-completed"
781
+ })
782
+ );
783
+ eventStore.append(sessionId, { type: "message.done", data: { messageId: markerMsgId } });
784
+ logger.debug("Workflow executor complete", { sessionId, iterations });
785
+ const doneAction = { type: "DONE" };
786
+ return {
787
+ finalAction: doneAction,
788
+ iterations,
789
+ totalTime: totalTimeSeconds
790
+ };
791
+ }
792
+ if (nextStepId === TERMINAL_BLOCKED) {
793
+ sessionManager.setPhase(sessionId, "blocked");
794
+ if (executionId) {
795
+ sessionManager.blockWorkflow(
796
+ sessionId,
797
+ executionId,
798
+ workflow.metadata.id,
799
+ workflow.metadata.name,
800
+ workflow.metadata.color
801
+ );
802
+ }
803
+ const reason = "No matching transition";
804
+ emitWorkflowMessage(eventStore, sessionId, `Runner blocked: ${reason}`, currentWindowMessageOptions, onMessage);
805
+ logger.warn("Workflow executor blocked", { sessionId, iterations, reason });
806
+ const blockedAction = { type: "BLOCKED", reason, blockedCriteria: [] };
807
+ return {
808
+ finalAction: blockedAction,
809
+ iterations,
810
+ totalTime: (performance.now() - startTime) / 1e3
811
+ };
812
+ }
813
+ currentStepId = nextStepId;
814
+ }
815
+ logger.warn("Workflow executor max iterations reached", { sessionId, iterations });
816
+ return {
817
+ finalAction: {
818
+ type: "BLOCKED",
819
+ reason: `Max iterations (${workflow.settings.maxIterations}) reached`,
820
+ blockedCriteria: []
821
+ },
822
+ iterations,
823
+ totalTime: (performance.now() - startTime) / 1e3
824
+ };
825
+ }
826
+
827
+ // src/server/runner/orchestrator.ts
828
+ async function runOrchestrator(options) {
829
+ const runtimeConfig = getRuntimeConfig();
830
+ const workflowId = options.workflowId ?? runtimeConfig.activeWorkflowId ?? "default";
831
+ const configDir = getGlobalConfigDir(runtimeConfig.mode ?? "production");
832
+ const session = options.sessionManager.requireSession(options.sessionId);
833
+ const projectDir = session.workdir;
834
+ const scope = normalizeWorkflowScope(options.scope);
835
+ let workflow;
836
+ if (scope === "builtin") {
837
+ workflow = findWorkflowById(workflowId, await loadDefaultWorkflows());
838
+ } else if (scope === "user") {
839
+ workflow = findWorkflowById(workflowId, await loadUserWorkflows(configDir));
840
+ } else if (scope === "project") {
841
+ workflow = projectDir ? findWorkflowById(workflowId, await loadProjectWorkflows(projectDir)) : void 0;
842
+ } else {
843
+ workflow = void 0;
844
+ }
845
+ if (!workflow) {
846
+ const workflows = await loadAllWorkflows(configDir, projectDir);
847
+ workflow = findWorkflowById(workflowId, workflows);
848
+ }
849
+ if (!workflow) {
850
+ throw new Error(`Workflow "${workflowId}" not found`);
851
+ }
852
+ const requiredParams = (workflow.metadata.parameters ?? []).filter((p) => p.required);
853
+ const suppliedParams = options.params ?? {};
854
+ const missing = requiredParams.filter((p) => !(p.id in suppliedParams));
855
+ if (missing.length > 0) {
856
+ const names = missing.map((p) => p.label || p.id).join(", ");
857
+ throw new Error(`Missing required parameter${missing.length > 1 ? "s" : ""}: ${names}`);
858
+ }
859
+ logger.debug("Using workflow executor", {
860
+ sessionId: options.sessionId,
861
+ workflow: workflow.metadata.id,
862
+ subGroup: options.subGroup
863
+ });
864
+ return executeWorkflow(workflow, options, options.subGroup);
865
+ }
866
+
867
+ // src/server/runner/launch.ts
868
+ var activeRuns = /* @__PURE__ */ new Map();
869
+ function abortRunnerRun(sessionId) {
870
+ const controller = activeRuns.get(sessionId);
871
+ if (!controller) return false;
872
+ controller.abort();
873
+ return true;
874
+ }
875
+ function launchWorkflowRun(deps, payload) {
876
+ const { sessionManager, sessionId, controller, llmClient, statsIdentity, broadcastForSession, onFinished } = deps;
877
+ const signal = controller.signal;
878
+ activeRuns.set(sessionId, controller);
879
+ sessionManager.setRunning(sessionId, true);
880
+ broadcastForSession(sessionId, createSessionRunningMessage(true));
881
+ const launchAttachments = payload.attachments;
882
+ const hasUserContent = payload.content && payload.content.trim().length > 0;
883
+ const hasUserAttachments = launchAttachments && launchAttachments.length > 0;
884
+ runOrchestrator({
885
+ sessionManager,
886
+ sessionId,
887
+ llmClient,
888
+ statsIdentity,
889
+ scope: normalizeWorkflowScope(payload.scope),
890
+ ...payload.workflowId ? { workflowId: payload.workflowId } : {},
891
+ ...payload.subGroup ? { subGroup: payload.subGroup } : {},
892
+ ...payload.params ? { params: payload.params } : {},
893
+ ...payload.resumeFrom ? { resumeFromStep: payload.resumeFrom } : {},
894
+ ...payload.stepOutput ? { initialStepOutput: payload.stepOutput } : {},
895
+ ...payload.userChoice ? { userChoice: payload.userChoice } : {},
896
+ ...payload.resumeFrom ? (() => {
897
+ const exec = sessionManager.getActiveWorkflowExecution(sessionId);
898
+ if (!exec) return {};
899
+ if (exec.status === "waiting") {
900
+ const resumed = sessionManager.resumeWorkflow(
901
+ sessionId,
902
+ exec.id,
903
+ exec.workflowId,
904
+ exec.workflowName,
905
+ exec.workflowColor
906
+ );
907
+ if (resumed) {
908
+ return {
909
+ params: resumed.params,
910
+ initialStepOutput: resumed.stepOutput,
911
+ ...exec.currentStepId ? { resumeFromStep: exec.currentStepId } : {},
912
+ ...exec.subGroup ? { subGroup: exec.subGroup } : {}
913
+ };
914
+ }
915
+ }
916
+ return {
917
+ ...Object.keys(exec.params).length > 0 ? { params: exec.params } : {},
918
+ ...Object.keys(exec.stepOutput).length > 0 ? { initialStepOutput: exec.stepOutput } : {},
919
+ ...exec.currentStepId ? { resumeFromStep: exec.currentStepId } : {},
920
+ ...exec.subGroup ? { subGroup: exec.subGroup } : {}
921
+ };
922
+ })() : {},
923
+ ...hasUserContent || hasUserAttachments ? {
924
+ userMessage: {
925
+ content: payload.content ?? "",
926
+ ...hasUserAttachments ? { attachments: launchAttachments } : {}
927
+ }
928
+ } : {},
929
+ signal,
930
+ onMessage: (msg) => broadcastForSession(sessionId, msg)
931
+ // For path confirmation dialogs
932
+ }).catch((error) => {
933
+ if (error instanceof Error && error.message === "Aborted") {
934
+ return;
935
+ }
936
+ const errorMessage = error instanceof Error ? error.message : String(error);
937
+ logger.error("Runner error", { error: errorMessage, sessionId });
938
+ broadcastForSession(sessionId, createServerMessage("chat.error", { error: errorMessage, recoverable: false }));
939
+ }).finally(() => {
940
+ if (activeRuns.get(sessionId) === controller) {
941
+ activeRuns.delete(sessionId);
942
+ }
943
+ try {
944
+ sessionManager.setRunning(sessionId, false);
945
+ broadcastForSession(sessionId, createSessionRunningMessage(false));
946
+ onFinished?.();
947
+ } catch {
948
+ }
949
+ });
950
+ }
951
+
952
+ export {
953
+ TEMPLATE_VARIABLES,
954
+ abortRunnerRun,
955
+ launchWorkflowRun
956
+ };
957
+ //# sourceMappingURL=chunk-3QQAIUZI.js.map