pyagent-patterns 0.1.0__py3-none-any.whl
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.
- pyagent_patterns/__init__.py +20 -0
- pyagent_patterns/advanced/__init__.py +8 -0
- pyagent_patterns/advanced/human_in_the_loop.py +103 -0
- pyagent_patterns/advanced/react.py +132 -0
- pyagent_patterns/advanced/swarm.py +106 -0
- pyagent_patterns/advanced/talker_reasoner.py +92 -0
- pyagent_patterns/advisor.py +166 -0
- pyagent_patterns/base.py +215 -0
- pyagent_patterns/composite.py +105 -0
- pyagent_patterns/guardrails.py +165 -0
- pyagent_patterns/orchestration/__init__.py +9 -0
- pyagent_patterns/orchestration/fan_out_fan_in.py +76 -0
- pyagent_patterns/orchestration/hierarchical.py +110 -0
- pyagent_patterns/orchestration/orchestrator_workers.py +97 -0
- pyagent_patterns/orchestration/pipeline.py +57 -0
- pyagent_patterns/orchestration/supervisor.py +88 -0
- pyagent_patterns/py.typed +0 -0
- pyagent_patterns/recovery.py +175 -0
- pyagent_patterns/registry.py +71 -0
- pyagent_patterns/resolution/__init__.py +9 -0
- pyagent_patterns/resolution/cross_reflection.py +79 -0
- pyagent_patterns/resolution/debate.py +103 -0
- pyagent_patterns/resolution/evaluator_optimizer.py +108 -0
- pyagent_patterns/resolution/self_reflection.py +80 -0
- pyagent_patterns/resolution/voting.py +93 -0
- pyagent_patterns/streaming.py +119 -0
- pyagent_patterns/structural/__init__.py +8 -0
- pyagent_patterns/structural/blackboard.py +137 -0
- pyagent_patterns/structural/layered.py +70 -0
- pyagent_patterns/structural/role_based.py +61 -0
- pyagent_patterns/structural/topology.py +123 -0
- pyagent_patterns-0.1.0.dist-info/METADATA +59 -0
- pyagent_patterns-0.1.0.dist-info/RECORD +34 -0
- pyagent_patterns-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Topology pattern: configurable communication graph — Chain, Star, or Mesh.
|
|
2
|
+
|
|
3
|
+
Controls which agents can communicate with which, affecting information
|
|
4
|
+
flow, overhead, and result quality.
|
|
5
|
+
|
|
6
|
+
- Chain: A→B→C (sequential, low overhead)
|
|
7
|
+
- Star: Hub↔{A,B,C} (centralized, easy to trace)
|
|
8
|
+
- Mesh: A↔B↔C↔A (rich but expensive)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
from enum import Enum
|
|
15
|
+
|
|
16
|
+
from pyagent_patterns.base import Agent, Context, Message, Pattern, Result
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TopologyType(str, Enum):
|
|
20
|
+
CHAIN = "chain"
|
|
21
|
+
STAR = "star"
|
|
22
|
+
MESH = "mesh"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Topology(Pattern):
|
|
26
|
+
"""Configurable agent communication topology.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
agents: List of agents participating in the topology.
|
|
30
|
+
topology: The communication structure (chain, star, mesh).
|
|
31
|
+
hub_index: For star topology, the index of the hub agent. Defaults to 0.
|
|
32
|
+
rounds: For mesh topology, number of communication rounds.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
agents: list[Agent],
|
|
38
|
+
topology: TopologyType = TopologyType.CHAIN,
|
|
39
|
+
hub_index: int = 0,
|
|
40
|
+
rounds: int = 1,
|
|
41
|
+
) -> None:
|
|
42
|
+
if len(agents) < 2:
|
|
43
|
+
raise ValueError("Topology requires at least 2 agents")
|
|
44
|
+
self._agents = agents
|
|
45
|
+
self._topology = topology
|
|
46
|
+
self._hub_index = hub_index
|
|
47
|
+
self._rounds = rounds
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def pattern_type(self) -> str:
|
|
51
|
+
return f"topology_{self._topology.value}"
|
|
52
|
+
|
|
53
|
+
async def _execute(self, ctx: Context) -> Result:
|
|
54
|
+
if self._topology == TopologyType.CHAIN:
|
|
55
|
+
return await self._chain(ctx)
|
|
56
|
+
elif self._topology == TopologyType.STAR:
|
|
57
|
+
return await self._star(ctx)
|
|
58
|
+
else:
|
|
59
|
+
return await self._mesh(ctx)
|
|
60
|
+
|
|
61
|
+
async def _chain(self, ctx: Context) -> Result:
|
|
62
|
+
"""A→B→C: sequential processing."""
|
|
63
|
+
messages: list[Message] = []
|
|
64
|
+
current = ctx.task
|
|
65
|
+
|
|
66
|
+
for agent in self._agents:
|
|
67
|
+
result = await agent.run([Message.user(current)])
|
|
68
|
+
messages.append(result)
|
|
69
|
+
current = result.content
|
|
70
|
+
|
|
71
|
+
return Result(output=current, messages=messages, metadata={"topology": "chain"})
|
|
72
|
+
|
|
73
|
+
async def _star(self, ctx: Context) -> Result:
|
|
74
|
+
"""Hub↔{spokes}: hub collects from all spokes."""
|
|
75
|
+
messages: list[Message] = []
|
|
76
|
+
hub = self._agents[self._hub_index]
|
|
77
|
+
spokes = [a for i, a in enumerate(self._agents) if i != self._hub_index]
|
|
78
|
+
|
|
79
|
+
# Spokes process in parallel
|
|
80
|
+
tasks = [spoke.run([Message.user(ctx.task)]) for spoke in spokes]
|
|
81
|
+
spoke_results = await asyncio.gather(*tasks)
|
|
82
|
+
messages.extend(spoke_results)
|
|
83
|
+
|
|
84
|
+
# Hub synthesizes
|
|
85
|
+
summary = "\n".join(
|
|
86
|
+
f"- {spokes[i].name}: {r.content}" for i, r in enumerate(spoke_results)
|
|
87
|
+
)
|
|
88
|
+
hub_result = await hub.run([Message.user(
|
|
89
|
+
f"Synthesize these inputs:\n{summary}\n\nOriginal task: {ctx.task}"
|
|
90
|
+
)])
|
|
91
|
+
messages.append(hub_result)
|
|
92
|
+
|
|
93
|
+
return Result(output=hub_result.content, messages=messages, metadata={"topology": "star"})
|
|
94
|
+
|
|
95
|
+
async def _mesh(self, ctx: Context) -> Result:
|
|
96
|
+
"""Full mesh: every agent sees every other agent's output per round."""
|
|
97
|
+
messages: list[Message] = []
|
|
98
|
+
outputs = {a.name: "" for a in self._agents}
|
|
99
|
+
|
|
100
|
+
# Initial round
|
|
101
|
+
tasks = [a.run([Message.user(ctx.task)]) for a in self._agents]
|
|
102
|
+
initial = await asyncio.gather(*tasks)
|
|
103
|
+
for agent, result in zip(self._agents, initial):
|
|
104
|
+
outputs[agent.name] = result.content
|
|
105
|
+
messages.append(result)
|
|
106
|
+
|
|
107
|
+
# Subsequent mesh rounds
|
|
108
|
+
for _ in range(1, self._rounds + 1):
|
|
109
|
+
for agent in self._agents:
|
|
110
|
+
peer_outputs = "\n".join(
|
|
111
|
+
f"- {name}: {content}"
|
|
112
|
+
for name, content in outputs.items()
|
|
113
|
+
if name != agent.name
|
|
114
|
+
)
|
|
115
|
+
result = await agent.run([Message.user(
|
|
116
|
+
f"Task: {ctx.task}\n\nPeer outputs:\n{peer_outputs}\n\nProvide your updated response."
|
|
117
|
+
)])
|
|
118
|
+
outputs[agent.name] = result.content
|
|
119
|
+
messages.append(result)
|
|
120
|
+
|
|
121
|
+
# Final output is concatenation of all agent outputs
|
|
122
|
+
final = "\n\n".join(f"[{name}]: {content}" for name, content in outputs.items())
|
|
123
|
+
return Result(output=final, messages=messages, metadata={"topology": "mesh", "rounds": self._rounds})
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyagent-patterns
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: 18 reusable multi-agent orchestration patterns for LLMs
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: LLM,agents,multi-agent,orchestration,patterns
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
14
|
+
Classifier: Typing :: Typed
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
18
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
19
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
20
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# pyagent-patterns
|
|
24
|
+
|
|
25
|
+
**18 reusable multi-agent orchestration patterns for LLMs** — zero dependencies, async-first, fully typed.
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install pyagent-patterns
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Patterns
|
|
34
|
+
|
|
35
|
+
| Tier | Patterns |
|
|
36
|
+
|------|----------|
|
|
37
|
+
| Orchestration | Supervisor, Pipeline, Fan-Out/Fan-In, Hierarchical, Orchestrator-Workers |
|
|
38
|
+
| Resolution | Self-Reflection, Cross-Reflection, Debate, Voting, Evaluator-Optimizer |
|
|
39
|
+
| Structural | Role-Based, Layered, Topology, Blackboard |
|
|
40
|
+
| Advanced | Talker-Reasoner, Swarm, Human-in-the-Loop, ReAct |
|
|
41
|
+
|
|
42
|
+
Plus: CompositePattern (escalation chains), PatternAdvisor, GuardrailChain, BoundedExecution, CircuitBreaker.
|
|
43
|
+
|
|
44
|
+
## Quick Example
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import asyncio
|
|
48
|
+
from pyagent_patterns.base import Agent, MockLLM
|
|
49
|
+
from pyagent_patterns.resolution import SelfReflection
|
|
50
|
+
|
|
51
|
+
llm = MockLLM(responses=["Draft code", "Needs error handling", "Improved code", "APPROVED"])
|
|
52
|
+
pattern = SelfReflection(agent=Agent("coder", llm), max_rounds=3)
|
|
53
|
+
result = asyncio.run(pattern.run("Write a sorting function"))
|
|
54
|
+
print(result.output)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Documentation
|
|
58
|
+
|
|
59
|
+
Full docs: [pyagent.dev](https://pyagent.dev)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
pyagent_patterns/__init__.py,sha256=c-lC-NmHEuWSQnKHe0FCFiqkWzFTCqKpS13hwIGaByI,550
|
|
2
|
+
pyagent_patterns/advisor.py,sha256=w6q9wbyjxqUw-7qtlnijDrltaI1IYEunF1RmNWEu0sw,6437
|
|
3
|
+
pyagent_patterns/base.py,sha256=n3zcIPm9JoVGu94408Q3crQMh0318avVO7ot4Ajwexo,6808
|
|
4
|
+
pyagent_patterns/composite.py,sha256=dPjMQpmrE9Me8mo_regUcKCkXHuKwdBtt39-fYjAKkM,3602
|
|
5
|
+
pyagent_patterns/guardrails.py,sha256=0ONWPu3hoevaSp4b1O5W53LuCsJrBUWUtNnl57PUE6s,5230
|
|
6
|
+
pyagent_patterns/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
pyagent_patterns/recovery.py,sha256=huhtK2v6qs7UvD6zRP-t1vaU0VKQy-6ilQ0YoOsg7x8,6310
|
|
8
|
+
pyagent_patterns/registry.py,sha256=cYjewpD0Aqv4bEUYc65IYTrQQWWlcNvfLaSrkOgJdx4,2679
|
|
9
|
+
pyagent_patterns/streaming.py,sha256=stmnBF1fNiC47-0-WTYeZPm1JzzStZGvcw8TeWdLcY0,4012
|
|
10
|
+
pyagent_patterns/advanced/__init__.py,sha256=Po2aJhSG1a-K2yHGVkpbTqVNz_8XYqlC5HQ8ImjQvfE,398
|
|
11
|
+
pyagent_patterns/advanced/human_in_the_loop.py,sha256=oNHCpolttYQ9xCbfKbZVuwnUvwYY_UpPcIL7Qu0JkGo,3378
|
|
12
|
+
pyagent_patterns/advanced/react.py,sha256=TVFy97D9hprJzElADN-bJ_gW8XjT-fgdT4yO9AGTr7c,4786
|
|
13
|
+
pyagent_patterns/advanced/swarm.py,sha256=bAtJLEr3Dan_UWm0JJUCsOoRwh-IulBVxBmi8GrbBTQ,3895
|
|
14
|
+
pyagent_patterns/advanced/talker_reasoner.py,sha256=U3i0QqksGiVo4jS-Z1oyArVy3ccdeJNW-G1b8BOTbQQ,3247
|
|
15
|
+
pyagent_patterns/orchestration/__init__.py,sha256=Sem1TXl34eUuiZMnMGdDLGcK8krLwXVuEZi7ZDLJ9k8,548
|
|
16
|
+
pyagent_patterns/orchestration/fan_out_fan_in.py,sha256=YWBPHPuI4rlp0jq6EpQXUa_Of3-B-pqJaoAizN3nhEI,2621
|
|
17
|
+
pyagent_patterns/orchestration/hierarchical.py,sha256=jENVb_8OYp-fouZM_e1mxYzft5TJ4VXvEZLdJ2WnUBg,3694
|
|
18
|
+
pyagent_patterns/orchestration/orchestrator_workers.py,sha256=yivBAKTvZD2wphuwIr15IEntB-V7yDoVmkU0S-_J9KQ,3764
|
|
19
|
+
pyagent_patterns/orchestration/pipeline.py,sha256=NfXWFhixC2ubCj9ZECe8eaQGSx-SNBS2TwC3CwOnAcU,1920
|
|
20
|
+
pyagent_patterns/orchestration/supervisor.py,sha256=xxrefRH7uyl93er8zZpHTHB953o9-YRIHo2L593sxv4,3015
|
|
21
|
+
pyagent_patterns/resolution/__init__.py,sha256=ZkLGVyx4P8Lw5NeXpl_L7YqKWKlOTE5HBpn-z-QF8rY,526
|
|
22
|
+
pyagent_patterns/resolution/cross_reflection.py,sha256=N-VFWQaKcljyL991HorjT5sWEPcUK8YLvf7mnNm23AU,2700
|
|
23
|
+
pyagent_patterns/resolution/debate.py,sha256=ZPlM3HUdkZ94AkIM0OVbPErmy7N_ZPgP7Gvju4tnrdU,3776
|
|
24
|
+
pyagent_patterns/resolution/evaluator_optimizer.py,sha256=Iri1F7HbYCEd5wlRJVlHL8Uj-uan_-8FASwfl5lGlDU,3906
|
|
25
|
+
pyagent_patterns/resolution/self_reflection.py,sha256=_nFx76VvDW4xviwaMirloXLkEi2ln-UoZgO0vNnS_ck,2809
|
|
26
|
+
pyagent_patterns/resolution/voting.py,sha256=Ry6nx4m7bcoiJRbjBPJ1p5ivF0jFI8FUyZAlbvvZ8Gg,3038
|
|
27
|
+
pyagent_patterns/structural/__init__.py,sha256=g-pxDMgh9rnXBkO0UshNc5NgvxP6rmkOrAo9u0Y5XdI,410
|
|
28
|
+
pyagent_patterns/structural/blackboard.py,sha256=urWX4U0FS8tq1QQcBVnUGZ7gusCzRzUBdVIv2Kd4KCg,4556
|
|
29
|
+
pyagent_patterns/structural/layered.py,sha256=j1YiKDulDlzFebI4fHFsNuqiS0c9xg6xRPkZTGTscdc,2138
|
|
30
|
+
pyagent_patterns/structural/role_based.py,sha256=DjYwlEIM1ypVBy8HWqBRre3_No-5QEVz4qZlywLmKIg,1978
|
|
31
|
+
pyagent_patterns/structural/topology.py,sha256=mtLGle7fww28oC0SRZ6Wg1wvwPtDLcQfy9q9Bo3pIqY,4444
|
|
32
|
+
pyagent_patterns-0.1.0.dist-info/METADATA,sha256=yCNmtR6oin-irZGLx5rpt-f4xSOhFJofHZhf2MGRr6c,1960
|
|
33
|
+
pyagent_patterns-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
34
|
+
pyagent_patterns-0.1.0.dist-info/RECORD,,
|