openfox 2.0.146 → 2.0.147

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 (31) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/CHANGELOG.md +16 -0
  3. package/dist/{auto-continue-IENGLXVQ.js → auto-continue-FGQ63HHR.js} +2 -2
  4. package/dist/{chat-handler-RJUJHVOX.js → chat-handler-VCED3JYF.js} +4 -4
  5. package/dist/{chunk-7BIGFGU5.js → chunk-2V6QL6IW.js} +285 -115
  6. package/dist/chunk-65KDNVRA.js +7 -0
  7. package/dist/{chunk-5D4MQG7P.js → chunk-ABXERHIY.js} +4 -4
  8. package/dist/{chunk-QR6FIHIP.js → chunk-AJMBQMJH.js} +16 -12
  9. package/dist/{chunk-L43S7FJM.js → chunk-ESHP42KO.js} +2 -2
  10. package/dist/{chunk-EZEFBLPY.js → chunk-QHFJRUJV.js} +3 -3
  11. package/dist/{chunk-OS4P2KQJ.js → chunk-UOBJP4GN.js} +7 -7
  12. package/dist/{chunk-7IETJ4D4.js → chunk-YQJ6HEFS.js} +29 -29
  13. package/dist/cli/dev.js +1 -1
  14. package/dist/cli/index.js +1 -1
  15. package/dist/{dynamic-context-IQUBKUCX.js → dynamic-context-YLRA34WJ.js} +2 -2
  16. package/dist/{export-import-NAQDPRET.js → export-import-R4E5BUQS.js} +2 -2
  17. package/dist/{launch-EUU25RFE.js → launch-QP2BI3PB.js} +5 -5
  18. package/dist/{orchestrator-PPAIE2UH.js → orchestrator-7T62RLDL.js} +4 -4
  19. package/dist/package.json +1 -1
  20. package/dist/{processor-7XMJPNCD.js → processor-LDLRELLS.js} +3 -3
  21. package/dist/{serve-3GNQNYG6.js → serve-A4AJAH2N.js} +8 -8
  22. package/dist/server/index.js +7 -7
  23. package/dist/{server-C4LB436R.js → server-A3EGJ6MD.js} +6 -6
  24. package/dist/skill-defaults/workflows/SKILL.md +149 -16
  25. package/dist/{tools-OH3WW6Q4.js → tools-MRC27SZG.js} +2 -2
  26. package/dist/{update-PG63SDV3.js → update-MLDVVG3D.js} +2 -2
  27. package/dist/web/assets/{index-jXXIgPm-.js → index-CkVmYTBd.js} +82 -82
  28. package/dist/web/index.html +1 -1
  29. package/dist/web/sw.js +1 -1
  30. package/package.json +1 -1
  31. package/dist/chunk-EABIZXTG.js +0 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.147 - 2026-09-14
4
+
5
+ ### Features
6
+
7
+ - **Parallel workflow steps** — run sub-agent and shell steps concurrently inside one workflow step, capped by max concurrency, with per-child output keys to branch on.
8
+ - **Parallel step editor** — build parallel steps in the workflow UI with a child list, per-child sub-agent/shell configuration, and slug-safe child ids.
9
+ - **Project dropdown on session rows** — switch projects, start sessions, or open tasks directly from the home session list.
10
+
11
+ ### Enhancements
12
+
13
+ - **Agent steps honor per-agent model overrides** — workflow steps pinned to a specific model (e.g. builder on Qwen) now actually run on it, matching the existing sub-agent behavior.
14
+
15
+ ### Bug Fixes
16
+
17
+ - **Background process logs stream live** — the log viewer shows new output as it arrives without reopening the panel.
18
+
3
19
  ## 2.0.146 - 2026-09-12
4
20
 
5
21
  ### Bug Fixes
package/dist/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.147 - 2026-09-14
4
+
5
+ ### Features
6
+
7
+ - **Parallel workflow steps** — run sub-agent and shell steps concurrently inside one workflow step, capped by max concurrency, with per-child output keys to branch on.
8
+ - **Parallel step editor** — build parallel steps in the workflow UI with a child list, per-child sub-agent/shell configuration, and slug-safe child ids.
9
+ - **Project dropdown on session rows** — switch projects, start sessions, or open tasks directly from the home session list.
10
+
11
+ ### Enhancements
12
+
13
+ - **Agent steps honor per-agent model overrides** — workflow steps pinned to a specific model (e.g. builder on Qwen) now actually run on it, matching the existing sub-agent behavior.
14
+
15
+ ### Bug Fixes
16
+
17
+ - **Background process logs stream live** — the log viewer shows new output as it arrives without reopening the panel.
18
+
3
19
  ## 2.0.146 - 2026-09-12
