bohr-agent-sdk 0.1.115__py3-none-any.whl → 0.1.117__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bohr-agent-sdk
3
- Version: 0.1.115
3
+ Version: 0.1.117
4
4
  Summary: SDK for scientific agents
5
5
  Home-page: https://github.com/dptech-corp/bohr-agent-sdk/
6
6
  Author: DP Technology
@@ -4,7 +4,7 @@ dp/agent/adapter/adk/__init__.py,sha256=mxX2SxGgDjwQ7WjfKMw9mQkq4ddl8XlCA6gnUinC
4
4
  dp/agent/adapter/adk/storage_artifact_service.py,sha256=Hd1CmEB8HgEz3x_riHVSSmYdw6W2bDYYa3c5ySCqmCE,5414
5
5
  dp/agent/adapter/adk/utils.py,sha256=UPCTpvAUCV2V1o0V8dmmFWbiLuUf6fJLIvVX68M3L-M,7698
6
6
  dp/agent/adapter/adk/client/__init__.py,sha256=F1xfFNa4ZG8jV9adeGI2D3YBiSX-5RkvqEdTqNdJce4,209
7
- dp/agent/adapter/adk/client/calculation_mcp_tool.py,sha256=tY0XXATaawCzUMZzDS8JvVvtXhfWqGYpZdFrAjQH0yk,12792
7
+ dp/agent/adapter/adk/client/calculation_mcp_tool.py,sha256=VDiDSEDsOYduGuCE1mp2cmOoDkdyfHhaTFhNRv0GnMY,12873
8
8
  dp/agent/adapter/camel/__init__.py,sha256=RN1NhdmsJyN43fTxTXFld4UKZksjpSV0b2QvFn5gK7o,77
9
9
  dp/agent/adapter/camel/client/__init__.py,sha256=ld-r0_WsZLFv6yyrmxjWmR8JgnrQzOw4fX0hwVHzciY,93
10
10
  dp/agent/adapter/camel/client/calculation_mcp_client.py,sha256=JZZUYYfMgXvHzK4f6IJp-ia33wn3aYZqDSDVa5yKtdc,1860
@@ -62,21 +62,21 @@ dp/agent/device/device/__init__.py,sha256=w7_1S16S1vWUq0RGl0GFgjq2vFkc5oNvy8cQTn
62
62
  dp/agent/device/device/device.py,sha256=9ZRIJth-4qMO-i-u_b_cO3d6a4eTbTQjPaxFsV_zEkc,9643
63
63
  dp/agent/device/device/types.py,sha256=JuxB-hjf1CjjvfBxCLwRAXVFlYS-nPEdiJpBWLFVCzo,1924
64
64
  dp/agent/server/__init__.py,sha256=rckaYd8pbYyB4ENEhgjXKeGMXjdnrgcJpdM1gu5u1Wc,508
65
- dp/agent/server/calculation_mcp_server.py,sha256=a0hKNVz-WoUbL8y9GhDx1hO830frvmdtvXTBf7V40lI,18478
65
+ dp/agent/server/calculation_mcp_server.py,sha256=VI1TI51QNTZEY9SPdlFFC0PFBcL8zPzL0PV6QTZNPOo,19167
66
66
  dp/agent/server/preprocessor.py,sha256=XUWu7QOwo_sIDMYS2b1OTrM33EXEVH_73vk-ju1Ok8A,1264
67
67
  dp/agent/server/utils.py,sha256=cIKaAg8UaP5yMwvIVTgUVBjy-B3S16bEdnucUf4UDIM,2055
68
68
  dp/agent/server/executor/__init__.py,sha256=s95M5qKQk39Yi9qaVJZhk_nfj54quSf7EDghR3OCFUA,248
69
69
  dp/agent/server/executor/base_executor.py,sha256=nR2jI-wFvKoOk8QaK11pnSAkHj2MsE6uyzPWDx-vgJA,3018
70
70
  dp/agent/server/executor/dispatcher_executor.py,sha256=CZRxbVkLaDvStXhNaMKrKcx2Z0tPPVzIxkU1ufqWgYc,12081
71
- dp/agent/server/executor/local_executor.py,sha256=pGXlDOrfjfP40hSMzbF-Wls3OnOTsH8PdkQjcDjP6_w,6580
71
+ dp/agent/server/executor/local_executor.py,sha256=qRVnfqhvaCGBXr-NO4uxcUteFja2BE_6NXauVJ8vnoo,6642
72
72
  dp/agent/server/storage/__init__.py,sha256=Sgsyp5hb0_hhIGugAPfQFzBHt_854rS_MuMuE3sn8Gs,389
73
73
  dp/agent/server/storage/base_storage.py,sha256=728-oNG6N8isV95gZVnyi4vTznJPJhSjxw9Gl5Y_y5o,2356
74
74
  dp/agent/server/storage/bohrium_storage.py,sha256=EsKX4dWWvZTn2TEhZv4zsvihfDK0mmPFecrln-Ytk40,10488
75
75
  dp/agent/server/storage/http_storage.py,sha256=KiySq7g9-iJr12XQCKKyJLn8wJoDnSRpQAR5_qPJ1ZU,1471
