agentensemble 0.1.0__tar.gz → 0.2.0__tar.gz

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 (72) hide show
  1. agentensemble-0.2.0/PKG-INFO +570 -0
  2. agentensemble-0.2.0/README.md +517 -0
  3. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/__init__.py +34 -1
  4. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/agents/__init__.py +3 -0
  5. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/agents/base.py +31 -19
  6. agentensemble-0.2.0/agentensemble/agents/hybrid_agent.py +265 -0
  7. agentensemble-0.2.0/agentensemble/agents/react_agent.py +300 -0
  8. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/agents/structured_agent.py +9 -1
  9. agentensemble-0.2.0/agentensemble/core/__init__.py +9 -0
  10. agentensemble-0.2.0/agentensemble/core/protocol.py +36 -0
  11. agentensemble-0.2.0/agentensemble/graph/__init__.py +9 -0
  12. agentensemble-0.2.0/agentensemble/graph/workflow.py +91 -0
  13. agentensemble-0.2.0/agentensemble/llm/__init__.py +34 -0
  14. agentensemble-0.2.0/agentensemble/llm/interface.py +142 -0
  15. agentensemble-0.2.0/agentensemble/llm/mistral_provider.py +207 -0
  16. agentensemble-0.2.0/agentensemble/memory/__init__.py +15 -0
  17. agentensemble-0.2.0/agentensemble/memory/session.py +54 -0
  18. agentensemble-0.2.0/agentensemble/memory/sqlite_session.py +104 -0
  19. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/orchestration/__init__.py +4 -4
  20. agentensemble-0.2.0/agentensemble/orchestration/debate.py +102 -0
  21. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/orchestration/ensemble.py +73 -40
  22. agentensemble-0.2.0/agentensemble/planner/__init__.py +9 -0
  23. agentensemble-0.2.0/agentensemble/planner/planner_agent.py +78 -0
  24. agentensemble-0.2.0/agentensemble/router/__init__.py +10 -0
  25. agentensemble-0.2.0/agentensemble/router/router_agent.py +175 -0
  26. agentensemble-0.2.0/agentensemble/runner.py +125 -0
  27. agentensemble-0.2.0/agentensemble/testing/comparison.py +117 -0
  28. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/tools/__init__.py +7 -0
  29. agentensemble-0.2.0/agentensemble/tools/adapters.py +118 -0
  30. agentensemble-0.2.0/agentensemble/tools/function_tool.py +82 -0
  31. agentensemble-0.2.0/agentensemble/tools/protocol.py +115 -0
  32. agentensemble-0.2.0/agentensemble/tools/validator.py +120 -0
  33. agentensemble-0.2.0/agentensemble/tracing/__init__.py +10 -0
  34. agentensemble-0.2.0/agentensemble/tracing/hooks.py +82 -0
  35. agentensemble-0.2.0/agentensemble.egg-info/PKG-INFO +570 -0
  36. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble.egg-info/SOURCES.txt +29 -1
  37. {agentensemble-0.1.0 → agentensemble-0.2.0}/pyproject.toml +2 -2
  38. {agentensemble-0.1.0 → agentensemble-0.2.0}/setup.py +1 -4
  39. agentensemble-0.2.0/tests/test_agents.py +115 -0
  40. agentensemble-0.2.0/tests/test_comparison.py +107 -0
  41. agentensemble-0.2.0/tests/test_memory.py +65 -0
  42. agentensemble-0.2.0/tests/test_orchestration.py +99 -0
  43. agentensemble-0.2.0/tests/test_react_session.py +34 -0
  44. agentensemble-0.2.0/tests/test_runner.py +82 -0
  45. agentensemble-0.2.0/tests/test_tools.py +81 -0
  46. agentensemble-0.1.0/PKG-INFO +0 -407
  47. agentensemble-0.1.0/README.md +0 -354
  48. agentensemble-0.1.0/agentensemble/agents/hybrid_agent.py +0 -147
  49. agentensemble-0.1.0/agentensemble/agents/react_agent.py +0 -118
  50. agentensemble-0.1.0/agentensemble/testing/comparison.py +0 -82
  51. agentensemble-0.1.0/agentensemble/tools/validator.py +0 -51
  52. agentensemble-0.1.0/agentensemble.egg-info/PKG-INFO +0 -407
  53. {agentensemble-0.1.0 → agentensemble-0.2.0}/MANIFEST.in +0 -0
  54. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/agents/rag_agent.py +0 -0
  55. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/agents/stategraph_agent.py +0 -0
  56. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/orchestration/pipeline.py +0 -0
  57. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/orchestration/supervisor.py +0 -0
  58. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/orchestration/swarm.py +0 -0
  59. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/py.typed +0 -0
  60. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/testing/__init__.py +0 -0
  61. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/testing/benchmark.py +0 -0
  62. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/testing/metrics.py +0 -0
  63. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/tools/rag.py +0 -0
  64. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/tools/registry.py +0 -0
  65. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/tools/scraper.py +0 -0
  66. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/tools/search.py +0 -0
  67. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/utils/__init__.py +0 -0
  68. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble/utils/llm.py +0 -0
  69. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble.egg-info/dependency_links.txt +0 -0
  70. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble.egg-info/requires.txt +0 -0
  71. {agentensemble-0.1.0 → agentensemble-0.2.0}/agentensemble.egg-info/top_level.txt +0 -0
  72. {agentensemble-0.1.0 → agentensemble-0.2.0}/setup.cfg +0 -0
