Skip to content

Commit 94696e9

Browse files
zzstoatzzclaude
andauthored
Deprecate Teams feature due to fundamental issues (#1221)
* Deprecate Teams feature due to fundamental issues The Teams feature (including Team, Swarm, RoundRobinTeam, and RandomTeam) has critical issues: 1. **Infinite delegation loops**: Swarm and other delegation-based teams get stuck in endless loops, generating hundreds of "Multiple EndTurn tools detected" warnings. 2. **No actual collaboration**: Basic Team doesn't enable agents to work together - only the first agent does any work. 3. **Broken documentation**: The HierarchicalTeam example in docs doesn't even work due to incorrect handling of the required `members` field. 4. **Incomplete implementation**: The feature appears to have been rushed for release without proper testing or validation. This commit: - Adds deprecation warnings to all Team classes (removal targeted for Feb 2026) - Fixes the broken documentation example - Adds clear warnings in docs about the deprecated status - Creates a deprecation utility module based on Prefect's patterns Users are advised to use individual Agents with explicit coordination instead of Teams. Fixes issues reported by community members struggling with non-functional examples. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix gitignore * Fix deprecation timeline and remove Sphinx directive - Set removal date to Sep 2025 (1 month from now, not 6) - Remove meaningless Sphinx directive from docstring - Fix documentation to show correct timeline * Fix Mintlify warning syntax - use proper HTML-like tags * big brother --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 69b6374 commit 94696e9

7 files changed

Lines changed: 156 additions & 39 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ wheels/
2323

2424
# database files
2525
**/*.db
26-
**/*.sqlite
26+
**/*.sqlite
27+
sandbox/

CLAUDE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
Marvin is a lightweight AI engineering toolkit for building natural language interfaces that are reliable, scalable, and easy to trust.
44

5+
## Reproductions
6+
- use the repros folder to reproduce the results (e.g. `uv run repros/1234.py`)
7+
- this folder is not checked into git
8+
59
## Architecture & Design Philosophy
610

711
- **Aggressively minimal and elegant**: Keep implementations simple and focused

docs/concepts/agents.mdx

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -124,42 +124,6 @@ editor = marvin.Agent(
124124
)
125125
```
126126

127-
## Teams
128-
129-
In Marvin, agents can be organized into teams to work together on tasks. A team is a way to govern how agents collaborate.
130-
131-
For a comprehensive guide on teams, see the [Teams](/concepts/teams) documentation page.
132-
133-
### Swarms
134-
135-
A swarm is a team of multiple agents that can freely collaborate and delegate tasks to each other. This is useful for complex tasks that require different types of expertise:
136-
137-
```python
138-
import marvin
139-
from marvin import Agent, Swarm
140-
141-
researcher = Agent(name="Researcher")
142-
writer = Agent(name="Writer")
143-
editor = Agent(name="Editor")
144-
145-
team = Swarm(members=[researcher, writer, editor])
146-
147-
result = team.run("Write a report about AI")
148-
```
149-
150-
<Tip>
151-
When you provide a list of agents to a task, Marvin will automatically treat them as a swarm.
152-
</Tip>
153-
154-
### Other Team Types
155-
156-
Marvin supports several team configurations beyond Swarms:
157-
158-
- **RoundRobinTeam**: Rotates through its members in sequence
159-
- **RandomTeam**: Randomly selects an agent for each turn
160-
161-
See the [Teams](/concepts/teams) documentation for more details and examples.
162-
163127
## Assigning agents to tasks
164128

165129
Agents must be assigned to tasks in order to work on them. You can assign agents by passing them to the `agents` parameter when creating a task:

docs/concepts/teams.mdx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ description: Coordinate multiple AI agents to solve complex problems
44
icon: users
55
---
66

7+
<Warning>
8+
**Deprecation Notice:** Teams and Swarms are deprecated as of August 2025 due to known issues with delegation loops and incomplete implementation. These features will be removed after September 2025.
9+
10+
**Recommended alternative:** Use individual Agents with explicit coordination through your application logic.
11+
</Warning>
12+
713
Teams in Marvin allow multiple agents to collaborate on tasks, combining their specialized skills and perspectives to achieve better results than a single agent could alone.
814

915
## What are Teams?
@@ -35,7 +41,11 @@ print(article)
3541

3642
Marvin offers several team configurations:
3743

38-
### Swarm
44+
### Swarm (Deprecated)
45+
46+
<Warning>
47+
**Swarm is deprecated** and has known issues with infinite delegation loops. It is not recommended for production use.
48+
</Warning>
3949

4050
A Swarm is the simplest type of team, where all agents can freely collaborate and delegate to each other. Any agent in the swarm can ask another agent for help at any time.
4151

@@ -125,9 +135,13 @@ class HierarchicalTeam(Team):
125135
leader: Agent = field(repr=False)
126136
specialists: list[Agent] = field(repr=False)
127137

138+
# Override members field to compute it from leader and specialists
139+
members: list[Agent] = field(init=False, repr=False, default_factory=list)
140+
128141
def __post_init__(self):
129142
self.members = [self.leader] + self.specialists
130-
self.active_member = self.leader
143+
# Call parent __post_init__ to properly initialize the team
144+
super().__post_init__()
131145
self.delegates = {self.leader: self.specialists}
132146

133147
# Usage

sandbox/prefect

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 602ae7cddb1540d0e6cbba66e17d2718ba571515
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
"""
2+
Deprecation utilities for Marvin.
3+
4+
Based on Prefect's deprecation patterns but simplified for Marvin's needs.
5+
"""
6+
7+
import functools
8+
import warnings
9+
from datetime import datetime, timedelta
10+
from typing import Any, Callable, Optional, TypeVar
11+
12+
from typing_extensions import ParamSpec
13+
14+
P = ParamSpec("P")
15+
R = TypeVar("R")
16+
T = TypeVar("T")
17+
18+
19+
class MarvinDeprecationWarning(DeprecationWarning):
20+
"""A Marvin-specific deprecation warning."""
21+
22+
23+
def generate_deprecation_message(
24+
name: str,
25+
start_date: Optional[datetime] = None,
26+
end_date: Optional[datetime] = None,
27+
help: str = "",
28+
) -> str:
29+
"""Generate a deprecation warning message."""
30+
if start_date is None and end_date is None:
31+
# Default to 1 month from now
32+
end_date = datetime.now() + timedelta(days=30)
33+
elif start_date and not end_date:
34+
# Calculate end date as 1 month after start
35+
end_date = start_date + timedelta(days=30)
36+
37+
end_date_str = end_date.strftime("%b %Y") if end_date else "unknown"
38+
39+
message = (
40+
f"{name} is deprecated and will be removed after {end_date_str}. {help}"
41+
).strip()
42+
43+
return message
44+
45+
46+
def deprecated_class(
47+
*,
48+
start_date: Optional[datetime] = None,
49+
end_date: Optional[datetime] = None,
50+
stacklevel: int = 2,
51+
help: str = "",
52+
) -> Callable[[type[T]], type[T]]:
53+
"""
54+
Decorator to mark a class as deprecated.
55+
56+
Example:
57+
@deprecated_class(
58+
start_date=datetime(2025, 1, 1),
59+
help="Use Agent directly instead."
60+
)
61+
class OldClass:
62+
pass
63+
"""
64+
65+
def decorator(cls: type[T]) -> type[T]:
66+
message = generate_deprecation_message(
67+
name=f"{cls.__module__}.{cls.__name__}",
68+
start_date=start_date,
69+
end_date=end_date,
70+
help=help,
71+
)
72+
73+
original_init = cls.__init__
74+
75+
@functools.wraps(original_init)
76+
def new_init(self: T, *args: Any, **kwargs: Any) -> None:
77+
warnings.warn(message, MarvinDeprecationWarning, stacklevel=stacklevel)
78+
original_init(self, *args, **kwargs)
79+
80+
cls.__init__ = new_init
81+
return cls
82+
83+
return decorator
84+
85+
86+
def deprecated_callable(
87+
*,
88+
start_date: Optional[datetime] = None,
89+
end_date: Optional[datetime] = None,
90+
stacklevel: int = 2,
91+
help: str = "",
92+
) -> Callable[[Callable[P, R]], Callable[P, R]]:
93+
"""
94+
Decorator to mark a function as deprecated.
95+
96+
Example:
97+
@deprecated_callable(
98+
start_date=datetime(2025, 1, 1),
99+
help="Use new_function() instead."
100+
)
101+
def old_function():
102+
pass
103+
"""
104+
105+
def decorator(fn: Callable[P, R]) -> Callable[P, R]:
106+
message = generate_deprecation_message(
107+
name=f"{fn.__module__}.{fn.__name__}",
108+
start_date=start_date,
109+
end_date=end_date,
110+
help=help,
111+
)
112+
113+
@functools.wraps(fn)
114+
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
115+
warnings.warn(message, MarvinDeprecationWarning, stacklevel=stacklevel)
116+
return fn(*args, **kwargs)
117+
118+
return wrapper
119+
120+
return decorator

src/marvin/agents/team.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ class Team(Actor):
3838
delegates: dict[Actor, list[Actor]] = field(default_factory=dict, repr=False)
3939

4040
def __post_init__(self):
41+
# Show deprecation warning for all Team instantiations
42+
import warnings
43+
44+
from marvin._internal.deprecation import MarvinDeprecationWarning
45+
46+
warnings.warn(
47+
f"{self.__class__.__module__}.{self.__class__.__name__} is deprecated and will be removed after Sep 2025. "
48+
"Team functionality is incomplete and does not provide meaningful agent collaboration. "
49+
"Consider using individual Agents with explicit coordination instead.",
50+
MarvinDeprecationWarning,
51+
stacklevel=3,
52+
)
53+
4154
if not self.members:
4255
raise ValueError("Team must have at least one member")
4356
self.active_member = self.members[0]

0 commit comments

Comments
 (0)