quantalogic 0.80__py3-none-any.whl → 0.93__py3-none-any.whl
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/flow/__init__.py +16 -34
- quantalogic/main.py +11 -6
- quantalogic/tools/tool.py +8 -922
- quantalogic-0.93.dist-info/METADATA +475 -0
- {quantalogic-0.80.dist-info → quantalogic-0.93.dist-info}/RECORD +8 -54
- quantalogic/codeact/TODO.md +0 -14
- quantalogic/codeact/__init__.py +0 -0
- quantalogic/codeact/agent.py +0 -478
- quantalogic/codeact/cli.py +0 -50
- quantalogic/codeact/cli_commands/__init__.py +0 -0
- quantalogic/codeact/cli_commands/create_toolbox.py +0 -45
- quantalogic/codeact/cli_commands/install_toolbox.py +0 -20
- quantalogic/codeact/cli_commands/list_executor.py +0 -15
- quantalogic/codeact/cli_commands/list_reasoners.py +0 -15
- quantalogic/codeact/cli_commands/list_toolboxes.py +0 -47
- quantalogic/codeact/cli_commands/task.py +0 -215
- quantalogic/codeact/cli_commands/tool_info.py +0 -24
- quantalogic/codeact/cli_commands/uninstall_toolbox.py +0 -43
- quantalogic/codeact/config.yaml +0 -21
- quantalogic/codeact/constants.py +0 -9
- quantalogic/codeact/events.py +0 -85
- quantalogic/codeact/examples/README.md +0 -342
- quantalogic/codeact/examples/agent_sample.yaml +0 -29
- quantalogic/codeact/executor.py +0 -186
- quantalogic/codeact/history_manager.py +0 -94
- quantalogic/codeact/llm_util.py +0 -57
- quantalogic/codeact/plugin_manager.py +0 -92
- quantalogic/codeact/prompts/error_format.j2 +0 -11
- quantalogic/codeact/prompts/generate_action.j2 +0 -77
- quantalogic/codeact/prompts/generate_program.j2 +0 -52
- quantalogic/codeact/prompts/response_format.j2 +0 -11
- quantalogic/codeact/react_agent.py +0 -318
- quantalogic/codeact/reasoner.py +0 -185
- quantalogic/codeact/templates/toolbox/README.md.j2 +0 -10
- quantalogic/codeact/templates/toolbox/pyproject.toml.j2 +0 -16
- quantalogic/codeact/templates/toolbox/tools.py.j2 +0 -6
- quantalogic/codeact/templates.py +0 -7
- quantalogic/codeact/tools_manager.py +0 -258
- quantalogic/codeact/utils.py +0 -62
- quantalogic/codeact/xml_utils.py +0 -126
- quantalogic/flow/flow.py +0 -1070
- quantalogic/flow/flow_extractor.py +0 -783
- quantalogic/flow/flow_generator.py +0 -322
- quantalogic/flow/flow_manager.py +0 -676
- quantalogic/flow/flow_manager_schema.py +0 -287
- quantalogic/flow/flow_mermaid.py +0 -365
- quantalogic/flow/flow_validator.py +0 -479
- quantalogic/flow/flow_yaml.linkedin.md +0 -31
- quantalogic/flow/flow_yaml.md +0 -767
- quantalogic/flow/templates/prompt_check_inventory.j2 +0 -1
- quantalogic/flow/templates/system_check_inventory.j2 +0 -1
- quantalogic-0.80.dist-info/METADATA +0 -900
- {quantalogic-0.80.dist-info → quantalogic-0.93.dist-info}/LICENSE +0 -0
- {quantalogic-0.80.dist-info → quantalogic-0.93.dist-info}/WHEEL +0 -0
- {quantalogic-0.80.dist-info → quantalogic-0.93.dist-info}/entry_points.txt +0 -0
@@ -1,342 +0,0 @@
|
|
1
|
-
# Quantalogic Agent Configuration YAML Format
|
2
|
-
|
3
|
-
This document describes the YAML configuration format for the `AgentConfig` class in the Quantalogic framework, used to configure an AI agent’s behavior, tools, and components. The configuration is flexible, supporting both simple setups and advanced customizations, and is fully backward-compatible with earlier versions.
|
4
|
-
|
5
|
-
## Overview
|
6
|
-
|
7
|
-
The YAML configuration file defines the settings for an `Agent` instance, controlling aspects such as the language model, task-solving parameters, tool usage, and agent personality. You can provide this configuration via a file (passed as a string to `Agent`) or directly as arguments to `AgentConfig`. All fields are optional unless specified, with sensible defaults ensuring compatibility with minimal setups.
|
8
|
-
|
9
|
-
### Example Minimal Configuration
|
10
|
-
```yaml
|
11
|
-
model: "gemini/gemini-2.0-flash"
|
12
|
-
max_iterations: 5
|
13
|
-
name: "MathBot"
|
14
|
-
personality: "witty"
|
15
|
-
```
|
16
|
-
|
17
|
-
### Example Advanced Configuration
|
18
|
-
```yaml
|
19
|
-
name: "EquationSolver"
|
20
|
-
model: "deepseek/deepseek-chat"
|
21
|
-
max_iterations: 5
|
22
|
-
max_history_tokens: 2000
|
23
|
-
profile: "math_expert"
|
24
|
-
customizations:
|
25
|
-
personality:
|
26
|
-
traits:
|
27
|
-
- "witty"
|
28
|
-
tools_config:
|
29
|
-
- name: "math_tools"
|
30
|
-
enabled: true
|
31
|
-
config:
|
32
|
-
precision: "high"
|
33
|
-
api_key: "{{ env.MATH_API_KEY }}"
|
34
|
-
reasoner:
|
35
|
-
name: "default"
|
36
|
-
config:
|
37
|
-
temperature: 0.7
|
38
|
-
executor:
|
39
|
-
name: "default"
|
40
|
-
config:
|
41
|
-
timeout: 300
|
42
|
-
sop: |
|
43
|
-
Always provide clear, concise answers.
|
44
|
-
Prioritize mathematical accuracy.
|
45
|
-
```
|
46
|
-
|
47
|
-
## Configuration Fields
|
48
|
-
|
49
|
-
Below is a detailed breakdown of each field in the YAML configuration, including the new `name` field.
|
50
|
-
|
51
|
-
---
|
52
|
-
|
53
|
-
### `name`
|
54
|
-
- **Description**: A unique identifier or nickname for the agent, included in the system prompt to personalize its identity.
|
55
|
-
- **Type**: String (optional)
|
56
|
-
- **Default**: `null`
|
57
|
-
- **Example**:
|
58
|
-
```yaml
|
59
|
-
name: "MathBot"
|
60
|
-
```
|
61
|
-
- **Notes**: If provided, the agent introduces itself with this name in the system prompt (e.g., "I am MathBot, an AI assistant.").
|
62
|
-
|
63
|
-
---
|
64
|
-
|
65
|
-
### `model`
|
66
|
-
- **Description**: Specifies the language model used by the agent for reasoning and text generation. Must be compatible with the `litellm` library.
|
67
|
-
- **Type**: String
|
68
|
-
- **Default**: `"gemini/gemini-2.0-flash"`
|
69
|
-
- **Example**:
|
70
|
-
```yaml
|
71
|
-
model: "deepseek/deepseek-chat"
|
72
|
-
```
|
73
|
-
|
74
|
-
---
|
75
|
-
|
76
|
-
### `max_iterations`
|
77
|
-
- **Description**: Sets the maximum number of reasoning steps the agent will take to solve a task using the ReAct framework.
|
78
|
-
- **Type**: Integer
|
79
|
-
- **Default**: `5`
|
80
|
-
- **Example**:
|
81
|
-
```yaml
|
82
|
-
max_iterations: 10
|
83
|
-
```
|
84
|
-
|
85
|
-
---
|
86
|
-
|
87
|
-
### `tools`
|
88
|
-
- **Description**: A list of pre-instantiated tools (as Python objects) to include in the agent. Typically used programmatically rather than in YAML.
|
89
|
-
- **Type**: List of `Tool` or callable objects (optional)
|
90
|
-
- **Default**: `null`
|
91
|
-
- **Example** (Programmatic):
|
92
|
-
```python
|
93
|
-
config = AgentConfig(tools=[my_custom_tool])
|
94
|
-
```
|
95
|
-
|
96
|
-
---
|
97
|
-
|
98
|
-
### `max_history_tokens`
|
99
|
-
- **Description**: Limits the number of tokens stored in the agent’s history, affecting memory usage and context retention.
|
100
|
-
- **Type**: Integer
|
101
|
-
- **Default**: `8000` (from `MAX_HISTORY_TOKENS`)
|
102
|
-
- **Example**:
|
103
|
-
```yaml
|
104
|
-
max_history_tokens: 4000
|
105
|
-
```
|
106
|
-
|
107
|
-
---
|
108
|
-
|
109
|
-
### `toolbox_directory`
|
110
|
-
- **Description**: Directory where custom toolbox modules are stored (used for local tool development).
|
111
|
-
- **Type**: String
|
112
|
-
- **Default**: `"toolboxes"`
|
113
|
-
- **Example**:
|
114
|
-
```yaml
|
115
|
-
toolbox_directory: "custom_tools"
|
116
|
-
```
|
117
|
-
|
118
|
-
---
|
119
|
-
|
120
|
-
### `enabled_toolboxes`
|
121
|
-
- **Description**: A list of toolbox names to load from registered entry points (e.g., installed Python packages).
|
122
|
-
- **Type**: List of strings (optional)
|
123
|
-
- **Default**: `null`
|
124
|
-
- **Example**:
|
125
|
-
```yaml
|
126
|
-
enabled_toolboxes:
|
127
|
-
- "math_tools"
|
128
|
-
- "text_tools"
|
129
|
-
```
|
130
|
-
|
131
|
-
---
|
132
|
-
|
133
|
-
### `reasoner_name` (Legacy)
|
134
|
-
- **Description**: Specifies the name of the reasoner plugin to use (older format, kept for compatibility).
|
135
|
-
- **Type**: String
|
136
|
-
- **Default**: `"default"`
|
137
|
-
- **Example**:
|
138
|
-
```yaml
|
139
|
-
reasoner_name: "advanced_reasoner"
|
140
|
-
```
|
141
|
-
|
142
|
-
---
|
143
|
-
|
144
|
-
### `executor_name` (Legacy)
|
145
|
-
- **Description**: Specifies the name of the executor plugin to use (older format, kept for compatibility).
|
146
|
-
- **Type**: String
|
147
|
-
- **Default**: `"default"`
|
148
|
-
- **Example**:
|
149
|
-
```yaml
|
150
|
-
executor_name: "secure_executor"
|
151
|
-
```
|
152
|
-
|
153
|
-
---
|
154
|
-
|
155
|
-
### `personality`
|
156
|
-
- **Description**: Defines the agent’s personality, influencing its system prompt. Can be a simple string (legacy) or a structured dictionary.
|
157
|
-
- **Type**: String or Dictionary (optional)
|
158
|
-
- **Default**: `null`
|
159
|
-
- **Subfields (when dictionary)**:
|
160
|
-
- `traits`: List of personality traits (e.g., "witty", "helpful").
|
161
|
-
- `tone`: Tone of responses (e.g., "formal", "casual").
|
162
|
-
- `humor_level`: Level of humor (e.g., "low", "medium", "high").
|
163
|
-
- **Examples**:
|
164
|
-
- Simple:
|
165
|
-
```yaml
|
166
|
-
personality: "witty"
|
167
|
-
```
|
168
|
-
- Structured:
|
169
|
-
```yaml
|
170
|
-
personality:
|
171
|
-
traits:
|
172
|
-
- "witty"
|
173
|
-
- "helpful"
|
174
|
-
tone: "informal"
|
175
|
-
humor_level: "medium"
|
176
|
-
```
|
177
|
-
|
178
|
-
---
|
179
|
-
|
180
|
-
### `backstory`
|
181
|
-
- **Description**: Provides a backstory for the agent, included in the system prompt. Can be a string (legacy) or a dictionary.
|
182
|
-
- **Type**: String or Dictionary (optional)
|
183
|
-
- **Default**: `null`
|
184
|
-
- **Subfields (when dictionary)**:
|
185
|
-
- `origin`: Where the agent was created.
|
186
|
-
- `purpose`: The agent’s intended purpose.
|
187
|
-
- `experience`: Relevant past experience.
|
188
|
-
- **Examples**:
|
189
|
-
- Simple:
|
190
|
-
```yaml
|
191
|
-
backstory: "A seasoned AI assistant."
|
192
|
-
```
|
193
|
-
- Structured:
|
194
|
-
```yaml
|
195
|
-
backstory:
|
196
|
-
origin: "Created by Quantalogic."
|
197
|
-
purpose: "Solve complex problems."
|
198
|
-
experience: "Trained on 10,000+ math tasks."
|
199
|
-
```
|
200
|
-
|
201
|
-
---
|
202
|
-
|
203
|
-
### `sop`
|
204
|
-
- **Description**: Standard Operating Procedure (SOP) as a multi-line string, guiding the agent’s behavior.
|
205
|
-
- **Type**: String (optional)
|
206
|
-
- **Default**: `null`
|
207
|
-
- **Example**:
|
208
|
-
```yaml
|
209
|
-
sop: |
|
210
|
-
Always provide clear, concise answers.
|
211
|
-
Prioritize accuracy over speed.
|
212
|
-
```
|
213
|
-
|
214
|
-
---
|
215
|
-
|
216
|
-
### `tools_config`
|
217
|
-
- **Description**: Configures specific tools or toolboxes, allowing enabling/disabling and setting properties.
|
218
|
-
- **Type**: List of dictionaries (optional)
|
219
|
-
- **Default**: `null`
|
220
|
-
- **Subfields**:
|
221
|
-
- `name`: Name of the tool or toolbox (matches `tool.name` or `tool.toolbox_name`).
|
222
|
-
- `enabled`: Boolean to include/exclude the tool/toolbox (default: `true`).
|
223
|
-
- Additional key-value pairs: Properties to set on the tool (e.g., `config`, `precision`).
|
224
|
-
- **Example**:
|
225
|
-
```yaml
|
226
|
-
tools_config:
|
227
|
-
- name: "math_tools"
|
228
|
-
enabled: true
|
229
|
-
config:
|
230
|
-
precision: "high"
|
231
|
-
- name: "agent_tool"
|
232
|
-
enabled: false
|
233
|
-
model: "custom_model"
|
234
|
-
```
|
235
|
-
|
236
|
-
---
|
237
|
-
|
238
|
-
### `reasoner`
|
239
|
-
- **Description**: Configures the reasoning component, replacing `reasoner_name` with added flexibility.
|
240
|
-
- **Type**: Dictionary (optional)
|
241
|
-
- **Default**: `{"name": "default"}`
|
242
|
-
- **Subfields**:
|
243
|
-
- `name`: Name of the reasoner plugin (e.g., `"default"`).
|
244
|
-
- `config`: Dictionary of reasoner-specific settings (e.g., `temperature`, `max_tokens`).
|
245
|
-
- **Example**:
|
246
|
-
```yaml
|
247
|
-
reasoner:
|
248
|
-
name: "default"
|
249
|
-
config:
|
250
|
-
temperature: 0.7
|
251
|
-
max_tokens: 1500
|
252
|
-
```
|
253
|
-
|
254
|
-
---
|
255
|
-
|
256
|
-
### `executor`
|
257
|
-
- **Description**: Configures the execution component, replacing `executor_name`.
|
258
|
-
- **Type**: Dictionary (optional)
|
259
|
-
- **Default**: `{"name": "default"}`
|
260
|
-
- **Subfields**:
|
261
|
-
- `name`: Name of the executor plugin (e.g., `"default"`).
|
262
|
-
- `config`: Dictionary of executor-specific settings (e.g., `timeout`).
|
263
|
-
- **Example**:
|
264
|
-
```yaml
|
265
|
-
executor:
|
266
|
-
name: "default"
|
267
|
-
config:
|
268
|
-
timeout: 600
|
269
|
-
```
|
270
|
-
|
271
|
-
---
|
272
|
-
|
273
|
-
### `profile`
|
274
|
-
- **Description**: Selects a predefined agent profile, setting defaults for other fields.
|
275
|
-
- **Type**: String (optional)
|
276
|
-
- **Default**: `null`
|
277
|
-
- **Supported Profiles**:
|
278
|
-
- `"math_expert"`: Configures for mathematical tasks.
|
279
|
-
- `"creative_writer"`: Configures for creative tasks.
|
280
|
-
- **Example**:
|
281
|
-
```yaml
|
282
|
-
profile: "math_expert"
|
283
|
-
```
|
284
|
-
|
285
|
-
---
|
286
|
-
|
287
|
-
### `customizations`
|
288
|
-
- **Description**: Overrides or extends profile defaults with custom settings.
|
289
|
-
- **Type**: Dictionary (optional)
|
290
|
-
- **Default**: `null`
|
291
|
-
- **Example**:
|
292
|
-
```yaml
|
293
|
-
profile: "math_expert"
|
294
|
-
customizations:
|
295
|
-
personality:
|
296
|
-
traits:
|
297
|
-
- "witty"
|
298
|
-
tools_config:
|
299
|
-
- name: "advanced_calculus"
|
300
|
-
enabled: true
|
301
|
-
```
|
302
|
-
|
303
|
-
---
|
304
|
-
|
305
|
-
## Tool Configuration Details
|
306
|
-
(unchanged from previous documentation, included for completeness)
|
307
|
-
|
308
|
-
---
|
309
|
-
|
310
|
-
## Backward Compatibility
|
311
|
-
|
312
|
-
The updated configuration format remains fully compatible with older versions:
|
313
|
-
- **New Field (`name`)**: Optional, defaults to `null`, so existing configs without `name` work unchanged.
|
314
|
-
- **Legacy Fields**: `reasoner_name`, `executor_name`, `personality` (string), and `backstory` (string) are still supported.
|
315
|
-
- **Minimal Configs**: A simple config like:
|
316
|
-
```yaml
|
317
|
-
model: "gemini/gemini-2.0-flash"
|
318
|
-
```
|
319
|
-
functions as before.
|
320
|
-
|
321
|
-
---
|
322
|
-
|
323
|
-
## Usage
|
324
|
-
|
325
|
-
### Example with Name
|
326
|
-
```yaml
|
327
|
-
name: "MathWizard"
|
328
|
-
model: "gemini/gemini-2.0-flash"
|
329
|
-
max_iterations: 5
|
330
|
-
profile: "math_expert"
|
331
|
-
```
|
332
|
-
|
333
|
-
The agent will introduce itself as: "I am MathWizard, an AI assistant with the following personality traits: precise, logical."
|
334
|
-
|
335
|
-
---
|
336
|
-
|
337
|
-
## Best Practices
|
338
|
-
|
339
|
-
- **Use `name`**: Assign a unique name to distinguish agents in multi-agent setups or logs.
|
340
|
-
- **Profiles**: Leverage `profile` for quick setup, refining with `customizations`.
|
341
|
-
- **Secrets**: Use `{{ env.VAR_NAME }}` for sensitive data in `tools_config`.
|
342
|
-
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# Model configuration
|
2
|
-
model: "deepseek/deepseek-chat"
|
3
|
-
# Task-solving parameters
|
4
|
-
max_iterations: 5
|
5
|
-
max_history_tokens: 2000
|
6
|
-
# Toolbox and tool configuration
|
7
|
-
toolbox_directory: "toolboxes"
|
8
|
-
enabled_toolboxes:
|
9
|
-
- math_tools
|
10
|
-
# Component selection
|
11
|
-
reasoner:
|
12
|
-
name: "default"
|
13
|
-
executor:
|
14
|
-
name: "default"
|
15
|
-
# Agent personality and behavior
|
16
|
-
profile: "math_expert"
|
17
|
-
customizations:
|
18
|
-
personality:
|
19
|
-
traits:
|
20
|
-
- witty
|
21
|
-
tools_config:
|
22
|
-
- name: "math_tools"
|
23
|
-
enabled: true
|
24
|
-
config:
|
25
|
-
precision: "high"
|
26
|
-
sop: |
|
27
|
-
Always provide clear, concise answers.
|
28
|
-
Prioritize mathematical accuracy and user satisfaction.
|
29
|
-
Inject humor where appropriate to keep interactions engaging.
|
quantalogic/codeact/executor.py
DELETED
@@ -1,186 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
import types
|
3
|
-
from abc import ABC, abstractmethod
|
4
|
-
from typing import Any, Callable, Dict, List, Optional # Added Optional, Any
|
5
|
-
|
6
|
-
from lxml import etree
|
7
|
-
from quantalogic_pythonbox import AsyncExecutionResult, execute_async
|
8
|
-
|
9
|
-
from quantalogic.tools import Tool
|
10
|
-
|
11
|
-
from .events import ToolExecutionCompletedEvent, ToolExecutionErrorEvent, ToolExecutionStartedEvent
|
12
|
-
from .tools_manager import ToolRegistry
|
13
|
-
from .utils import validate_code
|
14
|
-
from .xml_utils import XMLResultHandler
|
15
|
-
|
16
|
-
|
17
|
-
class BaseExecutor(ABC):
|
18
|
-
"""Abstract base class for execution components."""
|
19
|
-
|
20
|
-
@abstractmethod
|
21
|
-
async def execute_action(self, code: str, context_vars: Dict, step: int, timeout: int) -> str:
|
22
|
-
pass
|
23
|
-
|
24
|
-
@abstractmethod
|
25
|
-
def register_tool(self, tool: Tool) -> None:
|
26
|
-
pass
|
27
|
-
|
28
|
-
|
29
|
-
class Executor(BaseExecutor):
|
30
|
-
"""Manages action execution and context updates with dynamic tool registration."""
|
31
|
-
|
32
|
-
def __init__(self, tools: List[Tool], notify_event: Callable, config: Optional[Dict[str, Any]] = None, verbose: bool = True):
|
33
|
-
self.registry = ToolRegistry()
|
34
|
-
for tool in tools:
|
35
|
-
self.registry.register(tool)
|
36
|
-
self.tools: Dict[tuple[str, str], Tool] = self.registry.tools
|
37
|
-
self.notify_event = notify_event
|
38
|
-
self.config = config or {}
|
39
|
-
self.verbose = verbose
|
40
|
-
self.tool_namespace = self._build_tool_namespace()
|
41
|
-
|
42
|
-
def _build_tool_namespace(self) -> Dict:
|
43
|
-
"""Build the namespace with tools grouped by toolbox using SimpleNamespace."""
|
44
|
-
if not self.verbose:
|
45
|
-
toolboxes = {}
|
46
|
-
for (toolbox_name, tool_name), tool in self.tools.items():
|
47
|
-
if toolbox_name not in toolboxes:
|
48
|
-
toolboxes[toolbox_name] = types.SimpleNamespace()
|
49
|
-
setattr(toolboxes[toolbox_name], tool_name, tool.async_execute)
|
50
|
-
return {
|
51
|
-
"asyncio": asyncio,
|
52
|
-
"context_vars": {},
|
53
|
-
**toolboxes,
|
54
|
-
}
|
55
|
-
|
56
|
-
def wrap_tool(tool):
|
57
|
-
async def wrapped_tool(**kwargs):
|
58
|
-
current_step = self.tool_namespace.get("current_step", None)
|
59
|
-
parameters_summary = {
|
60
|
-
k: str(v)[:100] + "..." if len(str(v)) > 100 else str(v) for k, v in kwargs.items()
|
61
|
-
}
|
62
|
-
await self.notify_event(
|
63
|
-
ToolExecutionStartedEvent(
|
64
|
-
event_type="ToolExecutionStarted",
|
65
|
-
step_number=current_step,
|
66
|
-
tool_name=f"{tool.toolbox_name or 'default'}.{tool.name}",
|
67
|
-
parameters_summary=parameters_summary,
|
68
|
-
)
|
69
|
-
)
|
70
|
-
try:
|
71
|
-
result = await tool.async_execute(**kwargs)
|
72
|
-
result_summary = str(result)[:100] + "..." if len(str(result)) > 100 else str(result)
|
73
|
-
await self.notify_event(
|
74
|
-
ToolExecutionCompletedEvent(
|
75
|
-
event_type="ToolExecutionCompleted",
|
76
|
-
step_number=current_step,
|
77
|
-
tool_name=f"{tool.toolbox_name or 'default'}.{tool.name}",
|
78
|
-
result_summary=result_summary,
|
79
|
-
)
|
80
|
-
)
|
81
|
-
return result
|
82
|
-
except Exception as e:
|
83
|
-
await self.notify_event(
|
84
|
-
ToolExecutionErrorEvent(
|
85
|
-
event_type="ToolExecutionError",
|
86
|
-
step_number=current_step,
|
87
|
-
tool_name=f"{tool.toolbox_name or 'default'}.{tool.name}",
|
88
|
-
error=str(e)
|
89
|
-
)
|
90
|
-
)
|
91
|
-
raise
|
92
|
-
|
93
|
-
return wrapped_tool
|
94
|
-
|
95
|
-
toolboxes = {}
|
96
|
-
for (toolbox_name, tool_name), tool in self.tools.items():
|
97
|
-
if toolbox_name not in toolboxes:
|
98
|
-
toolboxes[toolbox_name] = types.SimpleNamespace()
|
99
|
-
setattr(toolboxes[toolbox_name], tool_name, wrap_tool(tool))
|
100
|
-
|
101
|
-
return {
|
102
|
-
"asyncio": asyncio,
|
103
|
-
"context_vars": {},
|
104
|
-
**toolboxes,
|
105
|
-
}
|
106
|
-
|
107
|
-
def register_tool(self, tool: Tool) -> None:
|
108
|
-
"""Register a new tool dynamically at runtime."""
|
109
|
-
self.registry.register(tool)
|
110
|
-
key = (tool.toolbox_name or "default", tool.name)
|
111
|
-
self.tools[key] = tool
|
112
|
-
toolbox_name = tool.toolbox_name or "default"
|
113
|
-
if toolbox_name not in self.tool_namespace:
|
114
|
-
self.tool_namespace[toolbox_name] = types.SimpleNamespace()
|
115
|
-
setattr(self.tool_namespace[toolbox_name], tool.name,
|
116
|
-
self._wrap_tool(tool) if self.verbose else tool.async_execute)
|
117
|
-
|
118
|
-
def _wrap_tool(self, tool: Tool) -> Callable:
|
119
|
-
"""Wrap a tool function to handle execution events (internal use)."""
|
120
|
-
async def wrapped_tool(**kwargs):
|
121
|
-
current_step = self.tool_namespace.get("current_step", None)
|
122
|
-
parameters_summary = {k: str(v)[:100] + "..." if len(str(v)) > 100 else str(v) for k, v in kwargs.items()}
|
123
|
-
await self.notify_event(
|
124
|
-
ToolExecutionStartedEvent(
|
125
|
-
event_type="ToolExecutionStarted",
|
126
|
-
step_number=current_step,
|
127
|
-
tool_name=f"{tool.toolbox_name or 'default'}.{tool.name}",
|
128
|
-
parameters_summary=parameters_summary,
|
129
|
-
)
|
130
|
-
)
|
131
|
-
try:
|
132
|
-
result = await tool.async_execute(**kwargs)
|
133
|
-
result_summary = str(result)[:100] + "..." if len(str(result)) > 100 else str(result)
|
134
|
-
await self.notify_event(
|
135
|
-
ToolExecutionCompletedEvent(
|
136
|
-
event_type="ToolExecutionCompleted",
|
137
|
-
step_number=current_step,
|
138
|
-
tool_name=f"{tool.toolbox_name or 'default'}.{tool.name}",
|
139
|
-
result_summary=result_summary,
|
140
|
-
)
|
141
|
-
)
|
142
|
-
return result
|
143
|
-
except Exception as e:
|
144
|
-
await self.notify_event(
|
145
|
-
ToolExecutionErrorEvent(
|
146
|
-
event_type="ToolExecutionError",
|
147
|
-
step_number=current_step,
|
148
|
-
tool_name=f"{tool.toolbox_name or 'default'}.{tool.name}",
|
149
|
-
error=str(e)
|
150
|
-
)
|
151
|
-
)
|
152
|
-
raise
|
153
|
-
|
154
|
-
return wrapped_tool
|
155
|
-
|
156
|
-
async def execute_action(self, code: str, context_vars: Dict, step: int, timeout: int = 300) -> str:
|
157
|
-
"""Execute the generated code and return the result with local variables, setting the step number."""
|
158
|
-
self.tool_namespace["context_vars"] = context_vars
|
159
|
-
self.tool_namespace["current_step"] = step
|
160
|
-
timeout = self.config.get("timeout", timeout) # Use config timeout if provided
|
161
|
-
if not validate_code(code):
|
162
|
-
return etree.tostring(
|
163
|
-
etree.Element("ExecutionResult", status="Error", message="Code lacks async main()"), encoding="unicode"
|
164
|
-
)
|
165
|
-
|
166
|
-
try:
|
167
|
-
result: AsyncExecutionResult = await execute_async(
|
168
|
-
code=code,
|
169
|
-
timeout=timeout,
|
170
|
-
entry_point="main",
|
171
|
-
allowed_modules=["asyncio", "math", "random", "time"],
|
172
|
-
namespace=self.tool_namespace,
|
173
|
-
ignore_typing=True
|
174
|
-
)
|
175
|
-
if result.local_variables:
|
176
|
-
context_vars.update(
|
177
|
-
{k: v for k, v in result.local_variables.items() if not k.startswith("__") and not callable(v)}
|
178
|
-
)
|
179
|
-
return XMLResultHandler.format_execution_result(result)
|
180
|
-
except Exception as e:
|
181
|
-
root = etree.Element("ExecutionResult")
|
182
|
-
root.append(etree.Element("Status", text="Error"))
|
183
|
-
root.append(etree.Element("Value", text=f"Execution error: {str(e)}"))
|
184
|
-
root.append(etree.Element("ExecutionTime", text="0.00 seconds"))
|
185
|
-
root.append(etree.Element("Completed", text="false"))
|
186
|
-
return etree.tostring(root, pretty_print=True, encoding="unicode")
|
@@ -1,94 +0,0 @@
|
|
1
|
-
"""History management module for storing and formatting agent steps."""
|
2
|
-
|
3
|
-
from typing import Dict, List
|
4
|
-
|
5
|
-
from loguru import logger
|
6
|
-
from lxml import etree
|
7
|
-
|
8
|
-
from .xml_utils import XMLResultHandler
|
9
|
-
|
10
|
-
|
11
|
-
class HistoryManager:
|
12
|
-
"""Manages the storage and formatting of agent step history with persistent context."""
|
13
|
-
|
14
|
-
def __init__(self, max_tokens: int = 64*1024, system_prompt: str = "", task_description: str = ""):
|
15
|
-
"""
|
16
|
-
Initialize the HistoryManager with a token limit and persistent context.
|
17
|
-
|
18
|
-
Args:
|
19
|
-
max_tokens (int): Maximum number of tokens for history formatting (default: 16000).
|
20
|
-
system_prompt (str): Persistent system-level instructions for the agent (default: "").
|
21
|
-
task_description (str): Persistent description of the current task (default: "").
|
22
|
-
"""
|
23
|
-
self.max_tokens: int = max_tokens
|
24
|
-
self.system_prompt: str = system_prompt
|
25
|
-
self.task_description: str = task_description
|
26
|
-
self.store: List[Dict] = []
|
27
|
-
logger.debug(f"Initialized HistoryManager with system_prompt: '{system_prompt}', task_description: '{task_description}'")
|
28
|
-
|
29
|
-
def add_step(self, step_data: Dict) -> None:
|
30
|
-
"""
|
31
|
-
Add a step to the history store.
|
32
|
-
|
33
|
-
Args:
|
34
|
-
step_data (Dict): Dictionary containing step details (step_number, thought, action, result).
|
35
|
-
"""
|
36
|
-
self.store.append(step_data)
|
37
|
-
logger.debug(f"Added step {step_data['step_number']} to history")
|
38
|
-
|
39
|
-
def format_history(self, max_iterations: int) -> str:
|
40
|
-
"""
|
41
|
-
Format the history with available variables, truncating to fit within max_tokens.
|
42
|
-
|
43
|
-
Args:
|
44
|
-
max_iterations (int): Maximum allowed iterations for context.
|
45
|
-
|
46
|
-
Returns:
|
47
|
-
str: Formatted string of previous steps, or "No previous steps" if empty.
|
48
|
-
"""
|
49
|
-
included_steps: List[str] = []
|
50
|
-
total_tokens: int = 0
|
51
|
-
for step in reversed(self.store):
|
52
|
-
try:
|
53
|
-
root = etree.fromstring(step['result'])
|
54
|
-
vars_elem = root.find("Variables")
|
55
|
-
available_vars = (
|
56
|
-
[var.get('name') for var in vars_elem.findall("Variable")]
|
57
|
-
if vars_elem is not None else []
|
58
|
-
)
|
59
|
-
except etree.XMLSyntaxError:
|
60
|
-
available_vars = []
|
61
|
-
|
62
|
-
step_str: str = (
|
63
|
-
f"===== Step {step['step_number']} of {max_iterations} max =====\n"
|
64
|
-
f"Thought:\n{step['thought']}\n\n"
|
65
|
-
f"Action:\n{step['action']}\n\n"
|
66
|
-
f"Result:\n{XMLResultHandler.format_result_summary(step['result']) if step.get('result') else 'No result available'}\n"
|
67
|
-
f"Available variables: {', '.join(available_vars) or 'None'}"
|
68
|
-
)
|
69
|
-
step_tokens: int = len(step_str.split())
|
70
|
-
if total_tokens + step_tokens > self.max_tokens:
|
71
|
-
break
|
72
|
-
included_steps.append(step_str)
|
73
|
-
total_tokens += step_tokens
|
74
|
-
return "\n".join(reversed(included_steps)) or "No previous steps"
|
75
|
-
|
76
|
-
def get_full_context(self, max_iterations: int) -> str:
|
77
|
-
"""
|
78
|
-
Return the full context including system prompt, task description, and formatted history.
|
79
|
-
|
80
|
-
Args:
|
81
|
-
max_iterations (int): Maximum allowed iterations for history formatting.
|
82
|
-
|
83
|
-
Returns:
|
84
|
-
str: Combined string of system prompt, task description, and history.
|
85
|
-
"""
|
86
|
-
context_parts = []
|
87
|
-
if self.system_prompt:
|
88
|
-
context_parts.append(f"System Prompt:\n{self.system_prompt}")
|
89
|
-
if self.task_description:
|
90
|
-
context_parts.append(f"Task Description:\n{self.task_description}")
|
91
|
-
history_str = self.format_history(max_iterations)
|
92
|
-
if history_str != "No previous steps":
|
93
|
-
context_parts.append(f"History:\n{history_str}")
|
94
|
-
return "\n\n".join(context_parts)
|