bohr-agent-sdk 0.1.19__py3-none-any.whl → 0.1.21__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.
- {bohr_agent_sdk-0.1.19.dist-info → bohr_agent_sdk-0.1.21.dist-info}/METADATA +1 -1
- {bohr_agent_sdk-0.1.19.dist-info → bohr_agent_sdk-0.1.21.dist-info}/RECORD +8 -8
- dp/agent/server/calculation_mcp_server.py +7 -3
- dp/agent/server/executor/dispatcher_executor.py +16 -13
- dp/agent/server/executor/local_executor.py +59 -4
- {bohr_agent_sdk-0.1.19.dist-info → bohr_agent_sdk-0.1.21.dist-info}/WHEEL +0 -0
- {bohr_agent_sdk-0.1.19.dist-info → bohr_agent_sdk-0.1.21.dist-info}/entry_points.txt +0 -0
- {bohr_agent_sdk-0.1.19.dist-info → bohr_agent_sdk-0.1.21.dist-info}/top_level.txt +0 -0
|
@@ -20,21 +20,21 @@ dp/agent/device/device/__init__.py,sha256=w7_1S16S1vWUq0RGl0GFgjq2vFkc5oNvy8cQTn
|
|
|
20
20
|
dp/agent/device/device/device.py,sha256=9ZRIJth-4qMO-i-u_b_cO3d6a4eTbTQjPaxFsV_zEkc,9643
|
|
21
21
|
dp/agent/device/device/types.py,sha256=JuxB-hjf1CjjvfBxCLwRAXVFlYS-nPEdiJpBWLFVCzo,1924
|
|
22
22
|
dp/agent/server/__init__.py,sha256=rckaYd8pbYyB4ENEhgjXKeGMXjdnrgcJpdM1gu5u1Wc,508
|
|
23
|
-
dp/agent/server/calculation_mcp_server.py,sha256=
|
|
23
|
+
dp/agent/server/calculation_mcp_server.py,sha256=oumU2xtqrrgp8BKiuF9YsqMNevXba2JACyYsvNy4nQo,11008
|
|
24
24
|
dp/agent/server/preprocessor.py,sha256=XUWu7QOwo_sIDMYS2b1OTrM33EXEVH_73vk-ju1Ok8A,1264
|
|
25
25
|
dp/agent/server/utils.py,sha256=8jgYZEW4XBp86AF2Km6QkwHltBmrnS-soTpHov7ZEJw,4501
|
|
26
26
|
dp/agent/server/executor/__init__.py,sha256=s95M5qKQk39Yi9qaVJZhk_nfj54quSf7EDghR3OCFUA,248
|
|
27
27
|
dp/agent/server/executor/base_executor.py,sha256=EFJBsYVYAvuRbiLAbLOwLTw3h7ScjN025xnSP4uJHrQ,2052
|
|
28
|
-
dp/agent/server/executor/dispatcher_executor.py,sha256=
|
|
29
|
-
dp/agent/server/executor/local_executor.py,sha256=
|
|
28
|
+
dp/agent/server/executor/dispatcher_executor.py,sha256=urpzmKH_tBOgblBdJEa3y8eEhXqUDrdcdWCnUdJpfZk,9420
|
|
29
|
+
dp/agent/server/executor/local_executor.py,sha256=9JEtZTEbKsmHAY5nsdLZ36gH5M_rSG6En0W9IrCUwm0,5803
|
|
30
30
|
dp/agent/server/storage/__init__.py,sha256=Sgsyp5hb0_hhIGugAPfQFzBHt_854rS_MuMuE3sn8Gs,389
|
|
31
31
|
dp/agent/server/storage/base_storage.py,sha256=728-oNG6N8isV95gZVnyi4vTznJPJhSjxw9Gl5Y_y5o,2356
|
|
32
32
|
dp/agent/server/storage/bohrium_storage.py,sha256=EsKX4dWWvZTn2TEhZv4zsvihfDK0mmPFecrln-Ytk40,10488
|
|
33
33
|
dp/agent/server/storage/http_storage.py,sha256=KiySq7g9-iJr12XQCKKyJLn8wJoDnSRpQAR5_qPJ1ZU,1471
|
|
34
34
|
dp/agent/server/storage/local_storage.py,sha256=t1wfjByjXew9ws3PuUxWxmZQ0-Wt1a6t4wmj3fW62GI,1352
|
|
35
35
|
dp/agent/server/storage/oss_storage.py,sha256=pgjmi7Gir3Y5wkMDCvU4fvSls15fXT7Ax-h9MYHFPK0,3359
|
|
36
|
-
bohr_agent_sdk-0.1.
|
|
37
|
-
bohr_agent_sdk-0.1.
|
|
38
|
-
bohr_agent_sdk-0.1.
|
|
39
|
-
bohr_agent_sdk-0.1.
|
|
40
|
-
bohr_agent_sdk-0.1.
|
|
36
|
+
bohr_agent_sdk-0.1.21.dist-info/METADATA,sha256=nHfB7MVnAuzZs1EUND-29vdVA3KDSzpuJmQxTswFT_I,6329
|
|
37
|
+
bohr_agent_sdk-0.1.21.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
38
|
+
bohr_agent_sdk-0.1.21.dist-info/entry_points.txt,sha256=5n5kneF5IbDQtoQ2WfF-QuBjDtsimJte9Rv9baSGgc0,86
|
|
39
|
+
bohr_agent_sdk-0.1.21.dist-info/top_level.txt,sha256=87xLUDhu_1nQHoGLwlhJ6XlO7OsjILh6i1nX6ljFzDo,3
|
|
40
|
+
bohr_agent_sdk-0.1.21.dist-info/RECORD,,
|
|
@@ -29,7 +29,7 @@ def parse_uri(uri):
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def init_storage(storage_config: Optional[dict] = None):
|
|
32
|
-
if storage_config
|
|
32
|
+
if not storage_config:
|
|
33
33
|
storage_config = {"type": "local"}
|
|
34
34
|
storage_config = deepcopy(storage_config)
|
|
35
35
|
storage_type = storage_config.pop("type")
|
|
@@ -38,7 +38,7 @@ def init_storage(storage_config: Optional[dict] = None):
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
def init_executor(executor_config: Optional[dict] = None):
|
|
41
|
-
if executor_config
|
|
41
|
+
if not executor_config:
|
|
42
42
|
executor_config = {"type": "local"}
|
|
43
43
|
executor_config = deepcopy(executor_config)
|
|
44
44
|
executor_type = executor_config.pop("type")
|
|
@@ -227,7 +227,11 @@ class CalculationMCPServer:
|
|
|
227
227
|
exec_id = res["job_id"]
|
|
228
228
|
job_id = "%s/%s" % (trace_id, exec_id)
|
|
229
229
|
logger.info("Job submitted (ID: %s)" % job_id)
|
|
230
|
-
|
|
230
|
+
result = {
|
|
231
|
+
"job_id": job_id,
|
|
232
|
+
"extra_info": res.get("extra_info"),
|
|
233
|
+
}
|
|
234
|
+
return convert_to_content(result, job_info={
|
|
231
235
|
"trace_id": trace_id,
|
|
232
236
|
"executor_type": executor_type,
|
|
233
237
|
"job_id": job_id,
|
|
@@ -12,12 +12,15 @@ from dpdispatcher import Machine, Resources, Task, Submission
|
|
|
12
12
|
|
|
13
13
|
from .base_executor import BaseExecutor
|
|
14
14
|
from .... import __path__
|
|
15
|
+
|
|
15
16
|
config = {
|
|
16
17
|
"username": os.environ.get("BOHRIUM_USERNAME", ""),
|
|
17
18
|
"password": os.environ.get("BOHRIUM_PASSWORD", ""),
|
|
18
19
|
"project_id": os.environ.get("BOHRIUM_PROJECT_ID", ""),
|
|
19
20
|
"access_key": os.environ.get("BOHRIUM_ACCESS_KEY", ""),
|
|
20
21
|
"app_key": os.environ.get("BOHRIUM_APP_KEY", "agent"),
|
|
22
|
+
"bohrium_url": os.environ.get("BOHRIUM_BOHRIUM_URL",
|
|
23
|
+
"https://bohrium.dp.tech"),
|
|
21
24
|
}
|
|
22
25
|
logger = logging.getLogger(__name__)
|
|
23
26
|
|
|
@@ -26,17 +29,17 @@ def get_source_code(fn):
|
|
|
26
29
|
source_lines, start_line = inspect.getsourcelines(fn)
|
|
27
30
|
source_file = inspect.getsourcefile(fn)
|
|
28
31
|
with open(source_file, "r", encoding="utf-8") as fd:
|
|
29
|
-
pre_lines = fd.readlines()[:start_line-1]
|
|
32
|
+
pre_lines = fd.readlines()[:start_line - 1]
|
|
30
33
|
return "".join(pre_lines + source_lines) + "\n"
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
class DispatcherExecutor(BaseExecutor):
|
|
34
37
|
def __init__(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
self,
|
|
39
|
+
machine=None,
|
|
40
|
+
resources=None,
|
|
41
|
+
python_packages=None,
|
|
42
|
+
python_executable="python3",
|
|
40
43
|
):
|
|
41
44
|
"""Use DPDispatcher to execute the tool
|
|
42
45
|
Refer to https://docs.deepmodeling.com/projects/dpdispatcher.
|
|
@@ -107,7 +110,7 @@ class DispatcherExecutor(BaseExecutor):
|
|
|
107
110
|
script += "if __name__ == \"__main__\":\n"
|
|
108
111
|
script += " cwd = os.getcwd()\n"
|
|
109
112
|
script += " kwargs = jsonpickle.loads(r'''%s''')\n" % \
|
|
110
|
-
|
|
113
|
+
jsonpickle.dumps(kwargs)
|
|
111
114
|
script += " try:\n"
|
|
112
115
|
if import_func_line is not None:
|
|
113
116
|
script += " " + import_func_line
|
|
@@ -118,8 +121,8 @@ class DispatcherExecutor(BaseExecutor):
|
|
|
118
121
|
script += " if isinstance(results, dict):\n"
|
|
119
122
|
script += " for name in results:\n"
|
|
120
123
|
script += " if isinstance(results[name], Path):\n"
|
|
121
|
-
script += " results[name] = "\
|
|
122
|
-
|
|
124
|
+
script += " results[name] = " \
|
|
125
|
+
"results[name].absolute().relative_to(cwd)\n"
|
|
123
126
|
script += " except Exception as e:\n"
|
|
124
127
|
script += " os.chdir(cwd)\n"
|
|
125
128
|
script += " with open('err', 'w') as f:\n"
|
|
@@ -173,8 +176,8 @@ class DispatcherExecutor(BaseExecutor):
|
|
|
173
176
|
extra_info = {
|
|
174
177
|
"bohr_job_id": bohr_job_id,
|
|
175
178
|
"bohr_group_id": bohr_group_id,
|
|
176
|
-
"job_link": "
|
|
177
|
-
|
|
179
|
+
"job_link": f"{config['bohrium_url']}/jobs/detail/%s" %
|
|
180
|
+
bohr_job_id,
|
|
178
181
|
}
|
|
179
182
|
logger.info(extra_info)
|
|
180
183
|
res["extra_info"] = extra_info
|
|
@@ -182,8 +185,8 @@ class DispatcherExecutor(BaseExecutor):
|
|
|
182
185
|
bohr_job_id = submission.belonging_jobs[0].job_id
|
|
183
186
|
extra_info = {
|
|
184
187
|
"bohr_job_id": bohr_job_id,
|
|
185
|
-
"job_link": "
|
|
186
|
-
|
|
188
|
+
"job_link": f"{config['bohrium_url']}/jobs/detail/%s" %
|
|
189
|
+
bohr_job_id,
|
|
187
190
|
}
|
|
188
191
|
logger.info(extra_info)
|
|
189
192
|
res["extra_info"] = extra_info
|
|
@@ -1,19 +1,43 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import importlib
|
|
3
3
|
import inspect
|
|
4
|
+
import io
|
|
4
5
|
import jsonpickle
|
|
5
6
|
import os
|
|
6
7
|
import psutil
|
|
8
|
+
import re
|
|
7
9
|
import sys
|
|
10
|
+
import time
|
|
8
11
|
import uuid
|
|
9
12
|
from multiprocessing import Process
|
|
10
13
|
from typing import Dict, Optional
|
|
11
14
|
|
|
12
15
|
from .base_executor import BaseExecutor
|
|
16
|
+
from ..utils import get_logger
|
|
13
17
|
|
|
18
|
+
DFLOW_ID_PATTERN = r"Workflow has been submitted \(ID: ([^,]*), UID: ([^)]*)\)"
|
|
19
|
+
DFLOW_LINK_PATTERN = r"Workflow link: (.*)"
|
|
20
|
+
logger = get_logger(__name__)
|
|
14
21
|
|
|
15
|
-
|
|
22
|
+
|
|
23
|
+
class Tee(io.TextIOBase):
|
|
24
|
+
def __init__(self, file, stdout):
|
|
25
|
+
self.file = file
|
|
26
|
+
self.stdout = stdout
|
|
27
|
+
|
|
28
|
+
def write(self, text):
|
|
29
|
+
self.stdout.write(text)
|
|
30
|
+
self.file.write(text)
|
|
31
|
+
self.file.flush()
|
|
32
|
+
return len(text)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def wrapped_fn(fn, kwargs, redirect_file=None):
|
|
16
36
|
pid = os.getpid()
|
|
37
|
+
if redirect_file:
|
|
38
|
+
stdout = sys.stdout
|
|
39
|
+
flog = open(redirect_file, "w")
|
|
40
|
+
sys.stdout = Tee(flog, stdout)
|
|
17
41
|
try:
|
|
18
42
|
if inspect.iscoroutinefunction(fn):
|
|
19
43
|
result = asyncio.run(fn(**kwargs))
|
|
@@ -23,6 +47,10 @@ def wrapped_fn(fn, kwargs):
|
|
|
23
47
|
with open("err", "w") as f:
|
|
24
48
|
f.write(str(e))
|
|
25
49
|
raise e
|
|
50
|
+
finally:
|
|
51
|
+
if redirect_file:
|
|
52
|
+
sys.stdout = stdout
|
|
53
|
+
flog.close()
|
|
26
54
|
with open("%s.txt" % pid, "w") as f:
|
|
27
55
|
f.write(jsonpickle.dumps(result))
|
|
28
56
|
|
|
@@ -47,13 +75,16 @@ def reload_dflow_config():
|
|
|
47
75
|
|
|
48
76
|
|
|
49
77
|
class LocalExecutor(BaseExecutor):
|
|
50
|
-
def __init__(self, env: Optional[Dict[str, str]] = None
|
|
78
|
+
def __init__(self, env: Optional[Dict[str, str]] = None,
|
|
79
|
+
dflow: bool = False):
|
|
51
80
|
"""
|
|
52
81
|
Execute the tool locally
|
|
53
82
|
Args:
|
|
54
83
|
env: The environmental variables at run time
|
|
84
|
+
dflow: Wait until workflow submitted in submit method
|
|
55
85
|
"""
|
|
56
86
|
self.env = env or {}
|
|
87
|
+
self.dflow = dflow
|
|
57
88
|
|
|
58
89
|
def set_env(self):
|
|
59
90
|
old_env = {}
|
|
@@ -73,10 +104,34 @@ class LocalExecutor(BaseExecutor):
|
|
|
73
104
|
def submit(self, fn, kwargs):
|
|
74
105
|
os.environ["DP_AGENT_RUNNING_MODE"] = "1"
|
|
75
106
|
old_env = self.set_env()
|
|
76
|
-
|
|
107
|
+
params = {"fn": fn, "kwargs": kwargs}
|
|
108
|
+
if self.dflow:
|
|
109
|
+
params["redirect_file"] = "log.txt"
|
|
110
|
+
p = Process(target=wrapped_fn, kwargs=params)
|
|
77
111
|
p.start()
|
|
112
|
+
extra_info = {}
|
|
113
|
+
if self.dflow:
|
|
114
|
+
while True:
|
|
115
|
+
alive = p.is_alive()
|
|
116
|
+
if os.path.isfile("log.txt"):
|
|
117
|
+
with open("log.txt", "r") as f:
|
|
118
|
+
log = f.read()
|
|
119
|
+
match_id = re.search(DFLOW_ID_PATTERN, log)
|
|
120
|
+
match_link = re.search(DFLOW_LINK_PATTERN, log)
|
|
121
|
+
if match_id and match_link:
|
|
122
|
+
wf_id = match_id.group(1)
|
|
123
|
+
wf_uid = match_id.group(2)
|
|
124
|
+
wf_link = match_link.group(1)
|
|
125
|
+
extra_info["workflow_id"] = wf_id
|
|
126
|
+
extra_info["workflow_uid"] = wf_uid
|
|
127
|
+
extra_info["workflow_link"] = wf_link
|
|
128
|
+
break
|
|
129
|
+
if not alive:
|
|
130
|
+
break
|
|
131
|
+
logger.info("Waiting workflow to be submitted")
|
|
132
|
+
time.sleep(1)
|
|
78
133
|
self.recover_env(old_env)
|
|
79
|
-
return {"job_id": str(p.pid)}
|
|
134
|
+
return {"job_id": str(p.pid), "extra_info": extra_info}
|
|
80
135
|
|
|
81
136
|
def query_status(self, job_id):
|
|
82
137
|
try:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|