versionhq 1.2.1.16__tar.gz → 1.2.1.18__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.
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/PKG-INFO +1 -1
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/core/agent/ref.md +1 -1
- versionhq-1.2.1.18/docs/core/agent-network/index.md +43 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/core/tool.md +1 -1
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/quickstart.md +43 -42
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/mkdocs.yml +6 -4
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/pyproject.toml +1 -1
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/__init__.py +2 -2
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/_utils/process_config.py +1 -1
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/agent/model.py +93 -90
- versionhq-1.2.1.18/src/versionhq/agent_network/formation.py +157 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/agent_network/model.py +7 -8
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/task/model.py +32 -14
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq.egg-info/PKG-INFO +1 -1
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq.egg-info/SOURCES.txt +2 -1
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/agent_network/agent_network_test.py +28 -27
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/doc_test.py +2 -2
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/formation_test.py +7 -8
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/memory/memory_test.py +1 -1
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/task/task_test.py +0 -8
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/usecase_test.py +6 -1
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/uv.lock +1 -1
- versionhq-1.2.1.16/src/versionhq/task/formation.py +0 -159
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/.env.sample +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/.github/workflows/deploy_docs.yml +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/.github/workflows/publish.yml +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/.github/workflows/publish_testpypi.yml +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/.github/workflows/run_tests.yml +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/.github/workflows/security_check.yml +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/.gitignore +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/.pre-commit-config.yaml +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/.python-version +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/LICENSE +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/README.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/SECURITY.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/db/preprocess.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/CNAME +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/_logos/favicon.ico +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/_logos/logo192.png +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/core/agent/config.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/core/agent/index.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/core/agent/task-handling.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/core/llm/index.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/core/task/evaluation.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/core/task/index.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/core/task/response-field.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/core/task/task-output.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/core/task-graph/index.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/index.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/stylesheets/main.css +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/docs/tags.md +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/requirements-dev.txt +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/requirements.txt +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/runtime.txt +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/setup.cfg +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/_utils/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/_utils/i18n.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/_utils/logger.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/_utils/usage_metrics.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/_utils/vars.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/agent/TEMPLATES/Backstory.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/agent/TEMPLATES/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/agent/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/agent/inhouse_agents.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/agent/parser.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/agent/rpm_controller.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/agent_network/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/cli/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/clients/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/clients/customer/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/clients/customer/model.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/clients/product/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/clients/product/model.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/clients/workflow/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/clients/workflow/model.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/knowledge/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/knowledge/_utils.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/knowledge/embedding.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/knowledge/model.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/knowledge/source.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/knowledge/source_docling.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/knowledge/storage.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/llm/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/llm/llm_vars.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/llm/model.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/memory/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/memory/contextual_memory.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/memory/model.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/storage/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/storage/base.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/storage/ltm_sqlite_storage.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/storage/mem0_storage.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/storage/rag_storage.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/storage/task_output_storage.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/storage/utils.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/task/TEMPLATES/Description.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/task/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/task/evaluate.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/task/formatter.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/task/log_handler.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/task/structured_response.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/task_graph/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/task_graph/colors.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/task_graph/draft.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/task_graph/model.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/tool/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/tool/cache_handler.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/tool/composio_tool.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/tool/composio_tool_vars.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/tool/decorator.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/tool/model.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq/tool/tool_handler.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq.egg-info/dependency_links.txt +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq.egg-info/requires.txt +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/src/versionhq.egg-info/top_level.txt +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/agent/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/agent/agent_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/agent/doc_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/agent_network/Prompts/Demo_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/agent_network/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/cli/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/clients/customer_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/clients/product_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/clients/workflow_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/conftest.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/knowledge/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/knowledge/knowledge_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/knowledge/mock_report_compressed.pdf +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/llm/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/llm/llm_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/memory/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/task/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/task/doc_taskoutput_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/task/doc_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/task/llm_connection_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/task_graph/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/task_graph/doc_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/task_graph/task_graph_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/tool/__init__.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/tool/composio_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/tool/doc_test.py +0 -0
- {versionhq-1.2.1.16 → versionhq-1.2.1.18}/tests/tool/tool_test.py +0 -0
@@ -17,7 +17,7 @@
|
|
17
17
|
| **`use_developer_prompt`** | bool | True | - | Whether to use the system (developer) prompt when calling the model. |
|
18
18
|
| **`developer_promt_template`** | str | None | True | File path to the prompt template. |
|
19
19
|
| **`user_promt_template`** | str | None | True | File path to the prompt template. |
|
20
|
-
| **`
|
20
|
+
| **`networks`** | List[Any] | list() | True | Stores a list of agent networks that the agent belongs to. |
|
21
21
|
| **`allow_delegation`** | bool | False | - | Whether the agent can delegate assinged tasks to another agent. |
|
22
22
|
| **`max_retry_limit`** | int | 2 | - | Maximum number of retries when the task execution failed. |
|
23
23
|
| **`maxit`** | int | 25 | - | Maximum number of total optimization loops conducted when an error occues during the task execution. |
|
@@ -0,0 +1,43 @@
|
|
1
|
+
---
|
2
|
+
tags:
|
3
|
+
- Agent Network
|
4
|
+
---
|
5
|
+
|
6
|
+
# Agent Network
|
7
|
+
|
8
|
+
<class>`class` versionhq.agent_network.model.<bold>AgentNetwork<bold></class>
|
9
|
+
|
10
|
+
A Pydantic class to store `AgentNetwork` objects that handle multiple agent formations for the task execution.
|
11
|
+
|
12
|
+
You can specify a desired formation or allow the agents to determine it autonomously (default).
|
13
|
+
|
14
|
+
| | **Solo Agent** | **Supervising** | **Squad** | **Random** |
|
15
|
+
| :--- | :--- | :--- | :--- | :--- |
|
16
|
+
| **Formation** | <img src="https://res.cloudinary.com/dfeirxlea/image/upload/v1738818211/pj_m_agents/rbgxttfoeqqis1ettlfz.png" alt="solo" width="200"> | <img src="https://res.cloudinary.com/dfeirxlea/image/upload/v1738818211/pj_m_agents/zhungor3elxzer5dum10.png" alt="solo" width="200"> | <img src="https://res.cloudinary.com/dfeirxlea/image/upload/v1738818211/pj_m_agents/dnusl7iy7kiwkxwlpmg8.png" alt="solo" width="200"> | <img src="https://res.cloudinary.com/dfeirxlea/image/upload/v1738818211/pj_m_agents/sndpczatfzbrosxz9ama.png" alt="solo" width="200"> |
|
17
|
+
| **Usage** | <ul><li>A single agent with tools, knowledge, and memory.</li><li>When self-learning mode is on - it will turn into **Random** formation.</li></ul> | <ul><li>Leader agent gives directions, while sharing its knowledge and memory.</li><li>Subordinates can be solo agents or networks.</li></ul> | <ul><li>Share tasks, knowledge, and memory among network members.</li></ul> | <ul><li>A single agent handles tasks, asking help from other agents without sharing its memory or knowledge.</li></ul> |
|
18
|
+
| **Use case** | An email agent drafts promo message for the given audience. | The leader agent strategizes an outbound campaign plan and assigns components such as media mix or message creation to subordinate agents. | An email agent and social media agent share the product knowledge and deploy multi-channel outbound campaign. | 1. An email agent drafts promo message for the given audience, asking insights on tones from other email agents which oversee other clusters. 2. An agent calls the external agent to deploy the campaign. |
|
19
|
+
|
20
|
+
<hr>
|
21
|
+
|
22
|
+
## Quick Start
|
23
|
+
|
24
|
+
By default, lead agents will determine the best network formation autonomously based on the given task and its goal.
|
25
|
+
|
26
|
+
Calling `.launch()` method can start executing tasks by the network, then generate a response in text and JSON formats stored in the `TaskOutput` object.
|
27
|
+
|
28
|
+
```python
|
29
|
+
import versionhq as vhq
|
30
|
+
|
31
|
+
network = vhq.form_agent_network(
|
32
|
+
task=f"create a promo plan to attract a client",
|
33
|
+
expected_outcome='media mix, key messages, and CTA targets.'
|
34
|
+
)
|
35
|
+
|
36
|
+
res = network.launch()
|
37
|
+
|
38
|
+
assert isinstance(res, vhq.TaskOutput)
|
39
|
+
```
|
40
|
+
|
41
|
+
Ref. <a href="/core/task-output">TaskOutput</a> class
|
42
|
+
|
43
|
+
Visit <a href="https://versi0n.io">Playground</a>.
|
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
## Package installation
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
```
|
6
|
+
pip install versionhq
|
7
|
+
```
|
8
8
|
|
9
9
|
(Python 3.11, 3.12)
|
10
10
|
|
@@ -16,15 +16,15 @@ You can generate a network of multiple agents depending on your task complexity.
|
|
16
16
|
|
17
17
|
Here is a code snippet:
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
```python
|
20
|
+
import versionhq as vhq
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
network = vhq.form_agent_network(
|
23
|
+
task="YOUR AMAZING TASK OVERVIEW",
|
24
|
+
expected_outcome="YOUR OUTCOME EXPECTATION",
|
25
|
+
)
|
26
|
+
res = network.launch()
|
27
|
+
```
|
28
28
|
|
29
29
|
This will form a network with multiple agents on `Formation` and return results as a `TaskOutput` object, storing outputs in JSON, plane text, Pydantic model formats along with evaluation.
|
30
30
|
|
@@ -36,44 +36,45 @@ If you don't need to form a network or assign a specific agent to the network, y
|
|
36
36
|
Agents can execute tasks using `Task` model and return JSON format by default with plane text and pydantic model formats as options.
|
37
37
|
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
```python
|
40
|
+
import versionhq as vhq
|
41
|
+
from pydantic import BaseModel
|
42
|
+
|
43
|
+
class CustomOutput(BaseModel):
|
44
|
+
test1: str
|
45
|
+
test2: list[str]
|
42
46
|
|
43
|
-
|
44
|
-
|
45
|
-
test2: list[str]
|
47
|
+
def dummy_func(message: str, test1: str, test2: list[str]) -> str:
|
48
|
+
return f"""{message}: {test1}, {", ".join(test2)}"""
|
46
49
|
|
47
|
-
def dummy_func(message: str, test1: str, test2: list[str]) -> str:
|
48
|
-
return f"""{message}: {test1}, {", ".join(test2)}"""
|
49
50
|
|
51
|
+
agent = vhq.Agent(role="demo", goal="amazing project goal")
|
50
52
|
|
51
|
-
|
53
|
+
task = vhq.Task(
|
54
|
+
description="Amazing task",
|
55
|
+
pydantic_output=CustomOutput,
|
56
|
+
callback=dummy_func,
|
57
|
+
callback_kwargs=dict(message="Hi! Here is the result: ")
|
58
|
+
)
|
52
59
|
|
53
|
-
|
54
|
-
description="Amazing task",
|
55
|
-
pydantic_output=CustomOutput,
|
56
|
-
callback=dummy_func,
|
57
|
-
callback_kwargs=dict(message="Hi! Here is the result: ")
|
58
|
-
)
|
60
|
+
res = task.execute(agent=agent, context="amazing context to consider.")
|
59
61
|
|
60
|
-
|
61
|
-
|
62
|
-
```
|
62
|
+
assert isinstance(res, vhq.TaskOutput)
|
63
|
+
```
|
63
64
|
|
64
65
|
This will return a `TaskOutput` object that stores response in plane text, JSON, and Pydantic model: `CustomOutput` formats with a callback result, tool output (if given), and evaluation results (if given).
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
67
|
+
```python
|
68
|
+
res == TaskOutput(
|
69
|
+
task_id=UUID('<TASK UUID>'),
|
70
|
+
raw='{\"test1\":\"random str\", \"test2\":[\"str item 1\", \"str item 2\", \"str item 3\"]}',
|
71
|
+
json_dict={'test1': 'random str', 'test2': ['str item 1', 'str item 2', 'str item 3']},
|
72
|
+
pydantic=<class '__main__.CustomOutput'>,
|
73
|
+
tool_output=None,
|
74
|
+
callback_output='Hi! Here is the result: random str, str item 1, str item 2, str item 3', # returned a plain text summary
|
75
|
+
evaluation=None
|
76
|
+
)
|
77
|
+
```
|
77
78
|
|
78
79
|
## Supervising
|
79
80
|
|
@@ -106,8 +107,8 @@ network =vhq.AgentNetwork(
|
|
106
107
|
res = network.launch()
|
107
108
|
|
108
109
|
assert isinstance(res, vhq.NetworkOutput)
|
109
|
-
assert
|
110
|
-
assert
|
110
|
+
assert "agent b" in task_1.processed_agents # agent_b delegated by agent_a
|
111
|
+
assert "agent b" in task_2.processed_agents
|
111
112
|
```
|
112
113
|
|
113
114
|
This will return a list with dictionaries with keys defined in the `ResponseField` of each task.
|
@@ -110,7 +110,8 @@ theme:
|
|
110
110
|
nav:
|
111
111
|
- Home: 'index.md'
|
112
112
|
- Quick Start: 'quickstart.md'
|
113
|
-
-
|
113
|
+
- Agent Network:
|
114
|
+
- 'core/agent-network/index.md'
|
114
115
|
- Agent:
|
115
116
|
- 'core/agent/index.md'
|
116
117
|
- Configuration: 'core/agent/config.md'
|
@@ -118,15 +119,16 @@ nav:
|
|
118
119
|
- Reference: 'core/agent/ref.md'
|
119
120
|
- LLM:
|
120
121
|
- 'core/llm/index.md'
|
121
|
-
|
122
|
-
|
122
|
+
- Task Graph:
|
123
|
+
- 'core/task-graph/index.md'
|
123
124
|
- Task:
|
124
125
|
- 'core/task/index.md'
|
125
126
|
- TaskOutput: 'core/task/task-output.md'
|
126
127
|
- ResponseField: 'core/task/response-field.md'
|
127
128
|
- Evaluation: 'core/task/evaluation.md'
|
129
|
+
- Components:
|
128
130
|
- Tool: 'core/tool.md'
|
129
|
-
-
|
131
|
+
- Archive: 'tags.md'
|
130
132
|
- Cases:
|
131
133
|
- Playground: https://versi0n.io/playground
|
132
134
|
- Experiment - Agent Performance: https://github.com/versionHQ/exp-agent-performance
|
@@ -15,7 +15,7 @@ exclude = ["test*", "__pycache__", "*.egg-info"]
|
|
15
15
|
|
16
16
|
[project]
|
17
17
|
name = "versionhq"
|
18
|
-
version = "1.2.1.
|
18
|
+
version = "1.2.1.18"
|
19
19
|
authors = [{ name = "Kuriko Iwai", email = "kuriko@versi0n.io" }]
|
20
20
|
description = "An agentic orchestration framework for building agent networks that handle task automation."
|
21
21
|
readme = "README.md"
|
@@ -27,11 +27,11 @@ from versionhq.tool.composio_tool import ComposioHandler
|
|
27
27
|
from versionhq.memory.contextual_memory import ContextualMemory
|
28
28
|
from versionhq.memory.model import ShortTermMemory,LongTermMemory, UserMemory, MemoryItem
|
29
29
|
|
30
|
-
from versionhq.
|
30
|
+
from versionhq.agent_network.formation import form_agent_network
|
31
31
|
from versionhq.task_graph.draft import workflow
|
32
32
|
|
33
33
|
|
34
|
-
__version__ = "1.2.1.
|
34
|
+
__version__ = "1.2.1.18"
|
35
35
|
__all__ = [
|
36
36
|
"Agent",
|
37
37
|
|
@@ -8,7 +8,7 @@ def process_config(values_to_update: Dict[str, Any], model_class: Type[BaseModel
|
|
8
8
|
Refer to the Pydantic model class for field validation.
|
9
9
|
"""
|
10
10
|
|
11
|
-
config = values_to_update.pop("config"
|
11
|
+
config = values_to_update.pop("config") if "config" in values_to_update else {}
|
12
12
|
|
13
13
|
if config:
|
14
14
|
for k, v in config.items():
|
@@ -91,7 +91,7 @@ class Agent(BaseModel):
|
|
91
91
|
user_prompt_template: Optional[str] = Field(default=None, description="abs. file path to user prompt template")
|
92
92
|
|
93
93
|
# task execution rules
|
94
|
-
|
94
|
+
networks: Optional[List[Any]] = Field(default_factory=list, description="store a list of agent networks that the agent belong as a member")
|
95
95
|
allow_delegation: bool = Field(default=False, description="whether to delegate the task to another agent")
|
96
96
|
max_retry_limit: int = Field(default=2, description="max. number of task retries when an error occurs")
|
97
97
|
maxit: Optional[int] = Field(default=25, description="max. number of total optimization loops conducted when an error occurs")
|
@@ -149,94 +149,6 @@ class Agent(BaseModel):
|
|
149
149
|
return self
|
150
150
|
|
151
151
|
|
152
|
-
def _convert_to_llm_object(self, llm: Any = None) -> LLM:
|
153
|
-
"""
|
154
|
-
Convert the given value to LLM object.
|
155
|
-
When `llm` is dict or self.llm_config is not None, add these values to the LLM object after validating them.
|
156
|
-
"""
|
157
|
-
llm = llm if llm else self.llm if self.llm else DEFAULT_MODEL_NAME
|
158
|
-
|
159
|
-
if not llm:
|
160
|
-
pass
|
161
|
-
|
162
|
-
match llm:
|
163
|
-
case LLM():
|
164
|
-
return self._set_llm_params(llm=llm, config=self.llm_config)
|
165
|
-
|
166
|
-
case str():
|
167
|
-
llm_obj = LLM(model=llm)
|
168
|
-
return self._set_llm_params(llm=llm_obj, config=self.llm_config)
|
169
|
-
|
170
|
-
case dict():
|
171
|
-
model_name = llm.pop("model_name", llm.pop("deployment_name", str(llm)))
|
172
|
-
llm_obj = LLM(model=model_name if model_name else DEFAULT_MODEL_NAME)
|
173
|
-
config = llm.update(self.llm_config) if self.llm_config else llm
|
174
|
-
return self._set_llm_params(llm_obj, config=config)
|
175
|
-
|
176
|
-
case _:
|
177
|
-
model_name = (getattr(self.llm, "model_name") or getattr(self.llm, "deployment_name") or str(self.llm))
|
178
|
-
llm_obj = LLM(model=model_name if model_name else DEFAULT_MODEL_NAME)
|
179
|
-
llm_params = {
|
180
|
-
"max_tokens": (getattr(llm, "max_tokens") or 3000),
|
181
|
-
"timeout": getattr(llm, "timeout", self.max_execution_time),
|
182
|
-
"callbacks": getattr(llm, "callbacks", None),
|
183
|
-
"temperature": getattr(llm, "temperature", None),
|
184
|
-
"logprobs": getattr(llm, "logprobs", None),
|
185
|
-
"api_key": getattr(llm, "api_key", os.environ.get("LITELLM_API_KEY", None)),
|
186
|
-
"base_url": getattr(llm, "base_url", None),
|
187
|
-
}
|
188
|
-
config = llm_params.update(self.llm_config) if self.llm_config else llm_params
|
189
|
-
return self._set_llm_params(llm=llm_obj, config=config)
|
190
|
-
|
191
|
-
|
192
|
-
def _set_llm_params(self, llm: LLM, config: Dict[str, Any] = None) -> LLM:
|
193
|
-
"""
|
194
|
-
Add valid params to the LLM object.
|
195
|
-
"""
|
196
|
-
|
197
|
-
import litellm
|
198
|
-
from versionhq.llm.llm_vars import PARAMS
|
199
|
-
|
200
|
-
valid_config = {k: v for k, v in config.items() if v} if config else {}
|
201
|
-
|
202
|
-
if valid_config:
|
203
|
-
valid_keys = list()
|
204
|
-
try:
|
205
|
-
valid_keys = litellm.get_supported_openai_params(model=llm.model, custom_llm_provider=self.endpoint_provider, request_type="chat_completion")
|
206
|
-
if not valid_keys:
|
207
|
-
valid_keys = PARAMS.get("common")
|
208
|
-
except:
|
209
|
-
valid_keys = PARAMS.get("common")
|
210
|
-
|
211
|
-
valid_keys += PARAMS.get("litellm")
|
212
|
-
|
213
|
-
for key in valid_keys:
|
214
|
-
if key in valid_config and valid_config[key]:
|
215
|
-
val = valid_config[key]
|
216
|
-
if [key == k for k, v in LLM.model_fields.items()]:
|
217
|
-
setattr(llm, key, val)
|
218
|
-
else:
|
219
|
-
llm.other_valid_config.update({ key: val})
|
220
|
-
|
221
|
-
|
222
|
-
llm.timeout = self.max_execution_time if llm.timeout is None else llm.timeout
|
223
|
-
# llm.max_tokens = self.max_tokens if self.max_tokens else llm.max_tokens
|
224
|
-
|
225
|
-
if llm.provider is None:
|
226
|
-
provider_name = llm.model.split("/")[0]
|
227
|
-
valid_provider = provider_name if provider_name in PROVIDERS else None
|
228
|
-
llm.provider = valid_provider
|
229
|
-
|
230
|
-
if self.callbacks:
|
231
|
-
llm.callbacks = self.callbacks
|
232
|
-
llm._set_callbacks(llm.callbacks)
|
233
|
-
|
234
|
-
if self.respect_context_window == False:
|
235
|
-
llm.context_window_size = DEFAULT_CONTEXT_WINDOW_SIZE
|
236
|
-
|
237
|
-
return llm
|
238
|
-
|
239
|
-
|
240
152
|
@model_validator(mode="after")
|
241
153
|
def set_up_tools(self) -> Self:
|
242
154
|
"""
|
@@ -369,6 +281,94 @@ class Agent(BaseModel):
|
|
369
281
|
return self
|
370
282
|
|
371
283
|
|
284
|
+
def _convert_to_llm_object(self, llm: Any = None) -> LLM:
|
285
|
+
"""
|
286
|
+
Convert the given value to LLM object.
|
287
|
+
When `llm` is dict or self.llm_config is not None, add these values to the LLM object after validating them.
|
288
|
+
"""
|
289
|
+
llm = llm if llm else self.llm if self.llm else DEFAULT_MODEL_NAME
|
290
|
+
|
291
|
+
if not llm:
|
292
|
+
pass
|
293
|
+
|
294
|
+
match llm:
|
295
|
+
case LLM():
|
296
|
+
return self._set_llm_params(llm=llm, config=self.llm_config)
|
297
|
+
|
298
|
+
case str():
|
299
|
+
llm_obj = LLM(model=llm)
|
300
|
+
return self._set_llm_params(llm=llm_obj, config=self.llm_config)
|
301
|
+
|
302
|
+
case dict():
|
303
|
+
model_name = llm.pop("model_name", llm.pop("deployment_name", str(llm)))
|
304
|
+
llm_obj = LLM(model=model_name if model_name else DEFAULT_MODEL_NAME)
|
305
|
+
config = llm.update(self.llm_config) if self.llm_config else llm
|
306
|
+
return self._set_llm_params(llm_obj, config=config)
|
307
|
+
|
308
|
+
case _:
|
309
|
+
model_name = (getattr(self.llm, "model_name") or getattr(self.llm, "deployment_name") or str(self.llm))
|
310
|
+
llm_obj = LLM(model=model_name if model_name else DEFAULT_MODEL_NAME)
|
311
|
+
llm_params = {
|
312
|
+
"max_tokens": (getattr(llm, "max_tokens") or 3000),
|
313
|
+
"timeout": getattr(llm, "timeout", self.max_execution_time),
|
314
|
+
"callbacks": getattr(llm, "callbacks", None),
|
315
|
+
"temperature": getattr(llm, "temperature", None),
|
316
|
+
"logprobs": getattr(llm, "logprobs", None),
|
317
|
+
"api_key": getattr(llm, "api_key", os.environ.get("LITELLM_API_KEY", None)),
|
318
|
+
"base_url": getattr(llm, "base_url", None),
|
319
|
+
}
|
320
|
+
config = llm_params.update(self.llm_config) if self.llm_config else llm_params
|
321
|
+
return self._set_llm_params(llm=llm_obj, config=config)
|
322
|
+
|
323
|
+
|
324
|
+
def _set_llm_params(self, llm: LLM, config: Dict[str, Any] = None) -> LLM:
|
325
|
+
"""
|
326
|
+
Add valid params to the LLM object.
|
327
|
+
"""
|
328
|
+
|
329
|
+
import litellm
|
330
|
+
from versionhq.llm.llm_vars import PARAMS
|
331
|
+
|
332
|
+
valid_config = {k: v for k, v in config.items() if v} if config else {}
|
333
|
+
|
334
|
+
if valid_config:
|
335
|
+
valid_keys = list()
|
336
|
+
try:
|
337
|
+
valid_keys = litellm.get_supported_openai_params(model=llm.model, custom_llm_provider=self.endpoint_provider, request_type="chat_completion")
|
338
|
+
if not valid_keys:
|
339
|
+
valid_keys = PARAMS.get("common")
|
340
|
+
except:
|
341
|
+
valid_keys = PARAMS.get("common")
|
342
|
+
|
343
|
+
valid_keys += PARAMS.get("litellm")
|
344
|
+
|
345
|
+
for key in valid_keys:
|
346
|
+
if key in valid_config and valid_config[key]:
|
347
|
+
val = valid_config[key]
|
348
|
+
if [key == k for k, v in LLM.model_fields.items()]:
|
349
|
+
setattr(llm, key, val)
|
350
|
+
else:
|
351
|
+
llm.other_valid_config.update({ key: val})
|
352
|
+
|
353
|
+
|
354
|
+
llm.timeout = self.max_execution_time if llm.timeout is None else llm.timeout
|
355
|
+
# llm.max_tokens = self.max_tokens if self.max_tokens else llm.max_tokens
|
356
|
+
|
357
|
+
if llm.provider is None:
|
358
|
+
provider_name = llm.model.split("/")[0]
|
359
|
+
valid_provider = provider_name if provider_name in PROVIDERS else None
|
360
|
+
llm.provider = valid_provider
|
361
|
+
|
362
|
+
if self.callbacks:
|
363
|
+
llm.callbacks = self.callbacks
|
364
|
+
llm._set_callbacks(llm.callbacks)
|
365
|
+
|
366
|
+
if self.respect_context_window == False:
|
367
|
+
llm.context_window_size = DEFAULT_CONTEXT_WINDOW_SIZE
|
368
|
+
|
369
|
+
return llm
|
370
|
+
|
371
|
+
|
372
372
|
def _update_llm(self, llm: Any = None, llm_config: Optional[Dict[str, Any]] = None) -> Self:
|
373
373
|
"""
|
374
374
|
Update llm and llm_config of the exsiting agent. (Other conditions will remain the same.)
|
@@ -567,7 +567,7 @@ class Agent(BaseModel):
|
|
567
567
|
|
568
568
|
|
569
569
|
## comment out for now
|
570
|
-
# if self.
|
570
|
+
# if self.networks and self.networks._train:
|
571
571
|
# task_prompt = self._training_handler(task_prompt=task_prompt)
|
572
572
|
# else:
|
573
573
|
# task_prompt = self._use_trained_data(task_prompt=task_prompt)
|
@@ -599,3 +599,6 @@ class Agent(BaseModel):
|
|
599
599
|
|
600
600
|
def __repr__(self):
|
601
601
|
return f"Agent(role={self.role}, goal={self.goal}"
|
602
|
+
|
603
|
+
def __str__(self):
|
604
|
+
return super().__str__()
|
@@ -0,0 +1,157 @@
|
|
1
|
+
from typing import List, Type
|
2
|
+
from enum import Enum
|
3
|
+
|
4
|
+
from pydantic import BaseModel, create_model, Field
|
5
|
+
|
6
|
+
from versionhq.task.model import Task
|
7
|
+
from versionhq.agent.model import Agent
|
8
|
+
from versionhq.agent_network.model import AgentNetwork, Member, Formation
|
9
|
+
from versionhq.agent.inhouse_agents import vhq_formation_planner
|
10
|
+
from versionhq._utils import Logger
|
11
|
+
|
12
|
+
|
13
|
+
def form_agent_network(
|
14
|
+
task: str,
|
15
|
+
expected_outcome: str | Type[BaseModel],
|
16
|
+
agents: List[Agent] = None,
|
17
|
+
context: str = None,
|
18
|
+
formation: Type[Formation] = None
|
19
|
+
) -> AgentNetwork | None:
|
20
|
+
"""
|
21
|
+
Make a formation of agents from the given task description, expected outcome, agents (optional), and context (optional).
|
22
|
+
"""
|
23
|
+
|
24
|
+
if not task:
|
25
|
+
Logger(verbose=True).log(level="error", message="Missing task description.", color="red")
|
26
|
+
return None
|
27
|
+
|
28
|
+
if not expected_outcome:
|
29
|
+
Logger(verbose=True).log(level="error", message="Missing expected outcome.", color="red")
|
30
|
+
return None
|
31
|
+
|
32
|
+
if formation:
|
33
|
+
try:
|
34
|
+
match formation:
|
35
|
+
case Formation():
|
36
|
+
pass
|
37
|
+
|
38
|
+
case str():
|
39
|
+
matched = [item for item in Formation.s_ if item == formation.upper()]
|
40
|
+
if matched:
|
41
|
+
formation = getattr(Formation, matched[0])
|
42
|
+
else:
|
43
|
+
# Formation._generate_next_value_(name=f"CUSTOM_{formation.upper()}", start=100, count=6, last_values=Formation.HYBRID.name)
|
44
|
+
Logger(verbose=True).log(level="warning", message=f"The formation {formation} is invalid. We'll recreate a valid formation.", color="yellow")
|
45
|
+
formation = None
|
46
|
+
|
47
|
+
case int() | float():
|
48
|
+
formation = Formation(int(formation))
|
49
|
+
|
50
|
+
case _:
|
51
|
+
Logger(verbose=True).log(level="warning", message=f"The formation {formation} is invalid. We'll recreate a valid formation.", color="yellow")
|
52
|
+
formation = None
|
53
|
+
|
54
|
+
except Exception as e:
|
55
|
+
Logger(verbose=True).log(level="warning", message=f"The formation {formation} is invalid: {str(e)}. We'll recreate a formation.", color="yellow")
|
56
|
+
formation = None
|
57
|
+
|
58
|
+
# try:
|
59
|
+
prompt_formation = formation.name if formation and isinstance(formation, Formation) else f"Select the best formation to effectively execute the tasks from the given Enum sets: {str(Formation.__dict__)}."
|
60
|
+
|
61
|
+
prompt_expected_outcome = expected_outcome if isinstance(expected_outcome, str) else expected_outcome.model_dump_json()
|
62
|
+
|
63
|
+
class Outcome(BaseModel):
|
64
|
+
formation: Enum
|
65
|
+
agent_roles: list[str]
|
66
|
+
task_descriptions: list[str]
|
67
|
+
task_outcomes: list[list[str]]
|
68
|
+
leader_agent: str
|
69
|
+
|
70
|
+
vhq_task = Task(
|
71
|
+
description=f"Design a team of specialized agents to fully automate the following task and achieve the expected outcome. For each agent, define its role, task description, and expected outputs via the task with items in a list. Then specify the team formation if the formation is not given. If you think SUPERVISING or HYBRID is the best formation, include a leader_agent role, else leave the leader_agent role blank.\nTask: {str(task)}\nExpected outcome: {prompt_expected_outcome}\nFormation: {prompt_formation}",
|
72
|
+
pydantic_output=Outcome
|
73
|
+
)
|
74
|
+
|
75
|
+
if agents:
|
76
|
+
vhq_task.description += "Consider adding following agents in the formation: " + ", ".join([agent.role for agent in agents if isinstance(agent, Agent)])
|
77
|
+
|
78
|
+
res = vhq_task.execute(agent=vhq_formation_planner, context=context)
|
79
|
+
|
80
|
+
formation_keys = ([k for k in Formation._member_map_.keys() if k == res.pydantic.formation.upper()]
|
81
|
+
if res.pydantic else [k for k in Formation._member_map_.keys() if k == res.json_dict["formation"].upper()])
|
82
|
+
_formation = Formation[formation_keys[0]] if formation_keys else Formation.SUPERVISING
|
83
|
+
|
84
|
+
network_tasks = []
|
85
|
+
members = []
|
86
|
+
leader = str(res.pydantic.leader_agent) if res.pydantic else str(res.json_dict["leader_agent"])
|
87
|
+
|
88
|
+
created_agents = [Agent(role=item, goal=item) for item in res.pydantic.agent_roles]
|
89
|
+
created_tasks = []
|
90
|
+
|
91
|
+
if res.pydantic:
|
92
|
+
for i, item in enumerate(res.pydantic.task_outcomes):
|
93
|
+
if len(res.pydantic.task_descriptions) > i and res.pydantic.task_descriptions[i]:
|
94
|
+
fields = {}
|
95
|
+
for ob in item:
|
96
|
+
try:
|
97
|
+
field_name = str(ob).lower().split(":")[0].replace(" ", "_")[0: 16]
|
98
|
+
fields[field_name] = (str, Field(default=None))
|
99
|
+
except:
|
100
|
+
pass
|
101
|
+
output = create_model("Output", **fields) if fields else None
|
102
|
+
_task = Task(description=res.pydantic.task_descriptions[i], pydantic_output=output)
|
103
|
+
created_tasks.append(_task)
|
104
|
+
|
105
|
+
elif res.json_dict:
|
106
|
+
for i, item in enumerate(res["task_outcomes"]):
|
107
|
+
if len(res["task_descriptions"]) > i and res["task_descriptions"][i]:
|
108
|
+
fields = {}
|
109
|
+
for ob in item:
|
110
|
+
try:
|
111
|
+
field_name = str(ob).lower().split(":")[0].replace(" ", "_")[0: 16]
|
112
|
+
fields[field_name] = (str, Field(default=None))
|
113
|
+
except:
|
114
|
+
pass
|
115
|
+
output = create_model("Output", **fields) if fields else None
|
116
|
+
_task = Task(description=res["task_descriptions"][i], pydantic_output=output)
|
117
|
+
created_tasks.append(_task)
|
118
|
+
|
119
|
+
|
120
|
+
if len(created_tasks) <= len(created_agents):
|
121
|
+
for i in range(len(created_tasks)):
|
122
|
+
is_manager = bool(created_agents[i].role.lower() == leader.lower())
|
123
|
+
member = Member(agent=created_agents[i], is_manager=is_manager, tasks=[created_tasks[i]])
|
124
|
+
members.append(member)
|
125
|
+
|
126
|
+
for i in range(len(created_tasks), len(created_agents)):
|
127
|
+
try:
|
128
|
+
is_manager = bool(created_agents[i].role.lower() == leader.lower())
|
129
|
+
member_w_o_task = Member(agent=created_agents[i], is_manager=is_manager)
|
130
|
+
members.append(member_w_o_task)
|
131
|
+
except:
|
132
|
+
pass
|
133
|
+
|
134
|
+
elif len(created_tasks) > len(created_agents):
|
135
|
+
for i in range(len(created_agents)):
|
136
|
+
is_manager = bool(created_agents[i].role.lower() == leader.lower())
|
137
|
+
member = Member(agent=created_agents[i], is_manager=is_manager, tasks=[created_tasks[i]])
|
138
|
+
members.append(member)
|
139
|
+
|
140
|
+
network_tasks.extend(created_tasks[len(created_agents):len(created_tasks)])
|
141
|
+
|
142
|
+
|
143
|
+
if _formation == Formation.SUPERVISING and not [member for member in members if member.is_manager]:
|
144
|
+
manager = Member(agent=Agent(role=leader, goal=leader), is_manager=True)
|
145
|
+
members.append(manager)
|
146
|
+
|
147
|
+
members.sort(key=lambda x: x.is_manager == False)
|
148
|
+
network = AgentNetwork(members=members, formation=_formation, network_tasks=network_tasks)
|
149
|
+
|
150
|
+
Logger().log(level="info", message=f"Successfully created a agent network: {str(network.id)} with {len(network.members)} agents.", color="blue")
|
151
|
+
|
152
|
+
return network
|
153
|
+
|
154
|
+
|
155
|
+
# except Exception as e:
|
156
|
+
# Logger().log(level="error", message=f"Failed to create a agent network - return None. You can try with solo agent. Error: {str(e)}", color="red")
|
157
|
+
# return None
|