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.
- agentensemble-0.4.0/CHANGELOG.md +73 -0
- agentensemble-0.4.0/LICENSE +21 -0
- {agentensemble-0.2.0 → agentensemble-0.4.0}/MANIFEST.in +2 -2
- {agentensemble-0.2.0/agentensemble.egg-info → agentensemble-0.4.0}/PKG-INFO +255 -61
- agentensemble-0.2.0/PKG-INFO → agentensemble-0.4.0/README.md +229 -94
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/__init__.py +29 -24
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/agents/__init__.py +4 -3
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/agents/base.py +11 -10
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/agents/hybrid_agent.py +27 -23
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/agents/rag_agent.py +19 -19
- agentensemble-0.4.0/agentensemble/agents/react_agent.py +465 -0
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/agents/stategraph_agent.py +23 -23
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/agents/structured_agent.py +51 -51
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/core/protocol.py +4 -5
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/graph/__init__.py +1 -1
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/graph/workflow.py +12 -9
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/llm/__init__.py +3 -2
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/llm/interface.py +17 -20
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/llm/mistral_provider.py +48 -19
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/memory/__init__.py +1 -1
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/memory/session.py +6 -6
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/memory/sqlite_session.py +5 -5
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/orchestration/__init__.py +2 -3
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/orchestration/debate.py +6 -6
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/orchestration/ensemble.py +37 -56
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/orchestration/pipeline.py +6 -6
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/orchestration/supervisor.py +6 -6
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/orchestration/swarm.py +6 -6
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/planner/planner_agent.py +10 -9
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/router/router_agent.py +12 -10
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/runner.py +21 -14
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/testing/__init__.py +1 -2
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/testing/benchmark.py +12 -13
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/testing/comparison.py +25 -17
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/testing/metrics.py +20 -21
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/__init__.py +4 -4
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/adapters.py +8 -7
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/function_tool.py +6 -6
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/protocol.py +11 -14
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/rag.py +10 -11
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/registry.py +21 -22
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/scraper.py +8 -25
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/search.py +20 -5
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/tools/validator.py +9 -11
- agentensemble-0.4.0/agentensemble/tracing/__init__.py +16 -0
- agentensemble-0.4.0/agentensemble/tracing/hooks.py +127 -0
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/utils/__init__.py +1 -2
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/utils/llm.py +6 -8
- agentensemble-0.2.0/README.md → agentensemble-0.4.0/agentensemble.egg-info/PKG-INFO +289 -42
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble.egg-info/SOURCES.txt +5 -2
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble.egg-info/requires.txt +10 -11
- {agentensemble-0.2.0 → agentensemble-0.4.0}/pyproject.toml +45 -33
- {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_agents.py +5 -5
- {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_comparison.py +1 -1
- {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_memory.py +8 -8
- {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_orchestration.py +5 -2
- {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_react_session.py +6 -6
- agentensemble-0.4.0/tests/test_release.py +98 -0
- {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_runner.py +23 -3
- {agentensemble-0.2.0 → agentensemble-0.4.0}/tests/test_tools.py +3 -5
- agentensemble-0.4.0/tests/test_tracing.py +47 -0
- agentensemble-0.2.0/agentensemble/agents/react_agent.py +0 -300
- agentensemble-0.2.0/agentensemble/tracing/__init__.py +0 -10
- agentensemble-0.2.0/agentensemble/tracing/hooks.py +0 -82
- agentensemble-0.2.0/setup.py +0 -15
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/core/__init__.py +0 -0
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/planner/__init__.py +0 -0
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/py.typed +0 -0
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble/router/__init__.py +0 -0
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble.egg-info/dependency_links.txt +0 -0
- {agentensemble-0.2.0 → agentensemble-0.4.0}/agentensemble.egg-info/top_level.txt +0 -0
- {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,41 +1,47 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentensemble
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
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
|
-
|
|
13
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
25
|
-
Requires-Dist: langchain
|
|
26
|
-
Requires-Dist: langchain-
|
|
27
|
-
Requires-Dist: langchain-
|
|
28
|
-
Requires-Dist:
|
|
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:
|
|
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[
|
|
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
|
-
**
|
|
64
|
+
**Build, orchestrate, trace, and test multi-agent LLM systems in Python.**
|
|
57
65
|
|
|
58
|
-
|
|
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
|
-
[](https://pypi.org/project/agentensemble/)
|
|
70
|
+
[](https://pypi.org/project/agentensemble/)
|
|
71
|
+
[](https://github.com/irfanalidv/AgentEnsemble/actions/workflows/tests.yml)
|
|
63
72
|
[](https://pepy.tech/projects/agentensemble)
|
|
73
|
+
[](https://github.com/irfanalidv/AgentEnsemble/blob/main/LICENSE)
|
|
74
|
+
[](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="
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
│
|
|
87
|
-
|
|
88
|
-
│
|
|
89
|
-
|
|
90
|
-
│ ReActAgent
|
|
91
|
-
│
|
|
92
|
-
│ RAGAgent
|
|
93
|
-
│ HybridAgent
|
|
94
|
-
│ RouterAgent │
|
|
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
|
-
##
|
|
195
|
+
## LLM quick start
|
|
102
196
|
|
|
103
197
|
```bash
|
|
104
|
-
pip install agentensemble
|
|
105
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
350
|
-
def
|
|
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.
|
|
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
|
-
###
|
|
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,
|
|
419
|
-
|
|
420
|
-
|
|
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
|
|
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
|
|
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
|
|
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**:
|
|
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
|
|
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).
|