massgen 0.1.0a3__py3-none-any.whl → 0.1.1__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.
Potentially problematic release.
This version of massgen might be problematic. Click here for more details.
- massgen/__init__.py +1 -1
- massgen/agent_config.py +17 -0
- massgen/api_params_handler/_api_params_handler_base.py +1 -0
- massgen/api_params_handler/_chat_completions_api_params_handler.py +8 -1
- massgen/api_params_handler/_claude_api_params_handler.py +8 -1
- massgen/api_params_handler/_gemini_api_params_handler.py +73 -0
- massgen/api_params_handler/_response_api_params_handler.py +8 -1
- massgen/backend/base.py +31 -0
- massgen/backend/{base_with_mcp.py → base_with_custom_tool_and_mcp.py} +282 -11
- massgen/backend/chat_completions.py +182 -92
- massgen/backend/claude.py +115 -18
- massgen/backend/claude_code.py +378 -14
- massgen/backend/docs/CLAUDE_API_RESEARCH.md +3 -3
- massgen/backend/gemini.py +1275 -1607
- massgen/backend/gemini_mcp_manager.py +545 -0
- massgen/backend/gemini_trackers.py +344 -0
- massgen/backend/gemini_utils.py +43 -0
- massgen/backend/response.py +129 -70
- massgen/cli.py +577 -110
- massgen/config_builder.py +376 -27
- massgen/configs/README.md +111 -80
- massgen/configs/basic/multi/three_agents_default.yaml +1 -1
- massgen/configs/basic/single/single_agent.yaml +1 -1
- massgen/configs/providers/openai/gpt5_nano.yaml +3 -3
- massgen/configs/tools/custom_tools/claude_code_custom_tool_example.yaml +32 -0
- massgen/configs/tools/custom_tools/claude_code_custom_tool_example_no_path.yaml +28 -0
- massgen/configs/tools/custom_tools/claude_code_custom_tool_with_mcp_example.yaml +40 -0
- massgen/configs/tools/custom_tools/claude_code_custom_tool_with_wrong_mcp_example.yaml +38 -0
- massgen/configs/tools/custom_tools/claude_code_wrong_custom_tool_with_mcp_example.yaml +38 -0
- massgen/configs/tools/custom_tools/claude_custom_tool_example.yaml +24 -0
- massgen/configs/tools/custom_tools/claude_custom_tool_example_no_path.yaml +22 -0
- massgen/configs/tools/custom_tools/claude_custom_tool_with_mcp_example.yaml +35 -0
- massgen/configs/tools/custom_tools/claude_custom_tool_with_wrong_mcp_example.yaml +33 -0
- massgen/configs/tools/custom_tools/claude_wrong_custom_tool_with_mcp_example.yaml +33 -0
- massgen/configs/tools/custom_tools/gemini_custom_tool_example.yaml +24 -0
- massgen/configs/tools/custom_tools/gemini_custom_tool_example_no_path.yaml +22 -0
- massgen/configs/tools/custom_tools/gemini_custom_tool_with_mcp_example.yaml +35 -0
- massgen/configs/tools/custom_tools/gemini_custom_tool_with_wrong_mcp_example.yaml +33 -0
- massgen/configs/tools/custom_tools/gemini_wrong_custom_tool_with_mcp_example.yaml +33 -0
- massgen/configs/tools/custom_tools/github_issue_market_analysis.yaml +94 -0
- massgen/configs/tools/custom_tools/gpt5_nano_custom_tool_example.yaml +24 -0
- massgen/configs/tools/custom_tools/gpt5_nano_custom_tool_example_no_path.yaml +22 -0
- massgen/configs/tools/custom_tools/gpt5_nano_custom_tool_with_mcp_example.yaml +35 -0
- massgen/configs/tools/custom_tools/gpt5_nano_custom_tool_with_wrong_mcp_example.yaml +33 -0
- massgen/configs/tools/custom_tools/gpt5_nano_wrong_custom_tool_with_mcp_example.yaml +33 -0
- massgen/configs/tools/custom_tools/gpt_oss_custom_tool_example.yaml +25 -0
- massgen/configs/tools/custom_tools/gpt_oss_custom_tool_example_no_path.yaml +23 -0
- massgen/configs/tools/custom_tools/gpt_oss_custom_tool_with_mcp_example.yaml +34 -0
- massgen/configs/tools/custom_tools/gpt_oss_custom_tool_with_wrong_mcp_example.yaml +34 -0
- massgen/configs/tools/custom_tools/gpt_oss_wrong_custom_tool_with_mcp_example.yaml +34 -0
- massgen/configs/tools/custom_tools/grok3_mini_custom_tool_example.yaml +24 -0
- massgen/configs/tools/custom_tools/grok3_mini_custom_tool_example_no_path.yaml +22 -0
- massgen/configs/tools/custom_tools/grok3_mini_custom_tool_with_mcp_example.yaml +35 -0
- massgen/configs/tools/custom_tools/grok3_mini_custom_tool_with_wrong_mcp_example.yaml +33 -0
- massgen/configs/tools/custom_tools/grok3_mini_wrong_custom_tool_with_mcp_example.yaml +33 -0
- massgen/configs/tools/custom_tools/qwen_api_custom_tool_example.yaml +25 -0
- massgen/configs/tools/custom_tools/qwen_api_custom_tool_example_no_path.yaml +23 -0
- massgen/configs/tools/custom_tools/qwen_api_custom_tool_with_mcp_example.yaml +36 -0
- massgen/configs/tools/custom_tools/qwen_api_custom_tool_with_wrong_mcp_example.yaml +34 -0
- massgen/configs/tools/custom_tools/qwen_api_wrong_custom_tool_with_mcp_example.yaml +34 -0
- massgen/configs/tools/custom_tools/qwen_local_custom_tool_example.yaml +24 -0
- massgen/configs/tools/custom_tools/qwen_local_custom_tool_example_no_path.yaml +22 -0
- massgen/configs/tools/custom_tools/qwen_local_custom_tool_with_mcp_example.yaml +35 -0
- massgen/configs/tools/custom_tools/qwen_local_custom_tool_with_wrong_mcp_example.yaml +33 -0
- massgen/configs/tools/custom_tools/qwen_local_wrong_custom_tool_with_mcp_example.yaml +33 -0
- massgen/configs/tools/filesystem/claude_code_context_sharing.yaml +1 -1
- massgen/configs/voting/gemini_gpt_voting_sensitivity.yaml +67 -0
- massgen/formatter/_chat_completions_formatter.py +104 -0
- massgen/formatter/_claude_formatter.py +120 -0
- massgen/formatter/_gemini_formatter.py +448 -0
- massgen/formatter/_response_formatter.py +88 -0
- massgen/frontend/coordination_ui.py +4 -2
- massgen/logger_config.py +35 -3
- massgen/message_templates.py +56 -6
- massgen/orchestrator.py +179 -10
- massgen/stream_chunk/base.py +3 -0
- massgen/tests/custom_tools_example.py +392 -0
- massgen/tests/mcp_test_server.py +17 -7
- massgen/tests/test_config_builder.py +423 -0
- massgen/tests/test_custom_tools.py +401 -0
- massgen/tests/test_tools.py +127 -0
- massgen/tool/README.md +935 -0
- massgen/tool/__init__.py +39 -0
- massgen/tool/_async_helpers.py +70 -0
- massgen/tool/_basic/__init__.py +8 -0
- massgen/tool/_basic/_two_num_tool.py +24 -0
- massgen/tool/_code_executors/__init__.py +10 -0
- massgen/tool/_code_executors/_python_executor.py +74 -0
- massgen/tool/_code_executors/_shell_executor.py +61 -0
- massgen/tool/_exceptions.py +39 -0
- massgen/tool/_file_handlers/__init__.py +10 -0
- massgen/tool/_file_handlers/_file_operations.py +218 -0
- massgen/tool/_manager.py +634 -0
- massgen/tool/_registered_tool.py +88 -0
- massgen/tool/_result.py +66 -0
- massgen/tool/_self_evolution/_github_issue_analyzer.py +369 -0
- massgen/tool/docs/builtin_tools.md +681 -0
- massgen/tool/docs/exceptions.md +794 -0
- massgen/tool/docs/execution_results.md +691 -0
- massgen/tool/docs/manager.md +887 -0
- massgen/tool/docs/workflow_toolkits.md +529 -0
- massgen/tool/workflow_toolkits/__init__.py +57 -0
- massgen/tool/workflow_toolkits/base.py +55 -0
- massgen/tool/workflow_toolkits/new_answer.py +126 -0
- massgen/tool/workflow_toolkits/vote.py +167 -0
- {massgen-0.1.0a3.dist-info → massgen-0.1.1.dist-info}/METADATA +89 -131
- {massgen-0.1.0a3.dist-info → massgen-0.1.1.dist-info}/RECORD +111 -36
- {massgen-0.1.0a3.dist-info → massgen-0.1.1.dist-info}/WHEEL +0 -0
- {massgen-0.1.0a3.dist-info → massgen-0.1.1.dist-info}/entry_points.txt +0 -0
- {massgen-0.1.0a3.dist-info → massgen-0.1.1.dist-info}/licenses/LICENSE +0 -0
- {massgen-0.1.0a3.dist-info → massgen-0.1.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,681 @@
|
|
|
1
|
+
# Built-in Tools Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
MassGen provides a comprehensive set of built-in tools that give AI agents capabilities for code execution, file operations, and multimedia processing. These tools are production-ready, well-tested, and designed to integrate seamlessly with the Tool System.
|
|
6
|
+
|
|
7
|
+
## Tool Categories
|
|
8
|
+
|
|
9
|
+
Built-in tools are organized into several categories:
|
|
10
|
+
|
|
11
|
+
- **Code Executors**: Run Python and shell scripts safely
|
|
12
|
+
- **File Handlers**: Read, write, and modify files
|
|
13
|
+
- **Workflow Toolkits**: Specialized tools for agent coordination
|
|
14
|
+
|
|
15
|
+
## Code Execution Tools
|
|
16
|
+
|
|
17
|
+
### run_python_script
|
|
18
|
+
|
|
19
|
+
**What it does**: Executes Python code in an isolated subprocess environment. The code runs in a temporary file that's automatically cleaned up after execution.
|
|
20
|
+
|
|
21
|
+
**Why use it**: Allows agents to run Python code for calculations, data processing, or any task that requires Python. Isolation prevents interference with the main process.
|
|
22
|
+
|
|
23
|
+
**Location**: `massgen.tool._code_executors._python_executor`
|
|
24
|
+
|
|
25
|
+
#### Parameters
|
|
26
|
+
|
|
27
|
+
- `source_code` (required): Python code to execute as a string
|
|
28
|
+
- `max_duration` (optional): Maximum execution time in seconds (default: 300)
|
|
29
|
+
- `**extra_kwargs`: Additional keyword arguments (currently unused, reserved for future use)
|
|
30
|
+
|
|
31
|
+
#### Returns
|
|
32
|
+
|
|
33
|
+
ExecutionResult containing:
|
|
34
|
+
- `<exit_code>`: Process exit code (0 for success)
|
|
35
|
+
- `<stdout>`: Standard output from the script
|
|
36
|
+
- `<stderr>`: Standard error output
|
|
37
|
+
|
|
38
|
+
#### Security Features
|
|
39
|
+
|
|
40
|
+
- Runs in isolated subprocess
|
|
41
|
+
- Timeout protection (default 300 seconds)
|
|
42
|
+
- Temporary file cleanup
|
|
43
|
+
- No access to parent process environment
|
|
44
|
+
|
|
45
|
+
#### Examples
|
|
46
|
+
|
|
47
|
+
**Basic Calculation**:
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from massgen.tool import run_python_script
|
|
51
|
+
|
|
52
|
+
# Simple calculation
|
|
53
|
+
code = """
|
|
54
|
+
result = 2 + 2
|
|
55
|
+
print(f"Result: {result}")
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
result = await run_python_script(source_code=code)
|
|
59
|
+
print(result.output_blocks[0].data)
|
|
60
|
+
# Output:
|
|
61
|
+
# <exit_code>0</exit_code>
|
|
62
|
+
# <stdout>Result: 4
|
|
63
|
+
# </stdout>
|
|
64
|
+
# <stderr></stderr>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Data Processing**:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
# Process a list
|
|
71
|
+
code = """
|
|
72
|
+
data = [1, 2, 3, 4, 5]
|
|
73
|
+
squared = [x**2 for x in data]
|
|
74
|
+
print(f"Squared: {squared}")
|
|
75
|
+
print(f"Sum: {sum(squared)}")
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
result = await run_python_script(source_code=code)
|
|
79
|
+
# Output includes squared values and sum
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**With External Libraries**:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
# Use installed packages
|
|
86
|
+
code = """
|
|
87
|
+
import json
|
|
88
|
+
import math
|
|
89
|
+
|
|
90
|
+
data = {"values": [1, 4, 9, 16, 25]}
|
|
91
|
+
sqrt_values = [math.sqrt(x) for x in data["values"]]
|
|
92
|
+
|
|
93
|
+
output = {"original": data["values"], "sqrt": sqrt_values}
|
|
94
|
+
print(json.dumps(output, indent=2))
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
result = await run_python_script(source_code=code)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**File Operations in Script**:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
# Create and read a file
|
|
104
|
+
code = """
|
|
105
|
+
# Write to file
|
|
106
|
+
with open('/tmp/test.txt', 'w') as f:
|
|
107
|
+
f.write('Hello from Python!')
|
|
108
|
+
|
|
109
|
+
# Read back
|
|
110
|
+
with open('/tmp/test.txt', 'r') as f:
|
|
111
|
+
content = f.read()
|
|
112
|
+
print(f"File content: {content}")
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
result = await run_python_script(source_code=code)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Error Handling**:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
# Code with error
|
|
122
|
+
code = """
|
|
123
|
+
def divide(a, b):
|
|
124
|
+
return a / b
|
|
125
|
+
|
|
126
|
+
result = divide(10, 0) # Division by zero
|
|
127
|
+
print(f"Result: {result}")
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
result = await run_python_script(source_code=code)
|
|
131
|
+
print(result.output_blocks[0].data)
|
|
132
|
+
# Output includes:
|
|
133
|
+
# <exit_code>1</exit_code>
|
|
134
|
+
# <stderr>ZeroDivisionError: division by zero</stderr>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Timeout Example**:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
# Long-running script with timeout
|
|
141
|
+
code = """
|
|
142
|
+
import time
|
|
143
|
+
for i in range(100):
|
|
144
|
+
time.sleep(1)
|
|
145
|
+
print(f"Second {i+1}")
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
result = await run_python_script(
|
|
149
|
+
source_code=code,
|
|
150
|
+
max_duration=5.0 # Stop after 5 seconds
|
|
151
|
+
)
|
|
152
|
+
# Will show timeout error in stderr
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### Best Practices
|
|
156
|
+
|
|
157
|
+
1. **Always Set Timeout**: Prevent runaway scripts
|
|
158
|
+
2. **Print Results**: Use `print()` to capture output
|
|
159
|
+
3. **Handle Errors**: Check exit_code and stderr
|
|
160
|
+
4. **Clean Code**: Test code before running in production
|
|
161
|
+
5. **Limit External Dependencies**: Not all packages may be available
|
|
162
|
+
|
|
163
|
+
#### Common Issues
|
|
164
|
+
|
|
165
|
+
**Import Errors**:
|
|
166
|
+
```python
|
|
167
|
+
# Problem: Missing package
|
|
168
|
+
code = "import nonexistent_package"
|
|
169
|
+
# Solution: Check package is installed in environment
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**No Output**:
|
|
173
|
+
```python
|
|
174
|
+
# Problem: Forgot to print
|
|
175
|
+
code = "result = 2 + 2" # No print statement
|
|
176
|
+
# Solution: Add print()
|
|
177
|
+
code = "result = 2 + 2; print(result)"
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Timeout Too Short**:
|
|
181
|
+
```python
|
|
182
|
+
# Problem: Complex operation needs more time
|
|
183
|
+
result = await run_python_script(code, max_duration=1.0) # Too short
|
|
184
|
+
# Solution: Increase timeout
|
|
185
|
+
result = await run_python_script(code, max_duration=60.0) # Better
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
### run_shell_script
|
|
191
|
+
|
|
192
|
+
**What it does**: Executes shell commands in a subprocess. Similar to run_python_script but for shell commands.
|
|
193
|
+
|
|
194
|
+
**Why use it**: Allows agents to run system commands, scripts, or CLI tools.
|
|
195
|
+
|
|
196
|
+
**Location**: `massgen.tool._code_executors._shell_executor`
|
|
197
|
+
|
|
198
|
+
**Note**: Implementation details similar to run_python_script. Use with caution due to security implications of shell access.
|
|
199
|
+
|
|
200
|
+
## File Operation Tools
|
|
201
|
+
|
|
202
|
+
### read_file_content
|
|
203
|
+
|
|
204
|
+
**What it does**: Reads the contents of a file with optional line range specification. Can read entire files or specific line ranges, including negative indices for reading from the end.
|
|
205
|
+
|
|
206
|
+
**Why use it**: Essential for agents that need to examine files, load data, or read configuration. Supports partial reads for large files.
|
|
207
|
+
|
|
208
|
+
**Location**: `massgen.tool._file_handlers._file_operations`
|
|
209
|
+
|
|
210
|
+
#### Parameters
|
|
211
|
+
|
|
212
|
+
- `target_path` (required): Absolute or relative path to the file
|
|
213
|
+
- `line_range` (optional): `[start, end]` line numbers (1-based, inclusive)
|
|
214
|
+
- Positive numbers: Count from beginning (1 is first line)
|
|
215
|
+
- Negative numbers: Count from end (-1 is last line)
|
|
216
|
+
|
|
217
|
+
#### Returns
|
|
218
|
+
|
|
219
|
+
ExecutionResult containing:
|
|
220
|
+
- File content (with line numbers if range specified)
|
|
221
|
+
- Error message if file doesn't exist or isn't readable
|
|
222
|
+
|
|
223
|
+
#### Examples
|
|
224
|
+
|
|
225
|
+
**Read Entire File**:
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
from massgen.tool import read_file_content
|
|
229
|
+
|
|
230
|
+
# Read complete file
|
|
231
|
+
result = await read_file_content(target_path="config.json")
|
|
232
|
+
print(result.output_blocks[0].data)
|
|
233
|
+
# Output: Content of config.json:
|
|
234
|
+
# ```
|
|
235
|
+
# {
|
|
236
|
+
# "setting1": "value1",
|
|
237
|
+
# "setting2": "value2"
|
|
238
|
+
# }
|
|
239
|
+
# ```
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**Read Specific Lines**:
|
|
243
|
+
|
|
244
|
+
```python
|
|
245
|
+
# Read lines 10-20
|
|
246
|
+
result = await read_file_content(
|
|
247
|
+
target_path="large_file.txt",
|
|
248
|
+
line_range=[10, 20]
|
|
249
|
+
)
|
|
250
|
+
# Output shows lines 10-20 with line numbers
|
|
251
|
+
# Content of large_file.txt (lines 10-20):
|
|
252
|
+
# ```
|
|
253
|
+
# 10│ Line 10 content
|
|
254
|
+
# 11│ Line 11 content
|
|
255
|
+
# ...
|
|
256
|
+
# 20│ Line 20 content
|
|
257
|
+
# ```
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Read Last N Lines**:
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
# Read last 100 lines
|
|
264
|
+
result = await read_file_content(
|
|
265
|
+
target_path="app.log",
|
|
266
|
+
line_range=[-100, -1]
|
|
267
|
+
)
|
|
268
|
+
# Shows last 100 lines of the log file
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Read First N Lines**:
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
# Read first 50 lines
|
|
275
|
+
result = await read_file_content(
|
|
276
|
+
target_path="data.csv",
|
|
277
|
+
line_range=[1, 50]
|
|
278
|
+
)
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Error Handling**:
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
# File doesn't exist
|
|
285
|
+
result = await read_file_content(target_path="nonexistent.txt")
|
|
286
|
+
print(result.output_blocks[0].data)
|
|
287
|
+
# Output: Error: File 'nonexistent.txt' does not exist.
|
|
288
|
+
|
|
289
|
+
# Not a file (is a directory)
|
|
290
|
+
result = await read_file_content(target_path="/etc")
|
|
291
|
+
# Output: Error: Path '/etc' is not a file.
|
|
292
|
+
|
|
293
|
+
# Invalid line range
|
|
294
|
+
result = await read_file_content(
|
|
295
|
+
target_path="small_file.txt",
|
|
296
|
+
line_range=[100, 200] # File only has 50 lines
|
|
297
|
+
)
|
|
298
|
+
# Output: Error: Invalid line range [100, 200] for file with 50 lines.
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
#### Best Practices
|
|
302
|
+
|
|
303
|
+
1. **Check File Exists**: Handle error results gracefully
|
|
304
|
+
2. **Use Line Ranges**: For large files, avoid reading entire content
|
|
305
|
+
3. **Absolute Paths**: Use absolute paths when possible
|
|
306
|
+
4. **UTF-8 Encoding**: Assumes UTF-8 encoding (most common)
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
### save_file_content
|
|
311
|
+
|
|
312
|
+
**What it does**: Writes content to a file, optionally creating parent directories. Overwrites existing files.
|
|
313
|
+
|
|
314
|
+
**Why use it**: Allows agents to create files, save results, write reports, or persist data.
|
|
315
|
+
|
|
316
|
+
**Location**: `massgen.tool._file_handlers._file_operations`
|
|
317
|
+
|
|
318
|
+
#### Parameters
|
|
319
|
+
|
|
320
|
+
- `target_path` (required): Path where file will be saved
|
|
321
|
+
- `file_content` (required): Content to write (string)
|
|
322
|
+
- `create_dirs` (optional): Create parent directories if they don't exist (default: True)
|
|
323
|
+
|
|
324
|
+
#### Returns
|
|
325
|
+
|
|
326
|
+
ExecutionResult containing:
|
|
327
|
+
- Success message with character count
|
|
328
|
+
- Error message if write fails
|
|
329
|
+
|
|
330
|
+
#### Examples
|
|
331
|
+
|
|
332
|
+
**Simple Write**:
|
|
333
|
+
|
|
334
|
+
```python
|
|
335
|
+
from massgen.tool import save_file_content
|
|
336
|
+
|
|
337
|
+
# Write a text file
|
|
338
|
+
result = await save_file_content(
|
|
339
|
+
target_path="output.txt",
|
|
340
|
+
file_content="Hello, World!"
|
|
341
|
+
)
|
|
342
|
+
print(result.output_blocks[0].data)
|
|
343
|
+
# Output: Successfully wrote 13 characters to output.txt
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**Write JSON**:
|
|
347
|
+
|
|
348
|
+
```python
|
|
349
|
+
import json
|
|
350
|
+
|
|
351
|
+
data = {"name": "Alice", "age": 30, "city": "NYC"}
|
|
352
|
+
content = json.dumps(data, indent=2)
|
|
353
|
+
|
|
354
|
+
result = await save_file_content(
|
|
355
|
+
target_path="data.json",
|
|
356
|
+
file_content=content
|
|
357
|
+
)
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
**Write with Directory Creation**:
|
|
361
|
+
|
|
362
|
+
```python
|
|
363
|
+
# Create nested directories automatically
|
|
364
|
+
result = await save_file_content(
|
|
365
|
+
target_path="reports/2024/march/summary.txt",
|
|
366
|
+
file_content="Monthly summary...",
|
|
367
|
+
create_dirs=True # Creates reports/2024/march/ if needed
|
|
368
|
+
)
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**Overwrite Existing File**:
|
|
372
|
+
|
|
373
|
+
```python
|
|
374
|
+
# Overwrites without warning
|
|
375
|
+
result = await save_file_content(
|
|
376
|
+
target_path="existing.txt",
|
|
377
|
+
file_content="New content" # Old content is lost
|
|
378
|
+
)
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**Error Handling**:
|
|
382
|
+
|
|
383
|
+
```python
|
|
384
|
+
# Permission denied
|
|
385
|
+
result = await save_file_content(
|
|
386
|
+
target_path="/root/protected.txt",
|
|
387
|
+
file_content="content"
|
|
388
|
+
)
|
|
389
|
+
# Output: Error writing file: Permission denied
|
|
390
|
+
|
|
391
|
+
# Cannot create directory
|
|
392
|
+
result = await save_file_content(
|
|
393
|
+
target_path="/readonly/file.txt",
|
|
394
|
+
file_content="content",
|
|
395
|
+
create_dirs=True
|
|
396
|
+
)
|
|
397
|
+
# Output: Error writing file: Cannot create directory
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
#### Best Practices
|
|
401
|
+
|
|
402
|
+
1. **Check Results**: Verify success message
|
|
403
|
+
2. **Use create_dirs**: Usually want to create parent directories
|
|
404
|
+
3. **Backup Important Files**: No confirmation before overwrite
|
|
405
|
+
4. **Validate Content**: Ensure content is correct before writing
|
|
406
|
+
5. **UTF-8 Safe**: Ensure content is UTF-8 compatible
|
|
407
|
+
|
|
408
|
+
#### Common Use Cases
|
|
409
|
+
|
|
410
|
+
**Save Analysis Results**:
|
|
411
|
+
|
|
412
|
+
```python
|
|
413
|
+
results = analyze_data(dataset)
|
|
414
|
+
report = format_report(results)
|
|
415
|
+
|
|
416
|
+
await save_file_content(
|
|
417
|
+
target_path=f"reports/analysis_{datetime.now().date()}.txt",
|
|
418
|
+
file_content=report
|
|
419
|
+
)
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**Configuration Files**:
|
|
423
|
+
|
|
424
|
+
```python
|
|
425
|
+
config = {
|
|
426
|
+
"api_key": "secret",
|
|
427
|
+
"endpoint": "https://api.example.com",
|
|
428
|
+
"timeout": 30
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
await save_file_content(
|
|
432
|
+
target_path="config.json",
|
|
433
|
+
file_content=json.dumps(config, indent=2)
|
|
434
|
+
)
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**Log Files**:
|
|
438
|
+
|
|
439
|
+
```python
|
|
440
|
+
log_entry = f"[{datetime.now()}] Operation completed\n"
|
|
441
|
+
|
|
442
|
+
# Use append_file_content instead for logs
|
|
443
|
+
await append_file_content(
|
|
444
|
+
target_path="app.log",
|
|
445
|
+
additional_content=log_entry
|
|
446
|
+
)
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
### append_file_content
|
|
452
|
+
|
|
453
|
+
**What it does**: Appends content to the end of a file, or inserts content at a specific line position. Does not overwrite existing content.
|
|
454
|
+
|
|
455
|
+
**Why use it**: Perfect for log files, incremental data collection, or adding to existing documents without losing original content.
|
|
456
|
+
|
|
457
|
+
**Location**: `massgen.tool._file_handlers._file_operations`
|
|
458
|
+
|
|
459
|
+
#### Parameters
|
|
460
|
+
|
|
461
|
+
- `target_path` (required): Path to the file
|
|
462
|
+
- `additional_content` (required): Content to append or insert
|
|
463
|
+
- `line_position` (optional): Line number to insert at (1-based). If None, appends to end
|
|
464
|
+
|
|
465
|
+
#### Returns
|
|
466
|
+
|
|
467
|
+
ExecutionResult containing:
|
|
468
|
+
- Success message with character count and operation type
|
|
469
|
+
- Error message if operation fails
|
|
470
|
+
|
|
471
|
+
#### Examples
|
|
472
|
+
|
|
473
|
+
**Append to End**:
|
|
474
|
+
|
|
475
|
+
```python
|
|
476
|
+
from massgen.tool import append_file_content
|
|
477
|
+
|
|
478
|
+
# Append to log file
|
|
479
|
+
result = await append_file_content(
|
|
480
|
+
target_path="app.log",
|
|
481
|
+
additional_content="[2024-03-15] New log entry\n"
|
|
482
|
+
)
|
|
483
|
+
# Output: Successfully appended 30 characters to app.log
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
**Insert at Specific Line**:
|
|
487
|
+
|
|
488
|
+
```python
|
|
489
|
+
# Insert at line 5
|
|
490
|
+
result = await append_file_content(
|
|
491
|
+
target_path="document.txt",
|
|
492
|
+
additional_content="New paragraph here\n",
|
|
493
|
+
line_position=5
|
|
494
|
+
)
|
|
495
|
+
# Output: Successfully inserted content at line 5 in document.txt
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
**Continuous Logging**:
|
|
499
|
+
|
|
500
|
+
```python
|
|
501
|
+
# Log multiple entries
|
|
502
|
+
log_messages = [
|
|
503
|
+
"[INFO] Application started",
|
|
504
|
+
"[DEBUG] Loading configuration",
|
|
505
|
+
"[INFO] Server listening on port 8000"
|
|
506
|
+
]
|
|
507
|
+
|
|
508
|
+
for msg in log_messages:
|
|
509
|
+
await append_file_content(
|
|
510
|
+
target_path="server.log",
|
|
511
|
+
additional_content=f"{msg}\n"
|
|
512
|
+
)
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
**Insert Header**:
|
|
516
|
+
|
|
517
|
+
```python
|
|
518
|
+
# Insert at beginning of file
|
|
519
|
+
header = "# Report Generated on 2024-03-15\n\n"
|
|
520
|
+
|
|
521
|
+
await append_file_content(
|
|
522
|
+
target_path="report.md",
|
|
523
|
+
additional_content=header,
|
|
524
|
+
line_position=1 # Insert at first line
|
|
525
|
+
)
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
**Error Handling**:
|
|
529
|
+
|
|
530
|
+
```python
|
|
531
|
+
# File doesn't exist
|
|
532
|
+
result = await append_file_content(
|
|
533
|
+
target_path="nonexistent.txt",
|
|
534
|
+
additional_content="content"
|
|
535
|
+
)
|
|
536
|
+
# Output: Error: File 'nonexistent.txt' does not exist.
|
|
537
|
+
|
|
538
|
+
# Invalid line position
|
|
539
|
+
result = await append_file_content(
|
|
540
|
+
target_path="small_file.txt", # 10 lines
|
|
541
|
+
additional_content="content",
|
|
542
|
+
line_position=100 # Too large
|
|
543
|
+
)
|
|
544
|
+
# Output: Error: Invalid line position 100 for file with 10 lines.
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
#### Best Practices
|
|
548
|
+
|
|
549
|
+
1. **Include Newlines**: Add `\n` to keep formatting correct
|
|
550
|
+
2. **Timestamp Logs**: Include timestamps in log entries
|
|
551
|
+
3. **Atomic Operations**: Each append is a separate file operation
|
|
552
|
+
4. **Line Position Validation**: Check file length before inserting
|
|
553
|
+
5. **Use for Logs**: Perfect for append-only log files
|
|
554
|
+
|
|
555
|
+
#### Common Use Cases
|
|
556
|
+
|
|
557
|
+
**Activity Logging**:
|
|
558
|
+
|
|
559
|
+
```python
|
|
560
|
+
async def log_activity(activity: str):
|
|
561
|
+
timestamp = datetime.now().isoformat()
|
|
562
|
+
entry = f"[{timestamp}] {activity}\n"
|
|
563
|
+
|
|
564
|
+
await append_file_content(
|
|
565
|
+
target_path="activity.log",
|
|
566
|
+
additional_content=entry
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
# Usage
|
|
570
|
+
await log_activity("User logged in")
|
|
571
|
+
await log_activity("File uploaded")
|
|
572
|
+
await log_activity("Report generated")
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
**Data Collection**:
|
|
576
|
+
|
|
577
|
+
```python
|
|
578
|
+
# Collect measurements over time
|
|
579
|
+
async def record_measurement(value: float):
|
|
580
|
+
entry = f"{datetime.now()},{value}\n"
|
|
581
|
+
|
|
582
|
+
await append_file_content(
|
|
583
|
+
target_path="measurements.csv",
|
|
584
|
+
additional_content=entry
|
|
585
|
+
)
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
**Document Building**:
|
|
589
|
+
|
|
590
|
+
```python
|
|
591
|
+
# Build report incrementally
|
|
592
|
+
await save_file_content("report.md", "# Monthly Report\n\n")
|
|
593
|
+
|
|
594
|
+
await append_file_content("report.md", "## Sales Summary\n")
|
|
595
|
+
await append_file_content("report.md", sales_summary + "\n\n")
|
|
596
|
+
|
|
597
|
+
await append_file_content("report.md", "## User Statistics\n")
|
|
598
|
+
await append_file_content("report.md", user_stats + "\n\n")
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
## Integration with ToolManager
|
|
602
|
+
|
|
603
|
+
All built-in tools can be registered with ToolManager:
|
|
604
|
+
|
|
605
|
+
```python
|
|
606
|
+
from massgen.tool import ToolManager
|
|
607
|
+
|
|
608
|
+
manager = ToolManager()
|
|
609
|
+
|
|
610
|
+
# Register by name (auto-discovery)
|
|
611
|
+
manager.add_tool_function(func="run_python_script")
|
|
612
|
+
manager.add_tool_function(func="read_file_content")
|
|
613
|
+
manager.add_tool_function(func="save_file_content")
|
|
614
|
+
manager.add_tool_function(func="append_file_content")
|
|
615
|
+
|
|
616
|
+
# Register with custom configuration
|
|
617
|
+
manager.add_tool_function(
|
|
618
|
+
func="run_python_script",
|
|
619
|
+
preset_args={"max_duration": 60.0}, # Custom timeout
|
|
620
|
+
description="Execute Python code with 60-second timeout"
|
|
621
|
+
)
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
## Security Considerations
|
|
625
|
+
|
|
626
|
+
### Code Execution
|
|
627
|
+
|
|
628
|
+
1. **Untrusted Code**: Never execute untrusted user code without review
|
|
629
|
+
2. **Timeouts**: Always set reasonable timeouts
|
|
630
|
+
3. **Resource Limits**: Consider memory and CPU limits
|
|
631
|
+
4. **Sandboxing**: Code runs in subprocess but shares system access
|
|
632
|
+
|
|
633
|
+
### File Operations
|
|
634
|
+
|
|
635
|
+
1. **Path Validation**: Validate file paths before operations
|
|
636
|
+
2. **Permission Checks**: Ensure agent has necessary permissions
|
|
637
|
+
3. **Path Traversal**: Be careful with user-provided paths (../)
|
|
638
|
+
4. **Overwrite Protection**: save_file_content overwrites without confirmation
|
|
639
|
+
5. **Sensitive Data**: Don't write secrets or credentials to files
|
|
640
|
+
|
|
641
|
+
### Best Practices
|
|
642
|
+
|
|
643
|
+
```python
|
|
644
|
+
# Validate paths
|
|
645
|
+
import os
|
|
646
|
+
|
|
647
|
+
def is_safe_path(base_path: str, user_path: str) -> bool:
|
|
648
|
+
"""Check if user_path is within base_path."""
|
|
649
|
+
abs_base = os.path.abspath(base_path)
|
|
650
|
+
abs_user = os.path.abspath(os.path.join(base_path, user_path))
|
|
651
|
+
return abs_user.startswith(abs_base)
|
|
652
|
+
|
|
653
|
+
# Use with file operations
|
|
654
|
+
if is_safe_path("/safe/directory", user_provided_path):
|
|
655
|
+
result = await read_file_content(user_provided_path)
|
|
656
|
+
else:
|
|
657
|
+
print("Error: Path outside allowed directory")
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
## Performance Tips
|
|
661
|
+
|
|
662
|
+
### File Operations
|
|
663
|
+
|
|
664
|
+
1. **Batch Writes**: Combine multiple writes into one
|
|
665
|
+
2. **Line Ranges**: Use line_range for large files
|
|
666
|
+
3. **Stream Large Files**: Process in chunks if possible
|
|
667
|
+
4. **Cache Reads**: Cache frequently read files
|
|
668
|
+
|
|
669
|
+
### Code Execution
|
|
670
|
+
|
|
671
|
+
1. **Minimize Execution**: Cache results when possible
|
|
672
|
+
2. **Optimize Code**: Profile and optimize Python scripts
|
|
673
|
+
3. **Parallel Execution**: Use async for multiple operations
|
|
674
|
+
4. **Resource Monitoring**: Monitor memory and CPU usage
|
|
675
|
+
|
|
676
|
+
---
|
|
677
|
+
|
|
678
|
+
For more information, see:
|
|
679
|
+
- [ToolManager Documentation](manager.md)
|
|
680
|
+
- [ExecutionResult Documentation](execution_results.md)
|
|
681
|
+
- [Workflow Toolkits](workflow_toolkits.md)
|