adam-community 1.0.22__tar.gz → 1.0.24__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.
- {adam_community-1.0.22 → adam_community-1.0.24}/PKG-INFO +30 -1
- {adam_community-1.0.22 → adam_community-1.0.24}/README.md +29 -0
- adam_community-1.0.24/adam_community/__version__.py +1 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/tool.py +3 -1
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/util.py +194 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community.egg-info/PKG-INFO +30 -1
- adam_community-1.0.24/test/test_util_tool.py +438 -0
- adam_community-1.0.22/adam_community/__version__.py +0 -1
- adam_community-1.0.22/test/test_util_tool.py +0 -143
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/__init__.py +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/__init__.py +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/build.py +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/cli.py +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/init.py +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/parser.py +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/Makefile.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/README_agent.md.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/README_kit.md.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/__init__.py +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/agent_python.py.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/configure.json.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/initial_assistant_message.md.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/initial_assistant_message_en.md.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/initial_system_prompt.md.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/initial_system_prompt_en.md.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/input.json.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/kit_python.py.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/long_description.md.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/long_description_en.md.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/rag_python.py.j2 +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/updater.py +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community.egg-info/SOURCES.txt +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community.egg-info/dependency_links.txt +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community.egg-info/entry_points.txt +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community.egg-info/requires.txt +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/adam_community.egg-info/top_level.txt +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/setup.cfg +0 -0
- {adam_community-1.0.22 → adam_community-1.0.24}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: adam_community
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.24
|
|
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 类和函数的文档字符串
|
|
@@ -50,6 +50,35 @@ classes = parse_directory(Path("./"))
|
|
|
50
50
|
success, errors, zip_name = build_package(Path("./"))
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
### States Management(任务状态管理)
|
|
54
|
+
|
|
55
|
+
用于在任务执行过程中记录和读取状态,与服务端共享 `states.json` 文件。
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from adam_community.util import setState, getState, trackPath
|
|
59
|
+
|
|
60
|
+
# 记录文件列表(自动与服务端和其他 Tool 的文件合并)
|
|
61
|
+
setState("files", [
|
|
62
|
+
{"path": "output/result.json", "is_dir": False, "mtime": 1704100800},
|
|
63
|
+
{"path": "cache", "is_dir": True, "mtime": 1704100000}
|
|
64
|
+
])
|
|
65
|
+
|
|
66
|
+
# 获取合并后的文件列表(来自 server + 所有 tools)
|
|
67
|
+
files = getState("files")
|
|
68
|
+
|
|
69
|
+
# 记录自定义状态(支持嵌套 key)
|
|
70
|
+
setState("stage", "data_cleaning")
|
|
71
|
+
setState("config.threshold", 0.5)
|
|
72
|
+
|
|
73
|
+
# 获取状态
|
|
74
|
+
stage = getState("stage") # -> "data_cleaning"
|
|
75
|
+
threshold = getState("config.threshold") # -> 0.5
|
|
76
|
+
|
|
77
|
+
# 追踪文件/目录(自动检测 is_dir 和 mtime,先进先出,最多 30 条)
|
|
78
|
+
trackPath("/path/to/output/result.json")
|
|
79
|
+
trackPath("/path/to/cache")
|
|
80
|
+
```
|
|
81
|
+
|
|
53
82
|
## 功能特性
|
|
54
83
|
|
|
55
84
|
- **Python 文件解析**: 自动解析 Python 类和函数的文档字符串
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.24"
|
|
@@ -22,6 +22,8 @@ class Tool:
|
|
|
22
22
|
cls.CONDA_ENV = "base"
|
|
23
23
|
if not hasattr(cls, "calltype"):
|
|
24
24
|
cls.calltype = "bash"
|
|
25
|
+
if not hasattr(cls, "DISPLAY_NAME"):
|
|
26
|
+
cls.DISPLAY_NAME = cls.__name__
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
def inputShow(self, **kwargs):
|
|
@@ -42,7 +44,7 @@ class Tool:
|
|
|
42
44
|
|
|
43
45
|
scripts = '\n'.join(['bash -s << EOF', scripts, 'EOF'])
|
|
44
46
|
else:
|
|
45
|
-
scripts = f"""python {self.
|
|
47
|
+
scripts = f"""python {self.DISPLAY_NAME}.py"""
|
|
46
48
|
return Tool.markdown_terminal(scripts, workdir=kwargs["task_id"],
|
|
47
49
|
user=kwargs["user"], conda_env=self.CONDA_ENV)
|
|
48
50
|
|
|
@@ -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.24
|
|
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 类和函数的文档字符串
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import patch, MagicMock, PropertyMock
|
|
3
|
+
import sys
|
|
4
|
+
import os
|
|
5
|
+
import tempfile
|
|
6
|
+
import shutil
|
|
7
|
+
import json
|
|
8
|
+
import time
|
|
9
|
+
|
|
10
|
+
# 设置环境变量
|
|
11
|
+
os.environ['ADAM_API_TOKEN'] = 'test_token'
|
|
12
|
+
os.environ['ADAM_API_HOST'] = 'https://test.com'
|
|
13
|
+
|
|
14
|
+
# 添加项目根目录到 Python 路径
|
|
15
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
16
|
+
|
|
17
|
+
# Mock OpenAI client before importing util
|
|
18
|
+
with patch('openai.OpenAI'):
|
|
19
|
+
from adam_community.util import knowledgeSearch, completionCreate, runCmd, setState, getState, trackPath, RAG
|
|
20
|
+
from adam_community.tool import Tool
|
|
21
|
+
|
|
22
|
+
class TestUtil(unittest.TestCase):
|
|
23
|
+
def setUp(self):
|
|
24
|
+
self.test_params = {
|
|
25
|
+
"project": "test_project",
|
|
26
|
+
"name": "test_collection",
|
|
27
|
+
"query": "test query",
|
|
28
|
+
"limit": 10
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@patch('adam_community.util.RAG.call')
|
|
32
|
+
def test_knowledgeSearch(self, mock_rag_call):
|
|
33
|
+
"""测试knowledgeSearch函数"""
|
|
34
|
+
mock_rag_call.return_value = "test result content"
|
|
35
|
+
|
|
36
|
+
result = knowledgeSearch(
|
|
37
|
+
query_info="test query",
|
|
38
|
+
messages_prev=[{"role": "user", "content": "test"}],
|
|
39
|
+
project_name="test_project",
|
|
40
|
+
collection_name="test_collection"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# 验证返回的是 JSON 格式
|
|
44
|
+
import json
|
|
45
|
+
data = json.loads(result)
|
|
46
|
+
self.assertEqual(data["code"], 0)
|
|
47
|
+
self.assertEqual(data["data"]["collection_name"], "test_collection")
|
|
48
|
+
mock_rag_call.assert_called_once_with("test query", "test_collection")
|
|
49
|
+
|
|
50
|
+
@patch('subprocess.Popen')
|
|
51
|
+
@patch.dict(os.environ, {'ADAM_OUTPUT_RAW': ''}, clear=True)
|
|
52
|
+
def test_runCmd_success(self, mock_popen):
|
|
53
|
+
"""测试runCmd函数成功执行命令的情况"""
|
|
54
|
+
mock_process = MagicMock()
|
|
55
|
+
mock_process.poll.return_value = 0
|
|
56
|
+
mock_process.returncode = 0
|
|
57
|
+
mock_process.stdout.readline.return_value = "test output"
|
|
58
|
+
mock_process.stderr.readline.return_value = ""
|
|
59
|
+
mock_popen.return_value = mock_process
|
|
60
|
+
|
|
61
|
+
process = runCmd('echo "test output"')
|
|
62
|
+
self.assertEqual(process.returncode, 0)
|
|
63
|
+
mock_popen.assert_called_once()
|
|
64
|
+
|
|
65
|
+
@patch('subprocess.Popen')
|
|
66
|
+
@patch.dict(os.environ, {'ADAM_OUTPUT_RAW': ''}, clear=True)
|
|
67
|
+
def test_runCmd_failure(self, mock_popen):
|
|
68
|
+
"""测试runCmd函数执行失败的情况"""
|
|
69
|
+
mock_process = MagicMock()
|
|
70
|
+
mock_process.poll.return_value = 1
|
|
71
|
+
mock_process.returncode = 1
|
|
72
|
+
mock_process.stdout.readline.return_value = ""
|
|
73
|
+
mock_process.stderr.readline.return_value = "command not found"
|
|
74
|
+
mock_popen.return_value = mock_process
|
|
75
|
+
|
|
76
|
+
with self.assertRaises(SystemExit) as cm:
|
|
77
|
+
runCmd('nonexistent_command_123456')
|
|
78
|
+
self.assertEqual(cm.exception.code, 1)
|
|
79
|
+
|
|
80
|
+
@patch.dict(os.environ, {'ADAM_OUTPUT_RAW': 'true'}, clear=True)
|
|
81
|
+
def test_runCmd_with_raw_output(self):
|
|
82
|
+
"""测试runCmd函数在ADAM_OUTPUT_RAW环境变量设置时的情况"""
|
|
83
|
+
cmd = 'echo "test output"'
|
|
84
|
+
result = runCmd(cmd)
|
|
85
|
+
self.assertEqual(result, cmd)
|
|
86
|
+
|
|
87
|
+
class TestTool(unittest.TestCase):
|
|
88
|
+
def setUp(self):
|
|
89
|
+
class TestToolImpl(Tool):
|
|
90
|
+
def call(self, kwargs):
|
|
91
|
+
return "test command"
|
|
92
|
+
|
|
93
|
+
self.tool = TestToolImpl()
|
|
94
|
+
|
|
95
|
+
def test_inputShow(self):
|
|
96
|
+
"""测试inputShow方法"""
|
|
97
|
+
kwargs = {
|
|
98
|
+
"task_id": "test_task",
|
|
99
|
+
"user": "test_user",
|
|
100
|
+
"message": "test message"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
with patch.object(self.tool, 'call', return_value="test command"):
|
|
104
|
+
result = self.tool.inputShow(**kwargs)
|
|
105
|
+
self.assertIn("test_user@Adam", result)
|
|
106
|
+
self.assertIn("test_task", result)
|
|
107
|
+
|
|
108
|
+
def test_resAlloc(self):
|
|
109
|
+
"""测试resAlloc方法"""
|
|
110
|
+
kwargs = {
|
|
111
|
+
"tool_data": "test_data",
|
|
112
|
+
"tip": "test tip"
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
result = self.tool.resAlloc(kwargs)
|
|
116
|
+
self.assertIn("CPU", result)
|
|
117
|
+
self.assertIn("MEM_PER_CPU", result)
|
|
118
|
+
self.assertIn("GPU", result)
|
|
119
|
+
self.assertIn("PARTITION", result)
|
|
120
|
+
|
|
121
|
+
def test_outputShow(self):
|
|
122
|
+
"""测试outputShow方法"""
|
|
123
|
+
kwargs = {
|
|
124
|
+
"stdout": "test stdout",
|
|
125
|
+
"stderr": "test stderr",
|
|
126
|
+
"exit_code": 0
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
result, files = self.tool.outputShow(kwargs)
|
|
130
|
+
self.assertIn("test stdout", result)
|
|
131
|
+
self.assertIn("test stderr", result)
|
|
132
|
+
self.assertEqual(files, [])
|
|
133
|
+
|
|
134
|
+
def test_markdown_color(self):
|
|
135
|
+
"""测试markdown_color静态方法"""
|
|
136
|
+
result = Tool.markdown_color("test", "red")
|
|
137
|
+
self.assertEqual(result, '<span style="color: red">test</span>')
|
|
138
|
+
|
|
139
|
+
def test_markdown_terminal(self):
|
|
140
|
+
"""测试markdown_terminal静态方法"""
|
|
141
|
+
result = Tool.markdown_terminal("test command", "test_env", "test_user", "test_dir")
|
|
142
|
+
self.assertIn("test_user@Adam", result)
|
|
143
|
+
self.assertIn("test_dir", result)
|
|
144
|
+
self.assertIn("test command", result)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class TestStatesManager(unittest.TestCase):
|
|
148
|
+
"""测试 StatesManager 功能"""
|
|
149
|
+
|
|
150
|
+
def setUp(self):
|
|
151
|
+
"""每个测试前创建临时目录"""
|
|
152
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
153
|
+
self.original_cwd = os.getcwd()
|
|
154
|
+
os.chdir(self.temp_dir)
|
|
155
|
+
|
|
156
|
+
# 重置 _states 的缓存
|
|
157
|
+
from adam_community.util import _StatesManager
|
|
158
|
+
_StatesManager._states_file = None
|
|
159
|
+
|
|
160
|
+
def tearDown(self):
|
|
161
|
+
"""每个测试后清理"""
|
|
162
|
+
os.chdir(self.original_cwd)
|
|
163
|
+
shutil.rmtree(self.temp_dir, ignore_errors=True)
|
|
164
|
+
# 重置 _states 的缓存
|
|
165
|
+
from adam_community.util import _StatesManager
|
|
166
|
+
_StatesManager._states_file = None
|
|
167
|
+
|
|
168
|
+
def test_set_and_get_state(self):
|
|
169
|
+
"""测试设置和获取状态"""
|
|
170
|
+
setState("stage", "data_cleaning")
|
|
171
|
+
result = getState("stage")
|
|
172
|
+
self.assertEqual(result, "data_cleaning")
|
|
173
|
+
|
|
174
|
+
def test_set_nested_state(self):
|
|
175
|
+
"""测试设置嵌套状态"""
|
|
176
|
+
setState("config.threshold", 0.5)
|
|
177
|
+
result = getState("config.threshold")
|
|
178
|
+
self.assertEqual(result, 0.5)
|
|
179
|
+
|
|
180
|
+
def test_set_object_state(self):
|
|
181
|
+
"""测试设置对象状态"""
|
|
182
|
+
data = {"stage": "analysis", "rows": 1000}
|
|
183
|
+
setState("result", data)
|
|
184
|
+
result = getState("result")
|
|
185
|
+
self.assertEqual(result["stage"], "analysis")
|
|
186
|
+
self.assertEqual(result["rows"], 1000)
|
|
187
|
+
|
|
188
|
+
def test_get_nonexistent_state(self):
|
|
189
|
+
"""测试获取不存在的状态"""
|
|
190
|
+
result = getState("nonexistent")
|
|
191
|
+
self.assertIsNone(result)
|
|
192
|
+
|
|
193
|
+
def test_set_files(self):
|
|
194
|
+
"""测试设置文件列表"""
|
|
195
|
+
files = [
|
|
196
|
+
{"path": "output/result.json", "is_dir": False, "mtime": 1704100800},
|
|
197
|
+
{"path": "cache", "is_dir": True, "mtime": 1704100000}
|
|
198
|
+
]
|
|
199
|
+
setState("files", files)
|
|
200
|
+
|
|
201
|
+
# 验证文件写入
|
|
202
|
+
states_file = os.path.join(self.temp_dir, ".slurm", "states.json")
|
|
203
|
+
self.assertTrue(os.path.exists(states_file))
|
|
204
|
+
|
|
205
|
+
with open(states_file, 'r') as f:
|
|
206
|
+
data = json.load(f)
|
|
207
|
+
self.assertIn("tool", data["files"]["sources"])
|
|
208
|
+
self.assertEqual(len(data["files"]["sources"]["tool"]["items"]), 2)
|
|
209
|
+
|
|
210
|
+
def test_get_files_merges_sources(self):
|
|
211
|
+
"""测试获取文件列表时合并多个来源"""
|
|
212
|
+
# 先写入 server 的文件
|
|
213
|
+
server_file = os.path.join(self.temp_dir, ".slurm", "states.json")
|
|
214
|
+
os.makedirs(os.path.dirname(server_file), exist_ok=True)
|
|
215
|
+
with open(server_file, 'w') as f:
|
|
216
|
+
json.dump({
|
|
217
|
+
"files": {
|
|
218
|
+
"updated_at": "2024-01-01T00:00:00Z",
|
|
219
|
+
"sources": {
|
|
220
|
+
"server": {
|
|
221
|
+
"updated_at": "2024-01-01T00:00:00Z",
|
|
222
|
+
"items": [
|
|
223
|
+
{"path": "src/main.py", "is_dir": False, "mtime": 1704100000}
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
"states": {"source": None, "updated_at": None, "data": {}}
|
|
229
|
+
}, f)
|
|
230
|
+
|
|
231
|
+
# 写入 tool 的文件
|
|
232
|
+
setState("files", [
|
|
233
|
+
{"path": "output/result.json", "is_dir": False, "mtime": 1704100800}
|
|
234
|
+
])
|
|
235
|
+
|
|
236
|
+
# 获取并验证合并
|
|
237
|
+
files = getState("files")
|
|
238
|
+
self.assertEqual(len(files), 2)
|
|
239
|
+
paths = [f["path"] for f in files]
|
|
240
|
+
self.assertIn("src/main.py", paths)
|
|
241
|
+
self.assertIn("output/result.json", paths)
|
|
242
|
+
|
|
243
|
+
def test_get_files_sorted_by_mtime(self):
|
|
244
|
+
"""测试文件列表按 mtime 降序排序"""
|
|
245
|
+
setState("files", [
|
|
246
|
+
{"path": "old.txt", "is_dir": False, "mtime": 1704100000},
|
|
247
|
+
{"path": "new.txt", "is_dir": False, "mtime": 1704100800},
|
|
248
|
+
{"path": "middle.txt", "is_dir": False, "mtime": 1704100400}
|
|
249
|
+
])
|
|
250
|
+
|
|
251
|
+
files = getState("files")
|
|
252
|
+
mtimes = [f["mtime"] for f in files]
|
|
253
|
+
self.assertEqual(mtimes, sorted(mtimes, reverse=True))
|
|
254
|
+
|
|
255
|
+
def test_preserve_existing_data(self):
|
|
256
|
+
"""测试写入时保留已有数据"""
|
|
257
|
+
# 先写入 server 数据
|
|
258
|
+
server_file = os.path.join(self.temp_dir, ".slurm", "states.json")
|
|
259
|
+
os.makedirs(os.path.dirname(server_file), exist_ok=True)
|
|
260
|
+
with open(server_file, 'w') as f:
|
|
261
|
+
json.dump({
|
|
262
|
+
"files": {
|
|
263
|
+
"updated_at": "2024-01-01T00:00:00Z",
|
|
264
|
+
"sources": {
|
|
265
|
+
"server": {
|
|
266
|
+
"updated_at": "2024-01-01T00:00:00Z",
|
|
267
|
+
"items": [{"path": "main.py", "is_dir": False, "mtime": 1704100000}]
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
"states": {
|
|
272
|
+
"source": "server",
|
|
273
|
+
"updated_at": "2024-01-01T00:00:00Z",
|
|
274
|
+
"data": {"server_stage": "init"}
|
|
275
|
+
}
|
|
276
|
+
}, f)
|
|
277
|
+
|
|
278
|
+
# 写入 tool 状态
|
|
279
|
+
setState("stage", "processing")
|
|
280
|
+
|
|
281
|
+
# 验证 server 数据保留
|
|
282
|
+
with open(server_file, 'r') as f:
|
|
283
|
+
data = json.load(f)
|
|
284
|
+
self.assertIn("server", data["files"]["sources"])
|
|
285
|
+
self.assertEqual(data["states"]["data"]["server_stage"], "init")
|
|
286
|
+
self.assertEqual(data["states"]["data"]["stage"], "processing")
|
|
287
|
+
|
|
288
|
+
def test_nonexistent_directory_creates_slurm(self):
|
|
289
|
+
"""测试不存在的目录会自动创建 .slurm"""
|
|
290
|
+
os.chdir(self.original_cwd) # 切回非临时目录
|
|
291
|
+
test_dir = os.path.join(self.temp_dir, "new_task")
|
|
292
|
+
os.makedirs(test_dir)
|
|
293
|
+
os.chdir(test_dir)
|
|
294
|
+
|
|
295
|
+
setState("stage", "test")
|
|
296
|
+
states_file = os.path.join(test_dir, ".slurm", "states.json")
|
|
297
|
+
self.assertTrue(os.path.exists(states_file))
|
|
298
|
+
|
|
299
|
+
def test_trackPath_file(self):
|
|
300
|
+
"""测试追踪文件"""
|
|
301
|
+
# 设置环境变量
|
|
302
|
+
os.environ['ADAM_TASK_DIR'] = self.temp_dir
|
|
303
|
+
|
|
304
|
+
try:
|
|
305
|
+
# 创建测试文件
|
|
306
|
+
test_file = os.path.join(self.temp_dir, "test.txt")
|
|
307
|
+
with open(test_file, 'w') as f:
|
|
308
|
+
f.write("test content")
|
|
309
|
+
|
|
310
|
+
trackPath(test_file)
|
|
311
|
+
|
|
312
|
+
files = getState("files")
|
|
313
|
+
self.assertEqual(len(files), 1)
|
|
314
|
+
self.assertEqual(files[0]["path"], "test.txt")
|
|
315
|
+
self.assertFalse(files[0]["is_dir"])
|
|
316
|
+
finally:
|
|
317
|
+
del os.environ['ADAM_TASK_DIR']
|
|
318
|
+
|
|
319
|
+
def test_trackPath_directory(self):
|
|
320
|
+
"""测试追踪目录"""
|
|
321
|
+
# 设置环境变量
|
|
322
|
+
os.environ['ADAM_TASK_DIR'] = self.temp_dir
|
|
323
|
+
|
|
324
|
+
try:
|
|
325
|
+
# 创建测试目录
|
|
326
|
+
test_dir = os.path.join(self.temp_dir, "output")
|
|
327
|
+
os.makedirs(test_dir)
|
|
328
|
+
|
|
329
|
+
trackPath(test_dir)
|
|
330
|
+
|
|
331
|
+
files = getState("files")
|
|
332
|
+
self.assertEqual(len(files), 1)
|
|
333
|
+
self.assertEqual(files[0]["path"], "output")
|
|
334
|
+
self.assertTrue(files[0]["is_dir"])
|
|
335
|
+
finally:
|
|
336
|
+
del os.environ['ADAM_TASK_DIR']
|
|
337
|
+
|
|
338
|
+
def test_trackPath_nonexistent(self):
|
|
339
|
+
"""测试追踪不存在的路径"""
|
|
340
|
+
trackPath("/nonexistent/path/file.txt")
|
|
341
|
+
files = getState("files")
|
|
342
|
+
self.assertEqual(len(files), 0)
|
|
343
|
+
|
|
344
|
+
def test_trackPath_updates_existing(self):
|
|
345
|
+
"""测试追踪已存在的文件会更新 mtime 并移动到末尾"""
|
|
346
|
+
# 设置环境变量
|
|
347
|
+
os.environ['ADAM_TASK_DIR'] = self.temp_dir
|
|
348
|
+
|
|
349
|
+
try:
|
|
350
|
+
# 先创建几个文件
|
|
351
|
+
for name in ["a.txt", "b.txt", "file.txt"]:
|
|
352
|
+
with open(os.path.join(self.temp_dir, name), 'w') as f:
|
|
353
|
+
f.write(name)
|
|
354
|
+
|
|
355
|
+
# 追踪这些文件
|
|
356
|
+
trackPath(os.path.join(self.temp_dir, "a.txt"))
|
|
357
|
+
trackPath(os.path.join(self.temp_dir, "b.txt"))
|
|
358
|
+
trackPath(os.path.join(self.temp_dir, "file.txt"))
|
|
359
|
+
|
|
360
|
+
files = getState("files")
|
|
361
|
+
self.assertEqual(len(files), 3)
|
|
362
|
+
# file.txt 应该在最后(最新追踪的)
|
|
363
|
+
self.assertEqual(files[2]["path"], "file.txt")
|
|
364
|
+
|
|
365
|
+
# 再次追踪 file.txt,它应该移动到末尾
|
|
366
|
+
time.sleep(0.1) # 等待以确保 mtime 不同
|
|
367
|
+
with open(os.path.join(self.temp_dir, "file.txt"), 'w') as f:
|
|
368
|
+
f.write("v2")
|
|
369
|
+
mtime2 = int(os.path.getmtime(os.path.join(self.temp_dir, "file.txt")))
|
|
370
|
+
|
|
371
|
+
trackPath(os.path.join(self.temp_dir, "file.txt"))
|
|
372
|
+
|
|
373
|
+
files = getState("files")
|
|
374
|
+
self.assertEqual(len(files), 3)
|
|
375
|
+
# file.txt 仍然在最后
|
|
376
|
+
self.assertEqual(files[2]["path"], "file.txt")
|
|
377
|
+
# mtime 已更新
|
|
378
|
+
self.assertEqual(files[2]["mtime"], mtime2)
|
|
379
|
+
finally:
|
|
380
|
+
del os.environ['ADAM_TASK_DIR']
|
|
381
|
+
|
|
382
|
+
def test_trackPath_max_items_fifo(self):
|
|
383
|
+
"""测试追踪超过最大数量时先进先出"""
|
|
384
|
+
# 设置环境变量
|
|
385
|
+
os.environ['ADAM_TASK_DIR'] = self.temp_dir
|
|
386
|
+
|
|
387
|
+
try:
|
|
388
|
+
# 创建 35 个文件
|
|
389
|
+
for i in range(35):
|
|
390
|
+
with open(os.path.join(self.temp_dir, f"file_{i}.txt"), 'w') as f:
|
|
391
|
+
f.write(str(i))
|
|
392
|
+
|
|
393
|
+
# 追踪所有文件
|
|
394
|
+
for i in range(35):
|
|
395
|
+
trackPath(os.path.join(self.temp_dir, f"file_{i}.txt"))
|
|
396
|
+
|
|
397
|
+
files = getState("files")
|
|
398
|
+
# 应该保留 30 条(file_5 到 file_34)
|
|
399
|
+
self.assertEqual(len(files), 30)
|
|
400
|
+
|
|
401
|
+
# 检查最新追踪的文件是否保留
|
|
402
|
+
filenames = [f["path"] for f in files]
|
|
403
|
+
self.assertIn("file_34.txt", filenames)
|
|
404
|
+
self.assertIn("file_5.txt", filenames)
|
|
405
|
+
|
|
406
|
+
# 检查最早追踪的文件是否被移除
|
|
407
|
+
self.assertNotIn("file_0.txt", filenames)
|
|
408
|
+
self.assertNotIn("file_1.txt", filenames)
|
|
409
|
+
self.assertNotIn("file_2.txt", filenames)
|
|
410
|
+
self.assertNotIn("file_3.txt", filenames)
|
|
411
|
+
self.assertNotIn("file_4.txt", filenames)
|
|
412
|
+
finally:
|
|
413
|
+
del os.environ['ADAM_TASK_DIR']
|
|
414
|
+
|
|
415
|
+
def test_trackPath_with_task_dir_env(self):
|
|
416
|
+
"""测试追踪时使用环境变量的 task_dir"""
|
|
417
|
+
# 设置环境变量
|
|
418
|
+
os.environ['ADAM_TASK_DIR'] = self.temp_dir
|
|
419
|
+
|
|
420
|
+
try:
|
|
421
|
+
# 在子目录中创建文件
|
|
422
|
+
sub_dir = os.path.join(self.temp_dir, "src")
|
|
423
|
+
os.makedirs(sub_dir)
|
|
424
|
+
test_file = os.path.join(sub_dir, "main.py")
|
|
425
|
+
with open(test_file, 'w') as f:
|
|
426
|
+
f.write("print('hello')")
|
|
427
|
+
|
|
428
|
+
trackPath(test_file)
|
|
429
|
+
|
|
430
|
+
files = getState("files")
|
|
431
|
+
self.assertEqual(len(files), 1)
|
|
432
|
+
self.assertEqual(files[0]["path"], "src/main.py")
|
|
433
|
+
finally:
|
|
434
|
+
del os.environ['ADAM_TASK_DIR']
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
if __name__ == '__main__':
|
|
438
|
+
unittest.main()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.0.22"
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
from unittest.mock import patch, MagicMock, PropertyMock
|
|
3
|
-
import sys
|
|
4
|
-
import os
|
|
5
|
-
|
|
6
|
-
# 设置环境变量
|
|
7
|
-
os.environ['ADAM_API_TOKEN'] = 'test_token'
|
|
8
|
-
os.environ['ADAM_API_HOST'] = 'https://test.com'
|
|
9
|
-
|
|
10
|
-
# 添加项目根目录到 Python 路径
|
|
11
|
-
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
12
|
-
|
|
13
|
-
# Mock OpenAI client before importing util
|
|
14
|
-
with patch('openai.OpenAI'):
|
|
15
|
-
from adam_community.util import knowledgeSearch, completionCreate, runCmd
|
|
16
|
-
from adam_community.tool import Tool
|
|
17
|
-
|
|
18
|
-
class TestUtil(unittest.TestCase):
|
|
19
|
-
def setUp(self):
|
|
20
|
-
self.test_params = {
|
|
21
|
-
"project": "test_project",
|
|
22
|
-
"name": "test_collection",
|
|
23
|
-
"query": "test query",
|
|
24
|
-
"limit": 10
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
@patch('urllib.request.urlopen')
|
|
28
|
-
def test_knowledgeSearch(self, mock_urlopen):
|
|
29
|
-
"""测试knowledgeSearch函数"""
|
|
30
|
-
mock_response = MagicMock()
|
|
31
|
-
# 设置status属性为整数
|
|
32
|
-
type(mock_response).status = PropertyMock(return_value=200)
|
|
33
|
-
mock_response.read.return_value = b'{"result": "success"}'
|
|
34
|
-
mock_urlopen.return_value.__enter__.return_value = mock_response
|
|
35
|
-
|
|
36
|
-
result = knowledgeSearch(
|
|
37
|
-
query_info="test query",
|
|
38
|
-
messages_prev=[{"role": "user", "content": "test"}],
|
|
39
|
-
project_name="test_project",
|
|
40
|
-
collection_name="test_collection"
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
self.assertEqual(result, '{"result": "success"}')
|
|
44
|
-
mock_urlopen.assert_called_once()
|
|
45
|
-
|
|
46
|
-
@patch('subprocess.Popen')
|
|
47
|
-
@patch.dict(os.environ, {'ADAM_OUTPUT_RAW': ''}, clear=True)
|
|
48
|
-
def test_runCmd_success(self, mock_popen):
|
|
49
|
-
"""测试runCmd函数成功执行命令的情况"""
|
|
50
|
-
mock_process = MagicMock()
|
|
51
|
-
mock_process.poll.return_value = 0
|
|
52
|
-
mock_process.returncode = 0
|
|
53
|
-
mock_process.stdout.readline.return_value = "test output"
|
|
54
|
-
mock_process.stderr.readline.return_value = ""
|
|
55
|
-
mock_popen.return_value = mock_process
|
|
56
|
-
|
|
57
|
-
process = runCmd('echo "test output"')
|
|
58
|
-
self.assertEqual(process.returncode, 0)
|
|
59
|
-
mock_popen.assert_called_once()
|
|
60
|
-
|
|
61
|
-
@patch('subprocess.Popen')
|
|
62
|
-
@patch.dict(os.environ, {'ADAM_OUTPUT_RAW': ''}, clear=True)
|
|
63
|
-
def test_runCmd_failure(self, mock_popen):
|
|
64
|
-
"""测试runCmd函数执行失败的情况"""
|
|
65
|
-
mock_process = MagicMock()
|
|
66
|
-
mock_process.poll.return_value = 1
|
|
67
|
-
mock_process.returncode = 1
|
|
68
|
-
mock_process.stdout.readline.return_value = ""
|
|
69
|
-
mock_process.stderr.readline.return_value = "command not found"
|
|
70
|
-
mock_popen.return_value = mock_process
|
|
71
|
-
|
|
72
|
-
with self.assertRaises(SystemExit) as cm:
|
|
73
|
-
runCmd('nonexistent_command_123456')
|
|
74
|
-
self.assertEqual(cm.exception.code, 1)
|
|
75
|
-
|
|
76
|
-
@patch.dict(os.environ, {'ADAM_OUTPUT_RAW': 'true'}, clear=True)
|
|
77
|
-
def test_runCmd_with_raw_output(self):
|
|
78
|
-
"""测试runCmd函数在ADAM_OUTPUT_RAW环境变量设置时的情况"""
|
|
79
|
-
cmd = 'echo "test output"'
|
|
80
|
-
result = runCmd(cmd)
|
|
81
|
-
self.assertEqual(result, cmd)
|
|
82
|
-
|
|
83
|
-
class TestTool(unittest.TestCase):
|
|
84
|
-
def setUp(self):
|
|
85
|
-
class TestToolImpl(Tool):
|
|
86
|
-
def call(self, kwargs):
|
|
87
|
-
return "test command"
|
|
88
|
-
|
|
89
|
-
self.tool = TestToolImpl()
|
|
90
|
-
|
|
91
|
-
def test_inputShow(self):
|
|
92
|
-
"""测试inputShow方法"""
|
|
93
|
-
kwargs = {
|
|
94
|
-
"task_id": "test_task",
|
|
95
|
-
"user": "test_user",
|
|
96
|
-
"message": "test message"
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
with patch.object(self.tool, 'call', return_value="test command"):
|
|
100
|
-
result = self.tool.inputShow(**kwargs)
|
|
101
|
-
self.assertIn("test_user@Adam", result)
|
|
102
|
-
self.assertIn("test_task", result)
|
|
103
|
-
|
|
104
|
-
def test_resAlloc(self):
|
|
105
|
-
"""测试resAlloc方法"""
|
|
106
|
-
kwargs = {
|
|
107
|
-
"tool_data": "test_data",
|
|
108
|
-
"tip": "test tip"
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
result = self.tool.resAlloc(kwargs)
|
|
112
|
-
self.assertIn("CPU", result)
|
|
113
|
-
self.assertIn("MEM_PER_CPU", result)
|
|
114
|
-
self.assertIn("GPU", result)
|
|
115
|
-
self.assertIn("PARTITION", result)
|
|
116
|
-
|
|
117
|
-
def test_outputShow(self):
|
|
118
|
-
"""测试outputShow方法"""
|
|
119
|
-
kwargs = {
|
|
120
|
-
"stdout": "test stdout",
|
|
121
|
-
"stderr": "test stderr",
|
|
122
|
-
"exit_code": 0
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
result, files = self.tool.outputShow(kwargs)
|
|
126
|
-
self.assertIn("test stdout", result)
|
|
127
|
-
self.assertIn("test stderr", result)
|
|
128
|
-
self.assertEqual(files, [])
|
|
129
|
-
|
|
130
|
-
def test_markdown_color(self):
|
|
131
|
-
"""测试markdown_color静态方法"""
|
|
132
|
-
result = Tool.markdown_color("test", "red")
|
|
133
|
-
self.assertEqual(result, '<span style="color: red">test</span>')
|
|
134
|
-
|
|
135
|
-
def test_markdown_terminal(self):
|
|
136
|
-
"""测试markdown_terminal静态方法"""
|
|
137
|
-
result = Tool.markdown_terminal("test command", "test_env", "test_user", "test_dir")
|
|
138
|
-
self.assertIn("test_user@Adam", result)
|
|
139
|
-
self.assertIn("test_dir", result)
|
|
140
|
-
self.assertIn("test command", result)
|
|
141
|
-
|
|
142
|
-
if __name__ == '__main__':
|
|
143
|
-
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/README_agent.md.j2
RENAMED
|
File without changes
|
{adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/README_kit.md.j2
RENAMED
|
File without changes
|
|
File without changes
|
{adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/agent_python.py.j2
RENAMED
|
File without changes
|
{adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/configure.json.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/kit_python.py.j2
RENAMED
|
File without changes
|
{adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/long_description.md.j2
RENAMED
|
File without changes
|
|
File without changes
|
{adam_community-1.0.22 → adam_community-1.0.24}/adam_community/cli/templates/rag_python.py.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{adam_community-1.0.22 → adam_community-1.0.24}/adam_community.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|