4
20
 
5
21
  ### Bug Fixes
@@ -1,4 +1,4 @@
1
- import "./chunk-QR6FIHIP.js";
1
+ import "./chunk-AJMBQMJH.js";
2
2
  import "./chunk-OAN4BXEW.js";
3
3
  import "./chunk-DJH6LMBT.js";
4
4
  import "./chunk-PHR64A6U.js";
@@ -108,4 +108,4 @@ export {
108
108
  planBootContinuation,
109
109
  runBootAutoContinuations
110
110
  };
111
- //# sourceMappingURL=auto-continue-IENGLXVQ.js.map
111
+ //# sourceMappingURL=auto-continue-FGQ63HHR.js.map
@@ -5,9 +5,9 @@ import {
5
5
  } from "./chunk-ORIPUMOQ.js";
6
6
  import {
7
7
  runChatTurn
8
- } from "./chunk-5D4MQG7P.js";
9
- import "./chunk-L43S7FJM.js";
10
- import "./chunk-QR6FIHIP.js";
8
+ } from "./chunk-ABXERHIY.js";
9
+ import "./chunk-ESHP42KO.js";
10
+ import "./chunk-AJMBQMJH.js";
11
11
  import "./chunk-OAN4BXEW.js";
12
12
  import "./chunk-DJH6LMBT.js";
13
13
  import "./chunk-PHR64A6U.js";
@@ -181,4 +181,4 @@ export {
181
181
  startChatSession,
182
182
  stopSessionExecution
183
183
  };
184
- //# sourceMappingURL=chat-handler-RJUJHVOX.js.map
184
+ //# sourceMappingURL=chat-handler-VCED3JYF.js.map
@@ -1,10 +1,12 @@
1
1
  import {
2
2
  runAgentTurn
3
- } from "./chunk-5D4MQG7P.js";
3
+ } from "./chunk-ABXERHIY.js";
4
4
  import {
5
+ buildAgentOverrideStatsIdentity,
5
6
  executeSubAgent,
6
- getToolRegistryForAgent
7
- } from "./chunk-QR6FIHIP.js";
7
+ getToolRegistryForAgent,
8
+ resolveLLMClientForAgent
9
+ } from "./chunk-AJMBQMJH.js";
8
10
  import {
9
11
  gitSpawnEnv
10
12
  } from "./chunk-J7GAZGZT.js";
@@ -204,13 +206,13 @@ function executeShellCommand(command, cwd, timeout, signal) {
204
206
  });
205
207
  }
206
208
 
