quantalogic 0.30.8__tar.gz → 0.31.1__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.
- {quantalogic-0.30.8 → quantalogic-0.31.1}/PKG-INFO +27 -2
- {quantalogic-0.30.8 → quantalogic-0.31.1}/README.md +24 -1
- {quantalogic-0.30.8 → quantalogic-0.31.1}/pyproject.toml +3 -1
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/__init__.py +15 -5
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/agent.py +79 -29
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/agent_config.py +10 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/agent_factory.py +66 -11
- quantalogic-0.31.1/quantalogic/config.py +15 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/generative_model.py +17 -98
- quantalogic-0.31.1/quantalogic/get_model_info.py +44 -0
- quantalogic-0.31.1/quantalogic/interactive_text_editor.py +368 -0
- quantalogic-0.31.1/quantalogic/llm.py +135 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/main.py +60 -11
- quantalogic-0.31.1/quantalogic/prompts.py +119 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/task_runner.py +26 -39
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tool_manager.py +66 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/execute_bash_command_tool.py +13 -11
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/replace_in_file_tool.py +1 -1
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/search_definition_names.py +2 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/sql_query_tool.py +4 -2
- quantalogic-0.31.1/quantalogic/utils/get_all_models.py +20 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/xml_parser.py +1 -0
- quantalogic-0.30.8/quantalogic/get_model_info.py +0 -16
- quantalogic-0.30.8/quantalogic/interactive_text_editor.py +0 -194
- quantalogic-0.30.8/quantalogic/prompts.py +0 -94
- {quantalogic-0.30.8 → quantalogic-0.31.1}/LICENSE +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/coding_agent.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/console_print_events.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/console_print_token.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/docs_cli.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/event_emitter.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/memory.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/model_names.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/search_agent.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/server/__init__.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/server/agent_server.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/server/models.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/server/routes.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/server/state.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/server/static/js/event_visualizer.js +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/server/static/js/quantalogic.js +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/server/templates/index.html +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/task_file_reader.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/__init__.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/agent_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/dalle_e.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/download_http_file_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/duckduckgo_search_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/edit_whole_content_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/elixir_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/generate_database_report_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/grep_app_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/input_question_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/jinja_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/language_handlers/__init__.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/language_handlers/c_handler.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/language_handlers/cpp_handler.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/language_handlers/go_handler.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/language_handlers/java_handler.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/language_handlers/javascript_handler.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/language_handlers/python_handler.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/language_handlers/rust_handler.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/language_handlers/scala_handler.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/language_handlers/typescript_handler.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/list_directory_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/llm_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/llm_vision_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/markitdown_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/nodejs_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/python_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/read_file_block_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/read_file_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/read_html_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/ripgrep_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/serpapi_search_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/task_complete_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/unified_diff_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/utils/__init__.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/utils/create_sample_database.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/utils/generate_database_report.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/wikipedia_search_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/tools/write_file_tool.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/utils/__init__.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/utils/ask_user_validation.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/utils/check_version.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/utils/download_http_file.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/utils/get_coding_environment.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/utils/get_environment.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/utils/get_quantalogic_rules_content.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/utils/git_ls.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/utils/read_file.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/utils/read_http_text_content.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/version.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/version_check.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/welcome_message.py +0 -0
- {quantalogic-0.30.8 → quantalogic-0.31.1}/quantalogic/xml_tool_parser.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: quantalogic
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.31.1
|
4
4
|
Summary: QuantaLogic ReAct Agents
|
5
5
|
Author: Raphaël MANSUY
|
6
6
|
Author-email: raphael.mansuy@gmail.com
|
@@ -14,6 +14,7 @@ Requires-Dist: click (>=8.1.8,<9.0.0)
|
|
14
14
|
Requires-Dist: duckduckgo-search (>=7.2.1,<8.0.0)
|
15
15
|
Requires-Dist: faker (>=33.3.1,<34.0.0)
|
16
16
|
Requires-Dist: fastapi (>=0.115.6,<0.116.0)
|
17
|
+
Requires-Dist: fuzzywuzzy (>=0.18.0,<0.19.0)
|
17
18
|
Requires-Dist: google-auth (>=2.20.0,<3.0.0)
|
18
19
|
Requires-Dist: google-search-results (>=2.4.2,<3.0.0)
|
19
20
|
Requires-Dist: jinja2 (>=3.1.5,<4.0.0)
|
@@ -35,6 +36,7 @@ Requires-Dist: prompt-toolkit (>=3.0.48,<4.0.0)
|
|
35
36
|
Requires-Dist: pydantic (>=2.10.4,<3.0.0)
|
36
37
|
Requires-Dist: pymdown-extensions (>=10.3.1,<11.0.0)
|
37
38
|
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
39
|
+
Requires-Dist: python-levenshtein (>=0.26.1,<0.27.0)
|
38
40
|
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
39
41
|
Requires-Dist: rich (>=13.9.4,<14.0.0)
|
40
42
|
Requires-Dist: serpapi (>=0.1.5,<0.2.0)
|
@@ -114,7 +116,7 @@ We created [QuantaLogic](https://www.quantalogic.app) because we saw a significa
|
|
114
116
|
|
115
117
|
## Usage
|
116
118
|
|
117
|
-
**Usage:** `quantalogic [OPTIONS] COMMAND [ARGS]...`
|
119
|
+
**Usage:** `quantalogic [OPTIONS] COMMAND i[ARGS]...`
|
118
120
|
**Environment Variables:** Set `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, and `DEEPSEEK_API_KEY` for API integration.
|
119
121
|
|
120
122
|
**Options:**
|
@@ -129,6 +131,7 @@ We created [QuantaLogic](https://www.quantalogic.app) because we saw a significa
|
|
129
131
|
- `--help`: Show help message
|
130
132
|
|
131
133
|
**Commands:**
|
134
|
+
|
132
135
|
- `task`: Execute a task with the QuantaLogic AI Assistant
|
133
136
|
- `--file PATH`: Path to task file
|
134
137
|
- `--model-name TEXT`: Specify model
|
@@ -141,6 +144,25 @@ We created [QuantaLogic](https://www.quantalogic.app) because we saw a significa
|
|
141
144
|
- `--compact-every-n-iteration`: Memory optimization
|
142
145
|
- `--no-stream`: Disable streaming
|
143
146
|
|
147
|
+
|
148
|
+
- `list-models`: List available models with optional filtering.
|
149
|
+
- `--search TEXT`: Filter models by name or description.
|
150
|
+
- `--help`: Show help message.
|
151
|
+
|
152
|
+
Example:
|
153
|
+
```bash
|
154
|
+
quantalogic list-models --search qwen
|
155
|
+
```
|
156
|
+
|
157
|
+
Output:
|
158
|
+
```
|
159
|
+
Model Name Description
|
160
|
+
------------------- -------------------------------------------------------
|
161
|
+
dashscope/qwen-max Alibaba's Qwen-Max model optimized for maximum performance
|
162
|
+
dashscope/qwen-plus Alibaba's Qwen-Plus model offering balanced performance
|
163
|
+
```
|
164
|
+
|
165
|
+
|
144
166
|
## Release Notes
|
145
167
|
|
146
168
|
See our [Release Notes](RELEASE_NOTES.MD) for detailed version history and changes.
|
@@ -162,6 +184,9 @@ See our [Release Notes](RELEASE_NOTES.MD) for detailed version history and chang
|
|
162
184
|
| openrouter/openai/gpt-4o | OPENROUTER_API_KEY | OpenAI's GPT-4o model accessible through OpenRouter platform. |
|
163
185
|
| openrouter/mistralai/mistral-large-2411 | OPENROUTER_API_KEY | Mistral's large model optimized for complex reasoning tasks, available through OpenRouter with enhanced multilingual capabilities. |
|
164
186
|
| mistral/mistral-large-2407 | MISTRAL_API_KEY | Mistral's high-performance model designed for enterprise-grade applications, offering advanced reasoning and multilingual support. |
|
187
|
+
| dashscope/qwen-max | DASHSCOPE_API_KEY | Alibaba's Qwen-Max model optimized for maximum performance and extensive reasoning capabilities. |
|
188
|
+
| dashscope/qwen-plus | DASHSCOPE_API_KEY | Alibaba's Qwen-Plus model offering balanced performance and cost-efficiency for a variety of tasks. |
|
189
|
+
| dashscope/qwen-turbo | DASHSCOPE_API_KEY | Alibaba's Qwen-Turbo model designed for fast and efficient responses, ideal for high-throughput scenarios. |
|
165
190
|
|
166
191
|
To configure the environment API key for Quantalogic using LiteLLM, set the required environment variable for your chosen provider and any optional variables like `OPENAI_API_BASE` or `OPENROUTER_REFERRER`. Use a `.env` file or a secrets manager to securely store these keys, and load them in your code using `python-dotenv`. For advanced configurations, refer to the [LiteLLM documentation](https://docs.litellm.ai/docs/).
|
167
192
|
|
@@ -56,7 +56,7 @@ We created [QuantaLogic](https://www.quantalogic.app) because we saw a significa
|
|
56
56
|
|
57
57
|
## Usage
|
58
58
|
|
59
|
-
**Usage:** `quantalogic [OPTIONS] COMMAND [ARGS]...`
|
59
|
+
**Usage:** `quantalogic [OPTIONS] COMMAND i[ARGS]...`
|
60
60
|
**Environment Variables:** Set `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, and `DEEPSEEK_API_KEY` for API integration.
|
61
61
|
|
62
62
|
**Options:**
|
@@ -71,6 +71,7 @@ We created [QuantaLogic](https://www.quantalogic.app) because we saw a significa
|
|
71
71
|
- `--help`: Show help message
|
72
72
|
|
73
73
|
**Commands:**
|
74
|
+
|
74
75
|
- `task`: Execute a task with the QuantaLogic AI Assistant
|
75
76
|
- `--file PATH`: Path to task file
|
76
77
|
- `--model-name TEXT`: Specify model
|
@@ -83,6 +84,25 @@ We created [QuantaLogic](https://www.quantalogic.app) because we saw a significa
|
|
83
84
|
- `--compact-every-n-iteration`: Memory optimization
|
84
85
|
- `--no-stream`: Disable streaming
|
85
86
|
|
87
|
+
|
88
|
+
- `list-models`: List available models with optional filtering.
|
89
|
+
- `--search TEXT`: Filter models by name or description.
|
90
|
+
- `--help`: Show help message.
|
91
|
+
|
92
|
+
Example:
|
93
|
+
```bash
|
94
|
+
quantalogic list-models --search qwen
|
95
|
+
```
|
96
|
+
|
97
|
+
Output:
|
98
|
+
```
|
99
|
+
Model Name Description
|
100
|
+
------------------- -------------------------------------------------------
|
101
|
+
dashscope/qwen-max Alibaba's Qwen-Max model optimized for maximum performance
|
102
|
+
dashscope/qwen-plus Alibaba's Qwen-Plus model offering balanced performance
|
103
|
+
```
|
104
|
+
|
105
|
+
|
86
106
|
## Release Notes
|
87
107
|
|
88
108
|
See our [Release Notes](RELEASE_NOTES.MD) for detailed version history and changes.
|
@@ -104,6 +124,9 @@ See our [Release Notes](RELEASE_NOTES.MD) for detailed version history and chang
|
|
104
124
|
| openrouter/openai/gpt-4o | OPENROUTER_API_KEY | OpenAI's GPT-4o model accessible through OpenRouter platform. |
|
105
125
|
| openrouter/mistralai/mistral-large-2411 | OPENROUTER_API_KEY | Mistral's large model optimized for complex reasoning tasks, available through OpenRouter with enhanced multilingual capabilities. |
|
106
126
|
| mistral/mistral-large-2407 | MISTRAL_API_KEY | Mistral's high-performance model designed for enterprise-grade applications, offering advanced reasoning and multilingual support. |
|
127
|
+
| dashscope/qwen-max | DASHSCOPE_API_KEY | Alibaba's Qwen-Max model optimized for maximum performance and extensive reasoning capabilities. |
|
128
|
+
| dashscope/qwen-plus | DASHSCOPE_API_KEY | Alibaba's Qwen-Plus model offering balanced performance and cost-efficiency for a variety of tasks. |
|
129
|
+
| dashscope/qwen-turbo | DASHSCOPE_API_KEY | Alibaba's Qwen-Turbo model designed for fast and efficient responses, ideal for high-throughput scenarios. |
|
107
130
|
|
108
131
|
To configure the environment API key for Quantalogic using LiteLLM, set the required environment variable for your chosen provider and any optional variables like `OPENAI_API_BASE` or `OPENROUTER_REFERRER`. Use a `.env` file or a secrets manager to securely store these keys, and load them in your code using `python-dotenv`. For advanced configurations, refer to the [LiteLLM documentation](https://docs.litellm.ai/docs/).
|
109
132
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "quantalogic"
|
3
|
-
version = "0.
|
3
|
+
version = "0.31.1"
|
4
4
|
description = "QuantaLogic ReAct Agents"
|
5
5
|
authors = ["Raphaël MANSUY <raphael.mansuy@gmail.com>"]
|
6
6
|
readme = "README.md"
|
@@ -54,6 +54,8 @@ sqlalchemy = "^2.0.37"
|
|
54
54
|
python-dotenv = "^1.0.1"
|
55
55
|
networkx = "^3.4.2"
|
56
56
|
faker = "^33.3.1"
|
57
|
+
fuzzywuzzy = "^0.18.0"
|
58
|
+
python-levenshtein = "^0.26.1"
|
57
59
|
|
58
60
|
[tool.poetry.scripts]
|
59
61
|
quantalogic = "quantalogic.main:cli"
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
"""QuantaLogic package initialization."""
|
2
|
+
|
2
3
|
import warnings
|
3
4
|
|
4
5
|
# Suppress specific warnings related to Pydantic's V2 configuration changes
|
@@ -9,13 +10,22 @@ warnings.filterwarnings(
|
|
9
10
|
message=".*config keys have changed in V2:.*|.*'fields' config key is removed in V2.*",
|
10
11
|
)
|
11
12
|
|
12
|
-
|
13
|
+
# Import public API
|
13
14
|
from .agent import Agent # noqa: E402
|
14
15
|
from .console_print_events import console_print_events # noqa: E402
|
15
16
|
from .console_print_token import console_print_token # noqa: E402
|
16
17
|
from .event_emitter import EventEmitter # noqa: E402
|
18
|
+
from .llm import count_tokens, generate_completion, generate_image # noqa: E402
|
17
19
|
from .memory import AgentMemory, VariableMemory # noqa: E402
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
__all__ = [
|
22
|
+
"Agent",
|
23
|
+
"EventEmitter",
|
24
|
+
"AgentMemory",
|
25
|
+
"VariableMemory",
|
26
|
+
"console_print_events",
|
27
|
+
"console_print_token",
|
28
|
+
"generate_completion",
|
29
|
+
"generate_image",
|
30
|
+
"count_tokens"
|
31
|
+
]
|
@@ -5,7 +5,7 @@ from datetime import datetime
|
|
5
5
|
from typing import Any
|
6
6
|
|
7
7
|
from loguru import logger
|
8
|
-
from pydantic import BaseModel, ConfigDict
|
8
|
+
from pydantic import BaseModel, ConfigDict, PrivateAttr
|
9
9
|
|
10
10
|
from quantalogic.event_emitter import EventEmitter
|
11
11
|
from quantalogic.generative_model import GenerativeModel, ResponseStats, TokenUsage
|
@@ -52,12 +52,16 @@ class ObserveResponseResult(BaseModel):
|
|
52
52
|
class Agent(BaseModel):
|
53
53
|
"""Enhanced QuantaLogic agent implementing ReAct framework."""
|
54
54
|
|
55
|
-
model_config = ConfigDict(
|
55
|
+
model_config = ConfigDict(
|
56
|
+
arbitrary_types_allowed=True,
|
57
|
+
validate_assignment=True,
|
58
|
+
extra="forbid"
|
59
|
+
)
|
56
60
|
|
57
61
|
specific_expertise: str
|
58
62
|
model: GenerativeModel
|
59
|
-
memory: AgentMemory = AgentMemory()
|
60
|
-
variable_store: VariableMemory = VariableMemory()
|
63
|
+
memory: AgentMemory = AgentMemory() # A list User / Assistant Messages
|
64
|
+
variable_store: VariableMemory = VariableMemory() # A dictionary of variables
|
61
65
|
tools: ToolManager = ToolManager()
|
62
66
|
event_emitter: EventEmitter = EventEmitter()
|
63
67
|
config: AgentConfig
|
@@ -71,8 +75,9 @@ class Agent(BaseModel):
|
|
71
75
|
max_output_tokens: int = DEFAULT_MAX_OUTPUT_TOKENS
|
72
76
|
max_iterations: int = 30
|
73
77
|
system_prompt: str = ""
|
74
|
-
compact_every_n_iterations: int | None = None
|
75
|
-
max_tokens_working_memory: int | None = None
|
78
|
+
compact_every_n_iterations: int | None = None
|
79
|
+
max_tokens_working_memory: int | None = None
|
80
|
+
_model_name: str = PrivateAttr(default="")
|
76
81
|
|
77
82
|
def __init__(
|
78
83
|
self,
|
@@ -84,17 +89,18 @@ class Agent(BaseModel):
|
|
84
89
|
task_to_solve: str = "",
|
85
90
|
specific_expertise: str = "General AI assistant with coding and problem-solving capabilities",
|
86
91
|
get_environment: Callable[[], str] = get_environment,
|
87
|
-
compact_every_n_iterations: int | None = None,
|
88
|
-
max_tokens_working_memory: int | None = None,
|
92
|
+
compact_every_n_iterations: int | None = None,
|
93
|
+
max_tokens_working_memory: int | None = None,
|
89
94
|
):
|
90
95
|
"""Initialize the agent with model, memory, tools, and configurations."""
|
91
96
|
try:
|
92
97
|
logger.debug("Initializing agent...")
|
93
|
-
|
98
|
+
|
99
|
+
# Create event emitter
|
94
100
|
event_emitter = EventEmitter()
|
95
101
|
|
96
102
|
# Add TaskCompleteTool to the tools list if not already present
|
97
|
-
if TaskCompleteTool
|
103
|
+
if not any(isinstance(t, TaskCompleteTool) for t in tools):
|
98
104
|
tools.append(TaskCompleteTool())
|
99
105
|
|
100
106
|
tool_manager = ToolManager(tools={tool.name: tool for tool in tools})
|
@@ -114,32 +120,50 @@ class Agent(BaseModel):
|
|
114
120
|
system_prompt=system_prompt_text,
|
115
121
|
)
|
116
122
|
|
117
|
-
|
123
|
+
# Initialize using Pydantic's model_validate
|
118
124
|
super().__init__(
|
125
|
+
specific_expertise=specific_expertise,
|
119
126
|
model=GenerativeModel(model=model_name, event_emitter=event_emitter),
|
120
127
|
memory=memory,
|
121
128
|
variable_store=variable_store,
|
122
129
|
tools=tool_manager,
|
130
|
+
event_emitter=event_emitter,
|
123
131
|
config=config,
|
124
|
-
ask_for_user_validation=ask_for_user_validation,
|
125
132
|
task_to_solve=task_to_solve,
|
126
|
-
|
127
|
-
|
133
|
+
task_to_solve_summary="",
|
134
|
+
ask_for_user_validation=ask_for_user_validation,
|
135
|
+
last_tool_call={},
|
136
|
+
total_tokens=0,
|
137
|
+
current_iteration=0,
|
138
|
+
max_input_tokens=DEFAULT_MAX_INPUT_TOKENS,
|
139
|
+
max_output_tokens=DEFAULT_MAX_OUTPUT_TOKENS,
|
140
|
+
max_iterations=30,
|
141
|
+
system_prompt="",
|
142
|
+
compact_every_n_iterations=compact_every_n_iterations or 30,
|
143
|
+
max_tokens_working_memory=max_tokens_working_memory,
|
128
144
|
)
|
129
145
|
|
130
|
-
|
131
|
-
self.compact_every_n_iterations = compact_every_n_iterations or self.max_iterations
|
132
|
-
logger.debug(f"Memory will be compacted every {self.compact_every_n_iterations} iterations")
|
146
|
+
self._model_name = model_name
|
133
147
|
|
134
|
-
|
135
|
-
self.max_tokens_working_memory = max_tokens_working_memory
|
148
|
+
logger.debug(f"Memory will be compacted every {self.compact_every_n_iterations} iterations")
|
136
149
|
logger.debug(f"Max tokens for working memory set to: {self.max_tokens_working_memory}")
|
137
|
-
|
138
150
|
logger.debug("Agent initialized successfully.")
|
139
151
|
except Exception as e:
|
140
152
|
logger.error(f"Failed to initialize agent: {str(e)}")
|
141
153
|
raise
|
142
154
|
|
155
|
+
@property
|
156
|
+
def model_name(self) -> str:
|
157
|
+
"""Get the current model name."""
|
158
|
+
return self._model_name
|
159
|
+
|
160
|
+
@model_name.setter
|
161
|
+
def model_name(self, value: str) -> None:
|
162
|
+
"""Set the model name."""
|
163
|
+
self._model_name = value
|
164
|
+
# Update the model instance with the new name
|
165
|
+
self.model = GenerativeModel(model=value, event_emitter=self.event_emitter)
|
166
|
+
|
143
167
|
def clear_memory(self):
|
144
168
|
"""Clear the memory and reset the session."""
|
145
169
|
self._reset_session(clear_memory=True)
|
@@ -388,6 +412,9 @@ class Agent(BaseModel):
|
|
388
412
|
|
389
413
|
def _parse_tool_usage(self, content: str) -> dict:
|
390
414
|
"""Extract tool usage from the response content."""
|
415
|
+
if not content or not isinstance(content, str):
|
416
|
+
return {}
|
417
|
+
|
391
418
|
xml_parser = ToleranceXMLParser()
|
392
419
|
tool_names = self.tools.tool_names()
|
393
420
|
return xml_parser.extract_elements(text=content, element_names=tool_names)
|
@@ -478,6 +505,7 @@ class Agent(BaseModel):
|
|
478
505
|
|
479
506
|
# Format the response message
|
480
507
|
formatted_response = (
|
508
|
+
f"Your next step: you Must now plan the next tool call to complete the based on this new observation\n"
|
481
509
|
f"\n--- Observations for iteration {iteration} / max {self.max_iterations} ---\n"
|
482
510
|
f"\n--- Tool execution result in ${variable_name}$ ---\n"
|
483
511
|
f"<{variable_name}>\n{response_display}\n</{variable_name}>\n\n"
|
@@ -533,7 +561,10 @@ class Agent(BaseModel):
|
|
533
561
|
question_validation: str = (
|
534
562
|
"Do you permit the execution of this tool?\n"
|
535
563
|
f"Tool: {tool_name}\n"
|
536
|
-
|
564
|
+
"Arguments:\n"
|
565
|
+
"<arguments>\n"
|
566
|
+
+ "\n".join([f" <{key}>{value}</{key}>" for key, value in arguments_with_values.items()])
|
567
|
+
+ "\n</arguments>\n"
|
537
568
|
"Yes or No"
|
538
569
|
)
|
539
570
|
permission_granted = self.ask_for_user_validation(question_validation)
|
@@ -603,10 +634,14 @@ class Agent(BaseModel):
|
|
603
634
|
return executed_tool, response
|
604
635
|
|
605
636
|
def _interpolate_variables(self, text: str) -> str:
|
606
|
-
"""Interpolate variables using $
|
637
|
+
"""Interpolate variables using $var$ syntax in the given text."""
|
607
638
|
try:
|
639
|
+
import re
|
608
640
|
for var in self.variable_store.keys():
|
609
|
-
|
641
|
+
# Escape the variable name for regex, but use raw value for replacement
|
642
|
+
pattern = rf'\${re.escape(var)}\$'
|
643
|
+
replacement = self.variable_store[var]
|
644
|
+
text = re.sub(pattern, replacement, text)
|
610
645
|
return text
|
611
646
|
except Exception as e:
|
612
647
|
logger.error(f"Error in _interpolate_variables: {str(e)}")
|
@@ -645,6 +680,7 @@ class Agent(BaseModel):
|
|
645
680
|
"1. Select ONE tool per message\n"
|
646
681
|
"2. You will receive the tool's output in the next user response\n"
|
647
682
|
"3. Choose the most appropriate tool for each step\n"
|
683
|
+
"4. Use task_complete tool to confirm task completion\n"
|
648
684
|
)
|
649
685
|
return prompt_use_tools
|
650
686
|
|
@@ -706,23 +742,32 @@ class Agent(BaseModel):
|
|
706
742
|
return summary.response
|
707
743
|
|
708
744
|
def _generate_task_summary(self, content: str) -> str:
|
709
|
-
"""Generate a concise summary
|
745
|
+
"""Generate a concise task-focused summary using the generative model.
|
710
746
|
|
711
747
|
Args:
|
712
748
|
content (str): The content to summarize
|
713
749
|
|
714
750
|
Returns:
|
715
|
-
str: Generated summary
|
751
|
+
str: Generated task summary
|
716
752
|
"""
|
717
753
|
try:
|
718
754
|
prompt = (
|
719
|
-
"
|
720
|
-
|
721
|
-
"
|
755
|
+
"Create an ultra-concise task summary that captures ONLY: \n"
|
756
|
+
"1. Primary objective/purpose\n"
|
757
|
+
"2. Core actions/requirements\n"
|
758
|
+
"3. Desired end-state/outcome\n\n"
|
759
|
+
"Guidelines:\n"
|
760
|
+
"- Use imperative voice\n"
|
761
|
+
"- Exclude background, explanations, and examples\n"
|
762
|
+
"- Compress information using semantic density\n"
|
763
|
+
"- Strict 2-3 sentence maximum (under 50 words)\n"
|
764
|
+
"- Format: 'Concise Task Summary: [Your summary]'\n\n"
|
765
|
+
f"Input Task Description:\n{content}\n\n"
|
766
|
+
"Concise Task Summary:"
|
722
767
|
)
|
723
768
|
result = self.model.generate(prompt=prompt)
|
724
769
|
logger.debug(f"Generated summary: {result.response}")
|
725
|
-
return result.response
|
770
|
+
return result.response.strip() + "\n🚨 The FULL task is in <task> tag in the previous messages.\n"
|
726
771
|
except Exception as e:
|
727
772
|
logger.error(f"Error generating summary: {str(e)}")
|
728
773
|
return f"Summary generation failed: {str(e)}"
|
@@ -747,3 +792,8 @@ class Agent(BaseModel):
|
|
747
792
|
"session_add_message",
|
748
793
|
{"role": "assistant", "content": assistant_content},
|
749
794
|
)
|
795
|
+
|
796
|
+
def update_model(self, new_model_name: str) -> None:
|
797
|
+
"""Update the model name and recreate the model instance."""
|
798
|
+
self.model_name = new_model_name
|
799
|
+
self.model = GenerativeModel(model=new_model_name, event_emitter=self.event_emitter)
|
@@ -37,6 +37,14 @@ load_dotenv()
|
|
37
37
|
MODEL_NAME = "deepseek/deepseek-chat"
|
38
38
|
|
39
39
|
|
40
|
+
_current_model_name: str = ""
|
41
|
+
|
42
|
+
def get_current_model() -> str:
|
43
|
+
"""Retrieve the currently active model name."""
|
44
|
+
if not _current_model_name:
|
45
|
+
raise ValueError("No model initialized")
|
46
|
+
return _current_model_name
|
47
|
+
|
40
48
|
def create_agent(
|
41
49
|
model_name: str,
|
42
50
|
vision_model_name: str | None,
|
@@ -44,6 +52,8 @@ def create_agent(
|
|
44
52
|
compact_every_n_iteration: int | None = None,
|
45
53
|
max_tokens_working_memory: int | None = None
|
46
54
|
) -> Agent:
|
55
|
+
global _current_model_name
|
56
|
+
_current_model_name = model_name
|
47
57
|
"""Create an agent with the specified model and tools.
|
48
58
|
|
49
59
|
Args:
|
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
from typing import Optional
|
1
|
+
from typing import Dict, Optional
|
4
2
|
|
5
3
|
from loguru import logger
|
6
4
|
|
@@ -11,7 +9,57 @@ from quantalogic.agent_config import (
|
|
11
9
|
create_interpreter_agent,
|
12
10
|
)
|
13
11
|
from quantalogic.coding_agent import create_coding_agent
|
14
|
-
from quantalogic.search_agent import create_search_agent
|
12
|
+
from quantalogic.search_agent import create_search_agent # noqa: E402
|
13
|
+
|
14
|
+
|
15
|
+
class AgentRegistry:
|
16
|
+
"""Registry for managing agent instances by name."""
|
17
|
+
|
18
|
+
_instance = None
|
19
|
+
_agents: Dict[str, Agent] = {}
|
20
|
+
|
21
|
+
def __new__(cls):
|
22
|
+
if cls._instance is None:
|
23
|
+
cls._instance = super().__new__(cls)
|
24
|
+
return cls._instance
|
25
|
+
|
26
|
+
@classmethod
|
27
|
+
def register_agent(cls, name: str, agent: Agent) -> None:
|
28
|
+
"""Register an agent instance with a name.
|
29
|
+
|
30
|
+
Args:
|
31
|
+
name: Unique name for the agent
|
32
|
+
agent: Agent instance to register
|
33
|
+
"""
|
34
|
+
if name in cls._agents:
|
35
|
+
raise ValueError(f"Agent with name {name} already exists")
|
36
|
+
cls._agents[name] = agent
|
37
|
+
|
38
|
+
@classmethod
|
39
|
+
def get_agent(cls, name: str) -> Agent:
|
40
|
+
"""Retrieve a registered agent by name.
|
41
|
+
|
42
|
+
Args:
|
43
|
+
name: Name of the agent to retrieve
|
44
|
+
|
45
|
+
Returns:
|
46
|
+
Registered Agent instance
|
47
|
+
|
48
|
+
Raises:
|
49
|
+
KeyError: If no agent with that name exists
|
50
|
+
"""
|
51
|
+
return cls._agents[name]
|
52
|
+
|
53
|
+
@classmethod
|
54
|
+
def list_agents(cls) -> Dict[str, str]:
|
55
|
+
"""List all registered agents.
|
56
|
+
|
57
|
+
Returns:
|
58
|
+
Dictionary mapping agent names to their types
|
59
|
+
"""
|
60
|
+
return {name: type(agent).__name__ for name, agent in cls._agents.items()}
|
61
|
+
|
62
|
+
"""Agent factory module for creating different types of agents."""
|
15
63
|
|
16
64
|
|
17
65
|
def create_agent_for_mode(
|
@@ -46,7 +94,7 @@ def create_agent_for_mode(
|
|
46
94
|
|
47
95
|
if mode == "code":
|
48
96
|
logger.debug("Creating code agent without basic mode")
|
49
|
-
|
97
|
+
agent = create_coding_agent(
|
50
98
|
model_name,
|
51
99
|
vision_model_name,
|
52
100
|
basic=False,
|
@@ -54,8 +102,9 @@ def create_agent_for_mode(
|
|
54
102
|
compact_every_n_iteration=compact_every_n_iteration,
|
55
103
|
max_tokens_working_memory=max_tokens_working_memory
|
56
104
|
)
|
105
|
+
return agent
|
57
106
|
if mode == "code-basic":
|
58
|
-
|
107
|
+
agent = create_coding_agent(
|
59
108
|
model_name,
|
60
109
|
vision_model_name,
|
61
110
|
basic=True,
|
@@ -63,44 +112,50 @@ def create_agent_for_mode(
|
|
63
112
|
compact_every_n_iteration=compact_every_n_iteration,
|
64
113
|
max_tokens_working_memory=max_tokens_working_memory
|
65
114
|
)
|
115
|
+
return agent
|
66
116
|
elif mode == "basic":
|
67
|
-
|
117
|
+
agent = create_basic_agent(
|
68
118
|
model_name,
|
69
119
|
vision_model_name,
|
70
120
|
no_stream=no_stream,
|
71
121
|
compact_every_n_iteration=compact_every_n_iteration,
|
72
122
|
max_tokens_working_memory=max_tokens_working_memory
|
73
123
|
)
|
124
|
+
return agent
|
74
125
|
elif mode == "full":
|
75
|
-
|
126
|
+
agent = create_full_agent(
|
76
127
|
model_name,
|
77
128
|
vision_model_name,
|
78
129
|
no_stream=no_stream,
|
79
130
|
compact_every_n_iteration=compact_every_n_iteration,
|
80
131
|
max_tokens_working_memory=max_tokens_working_memory
|
81
132
|
)
|
133
|
+
return agent
|
82
134
|
elif mode == "interpreter":
|
83
|
-
|
135
|
+
agent = create_interpreter_agent(
|
84
136
|
model_name,
|
85
137
|
vision_model_name,
|
86
138
|
no_stream=no_stream,
|
87
139
|
compact_every_n_iteration=compact_every_n_iteration,
|
88
140
|
max_tokens_working_memory=max_tokens_working_memory
|
89
141
|
)
|
142
|
+
return agent
|
90
143
|
elif mode == "search":
|
91
|
-
|
144
|
+
agent = create_search_agent(
|
92
145
|
model_name,
|
93
146
|
no_stream=no_stream,
|
94
147
|
compact_every_n_iteration=compact_every_n_iteration,
|
95
148
|
max_tokens_working_memory=max_tokens_working_memory
|
96
149
|
)
|
150
|
+
return agent
|
97
151
|
if mode == "search-full":
|
98
|
-
|
152
|
+
agent = create_search_agent(
|
99
153
|
model_name,
|
100
154
|
mode_full=True,
|
101
155
|
no_stream=no_stream,
|
102
156
|
compact_every_n_iteration=compact_every_n_iteration,
|
103
157
|
max_tokens_working_memory=max_tokens_working_memory
|
104
158
|
)
|
159
|
+
return agent
|
105
160
|
else:
|
106
161
|
raise ValueError(f"Unknown agent mode: {mode}")
|
@@ -0,0 +1,15 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
|
3
|
+
|
4
|
+
@dataclass
|
5
|
+
class QLConfig:
|
6
|
+
"""Central configuration for QuantaLogic agent parameters."""
|
7
|
+
model_name: str
|
8
|
+
verbose: bool
|
9
|
+
mode: str
|
10
|
+
log: str
|
11
|
+
vision_model_name: str | None
|
12
|
+
max_iterations: int
|
13
|
+
compact_every_n_iteration: int | None
|
14
|
+
max_tokens_working_memory: int | None
|
15
|
+
no_stream: bool
|