76
76
  dp/agent/server/storage/local_storage.py,sha256=t1wfjByjXew9ws3PuUxWxmZQ0-Wt1a6t4wmj3fW62GI,1352
77
77
  dp/agent/server/storage/oss_storage.py,sha256=pgjmi7Gir3Y5wkMDCvU4fvSls15fXT7Ax-h9MYHFPK0,3359
78
- bohr_agent_sdk-0.1.115.dist-info/METADATA,sha256=7s_fuPz-I3NmkOMYYD60aJ8xgEZDXYEGAf-dsxrPrAA,11070
79
- bohr_agent_sdk-0.1.115.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
80
- bohr_agent_sdk-0.1.115.dist-info/entry_points.txt,sha256=5n5kneF5IbDQtoQ2WfF-QuBjDtsimJte9Rv9baSGgc0,86
81
- bohr_agent_sdk-0.1.115.dist-info/top_level.txt,sha256=87xLUDhu_1nQHoGLwlhJ6XlO7OsjILh6i1nX6ljFzDo,3
82
- bohr_agent_sdk-0.1.115.dist-info/RECORD,,
78
+ bohr_agent_sdk-0.1.117.dist-info/METADATA,sha256=kyyDZnKLQQFKuOF5ZV0ftTzlEp02fPnZhH06MmUzYyE,11070
79
+ bohr_agent_sdk-0.1.117.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
80
+ bohr_agent_sdk-0.1.117.dist-info/entry_points.txt,sha256=5n5kneF5IbDQtoQ2WfF-QuBjDtsimJte9Rv9baSGgc0,86
81
+ bohr_agent_sdk-0.1.117.dist-info/top_level.txt,sha256=87xLUDhu_1nQHoGLwlhJ6XlO7OsjILh6i1nX6ljFzDo,3
82
+ bohr_agent_sdk-0.1.117.dist-info/RECORD,,
@@ -93,16 +93,19 @@ class CalculationMCPTool(MCPTool):
93
93
  async def run_async(self, args, tool_context: ToolContext, **kwargs):
94
94
  # TODO: add progress callback when run_async
95
95
  args = deepcopy(args)
96
- if self.override or "executor" not in args:
96
+ if self.override:
97
97
  args["executor"] = self.executor
98
- if self.override or "storage" not in args:
99
98
  args["storage"] = self.storage
99
+ if not args.get("executor"):
100
+ args.pop("executor", None)
101
+ if not args.get("storage"):
102
+ args.pop("storage", None)
100
103
  if not self.async_mode and self.wait:
101
104
  return await super().run_async(
102
105
  args=args, tool_context=tool_context, **kwargs)
103
106
 
104
- executor = args["executor"]
105
- storage = args["storage"]
107
+ executor = args.get("executor")
108
+ storage = args.get("storage")
106
109
  res = await self.submit_tool.run_async(
107
110
  args=args, tool_context=tool_context, **kwargs)
108
111
  if isinstance(res, dict):
@@ -371,7 +371,9 @@ class CalculationMCPServer:
371
371
  self.mcp._tool_manager._tools[tool.name] = tool
372
372
  return tool
373
373
 
374
- def tool(self, preprocess_func=None):
374
+ def tool(self, preprocess_func=None, create_workdir=None):
375
+ # When create_workdir is None, do not create workdir when fn is async
376
+ # and running locally to avoid chdir conflicts, create otherwise
375
377
  if preprocess_func is None:
376
378
  preprocess_func = self.preprocess_func
377
379
 
@@ -381,10 +383,17 @@ class CalculationMCPServer:
381
383
  **kwargs) -> SubmitResult:
382
384
  trace_id = datetime.today().strftime('%Y-%m-%d-%H:%M:%S.%f')
383
385
  logger.info("Job processing (Trace ID: %s)" % trace_id)
