bohr-agent-sdk 0.1.109__tar.gz → 0.1.111__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.
Files changed (89) hide show
  1. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/PKG-INFO +1 -1
  2. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/setup.py +1 -1
  3. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/bohr_agent_sdk.egg-info/PKG-INFO +1 -1
  4. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/client/mcp_client.py +3 -3
  5. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/calculation_mcp_server.py +102 -1
  6. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/executor/base_executor.py +22 -0
  7. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/executor/dispatcher_executor.py +17 -3
  8. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/executor/local_executor.py +12 -2
  9. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/README.md +0 -0
  10. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/pyproject.toml +0 -0
  11. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/setup.cfg +0 -0
  12. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/bohr_agent_sdk.egg-info/SOURCES.txt +0 -0
  13. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/bohr_agent_sdk.egg-info/dependency_links.txt +0 -0
  14. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/bohr_agent_sdk.egg-info/entry_points.txt +0 -0
  15. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/bohr_agent_sdk.egg-info/requires.txt +0 -0
  16. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/bohr_agent_sdk.egg-info/top_level.txt +0 -0
  17. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/__init__.py +0 -0
  18. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/__init__.py +0 -0
  19. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/adapter/adk/__init__.py +0 -0
  20. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/adapter/adk/client/__init__.py +0 -0
  21. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/adapter/adk/client/calculation_mcp_tool.py +0 -0
  22. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/adapter/adk/storage_artifact_service.py +0 -0
  23. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/adapter/adk/utils.py +0 -0
  24. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/adapter/camel/__init__.py +0 -0
  25. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/adapter/camel/client/__init__.py +0 -0
  26. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/adapter/camel/client/calculation_mcp_client.py +0 -0
  27. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/__init__.py +0 -0
  28. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/cli.py +0 -0
  29. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/__init__.py +0 -0
  30. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/calculation/simple.py.template +0 -0
  31. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/device/tescan_device.py.template +0 -0
  32. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/main.py.template +0 -0
  33. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/__init__.py +0 -0
  34. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/api/__init__.py +0 -0
  35. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/api/config.py +0 -0
  36. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/api/constants.py +0 -0
  37. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/api/debug.py +0 -0
  38. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/api/files.py +0 -0
  39. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/api/files_upload.py +0 -0
  40. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/api/files_user.py +0 -0
  41. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/api/messages.py +0 -0
  42. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/api/projects.py +0 -0
  43. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/api/sessions.py +0 -0
  44. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/api/utils.py +0 -0
  45. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/api/websocket.py +0 -0
  46. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/config/__init__.py +0 -0
  47. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/config/agent_config.py +0 -0
  48. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/frontend/index.html +0 -0
  49. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/frontend/package.json +0 -0
  50. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/frontend/tsconfig.json +0 -0
  51. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/frontend/tsconfig.node.json +0 -0
  52. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/frontend/ui-static/assets/index-DdAmKhul.js +0 -0
  53. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/frontend/ui-static/assets/index-DfN2raU9.css +0 -0
  54. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/frontend/ui-static/index.html +0 -0
  55. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/frontend/vite.config.ts +0 -0
  56. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/scripts/build_ui.py +0 -0
  57. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/server/__init__.py +0 -0
  58. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/server/app.py +0 -0
  59. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/server/connection.py +0 -0
  60. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/server/file_watcher.py +0 -0
  61. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/server/middleware.py +0 -0
  62. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/server/models.py +0 -0
  63. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/server/session_manager.py +0 -0
  64. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/server/user_files.py +0 -0
  65. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/server/utils.py +0 -0
  66. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/test_download.py +0 -0
  67. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/ui_utils.py +0 -0
  68. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cli/templates/ui/websocket-server.py +0 -0
  69. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/client/__init__.py +0 -0
  70. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cloud/__init__.py +0 -0
  71. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cloud/main.py +0 -0
  72. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cloud/mcp.py +0 -0
  73. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/cloud/mqtt.py +0 -0
  74. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/device/__init__.py +0 -0
  75. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/device/device/__init__.py +0 -0
  76. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/device/device/device.py +0 -0
  77. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/device/device/types.py +0 -0
  78. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/device/mqtt_device_twin.py +0 -0
  79. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/__init__.py +0 -0
  80. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/executor/__init__.py +0 -0
  81. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/preprocessor.py +0 -0
  82. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/storage/__init__.py +0 -0
  83. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/storage/base_storage.py +0 -0
  84. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/storage/bohrium_storage.py +0 -0
  85. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/storage/http_storage.py +0 -0
  86. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/storage/local_storage.py +0 -0
  87. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/storage/oss_storage.py +0 -0
  88. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/src/dp/agent/server/utils.py +0 -0
  89. {bohr_agent_sdk-0.1.109 → bohr_agent_sdk-0.1.111}/tests/test_cli.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bohr-agent-sdk
