agentensemble 0.3.0__tar.gz → 0.5.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.5.0/CHANGELOG.md +96 -0
- agentensemble-0.5.0/LICENSE +21 -0
- {agentensemble-0.3.0 → agentensemble-0.5.0}/MANIFEST.in +2 -2
- {agentensemble-0.3.0/agentensemble.egg-info → agentensemble-0.5.0}/PKG-INFO +173 -43
- agentensemble-0.3.0/PKG-INFO → agentensemble-0.5.0/README.md +146 -76
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/__init__.py +27 -24
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/__init__.py +4 -3
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/base.py +11 -10
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/hybrid_agent.py +30 -34
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/rag_agent.py +19 -19
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/react_agent.py +103 -56
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/stategraph_agent.py +23 -23
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/structured_agent.py +51 -63
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/core/protocol.py +4 -5
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/graph/__init__.py +1 -1
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/graph/workflow.py +12 -9
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/llm/__init__.py +17 -3
- agentensemble-0.5.0/agentensemble/llm/factory.py +63 -0
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/llm/interface.py +17 -20
- agentensemble-0.3.0/agentensemble/llm/mistral_provider.py → agentensemble-0.5.0/agentensemble/llm/langchain_base.py +73 -86
- agentensemble-0.5.0/agentensemble/llm/mistral_provider.py +77 -0
- agentensemble-0.5.0/agentensemble/llm/openai_provider.py +79 -0
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/memory/__init__.py +1 -1
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/memory/session.py +6 -6
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/memory/sqlite_session.py +5 -5
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/orchestration/__init__.py +2 -3
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/orchestration/debate.py +6 -6
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/orchestration/ensemble.py +37 -56
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/orchestration/pipeline.py +6 -6
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/orchestration/supervisor.py +6 -6
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/orchestration/swarm.py +6 -6
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/planner/planner_agent.py +10 -9
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/router/router_agent.py +14 -20
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/runner.py +16 -15
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/testing/__init__.py +1 -2
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/testing/benchmark.py +12 -13
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/testing/comparison.py +25 -17
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/testing/metrics.py +20 -21
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/__init__.py +4 -4
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/adapters.py +8 -7
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/function_tool.py +6 -6
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/protocol.py +11 -14
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/rag.py +10 -11
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/registry.py +21 -22
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/scraper.py +8 -25
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/search.py +20 -5
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/validator.py +9 -11
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tracing/__init__.py +7 -1
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tracing/hooks.py +20 -14
- agentensemble-0.5.0/agentensemble/utils/__init__.py +17 -0
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/utils/llm.py +56 -8
- agentensemble-0.3.0/README.md → agentensemble-0.5.0/agentensemble.egg-info/PKG-INFO +207 -24
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble.egg-info/SOURCES.txt +7 -1
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble.egg-info/requires.txt +11 -11
- {agentensemble-0.3.0 → agentensemble-0.5.0}/pyproject.toml +47 -33
- {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_agents.py +5 -5
- {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_comparison.py +1 -1
- agentensemble-0.5.0/tests/test_llm_providers.py +165 -0
- {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_memory.py +8 -8
- {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_orchestration.py +5 -2
- {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_react_session.py +6 -6
- agentensemble-0.5.0/tests/test_release.py +98 -0
- {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_runner.py +2 -3
- {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_tools.py +3 -5
- {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_tracing.py +1 -3
- agentensemble-0.3.0/agentensemble/utils/__init__.py +0 -11
- agentensemble-0.3.0/setup.py +0 -15
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/core/__init__.py +0 -0
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/planner/__init__.py +0 -0
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/py.typed +0 -0
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/router/__init__.py +0 -0
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble.egg-info/dependency_links.txt +0 -0
- {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble.egg-info/top_level.txt +0 -0
- {agentensemble-0.3.0 → agentensemble-0.5.0}/setup.cfg +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
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.5.0] - 2026-10-31
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **OpenAI support.** New `OpenAILLMProvider` (LangChain `ChatOpenAI`, native tool calling).
|
|
14
|
+
Default model `gpt-4.1-mini`, configurable via `OPENAI_MODEL`; `OPENAI_BASE_URL` for
|
|
15
|
+
OpenAI-compatible endpoints. Temperature is omitted for reasoning models (o-series, gpt-5).
|
|
16
|
+
- `get_default_provider()` / `resolve_provider_name()`: agents now pick OpenAI when
|
|
17
|
+
`OPENAI_API_KEY` is set, otherwise Mistral; `AGENTENSEMBLE_LLM_PROVIDER` forces one.
|
|
18
|
+
- `agentensemble.utils.get_chat_model()` and `get_openai_model()`; `StructuredAgent` uses the
|
|
19
|
+
same OpenAI-or-Mistral selection.
|
|
20
|
+
- `langchain-openai` is now a core dependency.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- Calling a sync agent API twice (e.g. `agent.run()` then `agent.run()`, or `run()` followed by
|
|
24
|
+
`asyncio.run(agent.arun())`) failed with `RuntimeError: Event loop is closed`. Each sync call
|
|
25
|
+
uses `asyncio.run()`, and the LLM's async HTTP client stayed bound to the first, closed loop.
|
|
26
|
+
Providers now rebuild their chat model when used on a new event loop, and each OpenAI model
|
|
27
|
+
gets its own async HTTP client instead of the process-wide cached one.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- Shared LangChain conversion logic moved to `agentensemble.llm.langchain_base`
|
|
31
|
+
(`LangChainChatProvider`); `MistralLLMProvider` keeps its public API.
|
|
32
|
+
|
|
33
|
+
## [0.4.0] - 2026-10-31
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
- `ReActAgent` can now be constructed without `MISTRAL_API_KEY` (matching `HybridAgent` and
|
|
37
|
+
`RouterAgent`); `run()` / `astream()` raise a clear `RuntimeError` until an LLM is configured.
|
|
38
|
+
Previously the constructor raised `ValueError`, which broke 6 tests and any offline usage.
|
|
39
|
+
- `SearchTool`'s DuckDuckGo fallback works again: `langchain-community` now needs the `ddgs`
|
|
40
|
+
package (the `search` extra previously installed the old `duckduckgo-search`).
|
|
41
|
+
- `SearchTool` creates its backend lazily on first use, so it can be registered in a
|
|
42
|
+
`ToolRegistry` without optional dependencies; a missing backend raises an `ImportError` with
|
|
43
|
+
the `pip install 'agentensemble[search]'` hint. Unknown providers still fail fast.
|
|
44
|
+
- Tool schema type inference uses identity checks (`ann is str`), not equality.
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
- `MISTRAL_MODEL` environment variable to choose the default model for `MistralLLMProvider`.
|
|
48
|
+
- `__version__` read from installed package metadata (`importlib.metadata`).
|
|
49
|
+
- GitHub Actions CI (ruff lint + format check, pytest on Python 3.10–3.13).
|
|
50
|
+
- New tests: ReActAgent tool-calling loop with a fake LLM, SearchTool behaviour, version, model
|
|
51
|
+
override (64 tests total).
|
|
52
|
+
- SECURITY.md, CODE_OF_CONDUCT.md, issue/PR templates, Dependabot, CITATION.cff.
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
- Requires Python 3.10+ (3.9 is end-of-life); classifiers for 3.10–3.13.
|
|
56
|
+
- Packaging is `pyproject.toml`-only (removed `setup.py` and `requirements.txt`), PEP 639
|
|
57
|
+
`license = "MIT"`, LICENSE and CHANGELOG shipped in the sdist.
|
|
58
|
+
- Dependency floors raised to the versions the code actually needs: `langchain>=1.1`,
|
|
59
|
+
`langchain-core>=1.0`, `langchain-community>=0.3`, `langchain-mistralai>=0.2`. The unused
|
|
60
|
+
direct `langgraph` dependency was dropped (it is still installed transitively by `langchain`).
|
|
61
|
+
- `dev` extra now includes `build` and `twine`; `black` replaced by `ruff format`.
|
|
62
|
+
- Codebase formatted with `ruff format` and modernised type hints (`X | None`).
|
|
63
|
+
|
|
64
|
+
## [0.3.0] - 2026-03-10
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
- Observability (`TraceHooks`, token usage, cost estimation), human-in-the-loop
|
|
68
|
+
(`interrupt_before_tools`), architecture diagram.
|
|
69
|
+
|
|
70
|
+
## [0.2.0] - 2026-03-10
|
|
71
|
+
|
|
72
|
+
### Added
|
|
73
|
+
- `RouterAgent`, `PlannerAgent`, `WorkflowGraph`, tracing.
|
|
74
|
+
|
|
75
|
+
## [0.1.0] - 2025-12-09
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
- Initial release
|
|
79
|
+
- ReActAgent implementation
|
|
80
|
+
- StateGraphAgent implementation
|
|
81
|
+
- RAGAgent with fallback strategies
|
|
82
|
+
- HybridAgent with intelligent routing
|
|
83
|
+
- Ensemble orchestration patterns (Supervisor, Swarm, Pipeline)
|
|
84
|
+
- Tool ecosystem (Search, Scraper, RAG, Validator)
|
|
85
|
+
- Tool registry for centralized management
|
|
86
|
+
- Testing framework (AgentComparison, Benchmark, Metrics)
|
|
87
|
+
- Base agent class and state management
|
|
88
|
+
- Comprehensive documentation
|
|
89
|
+
|
|
90
|
+
### Infrastructure
|
|
91
|
+
- Python 3.9+ support
|
|
92
|
+
- pyproject.toml for modern packaging
|
|
93
|
+
- Development dependencies (pytest, black, ruff, mypy)
|
|
94
|
+
- MIT License
|
|
95
|
+
- Contributing guidelines
|
|
96
|
+
|
|
@@ -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,48 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentensemble
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.5.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,openai,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
|
|
34
|
+
Requires-Dist: langchain-openai>=1.0.0
|
|
29
35
|
Requires-Dist: pydantic>=2.0.0
|
|
30
36
|
Requires-Dist: typing-extensions>=4.5.0
|
|
31
37
|
Requires-Dist: python-dotenv>=1.0.0
|
|
32
38
|
Provides-Extra: dev
|
|
33
39
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
34
40
|
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
41
|
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
42
|
+
Requires-Dist: ruff>=0.6.0; extra == "dev"
|
|
43
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
44
|
+
Requires-Dist: build>=1.0.0; extra == "dev"
|
|
45
|
+
Requires-Dist: twine>=5.0.0; extra == "dev"
|
|
39
46
|
Provides-Extra: observability
|
|
40
47
|
Requires-Dist: langsmith>=0.1.0; extra == "observability"
|
|
41
48
|
Requires-Dist: opentelemetry-api>=1.20.0; extra == "observability"
|
|
@@ -44,23 +51,107 @@ Requires-Dist: chromadb>=0.4.0; extra == "rag"
|
|
|
44
51
|
Requires-Dist: sentence-transformers>=2.2.0; extra == "rag"
|
|
45
52
|
Requires-Dist: langchain-text-splitters>=0.0.1; extra == "rag"
|
|
46
53
|
Requires-Dist: beautifulsoup4>=4.12.0; extra == "rag"
|
|
47
|
-
Requires-Dist: langchain-mistralai>=0.1.0; extra == "rag"
|
|
48
54
|
Provides-Extra: search
|
|
49
|
-
Requires-Dist:
|
|
55
|
+
Requires-Dist: ddgs>=9.0.0; extra == "search"
|
|
50
56
|
Requires-Dist: google-search-results>=2.4.2; extra == "search"
|
|
51
57
|
Provides-Extra: all
|
|
52
|
-
Requires-Dist: agentensemble[
|
|
58
|
+
Requires-Dist: agentensemble[observability,rag,search]; extra == "all"
|
|
59
|
+
Dynamic: license-file
|
|
60
|
+
|
|
61
|
+
<div align="center">
|
|
53
62
|
|
|
54
63
|
# AgentEnsemble
|
|
55
64
|
|
|
56
|
-
**
|
|
65
|
+
**Build, orchestrate, trace, and test multi-agent LLM systems in Python.**
|
|
57
66
|
|
|
58
|
-
|
|
67
|
+
ReAct, RAG, router, planner, workflow graphs, swarms, debates, and pipelines, with sessions,
|
|
68
|
+
tracing, retries, and human-in-the-loop approval built in.
|
|
59
69
|
|
|
60
|
-
[](https://pypi.org/project/agentensemble/)
|
|
71
|
+
[](https://pypi.org/project/agentensemble/)
|
|
72
|
+
[](https://github.com/irfanalidv/AgentEnsemble/actions/workflows/tests.yml)
|
|
63
73
|
[](https://pepy.tech/projects/agentensemble)
|
|
74
|
+
[](https://github.com/irfanalidv/AgentEnsemble/blob/main/LICENSE)
|
|
75
|
+
[](https://github.com/astral-sh/ruff)
|
|
76
|
+
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
AgentEnsemble is a framework for building and orchestrating AI agent systems, designed for clarity,
|
|
82
|
+
extensibility, and production use. It covers similar ground to LangGraph, CrewAI, and AutoGen.
|
|
83
|
+
|
|
84
|
+
## Installation
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pip install agentensemble # core: agents, orchestration, graphs, memory, tracing
|
|
88
|
+
pip install "agentensemble[search]" # + DuckDuckGo / Serper web search for SearchTool
|
|
89
|
+
pip install "agentensemble[rag]" # + Chroma, sentence-transformers, loaders for RAGTool
|
|
90
|
+
pip install "agentensemble[observability]" # + LangSmith / OpenTelemetry
|
|
91
|
+
pip install "agentensemble[all]" # everything above
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Requires Python 3.10+.
|
|
95
|
+
|
|
96
|
+
## Quick start (no API key needed)
|
|
97
|
+
|
|
98
|
+
Graph workflows, state-graph agents, and the planner run without any LLM:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from agentensemble import WorkflowGraph
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def analyze(s):
|
|
105
|
+
return {"context": {**s.get("context", {}), "done": True}, "current_node": "summarize"}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def summarize(s):
|
|
109
|
+
return {"result": f"Summary for: {s['query']}", "current_node": "end"}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
graph = (
|
|
113
|
+
WorkflowGraph(entry="start", exit_nodes=["end"])
|
|
114
|
+
.add_node("start", lambda s: {"current_node": "analyze"})
|
|
115
|
+
.add_node("analyze", analyze)
|
|
116
|
+
.add_node("summarize", summarize)
|
|
117
|
+
.add_edge("start", "analyze")
|
|
118
|
+
.add_edge("analyze", "summarize")
|
|
119
|
+
.add_edge("summarize", "end")
|
|
120
|
+
)
|
|
121
|
+
print(graph.run("What is multi-agent AI?")["result"])
|
|
122
|
+
# Summary for: What is multi-agent AI?
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
LLM-powered agents (`ReActAgent`, `HybridAgent`, `RouterAgent`, `StructuredAgent`) work with
|
|
126
|
+
**OpenAI** or **Mistral**. The provider is picked from your environment: OpenAI if
|
|
127
|
+
`OPENAI_API_KEY` is set, otherwise Mistral if `MISTRAL_API_KEY` is set. You can also pass any
|
|
128
|
+
`LLMProvider` explicitly via `llm=...`:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from agentensemble import ReActAgent
|
|
132
|
+
from agentensemble.llm import OpenAILLMProvider, MistralLLMProvider
|
|
133
|
+
|
|
134
|
+
agent = ReActAgent(tools=[...], llm=OpenAILLMProvider(model="gpt-4.1-mini"))
|
|
135
|
+
agent = ReActAgent(tools=[...], llm=MistralLLMProvider(model="mistral-small-latest"))
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Configuration
|
|
139
|
+
|
|
140
|
+
| Variable | Purpose |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| `OPENAI_API_KEY` | Enables the OpenAI provider (preferred when set). |
|
|
143
|
+
| `OPENAI_MODEL` | Optional default model for `OpenAILLMProvider` (default: `gpt-4.1-mini`). Reasoning models such as `gpt-5-mini` work too; temperature is left at the API default for them. |
|
|
144
|
+
| `OPENAI_BASE_URL` | Optional OpenAI-compatible endpoint (Azure OpenAI proxy, vLLM, LM Studio, ...). |
|
|
145
|
+
| `MISTRAL_API_KEY` | Enables the Mistral provider (used when no OpenAI key is set). |
|
|
146
|
+
| `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. |
|
|
147
|
+
| `AGENTENSEMBLE_LLM_PROVIDER` | Optional. Force `openai` or `mistral` when both keys are set. |
|
|
148
|
+
| `SERPER_API_KEY` | Optional. When set, `SearchTool()` uses Serper; otherwise it falls back to DuckDuckGo (needs the `search` extra). |
|
|
149
|
+
|
|
150
|
+
Copy `.env.example` to `.env` and fill in your keys (`KEY=value`, no spaces around `=`); the
|
|
151
|
+
package loads `.env` automatically via `python-dotenv`.
|
|
152
|
+
|
|
153
|
+
Without an API key, LLM agents can still be constructed (and inspected or registered); calling
|
|
154
|
+
`run()` raises a clear `RuntimeError` explaining how to configure an LLM.
|
|
64
155
|
|
|
65
156
|
---
|
|
66
157
|
|
|
@@ -68,7 +159,7 @@ AgentEnsemble is a modern framework for building and orchestrating AI agent syst
|
|
|
68
159
|
|
|
69
160
|
- **Modular** — Agents, tools, orchestration, and memory are decoupled
|
|
70
161
|
- **Async-first** — `run()` and `arun()` on all agents; parallel execution via `asyncio.gather`
|
|
71
|
-
- **Provider-agnostic** — LLM interface
|
|
162
|
+
- **Provider-agnostic** — one LLM interface, OpenAI and Mistral built in
|
|
72
163
|
- **Production patterns** — Runner, retries, hooks, tracing, session memory
|
|
73
164
|
|
|
74
165
|
---
|
|
@@ -76,7 +167,7 @@ AgentEnsemble is a modern framework for building and orchestrating AI agent syst
|
|
|
76
167
|
## Architecture
|
|
77
168
|
|
|
78
169
|
<p align="center">
|
|
79
|
-
<img src="docs/agentensemble-architecture.png" alt="AgentEnsemble Architecture" width="900"/>
|
|
170
|
+
<img src="https://raw.githubusercontent.com/irfanalidv/AgentEnsemble/main/docs/agentensemble-architecture.png" alt="AgentEnsemble Architecture" width="900"/>
|
|
80
171
|
</p>
|
|
81
172
|
|
|
82
173
|
### Framework layers
|
|
@@ -116,11 +207,11 @@ AgentEnsemble is a modern framework for building and orchestrating AI agent syst
|
|
|
116
207
|
|
|
117
208
|
---
|
|
118
209
|
|
|
119
|
-
##
|
|
210
|
+
## LLM quick start
|
|
120
211
|
|
|
121
212
|
```bash
|
|
122
|
-
pip install agentensemble
|
|
123
|
-
#
|
|
213
|
+
pip install "agentensemble[search]"
|
|
214
|
+
export OPENAI_API_KEY=... # or: export MISTRAL_API_KEY=...
|
|
124
215
|
```
|
|
125
216
|
|
|
126
217
|
```python
|
|
@@ -137,7 +228,7 @@ print(result["result"])
|
|
|
137
228
|
|
|
138
229
|
## Examples — Code + Output
|
|
139
230
|
|
|
140
|
-
Each example is runnable. Requires
|
|
231
|
+
Each example is runnable. Requires `OPENAI_API_KEY` or `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.
|
|
141
232
|
|
|
142
233
|
---
|
|
143
234
|
|
|
@@ -166,10 +257,12 @@ enable machine learning with artificial neural networks.
|
|
|
166
257
|
```python
|
|
167
258
|
from agentensemble import ReActAgent, SearchTool, function_tool
|
|
168
259
|
|
|
260
|
+
|
|
169
261
|
@function_tool(description="Get current weather for a city")
|
|
170
262
|
def get_weather(city: str) -> str:
|
|
171
263
|
return f"Weather in {city}: 72°F, partly cloudy"
|
|
172
264
|
|
|
265
|
+
|
|
173
266
|
agent = ReActAgent(tools=[SearchTool(), get_weather], max_iterations=4)
|
|
174
267
|
result = agent.run("What is the weather in Paris?")
|
|
175
268
|
print(result["result"])
|
|
@@ -282,7 +375,9 @@ researcher = ReActAgent(name="researcher", tools=[SearchTool()], max_iterations=
|
|
|
282
375
|
validator = ReActAgent(name="validator", tools=[SearchTool()], max_iterations=2)
|
|
283
376
|
|
|
284
377
|
router = RouterAgent(agents={"researcher": researcher, "validator": validator})
|
|
285
|
-
ensemble = Ensemble(
|
|
378
|
+
ensemble = Ensemble(
|
|
379
|
+
conductor="supervisor", agents={"researcher": researcher, "validator": validator}, router=router
|
|
380
|
+
)
|
|
286
381
|
result = ensemble.perform("Latest developments in quantum computing")
|
|
287
382
|
for name, r in result["results"].items():
|
|
288
383
|
print(f"Routed to {name}: {r['result'][:120]}...")
|
|
@@ -302,9 +397,11 @@ Routed to researcher: Here are the latest developments in quantum computing:
|
|
|
302
397
|
```python
|
|
303
398
|
from agentensemble import PlannerAgent, StateGraphAgent
|
|
304
399
|
|
|
400
|
+
|
|
305
401
|
def worker(state):
|
|
306
402
|
return {"result": f"Processed: {state.query}"}
|
|
307
403
|
|
|
404
|
+
|
|
308
405
|
executor = StateGraphAgent(name="worker", nodes={"start": worker})
|
|
309
406
|
executor._route = lambda s, c: "end"
|
|
310
407
|
|
|
@@ -329,12 +426,15 @@ Result: Processed: Search for information... --- Processed: Summarize key findin
|
|
|
329
426
|
```python
|
|
330
427
|
from agentensemble import WorkflowGraph
|
|
331
428
|
|
|
429
|
+
|
|
332
430
|
def analyze(s):
|
|
333
431
|
return {"context": {**s.get("context", {}), "done": True}, "current_node": "summarize"}
|
|
334
432
|
|
|
433
|
+
|
|
335
434
|
def summarize(s):
|
|
336
435
|
return {"result": f"Summary for: {s['query']}", "current_node": "end"}
|
|
337
436
|
|
|
437
|
+
|
|
338
438
|
graph = (
|
|
339
439
|
WorkflowGraph(entry="start", exit_nodes=["end"])
|
|
340
440
|
.add_node("start", lambda s: {"current_node": "analyze"})
|
|
@@ -364,8 +464,14 @@ from agentensemble import ReActAgent, Runner, RunConfig, RunHooks, InMemorySessi
|
|
|
364
464
|
session = InMemorySession(session_id="chat-1")
|
|
365
465
|
agent = ReActAgent(name="chatbot", tools=[SearchTool()], session=session, max_iterations=3)
|
|
366
466
|
|
|
367
|
-
|
|
368
|
-
def
|
|
467
|
+
|
|
468
|
+
def on_start(q, _):
|
|
469
|
+
print(f"→ User: {q[:50]}...")
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def on_end(r):
|
|
473
|
+
print(f"← Agent: {r['result'][:80]}...\n")
|
|
474
|
+
|
|
369
475
|
|
|
370
476
|
config = RunConfig(hooks=RunHooks(on_start=on_start, on_end=on_end))
|
|
371
477
|
|
|
@@ -418,10 +524,12 @@ Events: ['run_start', 'llm_start', 'llm_end', 'tool_start', 'tool_end', 'llm_sta
|
|
|
418
524
|
```python
|
|
419
525
|
from agentensemble import ReActAgent, Runner, RunConfig, function_tool
|
|
420
526
|
|
|
527
|
+
|
|
421
528
|
@function_tool(description="Execute a payment")
|
|
422
529
|
def execute_payment(amount: float, recipient: str) -> str:
|
|
423
530
|
return f"Paid ${amount} to {recipient}"
|
|
424
531
|
|
|
532
|
+
|
|
425
533
|
agent = ReActAgent(tools=[execute_payment], max_iterations=2)
|
|
426
534
|
config = RunConfig(interrupt_before_tools=["execute_payment"])
|
|
427
535
|
|
|
@@ -430,7 +538,9 @@ result = Runner.run(agent, "Pay $50 to Alice", config=config)
|
|
|
430
538
|
if result.get("__interrupted__"):
|
|
431
539
|
print("Paused for approval:", result["pending_tool"])
|
|
432
540
|
# Simulate human approval
|
|
433
|
-
result = Runner.run(
|
|
541
|
+
result = Runner.run(
|
|
542
|
+
agent, "...", config=config, resume=result["run_state"], resume_value="Paid $50 to Alice"
|
|
543
|
+
)
|
|
434
544
|
print(result["result"])
|
|
435
545
|
```
|
|
436
546
|
|
|
@@ -470,11 +580,13 @@ manageable subtasks that can be executed by specialized agents...
|
|
|
470
580
|
from pydantic import BaseModel, Field
|
|
471
581
|
from agentensemble import StructuredAgent
|
|
472
582
|
|
|
583
|
+
|
|
473
584
|
class ProductReview(BaseModel):
|
|
474
585
|
product: str = Field(description="Product name")
|
|
475
586
|
rating: int = Field(description="1-5 stars")
|
|
476
587
|
summary: str = Field(description="Brief summary")
|
|
477
588
|
|
|
589
|
+
|
|
478
590
|
agent = StructuredAgent(response_format=ProductReview)
|
|
479
591
|
result = agent.run("Review: iPhone 15 Pro - 5 stars, excellent camera and battery")
|
|
480
592
|
print(result["structured_response"])
|
|
@@ -491,9 +603,15 @@ ProductReview(product='iPhone 15 Pro', rating=5, summary='Excellent camera and b
|
|
|
491
603
|
|
|
492
604
|
```python
|
|
493
605
|
from agentensemble import (
|
|
494
|
-
ReActAgent,
|
|
495
|
-
|
|
496
|
-
|
|
606
|
+
ReActAgent,
|
|
607
|
+
PlannerAgent,
|
|
608
|
+
StateGraphAgent,
|
|
609
|
+
SwarmOrchestrator,
|
|
610
|
+
DebateOrchestrator,
|
|
611
|
+
Runner,
|
|
612
|
+
RunConfig,
|
|
613
|
+
RunHooks,
|
|
614
|
+
SearchTool,
|
|
497
615
|
)
|
|
498
616
|
|
|
499
617
|
# 1. Executor: ReActAgent with search
|
|
@@ -594,7 +712,7 @@ Runs all demos with real API calls.
|
|
|
594
712
|
agentensemble/
|
|
595
713
|
├── agents/ # ReAct, StateGraph, RAG, Hybrid, Structured
|
|
596
714
|
├── core/ # AgentProtocol, RunnableProtocol
|
|
597
|
-
├── llm/ # LLMProvider, MistralLLMProvider
|
|
715
|
+
├── llm/ # LLMProvider, OpenAILLMProvider, MistralLLMProvider, get_default_provider
|
|
598
716
|
├── memory/ # Session, InMemorySession, SQLiteSession
|
|
599
717
|
├── orchestration/ # Ensemble, Supervisor, Swarm, Pipeline, Debate
|
|
600
718
|
├── tools/ # Tool protocol, @function_tool, built-ins
|
|
@@ -612,7 +730,7 @@ agentensemble/
|
|
|
612
730
|
|
|
613
731
|
| Feature | AgentEnsemble | LangGraph | CrewAI | AutoGen |
|
|
614
732
|
| ------------------ | ------------------------- | ------------ | ------ | ------- |
|
|
615
|
-
| Multi-provider LLM | Mistral (extensible)
|
|
733
|
+
| Multi-provider LLM | OpenAI, Mistral (extensible) | Any | Any | Any |
|
|
616
734
|
| Async API | `arun()` everywhere | Yes | Yes | Yes |
|
|
617
735
|
| Router agents | RouterAgent | Manual | Yes | Manual |
|
|
618
736
|
| Planner pattern | PlannerAgent | Manual | Yes | Manual |
|
|
@@ -636,14 +754,26 @@ agentensemble/
|
|
|
636
754
|
|
|
637
755
|
## Documentation
|
|
638
756
|
|
|
639
|
-
- **[Showcase](examples/showcase_all.py)** — Run
|
|
757
|
+
- **[Showcase](examples/showcase_all.py)** — Run the features end to end with real API calls
|
|
758
|
+
- [Changelog](CHANGELOG.md)
|
|
640
759
|
- [Examples](examples/) — `quickstart`, `react_llm`, `swarm`, `pipeline`, `streaming`, `debate`, `rag`, `research_agent`, `graph_workflow`, `runner`, `structured_output`
|
|
641
760
|
- [Roadmap](docs/ROADMAP_2025.md) — Planned improvements
|
|
642
761
|
|
|
643
|
-
> **Note:** Ensure `docs/agentensemble-architecture.png` is committed so the architecture diagram renders on GitHub.
|
|
644
|
-
|
|
645
762
|
---
|
|
646
763
|
|
|
764
|
+
## Contributing
|
|
765
|
+
|
|
766
|
+
Contributions are welcome. See [CONTRIBUTING.md](https://github.com/irfanalidv/AgentEnsemble/blob/main/CONTRIBUTING.md)
|
|
767
|
+
and the [Code of Conduct](https://github.com/irfanalidv/AgentEnsemble/blob/main/CODE_OF_CONDUCT.md).
|
|
768
|
+
|
|
769
|
+
```bash
|
|
770
|
+
git clone https://github.com/irfanalidv/AgentEnsemble.git && cd AgentEnsemble
|
|
771
|
+
pip install -e ".[dev]"
|
|
772
|
+
ruff check . && ruff format --check . && pytest
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
Security issues: please follow [SECURITY.md](https://github.com/irfanalidv/AgentEnsemble/blob/main/SECURITY.md).
|
|
776
|
+
|
|
647
777
|
## License
|
|
648
778
|
|
|
649
|
-
MIT — see [LICENSE](LICENSE).
|
|
779
|
+
MIT — see [LICENSE](https://github.com/irfanalidv/AgentEnsemble/blob/main/LICENSE).
|