384
- with set_directory(trace_id):
385
- if preprocess_func is not None:
386
- executor, storage, kwargs = preprocess_func(
387
- executor, storage, kwargs)
386
+ if preprocess_func is not None:
387
+ executor, storage, kwargs = preprocess_func(
388
+ executor, storage, kwargs)
389
+ executor_type, executor = init_executor(executor)
390
+ if create_workdir is False or (
391
+ create_workdir is None and inspect.iscoroutinefunction(fn)
392
+ and executor_type == "local"):
393
+ workdir = "."
394
+ else:
395
+ workdir = trace_id
396
+ with set_directory(workdir):
388
397
  job = {
389
398
  "tool_name": fn.__name__,
390
399
  "executor": executor,
@@ -394,10 +403,9 @@ class CalculationMCPServer:
394
403
  json.dump(job, f, indent=4)
395
404
  kwargs, input_artifacts = handle_input_artifacts(
396
405
  fn, kwargs, storage)
397
- executor_type, executor = init_executor(executor)
398
406
  res = executor.submit(fn, kwargs)
399
407
  exec_id = res["job_id"]
400
- job_id = "%s/%s" % (trace_id, exec_id)
408
+ job_id = "%s/%s" % (workdir, exec_id)
401
409
  logger.info("Job submitted (ID: %s)" % job_id)
402
410
  result = SubmitResult(
403
411
  job_id=job_id,
@@ -416,17 +424,23 @@ class CalculationMCPServer:
416
424
  context = self.mcp.get_context()
417
425
  trace_id = datetime.today().strftime('%Y-%m-%d-%H:%M:%S.%f')
418
426
  logger.info("Job processing (Trace ID: %s)" % trace_id)
419
- with set_directory(trace_id):
420
- if preprocess_func is not None:
421
- executor, storage, kwargs = preprocess_func(
422
- executor, storage, kwargs)
427
+ if preprocess_func is not None:
428
+ executor, storage, kwargs = preprocess_func(
429
+ executor, storage, kwargs)
430
+ executor_type, executor = init_executor(executor)
431
+ if create_workdir is False or (
432
+ create_workdir is None and inspect.iscoroutinefunction(fn)
433
+ and executor_type == "local"):
434
+ workdir = "."
435
+ else:
436
+ workdir = trace_id
437
+ with set_directory(workdir):
423
438
  kwargs, input_artifacts = handle_input_artifacts(
424
439
  fn, kwargs, storage)
425
- executor_type, executor = init_executor(executor)
426
440
  res = await executor.async_run(
427
- fn, kwargs, context, trace_id)
441
+ fn, kwargs, context, workdir)
428
442
  exec_id = res["job_id"]
429
- job_id = "%s/%s" % (trace_id, exec_id)
443
+ job_id = "%s/%s" % (workdir, exec_id)
430
444
  results = res["result"]
431
445
  results, output_artifacts = handle_output_artifacts(
432
446
  results, exec_id, storage)
@@ -32,13 +32,13 @@ class Tee(io.TextIOBase):
32
32
  return len(text)
33
33
 
34
34
 
35
- def wrapped_fn(fn, kwargs, redirect_file=None):
35
+ def wrapped_fn(fn, kwargs, redirect_log=False):
36
36
  pid = os.getpid()
37
37
  # explicitly reload dflow config
38
38
  reload_dflow_config()
39
- if redirect_file:
39
+ if redirect_log:
40
40
  stdout = sys.stdout
41
- flog = open(redirect_file, "w")
41
+ flog = open("%s.log" % pid, "w")
42
42
  sys.stdout = Tee(flog, stdout)
43
43
  try:
44
44
  if inspect.iscoroutinefunction(fn):
@@ -46,11 +46,11 @@ def wrapped_fn(fn, kwargs, redirect_file=None):
46
46
  else:
47
47
  result = fn(**kwargs)
48
48
  except Exception as e:
49
- with open("err", "w") as f:
49
+ with open("%s.err" % pid, "w") as f:
50
50
  f.write(str(e))
51
51
  raise e
52
52
  finally:
53
- if redirect_file:
53
+ if redirect_log:
54
54
  sys.stdout = stdout
55
55
  flog.close()
56
56
  with open("%s.txt" % pid, "w") as f:
@@ -111,15 +111,15 @@ class LocalExecutor(BaseExecutor):
111
111
  old_env = self.set_env()
112
112
  params = {"fn": fn, "kwargs": kwargs}
113
113
  if self.dflow:
114
- params["redirect_file"] = "log.txt"
114
+ params["redirect_log"] = True
115
115
  p = Process(target=wrapped_fn, kwargs=params)
116
116
  p.start()
117
117
  extra_info = {}
118
118
  if self.dflow:
119
119
  while True:
120
120
  alive = p.is_alive()
121
- if os.path.isfile("log.txt"):
122
- with open("log.txt", "r") as f:
121
+ if os.path.isfile("%s.log" % p.pid):
122
+ with open("%s.log" % p.pid, "r") as f:
123
123
  log = f.read()
124
124
  match_id = re.search(DFLOW_ID_PATTERN, log)
125
125
  match_link = re.search(DFLOW_LINK_PATTERN, log)
@@ -133,8 +133,8 @@ class LocalExecutor(BaseExecutor):
133
133
  extra_info["workflow_link"] = wf_link
134
134
  break
135
135
  if not alive:
136
- if os.path.isfile("err"):
137
- with open("err", "r") as f:
136
+ if os.path.isfile("%s.err" % p.pid):
137
+ with open("%s.err" % p.pid, "r") as f:
138
138
  err_msg = f.read()
139
139
  else:
140
140
  err_msg = "No workflow submitted"
@@ -175,8 +175,8 @@ class LocalExecutor(BaseExecutor):
175
175
  if os.path.isfile("%s.txt" % job_id):
176
176
  with open("%s.txt" % job_id, "r") as f:
177
177
  return jsonpickle.loads(f.read())
178
- elif os.path.isfile("err"):
179
- with open("err", "r") as f:
178
+ elif os.path.isfile("%s.err" % job_id):
179
+ with open("%s.err" % job_id, "r") as f:
180
180
  err_msg = f.read()
181
181
  raise RuntimeError(err_msg)
182
182
  return {}