adam-community 1.0.23__py3-none-any.whl → 1.0.25__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.
- adam_community/__version__.py +1 -1
- adam_community/cli/templates/agent_python.py.j2 +265 -70
- adam_community/util.py +194 -0
- {adam_community-1.0.23.dist-info → adam_community-1.0.25.dist-info}/METADATA +30 -1
- {adam_community-1.0.23.dist-info → adam_community-1.0.25.dist-info}/RECORD +8 -8
- {adam_community-1.0.23.dist-info → adam_community-1.0.25.dist-info}/WHEEL +0 -0
- {adam_community-1.0.23.dist-info → adam_community-1.0.25.dist-info}/entry_points.txt +0 -0
- {adam_community-1.0.23.dist-info → adam_community-1.0.25.dist-info}/top_level.txt +0 -0
adam_community/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.0.
|
|
1
|
+
__version__ = "1.0.25"
|
|
@@ -1,33 +1,159 @@
|
|
|
1
1
|
from adam_community.tool import Tool
|
|
2
2
|
from adam_community.util import runCmd
|
|
3
|
+
import json
|
|
4
|
+
import datetime
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# 输出处理常量
|
|
8
|
+
MAX_OUTPUT_LENGTH = 10000
|
|
9
|
+
TRUNCATE_PREFIX_LENGTH = 5000
|
|
10
|
+
TRUNCATE_SUFFIX_LENGTH = 5000
|
|
11
|
+
SUMMARY_STDOUT_LENGTH = 300
|
|
12
|
+
SUMMARY_STDERR_LENGTH = 200
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def truncate_output(text):
|
|
16
|
+
"""截断过长的输出文本。
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
text (str): 需要截断的文本
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
str: 截断后的文本
|
|
23
|
+
"""
|
|
24
|
+
if len(text) <= MAX_OUTPUT_LENGTH:
|
|
25
|
+
return text
|
|
26
|
+
return (text[:TRUNCATE_PREFIX_LENGTH] +
|
|
27
|
+
"\n...输出太长已省略...\n" +
|
|
28
|
+
text[-TRUNCATE_SUFFIX_LENGTH:])
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_status_info(exit_code):
|
|
32
|
+
"""获取执行状态信息。
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
exit_code (int): 退出码
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
tuple: (状态图标, 状态文本) 元组
|
|
39
|
+
"""
|
|
40
|
+
if exit_code == 0:
|
|
41
|
+
return "✅", "成功"
|
|
42
|
+
return "❌", "失败"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def format_output_display(stdout, stderr, exit_code, tool_display_name):
|
|
46
|
+
"""格式化输出显示文本。
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
stdout (str): 标准输出
|
|
50
|
+
stderr (str): 错误输出
|
|
51
|
+
exit_code (int): 退出码
|
|
52
|
+
tool_display_name (str): 工具显示名称
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
str: 格式化的Markdown文本
|
|
56
|
+
"""
|
|
57
|
+
status_icon, status_text = get_status_info(exit_code)
|
|
58
|
+
|
|
59
|
+
display_parts = [
|
|
60
|
+
f"## {status_icon} {tool_display_name}处理{status_text}",
|
|
61
|
+
"",
|
|
62
|
+
"### 📋 处理结果",
|
|
63
|
+
f"- 退出码: {exit_code}",
|
|
64
|
+
"- 标准输出:",
|
|
65
|
+
"```",
|
|
66
|
+
stdout,
|
|
67
|
+
"```"
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
if stderr:
|
|
71
|
+
display_parts.extend([
|
|
72
|
+
"",
|
|
73
|
+
"### ⚠️ 错误/警告信息",
|
|
74
|
+
"```",
|
|
75
|
+
stderr,
|
|
76
|
+
"```"
|
|
77
|
+
])
|
|
78
|
+
|
|
79
|
+
return "\n".join(display_parts)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def generate_summary(stdout, stderr, exit_code, tool_name):
|
|
83
|
+
"""生成执行结果摘要。
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
stdout (str): 标准输出
|
|
87
|
+
stderr (str): 错误输出
|
|
88
|
+
exit_code (int): 退出码
|
|
89
|
+
tool_name (str): 工具名称
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
str: 执行摘要文本
|
|
93
|
+
"""
|
|
94
|
+
if exit_code != 0:
|
|
95
|
+
summary = f"{tool_name}执行失败(退出码: {exit_code})。"
|
|
96
|
+
if stderr:
|
|
97
|
+
summary += f" 错误信息: {stderr[:SUMMARY_STDERR_LENGTH]}"
|
|
98
|
+
return summary
|
|
99
|
+
|
|
100
|
+
if stderr:
|
|
101
|
+
summary = f"{tool_name}执行完成但有警告。"
|
|
102
|
+
summary += f" 输出: {stdout[:SUMMARY_STDERR_LENGTH]}"
|
|
103
|
+
summary += f" 警告: {stderr[:SUMMARY_STDERR_LENGTH]}"
|
|
104
|
+
return summary
|
|
105
|
+
|
|
106
|
+
summary = f"{tool_name}执行成功。"
|
|
107
|
+
summary += f" 输出摘要: {stdout[:SUMMARY_STDOUT_LENGTH]}"
|
|
108
|
+
return summary
|
|
109
|
+
|
|
3
110
|
|
|
4
111
|
class {{ name.replace("-", "_") }}_tool(Tool):
|
|
5
112
|
"""
|
|
6
113
|
{{ description }}
|
|
7
114
|
|
|
8
|
-
:
|
|
9
|
-
|
|
115
|
+
Args:
|
|
116
|
+
input_text (str): 输入的文本内容
|
|
117
|
+
mode (str, optional): 处理模式,可选值:basic、advanced
|
|
10
118
|
"""
|
|
11
|
-
|
|
12
119
|
DISPLAY_NAME = "{{ display_name }}工具"
|
|
13
|
-
NETWORK = False
|
|
14
|
-
CPU = 1
|
|
15
|
-
GPU = 0
|
|
16
|
-
SIF = "adam-base:1.0.0"
|
|
120
|
+
NETWORK = False
|
|
121
|
+
CPU = 1
|
|
122
|
+
GPU = 0
|
|
123
|
+
SIF = "adam-base:1.0.0"
|
|
17
124
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
125
|
+
# 输出文件配置
|
|
126
|
+
OUTPUT_FILE = "output.txt"
|
|
127
|
+
|
|
128
|
+
def inputShow(self, **kwargs):
|
|
129
|
+
"""AI决定使用该工具时调用,用于向用户展示当前调用的工具信息。
|
|
21
130
|
|
|
22
131
|
Args:
|
|
23
|
-
kwargs: 包含args、message、files、user、task_id
|
|
132
|
+
kwargs (dict): 包含args、message、files、user、task_id等参数的字典。
|
|
24
133
|
|
|
25
134
|
Returns:
|
|
26
|
-
|
|
135
|
+
str: 给用户显示的字符串(可使用markdown渲染)。
|
|
27
136
|
"""
|
|
28
|
-
|
|
29
|
-
input_text =
|
|
30
|
-
mode =
|
|
137
|
+
args = kwargs['args']
|
|
138
|
+
input_text = args['input_text']
|
|
139
|
+
mode = args.get('mode', 'basic')
|
|
140
|
+
|
|
141
|
+
show_text = f"正在使用 {{ display_name }} 工具处理文本内容"
|
|
142
|
+
if mode == 'advanced':
|
|
143
|
+
show_text += "(高级模式)"
|
|
144
|
+
|
|
145
|
+
return Tool.markdown_terminal(
|
|
146
|
+
show_text,
|
|
147
|
+
workdir=kwargs.get("task_id", ""),
|
|
148
|
+
user=kwargs.get("user", "Adam"),
|
|
149
|
+
conda_env=getattr(self, "CONDA_ENV", "base")
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def call(self, kwargs):
|
|
153
|
+
"""Tool 逻辑实现函数"""
|
|
154
|
+
args = kwargs['args']
|
|
155
|
+
input_text = args['input_text']
|
|
156
|
+
mode = args.get('mode', 'basic')
|
|
31
157
|
|
|
32
158
|
# TODO: 在这里实现你的主要逻辑
|
|
33
159
|
if mode == 'advanced':
|
|
@@ -36,8 +162,7 @@ class {{ name.replace("-", "_") }}_tool(Tool):
|
|
|
36
162
|
result = f"基础模式处理: {input_text}"
|
|
37
163
|
|
|
38
164
|
# 生成bash命令
|
|
39
|
-
bash_script = f'''
|
|
40
|
-
# {{ display_name }} 处理脚本
|
|
165
|
+
bash_script = f'''# {{ display_name }} 处理脚本
|
|
41
166
|
echo "开始处理: {input_text}"
|
|
42
167
|
echo "处理模式: {mode}"
|
|
43
168
|
|
|
@@ -45,79 +170,104 @@ echo "处理模式: {mode}"
|
|
|
45
170
|
echo "{result}"
|
|
46
171
|
|
|
47
172
|
# 生成输出文件
|
|
48
|
-
echo "处理完成" >
|
|
49
|
-
echo "结果: {result}" >>
|
|
173
|
+
echo "处理完成" > {self.OUTPUT_FILE}
|
|
174
|
+
echo "结果: {result}" >> {self.OUTPUT_FILE}
|
|
50
175
|
|
|
51
|
-
echo "处理完成,结果已保存到
|
|
176
|
+
echo "处理完成,结果已保存到 {self.OUTPUT_FILE}"
|
|
52
177
|
'''
|
|
53
178
|
|
|
54
179
|
return runCmd(bash_script)
|
|
55
180
|
|
|
56
181
|
def outputShow(self, kwargs):
|
|
57
|
-
"""
|
|
58
|
-
自定义输出显示格式(可选)
|
|
59
|
-
"""
|
|
60
|
-
stdout = kwargs.get('stdout', '')
|
|
61
|
-
stderr = kwargs.get('stderr', '')
|
|
182
|
+
"""任务结束时调用,用于向用户展示工具执行结果。
|
|
62
183
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
### 📋 处理结果
|
|
66
|
-
```
|
|
67
|
-
{stdout}
|
|
68
|
-
```
|
|
69
|
-
"""
|
|
184
|
+
Args:
|
|
185
|
+
kwargs (dict): 包含stdout、stderr、exit_code等执行结果的字典。
|
|
70
186
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
187
|
+
Returns:
|
|
188
|
+
tuple: (用户显示字符串, 文件列表) 元组。
|
|
189
|
+
- 用户显示字符串 (str): 格式化的显示文本
|
|
190
|
+
- 文件列表 (list): 生成的文件列表,会在前端提供下载
|
|
191
|
+
"""
|
|
192
|
+
stdout = truncate_output(kwargs.get('stdout', ''))
|
|
193
|
+
stderr = truncate_output(kwargs.get('stderr', ''))
|
|
194
|
+
exit_code = kwargs.get('exit_code', 0)
|
|
78
195
|
|
|
79
|
-
|
|
80
|
-
|
|
196
|
+
display_text = format_output_display(
|
|
197
|
+
stdout, stderr, exit_code, "{{ display_name }} "
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# 根据执行结果判断生成的文件
|
|
201
|
+
file_list = []
|
|
202
|
+
if exit_code == 0 or self.OUTPUT_FILE in kwargs.get('stdout', ''):
|
|
203
|
+
file_list.append(self.OUTPUT_FILE)
|
|
81
204
|
|
|
82
205
|
return display_text, file_list
|
|
83
206
|
|
|
84
207
|
def summary(self, kwargs):
|
|
208
|
+
"""任务结束时调用,用于向AI提供执行结果摘要。
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
kwargs (dict): 包含stdout、stderr、exit_code等执行结果的字典。
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
str: 给AI的文本摘要,应简洁明了,避免上下文过长。
|
|
85
215
|
"""
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
stderr = kwargs.get('stderr', '')
|
|
216
|
+
stdout = truncate_output(kwargs.get('stdout', ''))
|
|
217
|
+
stderr = truncate_output(kwargs.get('stderr', ''))
|
|
218
|
+
exit_code = kwargs.get('exit_code', 0)
|
|
90
219
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return f"{{ display_name }}工具执行成功: {stdout[:200]}..."
|
|
220
|
+
return generate_summary(
|
|
221
|
+
stdout, stderr, exit_code, "{{ display_name }}工具"
|
|
222
|
+
)
|
|
95
223
|
|
|
96
224
|
|
|
97
|
-
class {{ name.replace("-", "_") }}_advanced_tool(Tool, calltype="python"):
|
|
98
|
-
"""
|
|
99
|
-
{{ description }} - 高级功能
|
|
100
|
-
|
|
101
|
-
:param str input_file: 输入文件路径
|
|
102
|
-
:param str output_format: 输出格式,可选值:json、csv、txt
|
|
103
|
-
"""
|
|
225
|
+
class {{ name.replace("-", "_") }}_advanced_tool(Tool, calltype="python"):
|
|
226
|
+
"""{{ description }} - 高级功能
|
|
104
227
|
|
|
228
|
+
Args:
|
|
229
|
+
input_file (str): 输入文件路径
|
|
230
|
+
output_format (str): 输出格式,可选值:json、csv、txt
|
|
231
|
+
"""
|
|
105
232
|
DISPLAY_NAME = "{{ display_name }}高级工具"
|
|
106
|
-
NETWORK = False
|
|
107
|
-
CPU = 1
|
|
108
|
-
GPU = 0
|
|
109
|
-
SIF = "adam-base:1.0.0"
|
|
110
|
-
CONDA_ENV = "base"
|
|
233
|
+
NETWORK = False
|
|
234
|
+
CPU = 1
|
|
235
|
+
GPU = 0
|
|
236
|
+
SIF = "adam-base:1.0.0"
|
|
237
|
+
CONDA_ENV = "base"
|
|
111
238
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
239
|
+
# 输出文件配置
|
|
240
|
+
OUTPUT_FILE = "result.json"
|
|
241
|
+
DEFAULT_OUTPUT_FORMAT = "json"
|
|
242
|
+
|
|
243
|
+
def inputShow(self, **kwargs):
|
|
244
|
+
"""AI决定使用该工具时调用,用于向用户展示当前调用的工具信息。
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
kwargs (dict): 包含args、message、files、user、task_id等参数的字典。
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
str: 给用户显示的字符串(可使用markdown渲染)。
|
|
115
251
|
"""
|
|
116
|
-
|
|
117
|
-
|
|
252
|
+
args = kwargs['args']
|
|
253
|
+
input_file = args['input_file']
|
|
254
|
+
output_format = args.get('output_format', self.DEFAULT_OUTPUT_FORMAT)
|
|
118
255
|
|
|
119
|
-
|
|
120
|
-
|
|
256
|
+
show_text = (f"正在使用 {{ display_name }} 高级工具处理文件: {input_file}"
|
|
257
|
+
f"(输出格式: {output_format})")
|
|
258
|
+
|
|
259
|
+
return Tool.markdown_terminal(
|
|
260
|
+
show_text,
|
|
261
|
+
workdir=kwargs.get("task_id", ""),
|
|
262
|
+
user=kwargs.get("user", "Adam"),
|
|
263
|
+
conda_env=self.CONDA_ENV
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
def call(self, kwargs):
|
|
267
|
+
"""Tool 逻辑实现函数"""
|
|
268
|
+
args = kwargs['args']
|
|
269
|
+
input_file = args['input_file']
|
|
270
|
+
output_format = args.get('output_format', self.DEFAULT_OUTPUT_FORMAT)
|
|
121
271
|
|
|
122
272
|
# TODO: 在这里实现你的Python逻辑
|
|
123
273
|
result = {
|
|
@@ -134,6 +284,51 @@ class {{ name.replace("-", "_") }}_advanced_tool(Tool, calltype="python"):
|
|
|
134
284
|
|
|
135
285
|
# 生成输出文件
|
|
136
286
|
if output_format == 'json':
|
|
137
|
-
with open(
|
|
287
|
+
with open(self.OUTPUT_FILE, 'w', encoding='utf-8') as f:
|
|
138
288
|
json.dump(result, f, indent=2, ensure_ascii=False)
|
|
139
|
-
print("结果已保存到
|
|
289
|
+
print(f"结果已保存到 {self.OUTPUT_FILE}")
|
|
290
|
+
|
|
291
|
+
def outputShow(self, kwargs):
|
|
292
|
+
"""任务结束时调用,用于向用户展示工具执行结果。
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
kwargs (dict): 包含stdout、stderr、exit_code等执行结果的字典。
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
tuple: (用户显示字符串, 文件列表) 元组。
|
|
299
|
+
- 用户显示字符串 (str): 格式化的显示文本
|
|
300
|
+
- 文件列表 (list): 生成的文件列表,会在前端提供下载
|
|
301
|
+
"""
|
|
302
|
+
stdout = truncate_output(kwargs.get('stdout', ''))
|
|
303
|
+
stderr = truncate_output(kwargs.get('stderr', ''))
|
|
304
|
+
exit_code = kwargs.get('exit_code', 0)
|
|
305
|
+
|
|
306
|
+
display_text = format_output_display(
|
|
307
|
+
stdout, stderr, exit_code, "{{ display_name }} 高级工具"
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
# 根据输出格式判断生成的文件
|
|
311
|
+
file_list = []
|
|
312
|
+
args = kwargs.get('args', {})
|
|
313
|
+
output_format = args.get('output_format', self.DEFAULT_OUTPUT_FORMAT)
|
|
314
|
+
if output_format == 'json' and exit_code == 0:
|
|
315
|
+
file_list.append(self.OUTPUT_FILE)
|
|
316
|
+
|
|
317
|
+
return display_text, file_list
|
|
318
|
+
|
|
319
|
+
def summary(self, kwargs):
|
|
320
|
+
"""任务结束时调用,用于向AI提供执行结果摘要。
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
kwargs (dict): 包含stdout、stderr、exit_code等执行结果的字典。
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
str: 给AI的文本摘要,应简洁明了,避免上下文过长。
|
|
327
|
+
"""
|
|
328
|
+
stdout = truncate_output(kwargs.get('stdout', ''))
|
|
329
|
+
stderr = truncate_output(kwargs.get('stderr', ''))
|
|
330
|
+
exit_code = kwargs.get('exit_code', 0)
|
|
331
|
+
|
|
332
|
+
return generate_summary(
|
|
333
|
+
stdout, stderr, exit_code, "{{ display_name }}高级工具"
|
|
334
|
+
)
|
adam_community/util.py
CHANGED
|
@@ -10,6 +10,7 @@ import logging
|
|
|
10
10
|
import ssl
|
|
11
11
|
from functools import wraps
|
|
12
12
|
from subprocess import run, CalledProcessError
|
|
13
|
+
import time
|
|
13
14
|
|
|
14
15
|
logger = logging.getLogger(__name__)
|
|
15
16
|
|
|
@@ -18,6 +19,7 @@ ADAM_API_TOKEN = os.getenv('ADAM_API_TOKEN')
|
|
|
18
19
|
ADAM_TASK_ID = os.getenv('ADAM_TASK_ID')
|
|
19
20
|
ADAM_USER_ID = os.getenv('ADAM_USER_ID')
|
|
20
21
|
CONDA_ENV = os.getenv('CONDA_ENV')
|
|
22
|
+
ADAM_TASK_DIR = os.getenv('ADAM_TASK_DIR')
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
def _build_akb_query_command(query: str, collection: str) -> str:
|
|
@@ -368,3 +370,195 @@ def markdown_terminal(content, conda_env="base", user="Adam", workdir=""):
|
|
|
368
370
|
user = markdown_color(f"{user}@Adam", "green")
|
|
369
371
|
workdir = markdown_color(f":~/{workdir}", "blue")
|
|
370
372
|
return f'({conda_env}) {user}{workdir}$ {content}'
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
# ========== States Management ==========
|
|
376
|
+
|
|
377
|
+
class _StatesManager:
|
|
378
|
+
"""内部状态管理类"""
|
|
379
|
+
_tool_name = "tool"
|
|
380
|
+
|
|
381
|
+
def _get_states_file(self) -> str:
|
|
382
|
+
"""获取 states.json 文件路径"""
|
|
383
|
+
# 1. 优先使用环境变量
|
|
384
|
+
task_dir = ADAM_TASK_DIR
|
|
385
|
+
if task_dir:
|
|
386
|
+
return os.path.join(task_dir, ".slurm", "states.json")
|
|
387
|
+
|
|
388
|
+
# 2. 尝试当前目录的 .slurm
|
|
389
|
+
current_dir = os.getcwd()
|
|
390
|
+
local_states = os.path.join(current_dir, ".slurm", "states.json")
|
|
391
|
+
if os.path.exists(local_states):
|
|
392
|
+
return local_states
|
|
393
|
+
|
|
394
|
+
# 3. 在当前目录创建
|
|
395
|
+
return local_states
|
|
396
|
+
|
|
397
|
+
def _read(self) -> dict:
|
|
398
|
+
"""读取 states.json,保留所有来源的数据"""
|
|
399
|
+
states_file = self._get_states_file()
|
|
400
|
+
if not os.path.exists(states_file):
|
|
401
|
+
return {
|
|
402
|
+
"files": {"updated_at": None, "sources": {}},
|
|
403
|
+
"states": {"source": None, "updated_at": None, "data": {}}
|
|
404
|
+
}
|
|
405
|
+
try:
|
|
406
|
+
with open(states_file, 'r', encoding='utf-8') as f:
|
|
407
|
+
return json.load(f)
|
|
408
|
+
except (json.JSONDecodeError, IOError):
|
|
409
|
+
return {
|
|
410
|
+
"files": {"updated_at": None, "sources": {}},
|
|
411
|
+
"states": {"source": None, "updated_at": None, "data": {}}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
def _write(self, data: dict):
|
|
415
|
+
"""写入 states.json"""
|
|
416
|
+
states_file = self._get_states_file()
|
|
417
|
+
os.makedirs(os.path.dirname(states_file), exist_ok=True)
|
|
418
|
+
with open(states_file, 'w', encoding='utf-8') as f:
|
|
419
|
+
json.dump(data, f, ensure_ascii=False, indent=2)
|
|
420
|
+
|
|
421
|
+
def _set_nested(self, data: dict, key: str, value):
|
|
422
|
+
"""设置嵌套值,支持 dot notation"""
|
|
423
|
+
keys = key.split('.')
|
|
424
|
+
current = data
|
|
425
|
+
for k in keys[:-1]:
|
|
426
|
+
current = current.setdefault(k, {})
|
|
427
|
+
current[keys[-1]] = value
|
|
428
|
+
|
|
429
|
+
def _get_nested(self, data: dict, key: str, default=None):
|
|
430
|
+
"""获取嵌套值,支持 dot notation"""
|
|
431
|
+
keys = key.split('.')
|
|
432
|
+
current = data
|
|
433
|
+
for k in keys:
|
|
434
|
+
if isinstance(current, dict):
|
|
435
|
+
current = current.get(k)
|
|
436
|
+
else:
|
|
437
|
+
return default
|
|
438
|
+
if current is None:
|
|
439
|
+
return default
|
|
440
|
+
return current
|
|
441
|
+
|
|
442
|
+
def set(self, key: str, value):
|
|
443
|
+
"""
|
|
444
|
+
设置状态
|
|
445
|
+
|
|
446
|
+
特殊 key:
|
|
447
|
+
"files" - 记录文件列表,会自动补充到 files.sources[tool_name]
|
|
448
|
+
其他 - 记录到 states.data
|
|
449
|
+
"""
|
|
450
|
+
data = self._read()
|
|
451
|
+
|
|
452
|
+
if key == "files":
|
|
453
|
+
data["files"]["sources"][self._tool_name] = {
|
|
454
|
+
"updated_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
|
455
|
+
"items": value
|
|
456
|
+
}
|
|
457
|
+
else:
|
|
458
|
+
self._set_nested(data["states"]["data"], key, value)
|
|
459
|
+
|
|
460
|
+
self._write(data)
|
|
461
|
+
|
|
462
|
+
def get(self, key: str):
|
|
463
|
+
"""
|
|
464
|
+
获取状态
|
|
465
|
+
|
|
466
|
+
Returns:
|
|
467
|
+
状态值,不存在返回 None
|
|
468
|
+
"""
|
|
469
|
+
data = self._read()
|
|
470
|
+
|
|
471
|
+
if key == "files":
|
|
472
|
+
# 合并所有来源的文件列表
|
|
473
|
+
merged = {}
|
|
474
|
+
for source, content in data["files"]["sources"].items():
|
|
475
|
+
for item in content.get("items", []):
|
|
476
|
+
path = item.get("path")
|
|
477
|
+
if not path:
|
|
478
|
+
continue
|
|
479
|
+
mtime = item.get("mtime", 0)
|
|
480
|
+
if path not in merged or mtime > merged[path]["mtime"]:
|
|
481
|
+
merged[path] = item
|
|
482
|
+
result = list(merged.values())
|
|
483
|
+
# 按 mtime 降序排序
|
|
484
|
+
result.sort(key=lambda x: x.get("mtime", 0), reverse=True)
|
|
485
|
+
return result
|
|
486
|
+
|
|
487
|
+
return self._get_nested(data["states"]["data"], key)
|
|
488
|
+
|
|
489
|
+
def cleanup(self):
|
|
490
|
+
"""清理当前工具的所有记录"""
|
|
491
|
+
data = self._read()
|
|
492
|
+
data["files"]["sources"].pop(self._tool_name, None)
|
|
493
|
+
self._write(data)
|
|
494
|
+
|
|
495
|
+
def trackPath(self, path: str, max_items: int = 30):
|
|
496
|
+
"""
|
|
497
|
+
追踪文件/目录,自动检测文件信息并记录
|
|
498
|
+
|
|
499
|
+
Args:
|
|
500
|
+
path: 文件或目录路径
|
|
501
|
+
max_items: 最大记录数量,先进先出
|
|
502
|
+
"""
|
|
503
|
+
if not os.path.exists(path):
|
|
504
|
+
return
|
|
505
|
+
|
|
506
|
+
# 检测文件信息
|
|
507
|
+
try:
|
|
508
|
+
is_dir = os.path.isdir(path)
|
|
509
|
+
mtime = int(os.path.getmtime(path))
|
|
510
|
+
# 从环境变量获取 task_dir
|
|
511
|
+
task_dir = os.getenv('ADAM_TASK_DIR')
|
|
512
|
+
if task_dir:
|
|
513
|
+
rel_path = os.path.relpath(path, task_dir)
|
|
514
|
+
else:
|
|
515
|
+
rel_path = path
|
|
516
|
+
except (OSError, ValueError):
|
|
517
|
+
return
|
|
518
|
+
|
|
519
|
+
# 获取当前文件列表
|
|
520
|
+
data = self._read()
|
|
521
|
+
source = self._tool_name
|
|
522
|
+
items = data["files"]["sources"].get(source, {}).get("items", [])
|
|
523
|
+
|
|
524
|
+
# 检查是否已存在相同路径,存在则移除(后面会加到末尾,保持最新追踪的在最后)
|
|
525
|
+
items = [item for item in items if item.get("path") != rel_path]
|
|
526
|
+
|
|
527
|
+
# 添加到末尾(最新的位置)
|
|
528
|
+
items.append({"path": rel_path, "is_dir": is_dir, "mtime": mtime})
|
|
529
|
+
|
|
530
|
+
# 先进先出,保留最多 max_items 条
|
|
531
|
+
if len(items) > max_items:
|
|
532
|
+
items = items[-max_items:]
|
|
533
|
+
|
|
534
|
+
# 写回
|
|
535
|
+
data["files"]["sources"][source] = {
|
|
536
|
+
"updated_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
|
537
|
+
"items": items
|
|
538
|
+
}
|
|
539
|
+
self._write(data)
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
# 全局实例
|
|
543
|
+
_states = _StatesManager()
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
def setState(key: str, value):
|
|
547
|
+
"""设置状态"""
|
|
548
|
+
return _states.set(key, value)
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
def getState(key: str):
|
|
552
|
+
"""获取状态"""
|
|
553
|
+
return _states.get(key)
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
def trackPath(path: str, max_items: int = 30):
|
|
557
|
+
"""
|
|
558
|
+
追踪文件/目录,自动检测文件信息并记录
|
|
559
|
+
|
|
560
|
+
Args:
|
|
561
|
+
path: 文件或目录路径
|
|
562
|
+
max_items: 最大记录数量,先进先出,默认 30
|
|
563
|
+
"""
|
|
564
|
+
return _states.trackPath(path, max_items)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: adam_community
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.25
|
|
4
4
|
Summary: Adam Community Tools and Utilities
|
|
5
5
|
Home-page: https://github.com/yourusername/adam-community
|
|
6
6
|
Author: Adam Community
|
|
@@ -80,6 +80,35 @@ classes = parse_directory(Path("./"))
|
|
|
80
80
|
success, errors, zip_name = build_package(Path("./"))
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
+
### States Management(任务状态管理)
|
|
84
|
+
|
|
85
|
+
用于在任务执行过程中记录和读取状态,与服务端共享 `states.json` 文件。
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from adam_community.util import setState, getState, trackPath
|
|
89
|
+
|
|
90
|
+
# 记录文件列表(自动与服务端和其他 Tool 的文件合并)
|
|
91
|
+
setState("files", [
|
|
92
|
+
{"path": "output/result.json", "is_dir": False, "mtime": 1704100800},
|
|
93
|
+
{"path": "cache", "is_dir": True, "mtime": 1704100000}
|
|
94
|
+
])
|
|
95
|
+
|
|
96
|
+
# 获取合并后的文件列表(来自 server + 所有 tools)
|
|
97
|
+
files = getState("files")
|
|
98
|
+
|
|
99
|
+
# 记录自定义状态(支持嵌套 key)
|
|
100
|
+
setState("stage", "data_cleaning")
|
|
101
|
+
setState("config.threshold", 0.5)
|
|
102
|
+
|
|
103
|
+
# 获取状态
|
|
104
|
+
stage = getState("stage") # -> "data_cleaning"
|
|
105
|
+
threshold = getState("config.threshold") # -> 0.5
|
|
106
|
+
|
|
107
|
+
# 追踪文件/目录(自动检测 is_dir 和 mtime,先进先出,最多 30 条)
|
|
108
|
+
trackPath("/path/to/output/result.json")
|
|
109
|
+
trackPath("/path/to/cache")
|
|
110
|
+
```
|
|
111
|
+
|
|
83
112
|
## 功能特性
|
|
84
113
|
|
|
85
114
|
- **Python 文件解析**: 自动解析 Python 类和函数的文档字符串
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
adam_community/__init__.py,sha256=vAmF9VQR6D4peppH0hnrHDmZK5cFeFPh11GIsTKUXhE,429
|
|
2
|
-
adam_community/__version__.py,sha256=
|
|
2
|
+
adam_community/__version__.py,sha256=_TgC2mrlgs6XxMzx9bzihItIy81yZaza2GnTmMNF5EA,23
|
|
3
3
|
adam_community/tool.py,sha256=F6jxRU3urqTfgjLIZSW-hVWyj0FpNwvY65jOODXI19w,4954
|
|
4
|
-
adam_community/util.py,sha256=
|
|
4
|
+
adam_community/util.py,sha256=SDXnWLHLfJxEJ5WBnwNq_FeHNwXxGK_F36dpI_hVkNc,17766
|
|
5
5
|
adam_community/cli/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
6
6
|
adam_community/cli/build.py,sha256=fCteEXjtU2ZsXXUWa-j61gh_JVU-6xSAH_LpOP5swFc,12623
|
|
7
7
|
adam_community/cli/cli.py,sha256=xlPvn0aq3TpAPjA7z9shsCqR1aHDVtZuhvtc_SNA_cQ,2811
|
|
@@ -13,7 +13,7 @@ adam_community/cli/templates/README_agent.md.j2,sha256=lbhaEPZrgbCfUG-T7GItkgfIV
|
|
|
13
13
|
adam_community/cli/templates/README_kit.md.j2,sha256=5_1ISGUxJKdDild2vNSWTC_hNhZHnEHvyN9Ez4Xbqwk,5715
|
|
14
14
|
adam_community/cli/templates/README_toolbox.md.j2,sha256=lbhaEPZrgbCfUG-T7GItkgfIV9h1rqxyfRQuGhcdOqU,8901
|
|
15
15
|
adam_community/cli/templates/__init__.py,sha256=43rU9rFkpsVrWjxR-brDnT2eakgRtb4XpnunbE-ais4,34
|
|
16
|
-
adam_community/cli/templates/agent_python.py.j2,sha256=
|
|
16
|
+
adam_community/cli/templates/agent_python.py.j2,sha256=7lim4KHtkZ78y6g0dE5YyDjhA6QKfIq-XaNKs2ryjho,10676
|
|
17
17
|
adam_community/cli/templates/configure.json.j2,sha256=HWhhFGEZsXxDJCkciehY8SqaV7kSPQ4588TR9WN__cI,354
|
|
18
18
|
adam_community/cli/templates/initial_assistant_message.md.j2,sha256=R17qhco2Ds5es2HMlAPcinVi5Z-vLfyyu1lY9HMBFk4,595
|
|
19
19
|
adam_community/cli/templates/initial_assistant_message_en.md.j2,sha256=o1nPDF_DBOA0pjnrxYCIjFWPLaNmE8G07OA-DMA5uNo,733
|
|
@@ -25,8 +25,8 @@ adam_community/cli/templates/long_description.md.j2,sha256=Rj6hcuNzEL0Sp17GQVCRJ
|
|
|
25
25
|
adam_community/cli/templates/long_description_en.md.j2,sha256=xSbahwGarXlWopZqHw7lrcv1dQuvwj2ChhZv5pJmUy4,1725
|
|
26
26
|
adam_community/cli/templates/rag_python.py.j2,sha256=YJL7-WIx-Dumt7lHuUGxl3Rbaw0kpkh8hpcCJ5lz9lA,2494
|
|
27
27
|
adam_community/cli/templates/toolbox_python.py.j2,sha256=EOnmsJUvQRrcO7K7c88kI42gMmcM0Z4ab46qwOJXbH8,4192
|
|
28
|
-
adam_community-1.0.
|
|
29
|
-
adam_community-1.0.
|
|
30
|
-
adam_community-1.0.
|
|
31
|
-
adam_community-1.0.
|
|
32
|
-
adam_community-1.0.
|
|
28
|
+
adam_community-1.0.25.dist-info/METADATA,sha256=3i_FpqlCX-IHuep5VdeEkel5JFB6MD13no1QsuY_3MY,3151
|
|
29
|
+
adam_community-1.0.25.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
30
|
+
adam_community-1.0.25.dist-info/entry_points.txt,sha256=4I7yRkn7cHwPY8-fWQLeAvKjc24zUy8Z65VsZNs0Wos,56
|
|
31
|
+
adam_community-1.0.25.dist-info/top_level.txt,sha256=MS8jbePXKZChih9kGizNVX0I1MFZFGWBMCIW_r86qhU,15
|
|
32
|
+
adam_community-1.0.25.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|