agentensemble 0.2.0__tar.gz → 0.4.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.4.0/CHANGELOG.md +73 -0
  2. agentensemble-0.4.0/LICENSE +21 -0
  3. {agentensemble-0.2.0 → agentensemble-0.4.0}/MANIFEST.in +2 -2
  4. {agentensemble-0.2.0/agentensemble.egg-info → agentensemble-0.4.0}/PKG-INFO +255 -61
  5. agentensemble-0.2.0/PKG-INFO → agentensemble-0.4.0/README.md +229 -94
  6. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/__init__.py +29 -24
  7. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/agents/__init__.py +4 -3
  8. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/agents/base.py +11 -10
  9. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/agents/hybrid_agent.py +27 -23
  10. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/agents/rag_agent.py +19 -19
  11. agentensemble-0.4.0/agentensemble/agents/react_agent.py +465 -0
  12. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/agents/stategraph_agent.py +23 -23
  13. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/agents/structured_agent.py +51 -51
  14. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/core/protocol.py +4 -5
  15. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/graph/__init__.py +1 -1
  16. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/graph/workflow.py +12 -9
  17. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/llm/__init__.py +3 -2
  18. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/llm/interface.py +17 -20
  19. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/llm/mistral_provider.py +48 -19
  20. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/memory/__init__.py +1 -1
  21. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/memory/session.py +6 -6
  22. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/memory/sqlite_session.py +5 -5
  23. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/orchestration/__init__.py +2 -3
  24. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/orchestration/debate.py +6 -6
  25. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/orchestration/ensemble.py +37 -56
  26. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/orchestration/pipeline.py +6 -6
  27. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/orchestration/supervisor.py +6 -6
  28. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/orchestration/swarm.py +6 -6
  29. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/planner/planner_agent.py +10 -9
  30. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/router/router_agent.py +12 -10
  31. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/runner.py +21 -14
  32. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/testing/__init__.py +1 -2
  33. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/testing/benchmark.py +12 -13
  34. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/testing/comparison.py +25 -17
  35. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/testing/metrics.py +20 -21
  36. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/__init__.py +4 -4
  37. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/adapters.py +8 -7
  38. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/function_tool.py +6 -6
  39. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/protocol.py +11 -14
  40. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/rag.py +10 -11
  41. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/registry.py +21 -22
  42. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/scraper.py +8 -25
  43. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/search.py +20 -5
  44. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/validator.py +9 -11
  45. agentensemble-0.4.0/agentensemble/tracing/__init__.py +16 -0
  46. agentensemble-0.4.0/agentensemble/tracing/hooks.py +127 -0
  47. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/utils/__init__.py +1 -2
  48. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/utils/llm.py +6 -8
  49. agentensemble-0.2.0/README.md → agentensemble-0.4.0/agentensemble.egg-info/PKG-INFO +289 -42
  50. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble.egg-info/SOURCES.txt +5 -2
  51. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble.egg-info/requires.txt +10 -11
  52. {agentensemble-0.2.0 → agentensemble-0.4.0}/pyproject.toml +45 -33
  53. {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_agents.py +5 -5
  54. {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_comparison.py +1 -1
  55. {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_memory.py +8 -8
  56. {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_orchestration.py +5 -2
  57. {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_react_session.py +6 -6
  58. agentensemble-0.4.0/tests/test_release.py +98 -0
  59. {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_runner.py +23 -3
  60. {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_tools.py +3 -5
  61. agentensemble-0.4.0/tests/test_tracing.py +47 -0
  62. agentensemble-0.2.0/agentensemble/agents/react_agent.py +0 -300
  63. agentensemble-0.2.0/agentensemble/tracing/__init__.py +0 -10
  64. agentensemble-0.2.0/agentensemble/tracing/hooks.py +0 -82
  65. agentensemble-0.2.0/setup.py +0 -15
  66. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/core/__init__.py +0 -0
  67. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/planner/__init__.py +0 -0
  68. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/py.typed +0 -0
  69. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/router/__init__.py +0 -0
  70. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble.egg-info/dependency_links.txt +0 -0
  71. {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble.egg-info/top_level.txt +0 -0
  72. {agentensemble-0.2.0 → agentensemble-0.4.0}/setup.cfg +0 -0
@@ -0,0 +1,73 @@
1
+ # Changelog
2
+
3
+ All notable changes to AgentEnsemble will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.4.0] - 2026-10-31
11
+
12
+ ### Fixed
13
+ - `ReActAgent` can now be constructed without `MISTRAL_API_KEY` (matching `HybridAgent` and
14
+ `RouterAgent`); `run()` / `astream()` raise a clear `RuntimeError` until an LLM is configured.
15
+ Previously the constructor raised `ValueError`, which broke 6 tests and any offline usage.
16
+ - `SearchTool`'s DuckDuckGo fallback works again: `langchain-community` now needs the `ddgs`
17
+ package (the `search` extra previously installed the old `duckduckgo-search`).
18
+ - `SearchTool` creates its backend lazily on first use, so it can be registered in a
19
+ `ToolRegistry` without optional dependencies; a missing backend raises an `ImportError` with
20
+ the `pip install 'agentensemble[search]'` hint. Unknown providers still fail fast.
21
+ - Tool schema type inference uses identity checks (`ann is str`), not equality.
22
+
23
+ ### Added
24
+ - `MISTRAL_MODEL` environment variable to choose the default model for `MistralLLMProvider`.
25
+ - `__version__` read from installed package metadata (`importlib.metadata`).
26
+ - GitHub Actions CI (ruff lint + format check, pytest on Python 3.10–3.13).
27
+ - New tests: ReActAgent tool-calling loop with a fake LLM, SearchTool behaviour, version, model
28
+ override (64 tests total).
29
+ - SECURITY.md, CODE_OF_CONDUCT.md, issue/PR templates, Dependabot, CITATION.cff.
30
+
31
+ ### Changed
32
+ - Requires Python 3.10+ (3.9 is end-of-life); classifiers for 3.10–3.13.
33
+ - Packaging is `pyproject.toml`-only (removed `setup.py` and `requirements.txt`), PEP 639
34
+ `license = "MIT"`, LICENSE and CHANGELOG shipped in the sdist.
35
+ - Dependency floors raised to the versions the code actually needs: `langchain>=1.1`,
36
+ `langchain-core>=1.0`, `langchain-community>=0.3`, `langchain-mistralai>=0.2`. The unused
37
+ direct `langgraph` dependency was dropped (it is still installed transitively by `langchain`).
38
+ - `dev` extra now includes `build` and `twine`; `black` replaced by `ruff format`.
39
+ - Codebase formatted with `ruff format` and modernised type hints (`X | None`).
40
+
41
+ ## [0.3.0] - 2026-03-10
42
+
43
+ ### Added
44
+ - Observability (`TraceHooks`, token usage, cost estimation), human-in-the-loop
45
+ (`interrupt_before_tools`), architecture diagram.
46
+
47
+ ## [0.2.0] - 2026-03-10
48
+
49
+ ### Added
50
+ - `RouterAgent`, `PlannerAgent`, `WorkflowGraph`, tracing.
51
+
52
+ ## [0.1.0] - 2025-12-09
53
+
54
+ ### Added
55
+ - Initial release
56
+ - ReActAgent implementation
57
+ - StateGraphAgent implementation
58
+ - RAGAgent with fallback strategies
59
+ - HybridAgent with intelligent routing
60
+ - Ensemble orchestration patterns (Supervisor, Swarm, Pipeline)
61
+ - Tool ecosystem (Search, Scraper, RAG, Validator)
62
+ - Tool registry for centralized management
63
+ - Testing framework (AgentComparison, Benchmark, Metrics)
64
+ - Base agent class and state management
65
+ - Comprehensive documentation
66
+
67
+ ### Infrastructure
68
+ - Python 3.9+ support
69
+ - pyproject.toml for modern packaging
70
+ - Development dependencies (pytest, black, ruff, mypy)
71
+ - MIT License
72
+ - Contributing guidelines
73
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Irfan Ali
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,6 +1,6 @@
1
1
  include README.md
2
+ include LICENSE
3
+ include CHANGELOG.md
2
4
  include pyproject.toml
3
5
  recursive-include agentensemble *.py
4
6
  recursive-include agentensemble py.typed
5
- exclude LICENSE
6
-
@@ -1,41 +1,47 @@
1
1
  Metadata-Version: 2.4
2
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
3
+ Version: 0.4.0
4
+ Summary: Build, orchestrate, trace, and test multi-agent LLM systems in Python: ReAct, RAG, router, planner, workflow graphs, swarms, debates, and pipelines.
5
5
  Author-email: Irfan Ali <irfanali29@hotmail.com>
6
6
  Maintainer-email: Irfan Ali <irfanali29@hotmail.com>
7
- License: MIT
7
+ License-Expression: MIT
8
8
  Project-URL: Homepage, https://github.com/irfanalidv/AgentEnsemble
9
9
  Project-URL: Documentation, https://github.com/irfanalidv/AgentEnsemble#readme
10
10
  Project-URL: Repository, https://github.com/irfanalidv/AgentEnsemble
11
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
12
+ Project-URL: Changelog, https://github.com/irfanalidv/AgentEnsemble/blob/main/CHANGELOG.md
13
+ Keywords: ai-agents,multi-agent,multi-agent-systems,agent-orchestration,orchestration,llm,langchain,langgraph,mistral,rag,react-agent,tool-calling,function-calling,agent-testing,agentic-ai,state-graph,workflow,tracing
14
+ Classifier: Development Status :: 4 - Beta
14
15
  Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Operating System :: OS Independent
15
18
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
- Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
20
  Classifier: Programming Language :: Python :: 3
18
- Classifier: Programming Language :: Python :: 3.9
19
21
  Classifier: Programming Language :: Python :: 3.10
20
22
  Classifier: Programming Language :: Python :: 3.11
21
23
  Classifier: Programming Language :: Python :: 3.12
22
- Requires-Python: >=3.9
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3 :: Only
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.10
23
28
  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
+ License-File: LICENSE
30
+ Requires-Dist: langchain>=1.1.0
31
+ Requires-Dist: langchain-core>=1.0.0
32
+ Requires-Dist: langchain-community>=0.3.0
33
+ Requires-Dist: langchain-mistralai>=0.2.0
29
34
  Requires-Dist: pydantic>=2.0.0
30
35
  Requires-Dist: typing-extensions>=4.5.0
31
36
  Requires-Dist: python-dotenv>=1.0.0
32
37
  Provides-Extra: dev
33
38
  Requires-Dist: pytest>=7.0.0; extra == "dev"
34
39
  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
40
  Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
41
+ Requires-Dist: ruff>=0.6.0; extra == "dev"
42
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
43
+ Requires-Dist: build>=1.0.0; extra == "dev"
44
+ Requires-Dist: twine>=5.0.0; extra == "dev"
39
45
  Provides-Extra: observability
40
46
  Requires-Dist: langsmith>=0.1.0; extra == "observability"
41
47
  Requires-Dist: opentelemetry-api>=1.20.0; extra == "observability"
@@ -44,23 +50,93 @@ Requires-Dist: chromadb>=0.4.0; extra == "rag"
44
50
  Requires-Dist: sentence-transformers>=2.2.0; extra == "rag"
45
51
  Requires-Dist: langchain-text-splitters>=0.0.1; extra == "rag"
46
52
  Requires-Dist: beautifulsoup4>=4.12.0; extra == "rag"
47
- Requires-Dist: langchain-mistralai>=0.1.0; extra == "rag"
48
53
  Provides-Extra: search
49
- Requires-Dist: duckduckgo-search>=4.0.0; extra == "search"
54
+ Requires-Dist: ddgs>=9.0.0; extra == "search"
50
55
  Requires-Dist: google-search-results>=2.4.2; extra == "search"
51
56
  Provides-Extra: all
52
- Requires-Dist: agentensemble[dev,observability,rag,search]; extra == "all"
57
+ Requires-Dist: agentensemble[observability,rag,search]; extra == "all"
58
+ Dynamic: license-file
59
+
60
+ <div align="center">
53
61
 
54
62
  # AgentEnsemble
55
63
 
56
- **Production-ready multi-agent orchestration for Python**
64
+ **Build, orchestrate, trace, and test multi-agent LLM systems in Python.**
57
65
 
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.
66
+ ReAct, RAG, router, planner, workflow graphs, swarms, debates, and pipelines, with sessions,
67
+ tracing, retries, and human-in-the-loop approval built in.
59
68
 
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/)
69
+ [![PyPI version](https://img.shields.io/pypi/v/agentensemble.svg)](https://pypi.org/project/agentensemble/)
70
+ [![Python versions](https://img.shields.io/pypi/pyversions/agentensemble.svg)](https://pypi.org/project/agentensemble/)
71
+ [![Tests](https://github.com/irfanalidv/AgentEnsemble/actions/workflows/tests.yml/badge.svg)](https://github.com/irfanalidv/AgentEnsemble/actions/workflows/tests.yml)
63
72
  [![PyPI Downloads](https://static.pepy.tech/badge/agentensemble)](https://pepy.tech/projects/agentensemble)
73
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/irfanalidv/AgentEnsemble/blob/main/LICENSE)
74
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
75
+
76
+ </div>
77
+
78
+ ---
79
+
80
+ AgentEnsemble is a framework for building and orchestrating AI agent systems, designed for clarity,
81
+ extensibility, and production use. It covers similar ground to LangGraph, CrewAI, and AutoGen.
82
+
83
+ ## Installation
84
+
85
+ ```bash
86
+ pip install agentensemble # core: agents, orchestration, graphs, memory, tracing
87
+ pip install "agentensemble[search]" # + DuckDuckGo / Serper web search for SearchTool
88
+ pip install "agentensemble[rag]" # + Chroma, sentence-transformers, loaders for RAGTool
89
+ pip install "agentensemble[observability]" # + LangSmith / OpenTelemetry
90
+ pip install "agentensemble[all]" # everything above
91
+ ```
92
+
93
+ Requires Python 3.10+.
94
+
95
+ ## Quick start (no API key needed)
96
+
97
+ Graph workflows, state-graph agents, and the planner run without any LLM:
98
+
99
+ ```python
100
+ from agentensemble import WorkflowGraph
101
+
102
+
103
+ def analyze(s):
104
+ return {"context": {**s.get("context", {}), "done": True}, "current_node": "summarize"}
105
+
106
+
107
+ def summarize(s):
108
+ return {"result": f"Summary for: {s['query']}", "current_node": "end"}
109
+
110
+
111
+ graph = (
112
+ WorkflowGraph(entry="start", exit_nodes=["end"])
113
+ .add_node("start", lambda s: {"current_node": "analyze"})
114
+ .add_node("analyze", analyze)
115
+ .add_node("summarize", summarize)
116
+ .add_edge("start", "analyze")
117
+ .add_edge("analyze", "summarize")
118
+ .add_edge("summarize", "end")
119
+ )
120
+ print(graph.run("What is multi-agent AI?")["result"])
121
+ # Summary for: What is multi-agent AI?
122
+ ```
123
+
124
+ LLM-powered agents (`ReActAgent`, `HybridAgent`, `RouterAgent`, `StructuredAgent`) use Mistral by
125
+ default. Set `MISTRAL_API_KEY`, or pass any `LLMProvider` implementation via `llm=...`.
126
+
127
+ ## Configuration
128
+
129
+ | Variable | Purpose |
130
+ | --- | --- |
131
+ | `MISTRAL_API_KEY` | Required for the default Mistral LLM provider (ReAct, Hybrid, Router, Structured agents). |
132
+ | `MISTRAL_MODEL` | Optional default model for `MistralLLMProvider` (default: `mistral-large-latest`). Use e.g. `mistral-small-latest` if your plan doesn't include the large model. |
133
+ | `SERPER_API_KEY` | Optional. When set, `SearchTool()` uses Serper; otherwise it falls back to DuckDuckGo (needs the `search` extra). |
134
+
135
+ Copy `.env.example` to `.env` and fill in your keys (`KEY=value`, no spaces around `=`); the
136
+ package loads `.env` automatically via `python-dotenv`.
137
+
138
+ Without an API key, LLM agents can still be constructed (and inspected or registered); calling
139
+ `run()` raises a clear `RuntimeError` explaining how to configure an LLM.
64
140
 
65
141
  ---
66
142
 
@@ -76,33 +152,51 @@ AgentEnsemble is a modern framework for building and orchestrating AI agent syst
76
152
  ## Architecture
77
153
 
78
154
  <p align="center">
79
- <img src="docs/agentensemble-architecture.png" alt="AgentEnsemble Architecture" width="800"/>
155
+ <img src="https://raw.githubusercontent.com/irfanalidv/AgentEnsemble/main/docs/agentensemble-architecture.png" alt="AgentEnsemble Architecture" width="900"/>
80
156
  </p>
81
157
 
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
- ```
158
+ ### Framework layers
159
+
160
+ ```
161
+ ┌──────────────────────────────────────────────────────────────────────────────────────────┐
162
+ │ AgentEnsemble — Layered Architecture │
163
+ ├─────────────────┬─────────────────────┬─────────────────────┬────────────────────────────┤
164
+ │ AGENTS │ ORCHESTRATION │ TOOLS │ MEMORY & RUNNER │
165
+ ├─────────────────┼─────────────────────┼─────────────────────┼────────────────────────────┤
166
+ │ ReActAgent │ Supervisor │ SearchTool │ Session (InMemory, SQLite) │
167
+ │ StateGraphAgent │ Swarm (parallel) │ RAGTool │ RunConfig, RunHooks │
168
+ │ RAGAgent │ Pipeline (seq) │ @function_tool │ TraceHooks (usage, cost) │
169
+ │ HybridAgent │ Debate (consensus) │ ValidationTool │ interrupt_before_tools │
170
+ │ RouterAgent │ Ensemble + Router │ ToolRegistry │ retries, session memory │
171
+ │ PlannerAgent │ WorkflowGraph │ │ │
172
+ └─────────────────┴─────────────────────┴─────────────────────┴────────────────────────────┘
173
+ │ │ │ │
174
+ └────────────────────┴────────────────────┴─────────────────────────┘
175
+ │
176
+ ┌───────────▼───────────┐
177
+ │ Use Case Spectrum │
178
+ └───────────────────────┘
179
+ ```
180
+
181
+ ### Use case spectrum
182
+
183
+ | Layer | Use cases |
184
+ |-------|-----------|
185
+ | **Research & fact-checking** | ReActAgent + SearchTool; Swarm for parallel verification |
186
+ | **Document Q&A** | RAGAgent + RAGTool; index URLs, ask questions |
187
+ | **Multi-agent coordination** | Supervisor, Swarm, Pipeline; RouterAgent for LLM-based selection |
188
+ | **Debate & consensus** | DebateOrchestrator; solvers propose → aggregator votes |
189
+ | **Custom workflows** | WorkflowGraph (DAG), StateGraphAgent (nodes), PlannerAgent (decompose) |
190
+ | **Human-in-loop** | `interrupt_before_tools` — pause before sensitive tools, resume with approval |
191
+ | **Production pipelines** | Runner + RunConfig, retries, TraceHooks (usage/cost), Session memory |
98
192
 
99
193
  ---
100
194
 
101
- ## Quick Start
195
+ ## LLM quick start
102
196
 
103
197
  ```bash
104
- pip install agentensemble
105
- # Optional: pip install agentensemble[search,rag]
198
+ pip install "agentensemble[search]"
199
+ export MISTRAL_API_KEY=...
106
200
  ```
107
201
 
108
202
  ```python
@@ -119,7 +213,7 @@ print(result["result"])
119
213
 
120
214
  ## Examples — Code + Output
121
215
 
122
- Each example is runnable. Requires `.env` with `MISTRAL_API_KEY` and `SERPER_API_KEY` (see `.env.example` for format).
216
+ Each example is runnable. Requires `MISTRAL_API_KEY` (and the `search` extra for `SearchTool`; `SERPER_API_KEY` is optional). Outputs below are from the author's runs; LLM answers will vary.
123
217
 
124
218
  ---
125
219
 
@@ -148,10 +242,12 @@ enable machine learning with artificial neural networks.
148
242
  ```python
149
243
  from agentensemble import ReActAgent, SearchTool, function_tool
150
244
 
245
+
151
246
  @function_tool(description="Get current weather for a city")
152
247
  def get_weather(city: str) -> str:
153
248
  return f"Weather in {city}: 72°F, partly cloudy"
154
249
 
250
+
155
251
  agent = ReActAgent(tools=[SearchTool(), get_weather], max_iterations=4)
156
252
  result = agent.run("What is the weather in Paris?")
157
253
  print(result["result"])
@@ -264,7 +360,9 @@ researcher = ReActAgent(name="researcher", tools=[SearchTool()], max_iterations=
264
360
  validator = ReActAgent(name="validator", tools=[SearchTool()], max_iterations=2)
265
361
 
266
362
  router = RouterAgent(agents={"researcher": researcher, "validator": validator})
267
- ensemble = Ensemble(conductor="supervisor", agents={"researcher": researcher, "validator": validator}, router=router)
363
+ ensemble = Ensemble(
364
+ conductor="supervisor", agents={"researcher": researcher, "validator": validator}, router=router
365
+ )
268
366
  result = ensemble.perform("Latest developments in quantum computing")
269
367
  for name, r in result["results"].items():
270
368
  print(f"Routed to {name}: {r['result'][:120]}...")
@@ -284,9 +382,11 @@ Routed to researcher: Here are the latest developments in quantum computing:
284
382
  ```python
285
383
  from agentensemble import PlannerAgent, StateGraphAgent
286
384
 
385
+
287
386
  def worker(state):
288
387
  return {"result": f"Processed: {state.query}"}
289
388
 
389
+
290
390
  executor = StateGraphAgent(name="worker", nodes={"start": worker})
291
391
  executor._route = lambda s, c: "end"
292
392
 
@@ -311,12 +411,15 @@ Result: Processed: Search for information... --- Processed: Summarize key findin
311
411
  ```python
312
412
  from agentensemble import WorkflowGraph
313
413
 
414
+
314
415
  def analyze(s):
315
416
  return {"context": {**s.get("context", {}), "done": True}, "current_node": "summarize"}
316
417
 
418
+
317
419
  def summarize(s):
318
420
  return {"result": f"Summary for: {s['query']}", "current_node": "end"}
319
421
 
422
+
320
423
  graph = (
321
424
  WorkflowGraph(entry="start", exit_nodes=["end"])
322
425
  .add_node("start", lambda s: {"current_node": "analyze"})
@@ -346,8 +449,14 @@ from agentensemble import ReActAgent, Runner, RunConfig, RunHooks, InMemorySessi
346
449
  session = InMemorySession(session_id="chat-1")
347
450
  agent = ReActAgent(name="chatbot", tools=[SearchTool()], session=session, max_iterations=3)
348
451
 
349
- def on_start(q, _): print(f"→ User: {q[:50]}...")
350
- def on_end(r): print(f"← Agent: {r['result'][:80]}...\n")
452
+
453
+ def on_start(q, _):
454
+ print(f"→ User: {q[:50]}...")
455
+
456
+
457
+ def on_end(r):
458
+ print(f"← Agent: {r['result'][:80]}...\n")
459
+
351
460
 
352
461
  config = RunConfig(hooks=RunHooks(on_start=on_start, on_end=on_end))
353
462
 
@@ -367,7 +476,69 @@ Runner.run(agent, "What about its population?", config=config) # Remembers cont
367
476
 
368
477
  ---
369
478
 
370
- ### 11. RAGAgent — Document Q&A (optional: `pip install agentensemble[rag]`)
479
+ ### 11. TraceHooks — Observability, token usage, cost estimation
480
+
481
+ ```python
482
+ from agentensemble import ReActAgent, Runner, RunConfig, TraceHooks, SearchTool
483
+
484
+ agent = ReActAgent(name="research", tools=[SearchTool()], max_iterations=3)
485
+ hooks = TraceHooks()
486
+
487
+ config = RunConfig(trace_hooks=hooks)
488
+ result = Runner.run(agent, "Who won the 2024 Nobel Prize in Physics?", config=config)
489
+
490
+ print(result["result"][:100], "...")
491
+ print("Usage:", result["metadata"].get("total_usage"))
492
+ print("Cost (USD):", result["metadata"].get("cost_usd"))
493
+ print("Events:", [e.type.value for e in hooks.events])
494
+ ```
495
+
496
+ **Output:**
497
+
498
+ ```
499
+ The 2024 Nobel Prize in Physics was awarded jointly to John J. Hopfield and Geoffrey E. Hinton...
500
+ Usage: {'input_tokens': 1247, 'output_tokens': 89, 'total_tokens': 1336}
501
+ Cost (USD): 0.00293
502
+ Events: ['run_start', 'llm_start', 'llm_end', 'tool_start', 'tool_end', 'llm_start', 'llm_end', 'run_end']
503
+ ```
504
+
505
+ ---
506
+
507
+ ### 12. Human-in-loop — Pause before sensitive tools, resume with approval
508
+
509
+ ```python
510
+ from agentensemble import ReActAgent, Runner, RunConfig, function_tool
511
+
512
+
513
+ @function_tool(description="Execute a payment")
514
+ def execute_payment(amount: float, recipient: str) -> str:
515
+ return f"Paid ${amount} to {recipient}"
516
+
517
+
518
+ agent = ReActAgent(tools=[execute_payment], max_iterations=2)
519
+ config = RunConfig(interrupt_before_tools=["execute_payment"])
520
+
521
+ result = Runner.run(agent, "Pay $50 to Alice", config=config)
522
+
523
+ if result.get("__interrupted__"):
524
+ print("Paused for approval:", result["pending_tool"])
525
+ # Simulate human approval
526
+ result = Runner.run(
527
+ agent, "...", config=config, resume=result["run_state"], resume_value="Paid $50 to Alice"
528
+ )
529
+ print(result["result"])
530
+ ```
531
+
532
+ **Output:**
533
+
534
+ ```
535
+ Paused for approval: {'name': 'execute_payment', 'arguments': {'amount': 50.0, 'recipient': 'Alice'}}
536
+ Paid $50 to Alice
537
+ ```
538
+
539
+ ---
540
+
541
+ ### 13. RAGAgent — Document Q&A (optional: `pip install agentensemble[rag]`)
371
542
 
372
543
  ```python
373
544
  from agentensemble import RAGAgent, RAGTool
@@ -388,17 +559,19 @@ manageable subtasks that can be executed by specialized agents...
388
559
 
389
560
  ---
390
561
 
391
- ### 12. StructuredAgent — Pydantic output (optional: `langchain>=1.1`)
562
+ ### 14. StructuredAgent — Pydantic output (optional: `langchain>=1.1`)
392
563
 
393
564
  ```python
394
565
  from pydantic import BaseModel, Field
395
566
  from agentensemble import StructuredAgent
396
567
 
568
+
397
569
  class ProductReview(BaseModel):
398
570
  product: str = Field(description="Product name")
399
571
  rating: int = Field(description="1-5 stars")
400
572
  summary: str = Field(description="Brief summary")
401
573
 
574
+
402
575
  agent = StructuredAgent(response_format=ProductReview)
403
576
  result = agent.run("Review: iPhone 15 Pro - 5 stars, excellent camera and battery")
404
577
  print(result["structured_response"])
@@ -415,9 +588,15 @@ ProductReview(product='iPhone 15 Pro', rating=5, summary='Excellent camera and b
415
588
 
416
589
  ```python
417
590
  from agentensemble import (
418
- ReActAgent, PlannerAgent, StateGraphAgent,
419
- SwarmOrchestrator, DebateOrchestrator,
420
- Runner, RunConfig, RunHooks, SearchTool,
591
+ ReActAgent,
592
+ PlannerAgent,
593
+ StateGraphAgent,
594
+ SwarmOrchestrator,
595
+ DebateOrchestrator,
596
+ Runner,
597
+ RunConfig,
598
+ RunHooks,
599
+ SearchTool,
421
600
  )
422
601
 
423
602
  # 1. Executor: ReActAgent with search
@@ -469,7 +648,7 @@ pip install agentensemble[search]
469
648
  PYTHONPATH=. python examples/showcase_all.py
470
649
  ```
471
650
 
472
- Runs all 10 demos with real API calls.
651
+ Runs all demos with real API calls.
473
652
 
474
653
  ---
475
654
 
@@ -507,7 +686,8 @@ Runs all 10 demos with real API calls.
507
686
 
508
687
  - **Session** — `InMemorySession`, `SQLiteSession` for multi-turn context
509
688
  - **Runner** — `Runner.run()`, `Runner.arun()` with `RunConfig`, `RunHooks`, retries
510
- - **TraceHooks** — Observability for runs, LLM calls, tools
689
+ - **TraceHooks** — Observability: run/LLM/tool events, token usage, cost estimation
690
+ - **Human-in-loop** — `interrupt_before_tools=["pay", "send_email"]` to pause for approval
511
691
 
512
692
  ---
513
693
 
@@ -542,7 +722,8 @@ agentensemble/
542
722
  | Graph workflows | WorkflowGraph, StateGraph | Native | No | No |
543
723
  | Debate pattern | DebateOrchestrator | Manual | Yes | Yes |
544
724
  | Session memory | InMemory, SQLite | Checkpointer | No | No |
545
- | Observability | TraceHooks | LangSmith | No | No |
725
+ | Observability | TraceHooks, usage, cost | LangSmith | No | No |
726
+ | Human-in-loop | interrupt_before_tools | interrupt() | No | No |
546
727
 
547
728
  ---
548
729
 
@@ -550,21 +731,34 @@ agentensemble/
550
731
 
551
732
  - **Retries**: `RunConfig(max_retries=2, retry_on=(RateLimitError, TimeoutError))`
552
733
  - **Session**: `Runner.run(agent, query, config=RunConfig(session=SQLiteSession()))`
553
- - **Tracing**: Attach `TraceHooks` to capture run/LLM/tool events
734
+ - **Tracing**: `RunConfig(trace_hooks=TraceHooks())` — captures run/LLM/tool events, usage, cost
735
+ - **Human-in-loop**: `RunConfig(interrupt_before_tools=["pay"])` — pause before sensitive tools; resume with `Runner.run(agent, ..., resume=run_state, resume_value="Approved")`
554
736
  - **Benchmarks**: `AgentComparison`, `Benchmark.research_tasks()`, `Metrics`
555
737
 
556
738
  ---
557
739
 
558
740
  ## Documentation
559
741
 
560
- - **[Showcase](examples/showcase_all.py)** — Run all 10 features with real API output
742
+ - **[Showcase](examples/showcase_all.py)** — Run the features end to end with real API calls
743
+ - [Changelog](CHANGELOG.md)
561
744
  - [Examples](examples/) — `quickstart`, `react_llm`, `swarm`, `pipeline`, `streaming`, `debate`, `rag`, `research_agent`, `graph_workflow`, `runner`, `structured_output`
562
745
  - [Roadmap](docs/ROADMAP_2025.md) — Planned improvements
563
746
 
564
- > **Note:** Ensure `docs/agentensemble-architecture.png` is committed so the architecture diagram renders on GitHub.
565
-
566
747
  ---
567
748
 
749
+ ## Contributing
750
+
751
+ Contributions are welcome. See [CONTRIBUTING.md](https://github.com/irfanalidv/AgentEnsemble/blob/main/CONTRIBUTING.md)
752
+ and the [Code of Conduct](https://github.com/irfanalidv/AgentEnsemble/blob/main/CODE_OF_CONDUCT.md).
753
+
754
+ ```bash
755
+ git clone https://github.com/irfanalidv/AgentEnsemble.git && cd AgentEnsemble
756
+ pip install -e ".[dev]"
757
+ ruff check . && ruff format --check . && pytest
758
+ ```
759
+
760
+ Security issues: please follow [SECURITY.md](https://github.com/irfanalidv/AgentEnsemble/blob/main/SECURITY.md).
761
+
568
762
  ## License
569
763
 
570
- MIT — see [LICENSE](LICENSE).
764
+ MIT — see [LICENSE](https://github.com/irfanalidv/AgentEnsemble/blob/main/LICENSE).