207
- // src/server/workflows/executor.ts
209
+ // src/server/workflows/template.ts
208
210
  var TEMPLATE_VARIABLES = [
209
211
  { name: "workdir", description: "Working directory of the session" },
210
212
  { name: "reason", description: 'Human-readable reason (e.g. "2 criteria remaining")' },
211
213
  {
212
214
  name: "stepOutput",
213
- description: "Structured output from the previous step (content, stdout, stderr, exitCode, etc.)"
215
+ description: "Structured output from the previous step (content, stdout, stderr, exitCode, etc.); parallel steps expose per-child keys <childId>.<key> and a summary"
214
216
  },
215
217
  {
216
218
  name: "verifierFindings",
@@ -225,16 +227,6 @@ var TEMPLATE_VARIABLES = [
225
227
  { name: "criteriaList", description: "Formatted list of all criteria with status" },
226
228
  { name: "modifiedFiles", description: "List of modified files" }
227
229
  ];
228
- function formatCriteriaList(entries) {
229
- if (entries.length === 0) return "(none)";
230
- return entries.map((e) => {
231
- const status = e.status === "passed" ? "[PASSED]" : e.status === "completed" ? "[NEEDS VERIFICATION]" : e.status === "failed" ? "[FAILED]" : "[NOT COMPLETED]";
232
- return `- **${e.id}** ${status}: ${e.description}`;
233
- }).join("\n");
234
- }
235
- async function formatModifiedFiles(workdir) {
236
- return formatGitDiffFiles(workdir);
237
- }
238
230
  function resolveTemplate(template, ctx) {
239
231
  let result = template;
240
232
  for (const { name } of TEMPLATE_VARIABLES) {
@@ -242,7 +234,7 @@ function resolveTemplate(template, ctx) {
242
234
  const value = String(ctx[name]);
243
235
  result = result.replace(new RegExp(`\\{\\{${name}\\}\\}`, "g"), value);
244
236
  }
245
- result = result.replace(/\{\{stepOutput\.(\w+)\}\}/g, (_, key) => ctx.stepOutput[key] ?? "");
237
+ result = result.replace(/\{\{stepOutput\.([\w.-]+)\}\}/g, (_, key) => ctx.stepOutput[key] ?? "");
246
238
  result = result.replace(/\{\{verifierFindings\}\}/g, ctx.stepOutput["content"] ?? "");
247
239
  result = result.replace(/\{\{previousStepOutput\}\}/g, ctx.stepOutput["stdout"] ?? "");
248
240
  for (const [key, value] of Object.entries(ctx.params)) {
@@ -250,6 +242,196 @@ function resolveTemplate(template, ctx) {
250
242
  }
251
243
  return result;
252
244
  }
245
+
246
+ // src/server/workflows/parallel.ts
247
+ async function mapPool(items, limit, task) {
248
+ const results = new Array(items.length);
249
+ let firstError = null;
250
+ let next = 0;
251
+ const workers = Array.from({ length: Math.min(Math.max(limit, 1), items.length) }, async () => {
252
+ while (next < items.length) {
253
+ const index = next++;
254
+ try {
255
+ results[index] = await task(items[index]);
256
+ } catch (error) {
257
+ if (firstError === null) {
258
+ firstError = error;
259
+ }
260
+ }
261
+ }
262
+ });
263
+ await Promise.all(workers);
264
+ if (firstError !== null) {
265
+ throw firstError;
266
+ }
267
+ return results;
268
+ }
269
+ function aggregateParallel(outcomes) {
270
+ const successCount = outcomes.filter((o) => o.result === "success").length;
271
+ const result = outcomes.length === 0 ? "failure" : successCount === outcomes.length ? "success" : successCount === 0 ? "failure" : "partial";
272
+ const output = {
273
+ result,
274
+ summary: outcomes.map((o) => `- ${o.id}: ${o.result}`).join("\n")
275
+ };
276
+ for (const o of outcomes) {
277
+ output[`${o.id}.result`] = o.result;
278
+ for (const [key, value] of Object.entries(o.output)) {
279
+ output[`${o.id}.${key}`] = value;
280
+ }
281
+ }
282
+ return { result, output };
283
+ }
284
+ function isAbortError(error) {
285
+ return error instanceof Error && error.message === "Aborted";
286
+ }
287
+ function failureOutcome(id, error) {
288
+ const message = error instanceof Error ? error.message : String(error);
289
+ logger.warn("Workflow child step failed", { child: id, error: message });
290
+ return { id, result: "failure", output: { error: message } };
291
+ }
292
+ async function runSubAgentChild(child, deps) {
293
+ const { sessionManager, sessionId, llmClient, ctx, signal, onMessage } = deps;
294
+ try {
295
+ const turnMetrics = new TurnMetrics();
296
+ const promptTemplate = child.prompt ?? "Perform your task.";
297
+ const resolvedPrompt = resolveTemplate(promptTemplate, ctx);
298
+ const allAgents = deps.agents ?? await loadAllAgentsDefault(sessionManager.getProjectWorkdir(sessionId));
299
+ const agentDef = findAgentById(child.subAgentType, allAgents);
300
+ if (!agentDef) {
301
+ logger.error("Sub-agent definition not found", { subAgentType: child.subAgentType });
302
+ return { id: child.id, result: "error", output: { error: `Unknown sub-agent type: ${child.subAgentType}` } };
303
+ }
304
+ const toolRegistry = getToolRegistryForAgent(agentDef);
305
+ const filteredToolRegistry = {
306
+ tools: toolRegistry.tools.filter((t) => t.name !== "step_done"),
307
+ definitions: toolRegistry.definitions.filter((d) => d.type === "function" && d.function.name !== "step_done"),
308
+ execute: toolRegistry.execute
309
+ };
310
+ const result = await executeSubAgent({
311
+ subAgentType: child.subAgentType,
312
+ prompt: resolvedPrompt,
313
+ sessionManager,
314
+ sessionId,
315
+ llmClient,
316
+ toolRegistry: filteredToolRegistry,
317
+ turnMetrics,
318
+ providerManager: sessionManager.getProviderManager?.(),
319
+ statsIdentity: deps.statsIdentity ?? {
320
+ providerId: "",
321
+ providerName: "",
322
+ backend: "unknown",
323
+ model: llmClient.getModel()
324
+ },
325
+ ...signal ? { signal } : {},
326
+ ...onMessage ? { onMessage } : {}
327
+ });
328
+ return {
329
+ id: child.id,
330
+ result: result.result ?? "success",
331
+ output: { content: result.content ?? "", ...result.result ? { result: result.result } : {} }
332
+ };
333
+ } catch (error) {
334
+ if (isAbortError(error)) {
335
+ throw error;
336
+ }
337
+ return failureOutcome(child.id, error);
338
+ }
339
+ }
340
+ async function runShellChild(child, deps) {
341
+ const { sessionManager, sessionId, ctx, label, signal, onMessage, eventStore, windowOptions } = deps;
342
+ if (child.command === void 0) {
343
+ logger.warn("Shell child has no command", { child: child.id });
344
+ return { id: child.id, result: "error", output: { error: "Missing command" } };
345
+ }
346
+ const command = resolveTemplate(child.command, ctx);
347
+ const timeout = child.timeout ?? 6e4;
348
+ const successCodes = child.successExitCodes ?? [0];
349
+ const runningContent = label ? serverT(
350
+ { en: "Running ({{label}}): `{{command}}`", fr: "Ex\xE9cution ({{label}}) : `{{command}}`" },
351
+ { label, command }
352
+ ) : serverT({ en: "Running: `{{command}}`", fr: "Ex\xE9cution : `{{command}}`" }, { command });
353
+ const shellMsgId = crypto.randomUUID();
354
+ eventStore.append(
355
+ sessionId,
356
+ createMessageStartEvent(shellMsgId, "user", runningContent, {
357
+ ...windowOptions ?? {},
358
+ isSystemGenerated: true,
359
+ messageKind: "auto-prompt",
360
+ metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
361
+ })
362
+ );
363
+ if (onMessage) {
364
+ onMessage(
365
+ createChatMessageMessage({
366
+ id: shellMsgId,
367
+ role: "user",
368
+ content: runningContent,
369
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
370
+ isSystemGenerated: true,
371
+ messageKind: "auto-prompt",
372
+ metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
373
+ })
374
+ );
375
+ }
376
+ const result = await executeShellCommand(command, sessionManager.getEffectiveWorkdir(sessionId), timeout, signal);
377
+ const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
378
+ const outputContent = output ? label ? serverT(
379
+ {
380
+ en: "Exit code ({{label}}): {{code}}\n```\n{{output}}\n```",
381
+ fr: "Code de sortie ({{label}}) : {{code}}\n```\n{{output}}\n```"
382
+ },
383
+ { label, code: result.exitCode, output: output.slice(0, 1e4) }
384
+ ) : serverT(
385
+ { en: "Exit code: {{code}}\n```\n{{output}}\n```", fr: "Code de sortie : {{code}}\n```\n{{output}}\n```" },
386
+ { code: result.exitCode, output: output.slice(0, 1e4) }
387
+ ) : label ? serverT(
388
+ { en: "Exit code ({{label}}): {{code}}", fr: "Code de sortie ({{label}}) : {{code}}" },
389
+ { label, code: result.exitCode }
390
+ ) : serverT({ en: "Exit code: {{code}}", fr: "Code de sortie : {{code}}" }, { code: result.exitCode });
391
+ eventStore.append(sessionId, { type: "message.done", data: { messageId: shellMsgId } });
392
+ const outputMsgId = crypto.randomUUID();
393
+ eventStore.append(
394
+ sessionId,
395
+ createMessageStartEvent(outputMsgId, "user", outputContent, {
396
+ ...windowOptions ?? {},
397
+ isSystemGenerated: true,
398
+ messageKind: "correction"
399
+ })
400
+ );
401
+ eventStore.append(sessionId, { type: "message.done", data: { messageId: outputMsgId } });
402
+ if (onMessage) {
403
+ onMessage(
404
+ createChatMessageMessage({
405
+ id: outputMsgId,
406
+ role: "user",
407
+ content: outputContent,
408
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
409
+ isSystemGenerated: true,
410
+ messageKind: "correction"
411
+ })
412
+ );
413
+ }
414
+ return {
415
+ id: child.id,
416
+ result: successCodes.includes(result.exitCode) ? "success" : "failure",
417
+ output: { stdout: result.stdout ?? "", stderr: result.stderr ?? "", exitCode: String(result.exitCode) }
418
+ };
419
+ }
420
+ async function runChild(child, deps) {
421
+ return child.type === "sub_agent" ? runSubAgentChild(child, deps) : runShellChild(child, deps);
422
+ }
423
+
424
+ // src/server/workflows/executor.ts
425
+ function formatCriteriaList(entries) {
426
+ if (entries.length === 0) return "(none)";
427
+ return entries.map((e) => {
428
+ const status = e.status === "passed" ? "[PASSED]" : e.status === "completed" ? "[NEEDS VERIFICATION]" : e.status === "failed" ? "[FAILED]" : "[NOT COMPLETED]";
429
+ return `- **${e.id}** ${status}: ${e.description}`;
430
+ }).join("\n");
431
+ }
432
+ async function formatModifiedFiles(workdir) {
433
+ return formatGitDiffFiles(workdir);
434
+ }
253
435
  function evaluateCondition(condition, stepOutcome, metadataEntries) {
254
436
  switch (condition.type) {
255
437
  case "step_result":
@@ -364,6 +546,20 @@ function buildReason(metadataEntries) {
364
546
  const remaining = entries.filter((e) => e.status !== "passed");
365
547
  return `${remaining.length} criteria remaining`;
366
548
  }
549
+ function buildStepChildDeps(options, templateCtx, eventStore, windowOptions) {
550
+ const { sessionManager, sessionId, llmClient, statsIdentity, signal, onMessage } = options;
551
+ return {
552
+ sessionManager,
553
+ sessionId,
554
+ llmClient,
555
+ ctx: templateCtx,
556
+ ...signal ? { signal } : {},
557
+ ...onMessage ? { onMessage } : {},
558
+ ...statsIdentity !== void 0 ? { statsIdentity } : {},
559
+ eventStore,
560
+ windowOptions
561
+ };
562
+ }
367
563
  async function executeWorkflow(workflow, options, subGroup) {
368
564
  const { sessionManager, sessionId, llmClient, signal, onMessage } = options;
369
565
  const eventStore = getEventStore();
@@ -582,22 +778,45 @@ async function executeWorkflow(workflow, options, subGroup) {
582
778
  const es = getEventStore();
583
779
  const append = (event) => es.append(sessionId, event);
584
780
  let stepDoneCalled = false;
781
+ const stepAgentId = agentStep.agentId ?? resolveDefaultAgentId();
782
+ const effectiveProviderManager = sessionManager.getProviderManager?.();
783
+ let stepLlmClient = llmClient;
784
+ let stepStatsIdentity = options.statsIdentity;
785
+ let stepGetSessionLLMClient = options.getSessionLLMClient;
786
+ if (effectiveProviderManager) {
787
+ const pinnedEffort = session.providerPinnedEffort ?? void 0;
788
+ const resolved = resolveLLMClientForAgent(stepAgentId, llmClient, effectiveProviderManager, pinnedEffort);
789
+ if (resolved.usedOverride && resolved.override) {
790
+ stepLlmClient = resolved.client;
791
+ stepStatsIdentity = buildAgentOverrideStatsIdentity(
792
+ effectiveProviderManager,
793
+ resolved.client,
794
+ resolved.override
795
+ );
796
+ stepGetSessionLLMClient = void 0;
797
+ } else if (resolved.warning) {
798
+ logger.warn("Agent step model override unavailable, falling back", {
799
+ agentId: stepAgentId,
800
+ warning: resolved.warning
801
+ });
802
+ }
803
+ }
585
804
  let agentResult;
586
805
  try {
587
806
  agentResult = await runAgentTurn(
588
807
  {
589
808
  sessionManager,
590
809
  sessionId,
591
- llmClient,
592
- ...options.getSessionLLMClient ? { getSessionLLMClient: options.getSessionLLMClient } : {},
593
- ...options.statsIdentity ? { statsIdentity: options.statsIdentity } : {},
810
+ llmClient: stepLlmClient,
811
+ ...stepGetSessionLLMClient ? { getSessionLLMClient: stepGetSessionLLMClient } : {},
812
+ ...stepStatsIdentity ? { statsIdentity: stepStatsIdentity } : {},
594
813
  ...signal ? { signal } : {},
595
814
  ...onMessage ? { onMessage } : {},
596
815
  ...options.llmRetryPolicy ? { llmRetryPolicy: options.llmRetryPolicy } : {},
597
816
  ...isResumingCurrentStep ? { skipAgentReminder: true } : {}
598
817
  },
599
818
  turnMetrics,
600
- agentStep.agentId ?? resolveDefaultAgentId(),
819
+ stepAgentId,
601
820
  append,
602
821
  {
603
822
  ...!firstEntryForStep.has(step.id) && !agentStep.prompt && !isResumingCurrentStep ? { injectKickoff: () => injectGenericKickoff(sessionId) } : {},
@@ -641,112 +860,63 @@ async function executeWorkflow(workflow, options, subGroup) {
641
860
  }
642
861
  case "sub_agent": {
643
862
  const subStep = step;
644
- const turnMetrics = new TurnMetrics();
645
- const promptTemplate = subStep.prompt ?? "Perform your task.";
646
- const resolvedPrompt = resolveTemplate(promptTemplate, templateCtx);
647
- const allAgents = await loadAllAgentsDefault(sessionManager.getProjectWorkdir(sessionId));
648
- const agentDef = findAgentById(subStep.subAgentType, allAgents);
649
- if (!agentDef) {
650
- logger.error("Sub-agent definition not found", { subAgentType: subStep.subAgentType });
651
- stepOutcome = { result: "error", output: {} };
652
- break;
863
+ const outcome = await runSubAgentChild(
864
+ subStep,
865
+ buildStepChildDeps(options, templateCtx, eventStore, currentWindowMessageOptions)
866
+ );
867
+ lastStepOutput = outcome.output;
868
+ stepOutcome = { result: outcome.result, output: lastStepOutput };
869
+ break;
870
+ }
871
+ case "shell": {
872
+ const shellStep = step;
873
+ const outcome = await runShellChild(
874
+ shellStep,
875
+ buildStepChildDeps(options, templateCtx, eventStore, currentWindowMessageOptions)
876
+ );
877
+ lastStepOutput = outcome.output;
878
+ stepOutcome = { result: outcome.result, output: lastStepOutput };
879
+ break;
880
+ }
881
+ case "parallel": {
882
+ const parallelStep = step;
883
+ if (parallelStep.children.length === 0) {
884
+ logger.warn("Parallel step has no children", { sessionId, stepId: step.id });
653
885
  }
654
- const toolRegistry = getToolRegistryForAgent(agentDef);
655
- const filteredToolRegistry = {
656
- tools: toolRegistry.tools.filter((t) => t.name !== "step_done"),
657
- definitions: toolRegistry.definitions.filter((d) => d.type === "function" && d.function.name !== "step_done"),
658
- execute: toolRegistry.execute
659
- };
660
- const result = await executeSubAgent({
661
- subAgentType: subStep.subAgentType,
662
- prompt: resolvedPrompt,
886
+ const childIds = parallelStep.children.map((c) => c.id);
887
+ if (new Set(childIds).size !== childIds.length) {
888
+ logger.warn("Parallel step has duplicate child ids", { sessionId, stepId: step.id, ids: childIds });
889
+ }
890
+ const allAgents = await loadAllAgentsDefault(sessionManager.getProjectWorkdir(sessionId));
891
+ const baseDeps = {
663
892
  sessionManager,
664
893
  sessionId,
665
894
  llmClient,
666
- toolRegistry: filteredToolRegistry,
667
- turnMetrics,
668
- providerManager: sessionManager.getProviderManager?.(),
895
+ ctx: templateCtx,
896
+ ...signal ? { signal } : {},
897
+ ...onMessage ? { onMessage } : {},
898
+ eventStore,
899
+ windowOptions: currentWindowMessageOptions,
669
900
  statsIdentity: options.statsIdentity ?? {
670
901
  providerId: "",
671
902
  providerName: "",
672
903
  backend: "unknown",
673
904
  model: llmClient.getModel()
674
905
  },
675
- ...signal ? { signal } : {},
676
- ...onMessage ? { onMessage } : {}
677
- });
678
- lastStepOutput = { content: result.content ?? "", ...result.result ? { result: result.result } : {} };
679
- stepOutcome = { result: result.result ?? "success", output: lastStepOutput };
680
- break;
681
- }
682
- case "shell": {
683
- const shellStep = step;
684
- const command = resolveTemplate(shellStep.command, templateCtx);
685
- const timeout = shellStep.timeout ?? 6e4;
686
- const successCodes = shellStep.successExitCodes ?? [0];
687
- const shellMsgId = crypto.randomUUID();
688
- const runningContent = serverT({ en: "Running: `{{command}}`", fr: "Ex\xE9cution : `{{command}}`" }, { command });
689
- eventStore.append(
690
- sessionId,
691
- createMessageStartEvent(shellMsgId, "user", runningContent, {
692
- ...currentWindowMessageOptions ?? {},
693
- isSystemGenerated: true,
694
- messageKind: "auto-prompt",
695
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
696
- })
697
- );
698
- if (onMessage) {
699
- onMessage(
700
- createChatMessageMessage({
701
- id: shellMsgId,
702
- role: "user",
703
- content: runningContent,
704
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
705
- isSystemGenerated: true,
706
- messageKind: "auto-prompt",
707
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
708
- })
709
- );
710
- }
711
- const result = await executeShellCommand(
712
- command,
713
- sessionManager.getEffectiveWorkdir(sessionId),
714
- timeout,
715
- signal
906
+ agents: allAgents
907
+ };
908
+ const limit = Math.min(
909
+ Math.max(Math.floor(parallelStep.maxConcurrency ?? parallelStep.children.length), 1),
910
+ parallelStep.children.length
716
911
  );
717
- const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
718
- lastStepOutput = { stdout: result.stdout ?? "", stderr: result.stderr ?? "", exitCode: String(result.exitCode) };
719
- const outputContent = output ? serverT(
720
- {
721
- en: "Exit code: {{code}}\n```\n{{output}}\n```",
722
- fr: "Code de sortie : {{code}}\n```\n{{output}}\n```"
723
- },
724
- { code: result.exitCode, output: output.slice(0, 1e4) }
725
- ) : serverT({ en: "Exit code: {{code}}", fr: "Code de sortie : {{code}}" }, { code: result.exitCode });
726
- eventStore.append(sessionId, { type: "message.done", data: { messageId: shellMsgId } });
727
- const outputMsgId = crypto.randomUUID();
728
- eventStore.append(
729
- sessionId,
730
- createMessageStartEvent(outputMsgId, "user", outputContent, {
731
- ...currentWindowMessageOptions ?? {},
732
- isSystemGenerated: true,
733
- messageKind: "correction"
734
- })
912
+ const outcomes = await mapPool(
913
+ parallelStep.children,
914
+ limit,
915
+ (child) => runChild(child, { ...baseDeps, label: child.id })
735
916
  );
736
- eventStore.append(sessionId, { type: "message.done", data: { messageId: outputMsgId } });
737
- if (onMessage) {
738
- onMessage(
739
- createChatMessageMessage({
740
- id: outputMsgId,
741
- role: "user",
742
- content: outputContent,
743
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
744
- isSystemGenerated: true,
745
- messageKind: "correction"
746
- })
747
- );
748
- }
749
- stepOutcome = { result: successCodes.includes(result.exitCode) ? "success" : "failure", output: lastStepOutput };
917
+ const aggregate = aggregateParallel(outcomes);
918
+ lastStepOutput = aggregate.output;
919
+ stepOutcome = { result: aggregate.result, output: lastStepOutput };
750
920
  break;
751
921
  }
752
922
  case "user": {
@@ -1026,4 +1196,4 @@ export {
1026
1196
  abortRunnerRun,
1027
1197
  launchWorkflowRun
1028
1198
  };
1029
- //# sourceMappingURL=chunk-7BIGFGU5.js.map
1199
+ //# sourceMappingURL=chunk-2V6QL6IW.js.map
@@ -0,0 +1,7 @@
1
+ // src/constants.ts
2
+ var VERSION = "2.0.147";
3
+
4
+ export {
5
+ VERSION
6
+ };
7
+ //# sourceMappingURL=chunk-65KDNVRA.js.map
@@ -3,14 +3,14 @@ import {
3
3
  checkToolChangesAndInject,
4
4
  computeDynamicContextHash,
5
5
  getToolFingerprint
6
- } from "./chunk-L43S7FJM.js";
6
+ } from "./chunk-ESHP42KO.js";
7
7
  import {
8
8
  createAssemblyResult,
9
9
  getConversationMessages,
10
10
  getToolRegistryForAgent,
11
11
  processEventsForConversation,
12
12
  runTopLevelAgentLoop
13
- } from "./chunk-QR6FIHIP.js";
13
+ } from "./chunk-AJMBQMJH.js";
14
14
  import {
15
15
  getAllInstructions,
16
16
  getEnabledSkillMetadata
@@ -357,7 +357,7 @@ async function runAgentTurn(options, turnMetrics, agentId, append, callbacks) {
357
357
  getConversationMessages: buildGetConversationMessages(options.sessionId, resolveAgentClient, append),
358
358
  injectAgentReminder: () => injectAgentReminder(options.sessionId, agentDef),
359
359
  rebuildCachedContext: async () => {
360
- const { applyDynamicContext } = await import("./dynamic-context-IQUBKUCX.js");
360
+ const { applyDynamicContext } = await import("./dynamic-context-YLRA34WJ.js");
361
361
  await applyDynamicContext(options.sessionManager, options.sessionId, agentLlmClient.getModel());
362
362
  },
363
363
  ...options.initialCompacting ? { initialCompacting: true } : {},
@@ -387,4 +387,4 @@ export {
387
387
  runChatTurn,
388
388
  runAgentTurn
389
389
  };
390
- //# sourceMappingURL=chunk-5D4MQG7P.js.map
390
+ //# sourceMappingURL=chunk-ABXERHIY.js.map
@@ -1162,6 +1162,16 @@ function resolveLLMClientForAgent(agentId, fallbackClient, providerManager, pinn
1162
1162
  override: effectiveEffort ? { ...override, reasoningEffort: effectiveEffort } : override
1163
1163
  };
1164
1164
  }
1165
+ function buildAgentOverrideStatsIdentity(providerManager, client, override) {
1166
+ const provider = providerManager.getProviders().find((p) => p.id === override.providerId);
1167
+ return {
1168
+ providerId: override.providerId,
1169
+ providerName: provider?.name ?? override.providerId,
1170
+ backend: provider?.backend ?? client.getBackend(),
1171
+ model: override.model,
1172
+ ...override.reasoningEffort ? { reasoningEffort: override.reasoningEffort } : {}
1173
+ };
1174
+ }
1165
1175
 
1166
1176
  // src/server/chat/tool-streaming.ts
1167
1177
  function parseProgressMessage(message) {
@@ -2241,14 +2251,7 @@ async function executeSubAgent(options) {
2241
2251
  if (resolved.usedOverride && resolved.override) {
2242
2252
  hasOverride = true;
2243
2253
  llmClient = resolved.client;
2244
- const provider = effectiveProviderManager.getProviders().find((p) => p.id === resolved.override.providerId);
2245
- statsIdentity = {
2246
- providerId: resolved.override.providerId,
2247
- providerName: provider?.name ?? resolved.override.providerId,
2248
- backend: provider?.backend ?? resolved.client.getBackend(),
2249
- model: resolved.override.model,
2250
- ...resolved.override.reasoningEffort ? { reasoningEffort: resolved.override.reasoningEffort } : {}
2251
- };
2254
+ statsIdentity = buildAgentOverrideStatsIdentity(effectiveProviderManager, resolved.client, resolved.override);
2252
2255
  const overrideEffort = effectiveProviderManager.resolveModelEffort(
2253
2256
  resolved.override.providerId,
2254
2257
  resolved.override.model,
@@ -2475,7 +2478,7 @@ var callSubAgentTool = {
2475
2478
  };
2476
2479
  }
2477
2480
  try {
2478
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-OH3WW6Q4.js");
2481
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-MRC27SZG.js");
2479
2482
  const toolRegistry = getToolRegistryForAgent2(agentDef);
2480
2483
  const turnMetrics = new TurnMetrics();
2481
2484
  const result = await executeSubAgent({
@@ -3579,11 +3582,11 @@ var mcpConfigTool = createTool(
3579
3582
  async function notifyContextChanged(sessionId) {
3580
3583
  context.sessionManager.setDynamicContextChanged(sessionId, true);
3581
3584
  mcpNotifyChanged?.(sessionId);
3582
- const { injectContextDriftReminders } = await import("./dynamic-context-IQUBKUCX.js");
3585
+ const { injectContextDriftReminders } = await import("./dynamic-context-YLRA34WJ.js");
3583
3586
  await injectContextDriftReminders(context.sessionManager, sessionId);
3584
3587
  }
3585
3588
  async function rebuildTools() {
3586
- const { setMcpTools: setMcpTools2 } = await import("./tools-OH3WW6Q4.js");
3589
+ const { setMcpTools: setMcpTools2 } = await import("./tools-MRC27SZG.js");
3587
3590
  const mcpTools = createMcpTools(mcpManagerForTools);
3588
3591
  setMcpTools2(mcpTools);
3589
3592
  }
@@ -4702,6 +4705,7 @@ export {
4702
4705
  getAgentModelOverride,
4703
4706
  setAgentModelOverride,
4704
4707
  resolveLLMClientForAgent,
4708
+ buildAgentOverrideStatsIdentity,
4705
4709
  runTopLevelAgentLoop,
4706
4710
  createAssemblyResult,
4707
4711
  getConversationMessages,
@@ -4725,4 +4729,4 @@ export {
4725
4729
  getToolRegistryForAgent,
4726
4730
  createToolRegistry
4727
4731
  };
4728
- //# sourceMappingURL=chunk-QR6FIHIP.js.map
4732
+ //# sourceMappingURL=chunk-AJMBQMJH.js.map