@@ -0,0 +1,570 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentensemble
3
+ Version: 0.2.0
4
+ Summary: Orchestrate AI agents in perfect harmony - A comprehensive Python framework for building, testing, and orchestrating multi-agent AI systems
5
+ Author-email: Irfan Ali <irfanali29@hotmail.com>
6
+ Maintainer-email: Irfan Ali <irfanali29@hotmail.com>
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/irfanalidv/AgentEnsemble
9
+ Project-URL: Documentation, https://github.com/irfanalidv/AgentEnsemble#readme
10
+ Project-URL: Repository, https://github.com/irfanalidv/AgentEnsemble
11
+ Project-URL: Issues, https://github.com/irfanalidv/AgentEnsemble/issues
12
+ Keywords: ai-agents,multi-agent,orchestration,langgraph,langchain,rag,agent-testing,agentic-ai,state-graph,react-agent
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: langchain>=0.1.0
25
+ Requires-Dist: langchain-core>=0.1.0
26
+ Requires-Dist: langchain-community>=0.0.20
27
+ Requires-Dist: langchain-mistralai>=0.1.0
28
+ Requires-Dist: langgraph>=0.0.20
29
+ Requires-Dist: pydantic>=2.0.0
30
+ Requires-Dist: typing-extensions>=4.5.0
31
+ Requires-Dist: python-dotenv>=1.0.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
34
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
35
+ Requires-Dist: black>=23.0.0; extra == "dev"
36
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
37
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
38
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
39
+ Provides-Extra: observability
40
+ Requires-Dist: langsmith>=0.1.0; extra == "observability"
41
+ Requires-Dist: opentelemetry-api>=1.20.0; extra == "observability"
42
+ Provides-Extra: rag
43
+ Requires-Dist: chromadb>=0.4.0; extra == "rag"
44
+ Requires-Dist: sentence-transformers>=2.2.0; extra == "rag"
45
+ Requires-Dist: langchain-text-splitters>=0.0.1; extra == "rag"
46
+ Requires-Dist: beautifulsoup4>=4.12.0; extra == "rag"
47
+ Requires-Dist: langchain-mistralai>=0.1.0; extra == "rag"
48
+ Provides-Extra: search
49
+ Requires-Dist: duckduckgo-search>=4.0.0; extra == "search"
50
+ Requires-Dist: google-search-results>=2.4.2; extra == "search"
51
+ Provides-Extra: all
52
+ Requires-Dist: agentensemble[dev,observability,rag,search]; extra == "all"
53
+
54
+ # AgentEnsemble
55
+
56
+ **Production-ready multi-agent orchestration for Python**
57
+
58
+ AgentEnsemble is a modern framework for building and orchestrating AI agent systems. Designed for clarity, extensibility, and production use—comparable to LangGraph, CrewAI, and AutoGen.
59
+
60
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
61
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
62
+ [![PyPI version](https://img.shields.io/pypi/v/agentensemble)](https://pypi.org/project/agentensemble/)
63
+ [![PyPI Downloads](https://static.pepy.tech/badge/agentensemble)](https://pepy.tech/projects/agentensemble)
64
+
65
+ ---
66
+
67
+ ## Design Philosophy
68
+
69
+ - **Modular** — Agents, tools, orchestration, and memory are decoupled
70
+ - **Async-first** — `run()` and `arun()` on all agents; parallel execution via `asyncio.gather`
71
+ - **Provider-agnostic** — LLM interface supports Mistral (OpenAI/Anthropic-ready)
72
+ - **Production patterns** — Runner, retries, hooks, tracing, session memory
73
+
74
+ ---
75
+
76
+ ## Architecture
77
+
78
+ <p align="center">
79
+ <img src="docs/agentensemble-architecture.png" alt="AgentEnsemble Architecture" width="800"/>
80
+ </p>
81
+
82
+ *Architecture, functionalities, and use cases — what AgentEnsemble is capable of.*
83
+
84
+ ```
85
+ ┌─────────────────────────────────────────────────────────────────┐
86
+ │ AgentEnsemble │
87
+ ├─────────────┬─────────────┬─────────────┬───────────────────────┤
88
+ │ Agents │ Orchestration│ Tools │ Memory & Runner │
89
+ ├─────────────┼─────────────┼─────────────┼───────────────────────┤
90
+ │ ReActAgent │ Ensemble │ SearchTool │ Session (InMemory, │
91
+ │ StateGraph │ Supervisor │ RAGTool │ SQLite) │
92
+ │ RAGAgent │ Swarm │ @function_ │ Runner + RunConfig │
93
+ │ HybridAgent │ Pipeline │ tool │ TraceHooks │
94
+ │ RouterAgent │ Debate │ Validation │ │
95
+ │ PlannerAgent│ │ │ │
96
+ └─────────────┴─────────────┴─────────────┴───────────────────────┘
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Quick Start
102
+
103
+ ```bash
104
+ pip install agentensemble
105
+ # Optional: pip install agentensemble[search,rag]
106
+ ```
107
+
108
+ ```python
109
+ from agentensemble import ReActAgent, SearchTool, Runner
110
+
111
+ agent = ReActAgent(name="research", tools=[SearchTool()], max_iterations=5)
112
+ result = Runner.run(agent, "What are the latest AI breakthroughs in 2024?")
113
+ print(result["result"])
114
+ ```
115
+
116
+ **Setup:** Copy `.env.example` to `.env` and add your keys. Use `KEY=value` format (no spaces around `=`).
117
+
118
+ ---
119
+
120
+ ## Examples — Code + Output
121
+
122
+ Each example is runnable. Requires `.env` with `MISTRAL_API_KEY` and `SERPER_API_KEY` (see `.env.example` for format).
123
+
124
+ ---
125
+
126
+ ### 1. ReActAgent — LLM decides when to search
127
+
128
+ ```python
129
+ from agentensemble import ReActAgent, SearchTool
130
+
131
+ agent = ReActAgent(name="research", tools=[SearchTool()], max_iterations=5)
132
+ result = agent.run("Who won the 2024 Nobel Prize in Physics?")
133
+ print(result["result"])
134
+ ```
135
+
136
+ **Output:**
137
+
138
+ ```
139
+ The 2024 Nobel Prize in Physics was awarded jointly to John J. Hopfield and
140
+ Geoffrey E. Hinton for their foundational discoveries and inventions that
141
+ enable machine learning with artificial neural networks.
142
+ ```
143
+
144
+ ---
145
+
146
+ ### 2. Custom @function_tool — Add your own tools
147
+
148
+ ```python
149
+ from agentensemble import ReActAgent, SearchTool, function_tool
150
+
151
+ @function_tool(description="Get current weather for a city")
152
+ def get_weather(city: str) -> str:
153
+ return f"Weather in {city}: 72°F, partly cloudy"
154
+
155
+ agent = ReActAgent(tools=[SearchTool(), get_weather], max_iterations=4)
156
+ result = agent.run("What is the weather in Paris?")
157
+ print(result["result"])
158
+ ```
159
+
160
+ **Output:**
161
+
162
+ ```
163
+ The current weather in Paris is 72°F (22°C) with partly cloudy conditions.
164
+ ```
165
+
166
+ ---
167
+
168
+ ### 3. HybridAgent — LLM routes SEARCH → RAG → VALIDATE → ANSWER
169
+
170
+ ```python
171
+ from agentensemble import HybridAgent, SearchTool
172
+
173
+ agent = HybridAgent(tools=[SearchTool()], max_iterations=5)
174
+ result = agent.run("What are the key trends in AI agents in 2024?")
175
+ print(result["result"][:300], "...")
176
+ print("Actions:", result["metadata"]["actions_taken"])
177
+ ```
178
+
179
+ **Output:**
180
+
181
+ ```
182
+ 1. Multi-Modal AI Models Redefined Possibilities · 2. AI Agents Stepping Into
183
+ the Spotlight · 3. AI's Bold Move into Video Creation · 4. Rise of Open-Source AI...
184
+ Actions: ['SEARCH', 'SEARCH', 'RAG', 'VALIDATE', 'ANSWER']
185
+ ```
186
+
187
+ ---
188
+
189
+ ### 4. Swarm — Parallel agents (multiple perspectives)
190
+
191
+ ```python
192
+ from agentensemble import ReActAgent, SwarmOrchestrator, SearchTool
193
+
194
+ researcher = ReActAgent(name="researcher", tools=[SearchTool()], max_iterations=2)
195
+ fact_checker = ReActAgent(name="fact_checker", tools=[SearchTool()], max_iterations=2)
196
+
197
+ swarm = SwarmOrchestrator(agents={"researcher": researcher, "fact_checker": fact_checker})
198
+ result = swarm.perform("What is the capital of France?")
199
+ for name, r in result["results"].items():
200
+ print(f"{name}: {r['result'][:80]}...")
201
+ ```
202
+
203
+ **Output:**
204
+
205
+ ```
206
+ researcher: The capital of France is Paris.
207
+ fact_checker: The capital of France is Paris.
208
+ ```
209
+
210
+ ---
211
+
212
+ ### 5. Pipeline — Sequential (search → summarize)
213
+
214
+ ```python
215
+ from agentensemble import ReActAgent, PipelineOrchestrator, SearchTool
216
+
217
+ searcher = ReActAgent(name="searcher", tools=[SearchTool()], max_iterations=2)
218
+ summarizer = ReActAgent(name="summarizer", tools=[], max_iterations=1)
219
+
220
+ pipeline = PipelineOrchestrator(agents={"searcher": searcher, "summarizer": summarizer})
221
+ result = pipeline.perform("Summarize the top 3 AI breakthroughs in 2024")
222
+ print(result["final_result"]["previous_result"][:250], "...")
223
+ ```
224
+
225
+ **Output:**
226
+
227
+ ```
228
+ 1. Multimodal AI Advancements (GPT-4o, Gemini 1.5) · 2. AI Agents Stepping Into
229
+ the Spotlight · 3. AI's Bold Move into Video Creation...
230
+ ```
231
+
232
+ ---
233
+
234
+ ### 6. Debate — Multi-agent consensus for reasoning
235
+
236
+ ```python
237
+ from agentensemble import ReActAgent, DebateOrchestrator
238
+
239
+ solver1 = ReActAgent(name="solver_1", tools=[], max_iterations=1)
240
+ solver2 = ReActAgent(name="solver_2", tools=[], max_iterations=1)
241
+ aggregator = ReActAgent(name="aggregator", tools=[], max_iterations=1)
242
+
243
+ debate = DebateOrchestrator(solvers=[solver1, solver2], aggregator=aggregator, rounds=2)
244
+ result = debate.debate("What is 15 * 7?")
245
+ print("Proposals:", result["proposals"])
246
+ print("Final:", result["result"])
247
+ ```
248
+
249
+ **Output:**
250
+
251
+ ```
252
+ Proposals: ['15 × 7 = 105', '15 × 7 equals 105']
253
+ Final: 15 × 7 equals 105.
254
+ ```
255
+
256
+ ---
257
+
258
+ ### 7. Router + Ensemble — LLM picks the best agent
259
+
260
+ ```python
261
+ from agentensemble import ReActAgent, RouterAgent, Ensemble, SearchTool
262
+
263
+ researcher = ReActAgent(name="researcher", tools=[SearchTool()], max_iterations=2)
264
+ validator = ReActAgent(name="validator", tools=[SearchTool()], max_iterations=2)
265
+
266
+ router = RouterAgent(agents={"researcher": researcher, "validator": validator})
267
+ ensemble = Ensemble(conductor="supervisor", agents={"researcher": researcher, "validator": validator}, router=router)
268
+ result = ensemble.perform("Latest developments in quantum computing")
269
+ for name, r in result["results"].items():
270
+ print(f"Routed to {name}: {r['result'][:120]}...")
271
+ ```
272
+
273
+ **Output:**
274
+
275
+ ```
276
+ Routed to researcher: Here are the latest developments in quantum computing:
277
+ 1. Hardware Advances · 2. Fault-tolerant quantum computing...
278
+ ```
279
+
280
+ ---
281
+
282
+ ### 8. Planner — Decompose task → executor runs subtasks
283
+
284
+ ```python
285
+ from agentensemble import PlannerAgent, StateGraphAgent
286
+
287
+ def worker(state):
288
+ return {"result": f"Processed: {state.query}"}
289
+
290
+ executor = StateGraphAgent(name="worker", nodes={"start": worker})
291
+ executor._route = lambda s, c: "end"
292
+
293
+ planner = PlannerAgent(executor=executor, max_subtasks=3)
294
+ result = planner.run("Research and compare LangGraph vs CrewAI")
295
+ print("Subtasks:", result["metadata"]["subtasks"])
296
+ print("Result:", result["result"][:200], "...")
297
+ ```
298
+
299
+ **Output:**
300
+
301
+ ```
302
+ Subtasks: ['Search for information about: Research and compare LangGraph vs CrewAI',
303
+ 'Summarize key findings from: Research and compare LangGraph vs CrewAI']
304
+ Result: Processed: Search for information... --- Processed: Summarize key findings...
305
+ ```
306
+
307
+ ---
308
+
309
+ ### 9. WorkflowGraph — Custom DAG with nodes and edges
310
+
311
+ ```python
312
+ from agentensemble import WorkflowGraph
313
+
314
+ def analyze(s):
315
+ return {"context": {**s.get("context", {}), "done": True}, "current_node": "summarize"}
316
+
317
+ def summarize(s):
318
+ return {"result": f"Summary for: {s['query']}", "current_node": "end"}
319
+
320
+ graph = (
321
+ WorkflowGraph(entry="start", exit_nodes=["end"])
322
+ .add_node("start", lambda s: {"current_node": "analyze"})
323
+ .add_node("analyze", analyze)
324
+ .add_node("summarize", summarize)
325
+ .add_edge("start", "analyze")
326
+ .add_edge("analyze", "summarize")
327
+ .add_edge("summarize", "end")
328
+ )
329
+ result = graph.run("What is multi-agent AI?")
330
+ print(result["result"])
331
+ ```
332
+
333
+ **Output:**
334
+
335
+ ```
336
+ Summary for: What is multi-agent AI?
337
+ ```
338
+
339
+ ---
340
+
341
+ ### 10. Runner + RunHooks + InMemorySession — Production-ready execution
342
+
343
+ ```python
344
+ from agentensemble import ReActAgent, Runner, RunConfig, RunHooks, InMemorySession, SearchTool
345
+
346
+ session = InMemorySession(session_id="chat-1")
347
+ agent = ReActAgent(name="chatbot", tools=[SearchTool()], session=session, max_iterations=3)
348
+
349
+ def on_start(q, _): print(f"→ User: {q[:50]}...")
350
+ def on_end(r): print(f"← Agent: {r['result'][:80]}...\n")
351
+
352
+ config = RunConfig(hooks=RunHooks(on_start=on_start, on_end=on_end))
353
+
354
+ Runner.run(agent, "What is the capital of Japan?", config=config)
355
+ Runner.run(agent, "What about its population?", config=config) # Remembers context
356
+ ```
357
+
358
+ **Output:**
359
+
360
+ ```
361
+ → User: What is the capital of Japan?...
362
+ ← Agent: The capital of Japan is Tokyo.
363
+
364
+ → User: What about its population?...
365
+ ← Agent: Tokyo's population is approximately 14 million...
366
+ ```
367
+
368
+ ---
369
+
370
+ ### 11. RAGAgent — Document Q&A (optional: `pip install agentensemble[rag]`)
371
+
372
+ ```python
373
+ from agentensemble import RAGAgent, RAGTool
374
+
375
+ rag_tool = RAGTool()
376
+ rag_tool.index_documents(["https://example.com/doc"]) # Index from URLs
377
+
378
+ agent = RAGAgent(name="doc_qa", tools=[rag_tool], fallback_strategies=2)
379
+ result = agent.run("What is task decomposition?")
380
+ print(result["result"][:200], "...")
381
+ ```
382
+
383
+ **Output:**
384
+ ```
385
+ Task decomposition is the process of breaking complex tasks into smaller,
386
+ manageable subtasks that can be executed by specialized agents...
387
+ ```
388
+
389
+ ---
390
+
391
+ ### 12. StructuredAgent — Pydantic output (optional: `langchain>=1.1`)
392
+
393
+ ```python
394
+ from pydantic import BaseModel, Field
395
+ from agentensemble import StructuredAgent
396
+
397
+ class ProductReview(BaseModel):
398
+ product: str = Field(description="Product name")
399
+ rating: int = Field(description="1-5 stars")
400
+ summary: str = Field(description="Brief summary")
401
+
402
+ agent = StructuredAgent(response_format=ProductReview)
403
+ result = agent.run("Review: iPhone 15 Pro - 5 stars, excellent camera and battery")
404
+ print(result["structured_response"])
405
+ ```
406
+
407
+ **Output:**
408
+ ```
409
+ ProductReview(product='iPhone 15 Pro', rating=5, summary='Excellent camera and battery')
410
+ ```
411
+
412
+ ---
413
+
414
+ ### Creative combo — Research pipeline (Planner + Swarm + Debate + Runner)
415
+
416
+ ```python
417
+ from agentensemble import (
418
+ ReActAgent, PlannerAgent, StateGraphAgent,
419
+ SwarmOrchestrator, DebateOrchestrator,
420
+ Runner, RunConfig, RunHooks, SearchTool,
421
+ )
422
+
423
+ # 1. Executor: ReActAgent with search
424
+ executor = ReActAgent(name="researcher", tools=[SearchTool()], max_iterations=3)
425
+
426
+ # 2. Planner decomposes → runs subtasks via executor
427
+ planner = PlannerAgent(executor=executor, max_subtasks=2)
428
+ plan_result = planner.run("Compare LangGraph vs CrewAI vs AutoGen")
429
+
430
+ # 3. Swarm: parallel research + fact-check
431
+ researcher = ReActAgent(name="r", tools=[SearchTool()], max_iterations=2)
432
+ checker = ReActAgent(name="c", tools=[SearchTool()], max_iterations=2)
433
+ swarm = SwarmOrchestrator(agents={"r": researcher, "c": checker})
434
+ swarm_result = swarm.perform("Top 3 AI agent frameworks 2024")
435
+
436
+ # 4. Debate: consensus on a fact
437
+ s1 = ReActAgent(name="s1", tools=[], max_iterations=1)
438
+ s2 = ReActAgent(name="s2", tools=[], max_iterations=1)
439
+ agg = ReActAgent(name="agg", tools=[], max_iterations=1)
440
+ debate = DebateOrchestrator(solvers=[s1, s2], aggregator=agg, rounds=2)
441
+ debate_result = debate.debate("What is 12 * 8?")
442
+
443
+ # 5. Runner with hooks
444
+ hooks = RunHooks(on_start=lambda q, _: print(f"Running: {q[:40]}..."))
445
+ result = Runner.run(executor, "Who won 2024 Nobel Physics?", RunConfig(hooks=hooks))
446
+
447
+ print("Planner:", plan_result["result"][:100], "...")
448
+ print("Swarm agents:", list(swarm_result["results"].keys()))
449
+ print("Debate answer:", debate_result["result"])
450
+ print("Runner:", result["result"][:80], "...")
451
+ ```
452
+
453
+ **Output:**
454
+
455
+ ```
456
+ Running: Who won 2024 Nobel Physics?...
457
+ Planner: Processed: Search for information... --- Processed: Summarize key findings...
458
+ Swarm agents: ['r', 'c']
459
+ Debate answer: 12 × 8 equals 96.
460
+ Runner: The 2024 Nobel Prize in Physics was awarded to John J. Hopfield and Geoffrey E. Hinton...
461
+ ```
462
+
463
+ ---
464
+
465
+ ## Run full showcase
466
+
467
+ ```bash
468
+ pip install agentensemble[search]
469
+ PYTHONPATH=. python examples/showcase_all.py
470
+ ```
471
+
472
+ Runs all 10 demos with real API calls.
473
+
474
+ ---
475
+
476
+ ## Core Components
477
+
478
+ ### Agents
479
+
480
+ | Agent | Use Case | LLM |
481
+ | ------------------- | ----------------------------- | -------- |
482
+ | **ReActAgent** | Research, tool use, reasoning | Yes |
483
+ | **StateGraphAgent** | Custom node workflows | No |
484
+ | **RAGAgent** | Document Q&A | Optional |
485
+ | **HybridAgent** | Search → RAG → Validate | Optional |
486
+ | **RouterAgent** | Route to best agent | Optional |
487
+ | **PlannerAgent** | Task decomposition | No |
488
+
489
+ ### Orchestration
490
+
491
+ | Pattern | Description |
492
+ | -------------- | -------------------------------------------------------------------- |
493
+ | **Supervisor** | Central coordinator; optional `router` for LLM-based agent selection |
494
+ | **Swarm** | Parallel execution via `asyncio.gather` |
495
+ | **Pipeline** | Sequential agent workflow |
496
+ | **Debate** | Solvers propose → feedback → aggregator votes |
497
+
498
+ ### Tools
499
+
500
+ - `@function_tool` — Decorate functions for automatic schema
501
+ - `SearchTool` — Serper or DuckDuckGo
502
+ - `RAGTool` — Document indexing and retrieval
503
+ - `ValidationTool` — Quality checks
504
+ - `ToolRegistry` — Dynamic tool management
505
+
506
+ ### Memory & Runner
507
+
508
+ - **Session** — `InMemorySession`, `SQLiteSession` for multi-turn context
509
+ - **Runner** — `Runner.run()`, `Runner.arun()` with `RunConfig`, `RunHooks`, retries
510
+ - **TraceHooks** — Observability for runs, LLM calls, tools
511
+
512
+ ---
513
+
514
+ ## Project Structure
515
+
516
+ ```
517
+ agentensemble/
518
+ ├── agents/ # ReAct, StateGraph, RAG, Hybrid, Structured
519
+ ├── core/ # AgentProtocol, RunnableProtocol
520
+ ├── llm/ # LLMProvider, MistralLLMProvider
521
+ ├── memory/ # Session, InMemorySession, SQLiteSession
522
+ ├── orchestration/ # Ensemble, Supervisor, Swarm, Pipeline, Debate
523
+ ├── tools/ # Tool protocol, @function_tool, built-ins
524
+ ├── router/ # RouterAgent (LLM-based routing)
525
+ ├── planner/ # PlannerAgent (task decomposition)
526
+ ├── graph/ # WorkflowGraph (composable workflows)
527
+ ├── tracing/ # TraceHooks, TraceEvent
528
+ ├── testing/ # Benchmark, AgentComparison, Metrics
529
+ └── runner.py # Runner, RunConfig, RunHooks
530
+ ```
531
+
532
+ ---
533
+
534
+ ## Comparison
535
+
536
+ | Feature | AgentEnsemble | LangGraph | CrewAI | AutoGen |
537
+ | ------------------ | ------------------------- | ------------ | ------ | ------- |
538
+ | Multi-provider LLM | Mistral (extensible) | Any | Any | Any |
539
+ | Async API | `arun()` everywhere | Yes | Yes | Yes |
540
+ | Router agents | RouterAgent | Manual | Yes | Manual |
541
+ | Planner pattern | PlannerAgent | Manual | Yes | Manual |
542
+ | Graph workflows | WorkflowGraph, StateGraph | Native | No | No |
543
+ | Debate pattern | DebateOrchestrator | Manual | Yes | Yes |
544
+ | Session memory | InMemory, SQLite | Checkpointer | No | No |
545
+ | Observability | TraceHooks | LangSmith | No | No |
546
+
547
+ ---
548
+
549
+ ## Production Use
550
+
551
+ - **Retries**: `RunConfig(max_retries=2, retry_on=(RateLimitError, TimeoutError))`
552
+ - **Session**: `Runner.run(agent, query, config=RunConfig(session=SQLiteSession()))`
553
+ - **Tracing**: Attach `TraceHooks` to capture run/LLM/tool events
554
+ - **Benchmarks**: `AgentComparison`, `Benchmark.research_tasks()`, `Metrics`
555
+
556
+ ---
557
+
558
+ ## Documentation
559
+
560
+ - **[Showcase](examples/showcase_all.py)** — Run all 10 features with real API output
561
+ - [Examples](examples/) — `quickstart`, `react_llm`, `swarm`, `pipeline`, `streaming`, `debate`, `rag`, `research_agent`, `graph_workflow`, `runner`, `structured_output`
562
+ - [Roadmap](docs/ROADMAP_2025.md) — Planned improvements
563
+
564
+ > **Note:** Ensure `docs/agentensemble-architecture.png` is committed so the architecture diagram renders on GitHub.
565
+
566
+ ---
567
+
568
+ ## License
569
+
570
+ MIT — see [LICENSE](LICENSE).