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.
Files changed (74) hide show
  1. agentensemble-0.5.0/CHANGELOG.md +96 -0
  2. agentensemble-0.5.0/LICENSE +21 -0
  3. {agentensemble-0.3.0 → agentensemble-0.5.0}/MANIFEST.in +2 -2
  4. {agentensemble-0.3.0/agentensemble.egg-info → agentensemble-0.5.0}/PKG-INFO +173 -43
  5. agentensemble-0.3.0/PKG-INFO → agentensemble-0.5.0/README.md +146 -76
  6. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/__init__.py +27 -24
  7. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/__init__.py +4 -3
  8. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/base.py +11 -10
  9. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/hybrid_agent.py +30 -34
  10. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/rag_agent.py +19 -19
  11. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/react_agent.py +103 -56
  12. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/stategraph_agent.py +23 -23
  13. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/agents/structured_agent.py +51 -63
  14. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/core/protocol.py +4 -5
  15. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/graph/__init__.py +1 -1
  16. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/graph/workflow.py +12 -9
  17. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/llm/__init__.py +17 -3
  18. agentensemble-0.5.0/agentensemble/llm/factory.py +63 -0
  19. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/llm/interface.py +17 -20
  20. agentensemble-0.3.0/agentensemble/llm/mistral_provider.py → agentensemble-0.5.0/agentensemble/llm/langchain_base.py +73 -86
  21. agentensemble-0.5.0/agentensemble/llm/mistral_provider.py +77 -0
  22. agentensemble-0.5.0/agentensemble/llm/openai_provider.py +79 -0
  23. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/memory/__init__.py +1 -1
  24. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/memory/session.py +6 -6
  25. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/memory/sqlite_session.py +5 -5
  26. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/orchestration/__init__.py +2 -3
  27. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/orchestration/debate.py +6 -6
  28. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/orchestration/ensemble.py +37 -56
  29. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/orchestration/pipeline.py +6 -6
  30. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/orchestration/supervisor.py +6 -6
  31. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/orchestration/swarm.py +6 -6
  32. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/planner/planner_agent.py +10 -9
  33. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/router/router_agent.py +14 -20
  34. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/runner.py +16 -15
  35. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/testing/__init__.py +1 -2
  36. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/testing/benchmark.py +12 -13
  37. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/testing/comparison.py +25 -17
  38. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/testing/metrics.py +20 -21
  39. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/__init__.py +4 -4
  40. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/adapters.py +8 -7
  41. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/function_tool.py +6 -6
  42. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/protocol.py +11 -14
  43. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/rag.py +10 -11
  44. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/registry.py +21 -22
  45. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/scraper.py +8 -25
  46. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/search.py +20 -5
  47. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tools/validator.py +9 -11
  48. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tracing/__init__.py +7 -1
  49. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/tracing/hooks.py +20 -14
  50. agentensemble-0.5.0/agentensemble/utils/__init__.py +17 -0
  51. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/utils/llm.py +56 -8
  52. agentensemble-0.3.0/README.md → agentensemble-0.5.0/agentensemble.egg-info/PKG-INFO +207 -24
  53. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble.egg-info/SOURCES.txt +7 -1
  54. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble.egg-info/requires.txt +11 -11
  55. {agentensemble-0.3.0 → agentensemble-0.5.0}/pyproject.toml +47 -33
  56. {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_agents.py +5 -5
  57. {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_comparison.py +1 -1
  58. agentensemble-0.5.0/tests/test_llm_providers.py +165 -0
  59. {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_memory.py +8 -8
  60. {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_orchestration.py +5 -2
  61. {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_react_session.py +6 -6
  62. agentensemble-0.5.0/tests/test_release.py +98 -0
  63. {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_runner.py +2 -3
  64. {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_tools.py +3 -5
  65. {agentensemble-0.3.0 → agentensemble-0.5.0}/tests/test_tracing.py +1 -3
  66. agentensemble-0.3.0/agentensemble/utils/__init__.py +0 -11
  67. agentensemble-0.3.0/setup.py +0 -15
  68. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/core/__init__.py +0 -0
  69. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/planner/__init__.py +0 -0
  70. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/py.typed +0 -0
  71. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble/router/__init__.py +0 -0
  72. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble.egg-info/dependency_links.txt +0 -0
  73. {agentensemble-0.3.0 → agentensemble-0.5.0}/agentensemble.egg-info/top_level.txt +0 -0
  74. {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,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,48 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentensemble
3
- Version: 0.3.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.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
- 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,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: 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
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: duckduckgo-search>=4.0.0; extra == "search"
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[dev,observability,rag,search]; extra == "all"
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
- **Production-ready multi-agent orchestration for Python**
65
+ **Build, orchestrate, trace, and test multi-agent LLM systems in Python.**
57
66
 
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.
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
- [![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/)
70
+ [![PyPI version](https://img.shields.io/pypi/v/agentensemble.svg)](https://pypi.org/project/agentensemble/)
71
+ [![Python versions](https://img.shields.io/pypi/pyversions/agentensemble.svg)](https://pypi.org/project/agentensemble/)
72
+ [![Tests](https://github.com/irfanalidv/AgentEnsemble/actions/workflows/tests.yml/badge.svg)](https://github.com/irfanalidv/AgentEnsemble/actions/workflows/tests.yml)
63
73
  [![PyPI Downloads](https://static.pepy.tech/badge/agentensemble)](https://pepy.tech/projects/agentensemble)
74
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/irfanalidv/AgentEnsemble/blob/main/LICENSE)
75
+ [![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)
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 supports Mistral (OpenAI/Anthropic-ready)
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
- ## Quick Start
210
+ ## LLM quick start
120
211
 
121
212
  ```bash
122
- pip install agentensemble
123
- # Optional: pip install agentensemble[search,rag]
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 `.env` with `MISTRAL_API_KEY` and `SERPER_API_KEY` (see `.env.example` for format).
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(conductor="supervisor", agents={"researcher": researcher, "validator": validator}, router=router)
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
- def on_start(q, _): print(f"→ User: {q[:50]}...")
368
- def on_end(r): print(f"← Agent: {r['result'][:80]}...\n")
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(agent, "...", config=config, resume=result["run_state"], resume_value="Paid $50 to Alice")
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, PlannerAgent, StateGraphAgent,
495
- SwarmOrchestrator, DebateOrchestrator,
496
- Runner, RunConfig, RunHooks, SearchTool,
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) | Any | Any | Any |
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 all 10 features with real API output
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).