bohr-agent-sdk 0.1.110__tar.gz → 0.1.112__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.
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/PKG-INFO +1 -1
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/setup.py +1 -1
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/bohr_agent_sdk.egg-info/PKG-INFO +1 -1
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/client/mcp_client.py +3 -3
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/calculation_mcp_server.py +156 -67
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/executor/dispatcher_executor.py +16 -3
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/utils.py +12 -1
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/README.md +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/pyproject.toml +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/setup.cfg +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/bohr_agent_sdk.egg-info/SOURCES.txt +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/bohr_agent_sdk.egg-info/dependency_links.txt +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/bohr_agent_sdk.egg-info/entry_points.txt +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/bohr_agent_sdk.egg-info/requires.txt +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/bohr_agent_sdk.egg-info/top_level.txt +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/adapter/adk/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/adapter/adk/client/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/adapter/adk/client/calculation_mcp_tool.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/adapter/adk/storage_artifact_service.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/adapter/adk/utils.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/adapter/camel/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/adapter/camel/client/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/adapter/camel/client/calculation_mcp_client.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/cli.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/calculation/simple.py.template +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/device/tescan_device.py.template +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/main.py.template +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/config.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/constants.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/debug.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/files.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/files_upload.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/files_user.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/messages.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/projects.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/sessions.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/utils.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/websocket.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/config/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/config/agent_config.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/frontend/index.html +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/frontend/package.json +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/frontend/tsconfig.json +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/frontend/tsconfig.node.json +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/frontend/ui-static/assets/index-DdAmKhul.js +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/frontend/ui-static/assets/index-DfN2raU9.css +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/frontend/ui-static/index.html +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/frontend/vite.config.ts +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/scripts/build_ui.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/app.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/connection.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/file_watcher.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/middleware.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/models.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/session_manager.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/user_files.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/utils.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/test_download.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/ui_utils.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/websocket-server.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/client/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cloud/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cloud/main.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cloud/mcp.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cloud/mqtt.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/device/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/device/device/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/device/device/device.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/device/device/types.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/device/mqtt_device_twin.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/executor/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/executor/base_executor.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/executor/local_executor.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/preprocessor.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/storage/__init__.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/storage/base_storage.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/storage/bohrium_storage.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/storage/http_storage.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/storage/local_storage.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/storage/oss_storage.py +0 -0
- {bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/tests/test_cli.py +0 -0
|
@@ -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.
|
|
12
|
+
version="0.1.112",
|
|
13
13
|
description="SDK for science agent and mcp tools",
|
|
14
14
|
long_description=long_description,
|
|
15
15
|
long_description_content_type="text/markdown",
|
|
@@ -125,7 +125,7 @@ class MCPClient:
|
|
|
125
125
|
|
|
126
126
|
executor = arguments.get("executor")
|
|
127
127
|
storage = arguments.get("storage")
|
|
128
|
-
res = await self.
|
|
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.
|
|
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.
|
|
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))
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/calculation_mcp_server.py
RENAMED
|
@@ -7,17 +7,17 @@ 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
|
|
10
|
+
from typing import Annotated, Literal, Optional, List, Dict
|
|
11
11
|
|
|
12
|
-
import mcp
|
|
13
12
|
from mcp.server.fastmcp import FastMCP
|
|
14
13
|
from mcp.server.fastmcp.utilities.context_injection import (
|
|
15
14
|
find_context_parameter,
|
|
16
15
|
)
|
|
17
16
|
from mcp.server.fastmcp.utilities.func_metadata import (
|
|
18
|
-
|
|
17
|
+
ArgModelBase,
|
|
19
18
|
func_metadata,
|
|
20
19
|
)
|
|
20
|
+
from pydantic import BaseModel, Field, create_model
|
|
21
21
|
from starlette.responses import JSONResponse
|
|
22
22
|
from starlette.routing import Route
|
|
23
23
|
|
|
@@ -65,18 +65,9 @@ def set_directory(workdir: str):
|
|
|
65
65
|
os.chdir(cwd)
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
def
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
executor = json.load(f)
|
|
72
|
-
return executor
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def load_storage(storage):
|
|
76
|
-
if not storage and os.path.exists("storage.json"):
|
|
77
|
-
with open("storage.json", "r") as f:
|
|
78
|
-
storage = json.load(f)
|
|
79
|
-
return storage
|
|
68
|
+
def load_job_info():
|
|
69
|
+
with open("job.json", "r") as f:
|
|
70
|
+
return json.load(f)
|
|
80
71
|
|
|
81
72
|
|
|
82
73
|
def query_job_status(job_id: str, executor: Optional[dict] = None
|
|
@@ -90,7 +81,7 @@ def query_job_status(job_id: str, executor: Optional[dict] = None
|
|
|
90
81
|
"""
|
|
91
82
|
trace_id, exec_id = job_id.split("/")
|
|
92
83
|
with set_directory(trace_id):
|
|
93
|
-
executor =
|
|
84
|
+
executor = load_job_info()["executor"] or executor
|
|
94
85
|
_, executor = init_executor(executor)
|
|
95
86
|
status = executor.query_status(exec_id)
|
|
96
87
|
logger.info("Job %s status is %s" % (job_id, status))
|
|
@@ -105,7 +96,7 @@ def terminate_job(job_id: str, executor: Optional[dict] = None):
|
|
|
105
96
|
"""
|
|
106
97
|
trace_id, exec_id = job_id.split("/")
|
|
107
98
|
with set_directory(trace_id):
|
|
108
|
-
executor =
|
|
99
|
+
executor = load_job_info()["executor"] or executor
|
|
109
100
|
_, executor = init_executor(executor)
|
|
110
101
|
executor.terminate(exec_id)
|
|
111
102
|
logger.info("Job %s is terminated" % job_id)
|
|
@@ -133,6 +124,69 @@ def handle_input_artifacts(fn, kwargs, storage):
|
|
|
133
124
|
"storage_type": scheme,
|
|
134
125
|
"uri": uri,
|
|
135
126
|
}
|
|
127
|
+
elif param.annotation is List[Path] or (
|
|
128
|
+
param.annotation is Optional[List[Path]] and
|
|
129
|
+
kwargs.get(name) is not None):
|
|
130
|
+
uris = kwargs[name]
|
|
131
|
+
new_paths = []
|
|
132
|
+
for uri in uris:
|
|
133
|
+
scheme, key = parse_uri(uri)
|
|
134
|
+
if scheme == storage_type:
|
|
135
|
+
s = storage
|
|
136
|
+
else:
|
|
137
|
+
s = storage_dict[scheme]()
|
|
138
|
+
path = s.download(key, "inputs/%s" % name)
|
|
139
|
+
new_paths.append(Path(path))
|
|
140
|
+
logger.info("Artifact %s downloaded to %s" % (
|
|
141
|
+
uri, path))
|
|
142
|
+
kwargs[name] = new_paths
|
|
143
|
+
input_artifacts[name] = {
|
|
144
|
+
"storage_type": storage_type,
|
|
145
|
+
"uri": uris,
|
|
146
|
+
}
|
|
147
|
+
elif param.annotation is Dict[str, Path] or (
|
|
148
|
+
param.annotation is Optional[Dict[str, Path]] and
|
|
149
|
+
kwargs.get(name) is not None):
|
|
150
|
+
uris_dict = kwargs[name]
|
|
151
|
+
new_paths_dict = {}
|
|
152
|
+
for key_name, uri in uris_dict.items():
|
|
153
|
+
scheme, key = parse_uri(uri)
|
|
154
|
+
if scheme == storage_type:
|
|
155
|
+
s = storage
|
|
156
|
+
else:
|
|
157
|
+
s = storage_dict[scheme]()
|
|
158
|
+
path = s.download(key, f"inputs/{name}/{key_name}")
|
|
159
|
+
new_paths_dict[key_name] = Path(path)
|
|
160
|
+
logger.info("Artifact %s (key=%s) downloaded to %s" % (
|
|
161
|
+
uri, key_name, path))
|
|
162
|
+
kwargs[name] = new_paths_dict
|
|
163
|
+
input_artifacts[name] = {
|
|
164
|
+
"storage_type": storage_type,
|
|
165
|
+
"uri": uris_dict,
|
|
166
|
+
}
|
|
167
|
+
elif param.annotation is Dict[str, List[Path]] or (
|
|
168
|
+
param.annotation is Optional[Dict[str, List[Path]]] and
|
|
169
|
+
kwargs.get(name) is not None):
|
|
170
|
+
uris_dict = kwargs[name]
|
|
171
|
+
new_paths_dict = {}
|
|
172
|
+
for key_name, uris in uris_dict.items():
|
|
173
|
+
new_paths = []
|
|
174
|
+
for uri in uris:
|
|
175
|
+
scheme, key = parse_uri(uri)
|
|
176
|
+
if scheme == storage_type:
|
|
177
|
+
s = storage
|
|
178
|
+
else:
|
|
179
|
+
s = storage_dict[scheme]()
|
|
180
|
+
path = s.download(key, f"inputs/{name}/{key_name}")
|
|
181
|
+
new_paths.append(Path(path))
|
|
182
|
+
logger.info("Artifact %s (key=%s) downloaded to %s" % (
|
|
183
|
+
uri, key_name, path))
|
|
184
|
+
new_paths_dict[key_name] = new_paths
|
|
185
|
+
kwargs[name] = new_paths_dict
|
|
186
|
+
input_artifacts[name] = {
|
|
187
|
+
"storage_type": storage_type,
|
|
188
|
+
"uri": uris_dict,
|
|
189
|
+
}
|
|
136
190
|
return kwargs, input_artifacts
|
|
137
191
|
|
|
138
192
|
|
|
@@ -152,13 +206,28 @@ def handle_output_artifacts(results, exec_id, storage):
|
|
|
152
206
|
"storage_type": storage_type,
|
|
153
207
|
"uri": uri,
|
|
154
208
|
}
|
|
209
|
+
elif isinstance(results[name], list) and all(
|
|
210
|
+
isinstance(item, Path) for item in results[name]):
|
|
211
|
+
new_uris = []
|
|
212
|
+
for item in results[name]:
|
|
213
|
+
key = storage.upload("%s/outputs/%s" % (exec_id, name),
|
|
214
|
+
item)
|
|
215
|
+
uri = storage_type + "://" + key
|
|
216
|
+
logger.info("Artifact %s uploaded to %s" % (
|
|
217
|
+
item, uri))
|
|
218
|
+
new_uris.append(uri)
|
|
219
|
+
results[name] = new_uris
|
|
220
|
+
output_artifacts[name] = {
|
|
221
|
+
"storage_type": storage_type,
|
|
222
|
+
"uri": new_uris,
|
|
223
|
+
}
|
|
155
224
|
return results, output_artifacts
|
|
156
225
|
|
|
157
226
|
|
|
158
227
|
# MCP does not regard Any as serializable in Python 3.12
|
|
159
228
|
# use Optional[Any] to work around
|
|
160
229
|
def get_job_results(job_id: str, executor: Optional[dict] = None,
|
|
161
|
-
storage: Optional[dict] = None)
|
|
230
|
+
storage: Optional[dict] = None):
|
|
162
231
|
"""
|
|
163
232
|
Get results of a calculation job
|
|
164
233
|
Args:
|
|
@@ -168,8 +237,9 @@ def get_job_results(job_id: str, executor: Optional[dict] = None,
|
|
|
168
237
|
"""
|
|
169
238
|
trace_id, exec_id = job_id.split("/")
|
|
170
239
|
with set_directory(trace_id):
|
|
171
|
-
|
|
172
|
-
|
|
240
|
+
job_info = load_job_info()
|
|
241
|
+
executor = job_info["executor"] or executor
|
|
242
|
+
storage = job_info["storage"] or storage
|
|
173
243
|
_, executor = init_executor(executor)
|
|
174
244
|
results = executor.get_results(exec_id)
|
|
175
245
|
results, output_artifacts = handle_output_artifacts(
|
|
@@ -177,7 +247,24 @@ def get_job_results(job_id: str, executor: Optional[dict] = None,
|
|
|
177
247
|
logger.info("Job %s result is %s" % (job_id, results))
|
|
178
248
|
return JobResult(result=results, job_info={
|
|
179
249
|
"output_artifacts": output_artifacts,
|
|
180
|
-
})
|
|
250
|
+
}, tool_name=job_info["tool_name"])
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
annotation_map = {
|
|
254
|
+
Path: str,
|
|
255
|
+
Optional[Path]: Optional[str],
|
|
256
|
+
List[Path]: List[str],
|
|
257
|
+
Optional[List[Path]]: Optional[List[str]],
|
|
258
|
+
Dict[str, Path]: Dict[str, str],
|
|
259
|
+
Optional[Dict[str, Path]]: Optional[Dict[str, str]],
|
|
260
|
+
Dict[str, List[Path]]: Dict[str, List[str]],
|
|
261
|
+
Optional[Dict[str, List[Path]]]: Optional[Dict[str, List[str]]],
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
class SubmitResult(BaseModel):
|
|
266
|
+
job_id: str
|
|
267
|
+
extra_info: dict | None = None
|
|
181
268
|
|
|
182
269
|
|
|
183
270
|
class CalculationMCPServer:
|
|
@@ -191,47 +278,47 @@ class CalculationMCPServer:
|
|
|
191
278
|
self.preprocess_func = preprocess_func
|
|
192
279
|
self.fastmcp_mode = fastmcp_mode
|
|
193
280
|
self.mcp = FastMCP(*args, **kwargs)
|
|
281
|
+
self.fn_metadata_map = {}
|
|
194
282
|
|
|
195
283
|
def add_patched_tool(self, fn, new_fn, name, is_async=False, doc=None,
|
|
196
284
|
override_return_annotation=False):
|
|
197
285
|
"""patch the metadata of the tool"""
|
|
198
286
|
context_kwarg = find_context_parameter(fn)
|
|
199
|
-
|
|
200
|
-
def _get_typed_signature_patched(call):
|
|
201
|
-
"""patch parameters"""
|
|
202
|
-
typed_signature = _get_typed_signature(call)
|
|
203
|
-
new_typed_signature = _get_typed_signature(new_fn)
|
|
204
|
-
parameters = []
|
|
205
|
-
for param in typed_signature.parameters.values():
|
|
206
|
-
if param.annotation is Path:
|
|
207
|
-
parameters.append(inspect.Parameter(
|
|
208
|
-
name=param.name, default=param.default,
|
|
209
|
-
annotation=str, kind=param.kind))
|
|
210
|
-
elif param.annotation is Optional[Path]:
|
|
211
|
-
parameters.append(inspect.Parameter(
|
|
212
|
-
name=param.name, default=param.default,
|
|
213
|
-
annotation=Optional[str], kind=param.kind))
|
|
214
|
-
else:
|
|
215
|
-
parameters.append(param)
|
|
216
|
-
for param in new_typed_signature.parameters.values():
|
|
217
|
-
if param.name != "kwargs":
|
|
218
|
-
parameters.append(param)
|
|
219
|
-
return inspect.Signature(
|
|
220
|
-
parameters,
|
|
221
|
-
return_annotation=(new_typed_signature.return_annotation
|
|
222
|
-
if override_return_annotation
|
|
223
|
-
else typed_signature.return_annotation))
|
|
224
|
-
|
|
225
|
-
# Due to the frequent changes of MCP, we use a patching style here
|
|
226
|
-
mcp.server.fastmcp.utilities.func_metadata._get_typed_signature = \
|
|
227
|
-
_get_typed_signature_patched
|
|
228
287
|
func_arg_metadata = func_metadata(
|
|
229
288
|
fn,
|
|
230
289
|
skip_names=[context_kwarg] if context_kwarg is not None else [],
|
|
231
|
-
structured_output=None,
|
|
232
290
|
)
|
|
233
|
-
|
|
234
|
-
|
|
291
|
+
self.fn_metadata_map[name] = func_arg_metadata
|
|
292
|
+
model_params = {}
|
|
293
|
+
params = inspect.signature(fn, eval_str=True).parameters
|
|
294
|
+
for n, annotation in \
|
|
295
|
+
func_arg_metadata.arg_model.__annotations__.items():
|
|
296
|
+
param = params[n]
|
|
297
|
+
if param.annotation in annotation_map:
|
|
298
|
+
model_params[n] = Annotated[
|
|
299
|
+
(annotation_map[param.annotation], Field())]
|
|
300
|
+
else:
|
|
301
|
+
model_params[n] = annotation
|
|
302
|
+
if param.default is not inspect.Parameter.empty:
|
|
303
|
+
model_params[n] = (model_params[n], param.default)
|
|
304
|
+
for n, param in inspect.signature(new_fn).parameters.items():
|
|
305
|
+
if n == "kwargs":
|
|
306
|
+
continue
|
|
307
|
+
model_params[n] = Annotated[(param.annotation, Field())]
|
|
308
|
+
if param.default is not inspect.Parameter.empty:
|
|
309
|
+
model_params[n] = (model_params[n], param.default)
|
|
310
|
+
|
|
311
|
+
func_arg_metadata.arg_model = create_model(
|
|
312
|
+
f"{fn.__name__}Arguments",
|
|
313
|
+
__base__=ArgModelBase,
|
|
314
|
+
**model_params,
|
|
315
|
+
)
|
|
316
|
+
if override_return_annotation:
|
|
317
|
+
new_func_arg_metadata = func_metadata(new_fn)
|
|
318
|
+
func_arg_metadata.output_model = new_func_arg_metadata.output_model
|
|
319
|
+
func_arg_metadata.output_schema = \
|
|
320
|
+
new_func_arg_metadata.output_schema
|
|
321
|
+
func_arg_metadata.wrap_output = new_func_arg_metadata.wrap_output
|
|
235
322
|
if self.fastmcp_mode and func_arg_metadata.wrap_output:
|
|
236
323
|
# Only simulate behavior of fastmcp for output_schema
|
|
237
324
|
func_arg_metadata.output_schema["x-fastmcp-wrap-result"] = True
|
|
@@ -240,16 +327,18 @@ class CalculationMCPServer:
|
|
|
240
327
|
tool = Tool(
|
|
241
328
|
fn=new_fn,
|
|
242
329
|
name=name,
|
|
243
|
-
description=doc or fn.__doc__,
|
|
330
|
+
description=doc or fn.__doc__ or "",
|
|
244
331
|
parameters=parameters,
|
|
245
332
|
fn_metadata=func_arg_metadata,
|
|
246
333
|
is_async=is_async,
|
|
247
334
|
context_kwarg=context_kwarg,
|
|
335
|
+
fn_metadata_map=self.fn_metadata_map,
|
|
248
336
|
)
|
|
249
337
|
self.mcp._tool_manager._tools[name] = tool
|
|
250
338
|
|
|
251
339
|
def add_tool(self, fn, *args, **kwargs):
|
|
252
|
-
tool = Tool.from_function(
|
|
340
|
+
tool = Tool.from_function(
|
|
341
|
+
fn, *args, fn_metadata_map=self.fn_metadata_map, **kwargs)
|
|
253
342
|
self.mcp._tool_manager._tools[tool.name] = tool
|
|
254
343
|
return tool
|
|
255
344
|
|
|
@@ -260,20 +349,20 @@ class CalculationMCPServer:
|
|
|
260
349
|
def decorator(fn: Callable) -> Callable:
|
|
261
350
|
def submit_job(executor: Optional[dict] = None,
|
|
262
351
|
storage: Optional[dict] = None,
|
|
263
|
-
**kwargs) ->
|
|
264
|
-
"job_id": str, "extra_info": Optional[dict]}):
|
|
352
|
+
**kwargs) -> SubmitResult:
|
|
265
353
|
trace_id = datetime.today().strftime('%Y-%m-%d-%H:%M:%S.%f')
|
|
266
354
|
logger.info("Job processing (Trace ID: %s)" % trace_id)
|
|
267
355
|
with set_directory(trace_id):
|
|
268
356
|
if preprocess_func is not None:
|
|
269
357
|
executor, storage, kwargs = preprocess_func(
|
|
270
358
|
executor, storage, kwargs)
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
359
|
+
job = {
|
|
360
|
+
"tool_name": fn.__name__,
|
|
361
|
+
"executor": executor,
|
|
362
|
+
"storage": storage,
|
|
363
|
+
}
|
|
364
|
+
with open("job.json", "w") as f:
|
|
365
|
+
json.dump(job, f, indent=4)
|
|
277
366
|
kwargs, input_artifacts = handle_input_artifacts(
|
|
278
367
|
fn, kwargs, storage)
|
|
279
368
|
executor_type, executor = init_executor(executor)
|
|
@@ -281,10 +370,10 @@ class CalculationMCPServer:
|
|
|
281
370
|
exec_id = res["job_id"]
|
|
282
371
|
job_id = "%s/%s" % (trace_id, exec_id)
|
|
283
372
|
logger.info("Job submitted (ID: %s)" % job_id)
|
|
284
|
-
result =
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
373
|
+
result = SubmitResult(
|
|
374
|
+
job_id=job_id,
|
|
375
|
+
extra_info=res.get("extra_info"),
|
|
376
|
+
)
|
|
288
377
|
return JobResult(result=result, job_info={
|
|
289
378
|
"trace_id": trace_id,
|
|
290
379
|
"executor_type": executor_type,
|
|
@@ -135,7 +135,7 @@ class DispatcherExecutor(BaseExecutor):
|
|
|
135
135
|
func_def_script, packages = get_func_def_script(fn)
|
|
136
136
|
self.python_packages.extend(packages)
|
|
137
137
|
|
|
138
|
-
script += "import asyncio, jsonpickle, os\n"
|
|
138
|
+
script += "import asyncio, jsonpickle, os, shutil\n"
|
|
139
139
|
script += "from pathlib import Path\n\n"
|
|
140
140
|
script += "if __name__ == \"__main__\":\n"
|
|
141
141
|
script += " cwd = os.getcwd()\n"
|
|
@@ -149,11 +149,24 @@ class DispatcherExecutor(BaseExecutor):
|
|
|
149
149
|
script += " results = asyncio.run(%s(**kwargs))\n" % fn_name
|
|
150
150
|
else:
|
|
151
151
|
script += " results = %s(**kwargs)\n" % fn_name
|
|
152
|
+
script += " result_dir = None\n"
|
|
153
|
+
script += " import uuid\n"
|
|
152
154
|
script += " if isinstance(results, dict):\n"
|
|
153
155
|
script += " for name in results:\n"
|
|
154
156
|
script += " if isinstance(results[name], Path):\n"
|
|
155
|
-
script += " results[name]
|
|
156
|
-
|
|
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"
|
|
157
170
|
script += " except Exception as e:\n"
|
|
158
171
|
script += " os.chdir(cwd)\n"
|
|
159
172
|
script += " with open('err', 'w') as f:\n"
|
|
@@ -21,6 +21,7 @@ def get_logger(name, level="INFO",
|
|
|
21
21
|
class JobResult(BaseModel):
|
|
22
22
|
result: Any
|
|
23
23
|
job_info: dict
|
|
24
|
+
tool_name: str | None = None
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
class Tool(mcp.server.fastmcp.tools.Tool):
|
|
@@ -28,13 +29,23 @@ class Tool(mcp.server.fastmcp.tools.Tool):
|
|
|
28
29
|
Workaround MCP server cannot print traceback
|
|
29
30
|
Add job info to first unstructured content
|
|
30
31
|
"""
|
|
32
|
+
fn_metadata_map: dict | None = None
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def from_function(cls, *args, fn_metadata_map=None, **kwargs):
|
|
36
|
+
tool = super().from_function(*args, **kwargs)
|
|
37
|
+
tool.fn_metadata_map = fn_metadata_map
|
|
38
|
+
return tool
|
|
39
|
+
|
|
31
40
|
async def run(self, *args, **kwargs):
|
|
32
41
|
try:
|
|
33
42
|
kwargs["convert_result"] = False
|
|
34
43
|
result = await super().run(*args, **kwargs)
|
|
35
44
|
if isinstance(result, JobResult):
|
|
36
45
|
job_info = result.job_info
|
|
37
|
-
|
|
46
|
+
fn_metadata = self.fn_metadata_map.get(
|
|
47
|
+
result.tool_name, self.fn_metadata)
|
|
48
|
+
result = fn_metadata.convert_result(result.result)
|
|
38
49
|
if isinstance(result, tuple) and len(result) == 2:
|
|
39
50
|
unstructured_content, _ = result
|
|
40
51
|
else:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/bohr_agent_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/bohr_agent_sdk.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/adapter/adk/client/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/adapter/camel/client/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/main.py.template
RENAMED
|
File without changes
|
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/__init__.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/config.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/constants.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/debug.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/files.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/files_upload.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/files_user.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/messages.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/projects.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/sessions.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/utils.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/api/websocket.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/config/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/frontend/index.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/scripts/build_ui.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/__init__.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/app.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/connection.py
RENAMED
|
File without changes
|
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/middleware.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/models.py
RENAMED
|
File without changes
|
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/user_files.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/server/utils.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/test_download.py
RENAMED
|
File without changes
|
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/cli/templates/ui/websocket-server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/executor/base_executor.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/executor/local_executor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/storage/base_storage.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/storage/bohrium_storage.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/storage/http_storage.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/storage/local_storage.py
RENAMED
|
File without changes
|
{bohr_agent_sdk-0.1.110 → bohr_agent_sdk-0.1.112}/src/dp/agent/server/storage/oss_storage.py
RENAMED
|
File without changes
|
|
File without changes
|