3
- Version: 0.1.109
3
+ Version: 0.1.111
4
4
  Summary: SDK for scientific agents
5
5
  Home-page: https://github.com/dptech-corp/bohr-agent-sdk/
6
6
  Author: DP Technology
@@ -9,7 +9,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
9
9
 
10
10
  setup(
11
11
  name="bohr-agent-sdk",
12
- version="0.1.109",
12
+ version="0.1.111",
13
13
  description="SDK for science agent and mcp tools",
14
14
  long_description=long_description,
15
15
  long_description_content_type="text/markdown",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bohr-agent-sdk
3
- Version: 0.1.109
3
+ Version: 0.1.111
4
4
  Summary: SDK for scientific agents
5
5
  Home-page: https://github.com/dptech-corp/bohr-agent-sdk/
6
6
  Author: DP Technology
@@ -125,7 +125,7 @@ class MCPClient:
125
125
 
126
126
  executor = arguments.get("executor")
127
127
  storage = arguments.get("storage")
128
- res = await self.session.call_tool("submit_" + tool_name, arguments)
128
+ res = await self.call_tool("submit_" + tool_name, arguments)
129
129
  if res.isError:
130
130
  logger.error("Failed to submit %s: %s" % (
131
131
  tool_name, res.content[0].text))
@@ -137,7 +137,7 @@ class MCPClient:
137
137
  logger.info(job_info["extra_info"])
138
138
 
139
139
  while True:
140
- res = await self.session.call_tool("query_job_status", {
140
+ res = await self.call_tool("query_job_status", {
141
141
  "job_id": job_id, "executor": executor})
142
142
  if res.isError:
143
143
  logger.error(res.content[0].text)
@@ -148,7 +148,7 @@ class MCPClient:
148
148
  break
149
149
  await asyncio.sleep(self.query_interval)
150
150
 
151
- res = await self.session.call_tool("get_job_results", {
151
+ res = await self.call_tool("get_job_results", {
152
152
  "job_id": job_id, "executor": executor, "storage": storage})
153
153
  if res.isError:
154
154
  logger.error("Job %s failed: %s" % (job_id, res.content[0].text))
@@ -7,7 +7,7 @@ from copy import deepcopy
7
7
  from datetime import datetime
8
8
  from pathlib import Path
9
9
  from urllib.parse import urlparse
10
- from typing import Any, Literal, Optional, TypedDict
10
+ from typing import Any, Literal, Optional, TypedDict, List, Dict
11
11
 
12
12
  import mcp
13
13
  from mcp.server.fastmcp import FastMCP
@@ -133,6 +133,69 @@ def handle_input_artifacts(fn, kwargs, storage):
133
133
  "storage_type": scheme,
134
134
  "uri": uri,
135
135
  }
136
+ elif param.annotation is List[Path] or (
137
+ param.annotation is Optional[List[Path]] and
138
+ kwargs.get(name) is not None):
139
+ uris = kwargs[name]
140
+ new_paths = []
141
+ for uri in uris:
142
+ scheme, key = parse_uri(uri)
143
+ if scheme == storage_type:
144
+ s = storage
145
+ else:
146
+ s = storage_dict[scheme]()
147
+ path = s.download(key, "inputs/%s" % name)
148
+ new_paths.append(Path(path))
149
+ logger.info("Artifact %s downloaded to %s" % (
150
+ uri, path))
151
+ kwargs[name] = new_paths
152
+ input_artifacts[name] = {
153
+ "storage_type": storage_type,
154
+ "uri": uris,
155
+ }
156
+ elif param.annotation is Dict[str, Path] or (
157
+ param.annotation is Optional[Dict[str, Path]] and
158
+ kwargs.get(name) is not None):
159
+ uris_dict = kwargs[name]
160
+ new_paths_dict = {}
161
+ for key_name, uri in uris_dict.items():
162
+ scheme, key = parse_uri(uri)
163
+ if scheme == storage_type:
164
+ s = storage
165
+ else:
166
+ s = storage_dict[scheme]()
167
+ path = s.download(key, f"inputs/{name}/{key_name}")
168
+ new_paths_dict[key_name] = Path(path)
169
+ logger.info("Artifact %s (key=%s) downloaded to %s" % (
170
+ uri, key_name, path))
171
+ kwargs[name] = new_paths_dict
172
+ input_artifacts[name] = {
173
+ "storage_type": storage_type,
174
+ "uri": uris_dict,
175
+ }
176
+ elif param.annotation is Dict[str, List[Path]] or (
177
+ param.annotation is Optional[Dict[str, List[Path]]] and
178
+ kwargs.get(name) is not None):
179
+ uris_dict = kwargs[name]
180
+ new_paths_dict = {}
181
+ for key_name, uris in uris_dict.items():
182
+ new_paths = []
183
+ for uri in uris:
184
+ scheme, key = parse_uri(uri)
185
+ if scheme == storage_type:
186
+ s = storage
187
+ else:
188
+ s = storage_dict[scheme]()
189
+ path = s.download(key, f"inputs/{name}/{key_name}")
190
+ new_paths.append(Path(path))
191
+ logger.info("Artifact %s (key=%s) downloaded to %s" % (
192
+ uri, key_name, path))
193
+ new_paths_dict[key_name] = new_paths
194
+ kwargs[name] = new_paths_dict
195
+ input_artifacts[name] = {
196
+ "storage_type": storage_type,
197
+ "uri": uris_dict,
198
+ }
136
199
  return kwargs, input_artifacts
137
200
 
138
201
 
@@ -152,6 +215,20 @@ def handle_output_artifacts(results, exec_id, storage):
152
215
  "storage_type": storage_type,
153
216
  "uri": uri,
154
217
  }
218
+ elif isinstance(results[name], list) and all(isinstance(item, Path) for item in results[name]):
219
+ new_uris = []
220
+ for item in results[name]:
221
+ key = storage.upload("%s/outputs/%s" % (exec_id, name),
222
+ item)
223
+ uri = storage_type + "://" + key
224
+ logger.info("Artifact %s uploaded to %s" % (
225
+ item, uri))
226
+ new_uris.append(uri)
227
+ results[name] = new_uris
228
+ output_artifacts[name] = {
229
+ "storage_type": storage_type,
230
+ "uri": new_uris,
231
+ }
155
232
  return results, output_artifacts
156
233
 
157
234
 
@@ -211,6 +288,30 @@ class CalculationMCPServer:
211
288
  parameters.append(inspect.Parameter(
212
289
  name=param.name, default=param.default,
213
290
  annotation=Optional[str], kind=param.kind))
291
+ elif param.annotation is List[Path]:
292
+ parameters.append(inspect.Parameter(
293
+ name=param.name, default=param.default,
294
+ annotation=List[str], kind=param.kind))
295
+ elif param.annotation is Optional[List[Path]]:
296
+ parameters.append(inspect.Parameter(
297
+ name=param.name, default=param.default,
298
+ annotation=Optional[List[str]], kind=param.kind))
299
+ elif param.annotation is Dict[str, Path]:
300
+ parameters.append(inspect.Parameter(
301
+ name=param.name, default=param.default,
302
+ annotation=Dict[str, str], kind=param.kind))
303
+ elif param.annotation is Optional[Dict[str, Path]]:
304
+ parameters.append(inspect.Parameter(
305
+ name=param.name, default=param.default,
306
+ annotation=Optional[Dict[str, str]], kind=param.kind))
307
+ elif param.annotation is Dict[str, List[Path]]:
308
+ parameters.append(inspect.Parameter(
309
+ name=param.name, default=param.default,
310
+ annotation=Dict[str, List[str]], kind=param.kind))
311
+ elif param.annotation is Optional[Dict[str, List[Path]]]:
312
+ parameters.append(inspect.Parameter(
313
+ name=param.name, default=param.default,
314
+ annotation=Optional[Dict[str, List[str]]], kind=param.kind))
214
315
  else:
215
316
  parameters.append(param)
216
317
  for param in new_typed_signature.parameters.values():
@@ -5,6 +5,8 @@ from collections.abc import Callable
5
5
  from typing import Any, Literal, TypedDict
6
6
 
7
7
  from mcp.server.fastmcp.server import Context
8
+ from mcp.shared.context import RequestContext
9
+ from starlette.requests import Request
8
10
  logger = logging.getLogger(__name__)
9
11
 
10
12
 
@@ -27,6 +29,26 @@ class BaseExecutor(ABC):
27
29
  def get_results(self, job_id: str) -> dict:
28
30
  pass
29
31
 
32
+ def prune_context(self, kwargs: dict):
33
+ for key, value in kwargs.items():
34
+ if isinstance(value, Context):
35
+ context = Context(request_context=RequestContext(
36
+ request_id=value.request_context.request_id,
37
+ meta=value.request_context.meta,
38
+ session=None,
39
+ lifespan_context=value.request_context.lifespan_context,
40
+ request=Request(
41
+ scope={
42
+ k: v for k, v in
43
+ value.request_context.request.scope.items()
44
+ if k not in ["app", "router", "endpoint",
45
+ "starlette.exception_handlers"]
46
+ },
47
+ )
48
+ ))
49
+ kwargs[key] = context
50
+ return kwargs
51
+
30
52
  async def async_run(
31
53
  self, fn: Callable, kwargs: dict, context: Context,
32
54
  trace_id: str) -> TypedDict(
@@ -129,12 +129,13 @@ class DispatcherExecutor(BaseExecutor):
129
129
  self.resources["envs"]["DP_AGENT_RUNNING_MODE"] = "1"
130
130
 
131
131
  def submit(self, fn, kwargs):
132
+ kwargs = self.prune_context(kwargs)
132
133
  script = ""
133
134
  fn_name = fn.__name__
134
135
  func_def_script, packages = get_func_def_script(fn)
135
136
  self.python_packages.extend(packages)
136
137
 
137
- script += "import asyncio, jsonpickle, os\n"
138
+ script += "import asyncio, jsonpickle, os, shutil\n"
138
139
  script += "from pathlib import Path\n\n"
139
140
  script += "if __name__ == \"__main__\":\n"
140
141
  script += " cwd = os.getcwd()\n"
@@ -148,11 +149,24 @@ class DispatcherExecutor(BaseExecutor):
148
149
  script += " results = asyncio.run(%s(**kwargs))\n" % fn_name
149
150
  else:
150
151
  script += " results = %s(**kwargs)\n" % fn_name
152
+ script += " result_dir = None\n"
153
+ script += " import uuid\n"
151
154
  script += " if isinstance(results, dict):\n"
152
155
  script += " for name in results:\n"
153
156
  script += " if isinstance(results[name], Path):\n"
154
- script += " results[name] = " \
155
- "results[name].absolute().relative_to(cwd)\n"
157
+ script += " if not results[name].absolute().is_relative_to(cwd):\n"
158
+ script += " if result_dir is None:\n"
159
+ script += " result_dir = Path('result_files_dir_' + str(uuid.uuid4()))\n"
160
+ script += " result_dir.mkdir(parents=True, exist_ok=True)\n"
161
+ script += " dest_path = result_dir / results[name].absolute().relative_to('/')\n"
162
+ script += " dest_path.parent.mkdir(parents=True, exist_ok=True)\n"
163
+ script += " if results[name].is_file():\n"
164
+ script += " shutil.copy2(results[name], dest_path)\n"
165
+ script += " elif results[name].is_dir():\n"
166
+ script += " shutil.copytree(results[name], dest_path, dirs_exist_ok=True)\n"
167
+ script += " results[name] = dest_path.absolute().relative_to(cwd)\n"
168
+ script += " else:\n"
169
+ script += " results[name] = results[name].absolute().relative_to(cwd)\n"
156
170
  script += " except Exception as e:\n"
157
171
  script += " os.chdir(cwd)\n"
158
172
  script += " with open('err', 'w') as f:\n"
@@ -88,6 +88,7 @@ class LocalExecutor(BaseExecutor):
88
88
  """
89
89
  self.env = env or {}
90
90
  self.dflow = dflow
91
+ self.workflow_id = None
91
92
 
92
93
  def set_env(self):
93
94
  old_env = {}
@@ -105,6 +106,7 @@ class LocalExecutor(BaseExecutor):
105
106
  del os.environ[k]
106
107
 
107
108
  def submit(self, fn, kwargs):
109
+ kwargs = self.prune_context(kwargs)
108
110
  os.environ["DP_AGENT_RUNNING_MODE"] = "1"
109
111
  old_env = self.set_env()
110
112
  params = {"fn": fn, "kwargs": kwargs}
@@ -123,6 +125,7 @@ class LocalExecutor(BaseExecutor):
123
125
  match_link = re.search(DFLOW_LINK_PATTERN, log)
124
126
  if match_id and match_link:
125
127
  wf_id = match_id.group(1)
128
+ self.workflow_id = wf_id
126
129
  wf_uid = match_id.group(2)
127
130
  wf_link = match_link.group(1)
128
131
  extra_info["workflow_id"] = wf_id
@@ -155,11 +158,18 @@ class LocalExecutor(BaseExecutor):
155
158
  return "Failed"
156
159
 
157
160
  def terminate(self, job_id):
161
+ if self.workflow_id is not None:
162
+ try:
163
+ from dflow import Workflow
164
+ wf = Workflow(id=self.workflow_id)
165
+ wf.terminate()
166
+ except Exception as e:
167
+ logger.error(f"Failed to terminate workflow: {e}")
158
168
  try:
159
169
  p = psutil.Process(int(job_id))
160
170
  p.terminate()
161
- except Exception:
162
- pass
171
+ except Exception as e:
172
+ logger.error(f"Failed to terminate process: {e}")
163
173
 
164
174
  def get_results(self, job_id):
165
175
  if os.path.isfile("%s.txt" % job_id):