kyegomez/swarms

[Improvement] ConcurrentWorkflow aborts the whole run when any single agent fails

Closed

#1,613 建立於 2026年5月14日

在 GitHub 查看
 (2 留言) (0 反應) (0 負責人)Python (948 fork)github user discovery
FEATenhancementgood first issuehelp wanted

倉庫指標

Star
 (6,809 star)
PR 合併指標
 (PR 指標待抓取)

描述

Summary

In ConcurrentWorkflow, one failed agent kills the entire run and discards all sibling outputs that already completed successfully. This contradicts the design goal of independent concurrent execution.

Repro

from swarms import Agent, ConcurrentWorkflow

a = Agent(agent_name="Good-1", model_name="gpt-4.1", max_loops=1)
b = Agent(agent_name="Good-2", model_name="gpt-4.1", max_loops=1)
c = Agent(agent_name="Bad",    model_name="gpt-4.1", max_loops=1)
c.run = lambda *a, **kw: (_ for _ in ()).throw(RuntimeError("boom"))

wf = ConcurrentWorkflow(agents=[a, b, c])
wf.run("Summarise the news today.")
# Expected: results for Good-1 and Good-2, plus an error marker for Bad.
# Actual:   RuntimeError propagates out — Good-1 and Good-2's outputs are lost.

Root cause

swarms/structs/concurrent_workflow.py:418-425 does not wrap future.result() in a try/except:

for future in as_completed(futures):
    output = future.result()        # raises on any failed worker
    self.conversation.add(...)

The dashboard variant already handles this correctly at concurrent_workflow.py:346-356. The non-dashboard path was missed.

Proposed fix

Wrap future.result() in try/except mirroring the dashboard path. On error, append a clearly-labeled error entry to the conversation (e.g., role f"{agent_name} (failed)") so callers can filter it, and continue collecting sibling results.

Add an opt-in constructor flag for users who prefer the old behavior:

on_error: Literal["raise", "store"] = "store"

"store" (default) collects per-agent errors and returns partial results. "raise" preserves today's fail-fast behavior.

Tests to add

  • ConcurrentWorkflow with one failing agent and two passing agents: assert partial results returned, failed agent's error captured under its name, no exception escapes.
  • on_error="raise": assert the exception still propagates.

貢獻者指南