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.
Files changed (34) hide show
  1. pyagent_patterns/__init__.py +20 -0
  2. pyagent_patterns/advanced/__init__.py +8 -0
  3. pyagent_patterns/advanced/human_in_the_loop.py +103 -0
  4. pyagent_patterns/advanced/react.py +132 -0
  5. pyagent_patterns/advanced/swarm.py +106 -0
  6. pyagent_patterns/advanced/talker_reasoner.py +92 -0
  7. pyagent_patterns/advisor.py +166 -0
  8. pyagent_patterns/base.py +215 -0
  9. pyagent_patterns/composite.py +105 -0
  10. pyagent_patterns/guardrails.py +165 -0
  11. pyagent_patterns/orchestration/__init__.py +9 -0
  12. pyagent_patterns/orchestration/fan_out_fan_in.py +76 -0
  13. pyagent_patterns/orchestration/hierarchical.py +110 -0
  14. pyagent_patterns/orchestration/orchestrator_workers.py +97 -0
  15. pyagent_patterns/orchestration/pipeline.py +57 -0
  16. pyagent_patterns/orchestration/supervisor.py +88 -0
  17. pyagent_patterns/py.typed +0 -0
  18. pyagent_patterns/recovery.py +175 -0
  19. pyagent_patterns/registry.py +71 -0
  20. pyagent_patterns/resolution/__init__.py +9 -0
  21. pyagent_patterns/resolution/cross_reflection.py +79 -0
  22. pyagent_patterns/resolution/debate.py +103 -0
  23. pyagent_patterns/resolution/evaluator_optimizer.py +108 -0
  24. pyagent_patterns/resolution/self_reflection.py +80 -0
  25. pyagent_patterns/resolution/voting.py +93 -0
  26. pyagent_patterns/streaming.py +119 -0
  27. pyagent_patterns/structural/__init__.py +8 -0
  28. pyagent_patterns/structural/blackboard.py +137 -0
  29. pyagent_patterns/structural/layered.py +70 -0
  30. pyagent_patterns/structural/role_based.py +61 -0
  31. pyagent_patterns/structural/topology.py +123 -0
  32. pyagent_patterns-0.1.0.dist-info/METADATA +59 -0
  33. pyagent_patterns-0.1.0.dist-info/RECORD +34 -0
  34. 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,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any