bohr-agent-sdk 0.1.18__tar.gz → 0.1.19__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 (47) hide show
  1. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/PKG-INFO +1 -1
  2. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/setup.py +1 -1
  3. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/bohr_agent_sdk.egg-info/PKG-INFO +1 -1
  4. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/bohr_agent_sdk.egg-info/SOURCES.txt +1 -0
  5. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/adapter/adk/__init__.py +3 -1
  6. bohr_agent_sdk-0.1.19/src/dp/agent/adapter/adk/storage_artifact_service.py +184 -0
  7. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/storage/bohrium_storage.py +3 -2
  8. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/README.md +0 -0
  9. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/pyproject.toml +0 -0
  10. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/setup.cfg +0 -0
  11. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/bohr_agent_sdk.egg-info/dependency_links.txt +0 -0
  12. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/bohr_agent_sdk.egg-info/entry_points.txt +0 -0
  13. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/bohr_agent_sdk.egg-info/requires.txt +0 -0
  14. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/bohr_agent_sdk.egg-info/top_level.txt +0 -0
  15. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/__init__.py +0 -0
  16. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/__init__.py +0 -0
  17. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/adapter/adk/client/__init__.py +0 -0
  18. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/adapter/adk/client/calculation_mcp_tool.py +0 -0
  19. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/adapter/adk/utils.py +0 -0
  20. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/adapter/camel/__init__.py +0 -0
  21. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/adapter/camel/client/__init__.py +0 -0
  22. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/adapter/camel/client/calculation_mcp_client.py +0 -0
  23. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/cli/__init__.py +0 -0
  24. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/cli/cli.py +0 -0
  25. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/cloud/__init__.py +0 -0
  26. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/cloud/main.py +0 -0
  27. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/cloud/mcp.py +0 -0
  28. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/cloud/mqtt.py +0 -0
  29. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/device/__init__.py +0 -0
  30. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/device/device/__init__.py +0 -0
  31. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/device/device/device.py +0 -0
  32. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/device/device/types.py +0 -0
  33. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/device/mqtt_device_twin.py +0 -0
  34. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/__init__.py +0 -0
  35. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/calculation_mcp_server.py +0 -0
  36. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/executor/__init__.py +0 -0
  37. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/executor/base_executor.py +0 -0
  38. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/executor/dispatcher_executor.py +0 -0
  39. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/executor/local_executor.py +0 -0
  40. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/preprocessor.py +0 -0
  41. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/storage/__init__.py +0 -0
  42. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/storage/base_storage.py +0 -0
  43. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/storage/http_storage.py +0 -0
  44. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/storage/local_storage.py +0 -0
  45. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/storage/oss_storage.py +0 -0
  46. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/src/dp/agent/server/utils.py +0 -0
  47. {bohr_agent_sdk-0.1.18 → bohr_agent_sdk-0.1.19}/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.18
3
+ Version: 0.1.19
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.18",
12
+ version="0.1.19",
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.18
3
+ Version: 0.1.19
4
4
  Summary: SDK for scientific agents
5
5
  Home-page: https://github.com/dptech-corp/bohr-agent-sdk/
6
6
  Author: DP Technology
@@ -10,6 +10,7 @@ src/bohr_agent_sdk.egg-info/top_level.txt
10
10
  src/dp/__init__.py
11
11
  src/dp/agent/__init__.py
12
12
  src/dp/agent/adapter/adk/__init__.py
13
+ src/dp/agent/adapter/adk/storage_artifact_service.py
13
14
  src/dp/agent/adapter/adk/utils.py
14
15
  src/dp/agent/adapter/adk/client/__init__.py
15
16
  src/dp/agent/adapter/adk/client/calculation_mcp_tool.py
@@ -3,6 +3,7 @@ from .client import (
3
3
  CalculationMCPToolset,
4
4
  BackgroundJobWatcher,
5
5
  )
6
+ from .storage_artifact_service import StorageArtifactService
6
7
  from .utils import (
7
8
  search_error_in_memory_handler,
8
9
  update_session_handler,
@@ -11,4 +12,5 @@ from .utils import (
11
12
 
12
13
  __all__ = ["CalculationMCPTool", "CalculationMCPToolset",
13
14
  "update_session_handler", "search_error_in_memory_handler",
14
- "BackgroundJobWatcher", "extract_job_info"]
15
+ "BackgroundJobWatcher", "extract_job_info",
16
+ "StorageArtifactService"]
@@ -0,0 +1,184 @@
1
+
2
+ import logging
3
+ import mimetypes
4
+ import os
5
+ import tempfile
6
+ from typing import Optional
7
+
8
+ from google.adk.artifacts import BaseArtifactService
9
+ from google.genai import types
10
+ from typing_extensions import override
11
+
12
+ from ...server.storage import BaseStorage
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class StorageArtifactService(BaseArtifactService):
18
+ """An artifact service implementation using storage plugin."""
19
+ def __init__(self, storage: BaseStorage):
20
+ self.storage = storage
21
+
22
+ def _file_has_user_namespace(self, filename: str) -> bool:
23
+ """Checks if the filename has a user namespace.
24
+
25
+ Args:
26
+ filename: The filename to check.
27
+
28
+ Returns:
29
+ True if the filename has a user namespace (starts with "user:"),
30
+ False otherwise.
31
+ """
32
+ return filename.startswith("user:")
33
+
34
+ def _get_key(
35
+ self,
36
+ app_name: str,
37
+ user_id: str,
38
+ session_id: str,
39
+ filename: str,
40
+ version: int,
41
+ ) -> str:
42
+ """Constructs the key.
43
+
44
+ Args:
45
+ app_name: The name of the application.
46
+ user_id: The ID of the user.
47
+ session_id: The ID of the session.
48
+ filename: The name of the artifact file.
49
+ version: The version of the artifact.
50
+
51
+ Returns:
52
+ The constructed key.
53
+ """
54
+ if self._file_has_user_namespace(filename):
55
+ return f"{app_name}/{user_id}/user/{filename}/{version}"
56
+ return f"{app_name}/{user_id}/{session_id}/{filename}/{version}"
57
+
58
+ @override
59
+ async def save_artifact(
60
+ self,
61
+ *,
62
+ app_name: str,
63
+ user_id: str,
64
+ session_id: str,
65
+ filename: str,
66
+ artifact: types.Part,
67
+ ) -> int:
68
+ versions = await self.list_versions(
69
+ app_name=app_name,
70
+ user_id=user_id,
71
+ session_id=session_id,
72
+ filename=filename,
73
+ )
74
+ version = 0 if not versions else max(versions) + 1
75
+
76
+ key = self._get_key(
77
+ app_name, user_id, session_id, filename, version
78
+ )
79
+ with tempfile.TemporaryDirectory() as tmpdir:
80
+ path = os.path.join(tmpdir, filename)
81
+ with open(path, "wb") as f:
82
+ f.write(artifact.inline_data.data)
83
+ self.storage._upload(key, path)
84
+
85
+ return version
86
+
87
+ @override
88
+ async def load_artifact(
89
+ self,
90
+ *,
91
+ app_name: str,
92
+ user_id: str,
93
+ session_id: str,
94
+ filename: str,
95
+ version: Optional[int] = None,
96
+ ) -> Optional[types.Part]:
97
+ if version is None:
98
+ versions = await self.list_versions(
99
+ app_name=app_name,
100
+ user_id=user_id,
101
+ session_id=session_id,
102
+ filename=filename,
103
+ )
104
+ if not versions:
105
+ return None
106
+ version = max(versions)
107
+
108
+ key = self._get_key(
109
+ app_name, user_id, session_id, filename, version
110
+ )
111
+ with tempfile.TemporaryDirectory() as tmpdir:
112
+ path = os.path.join(tmpdir, filename)
113
+ self.storage._download(key, path)
114
+ with open(path, "rb") as f:
115
+ artifact_bytes = f.read()
116
+
117
+ mime_type, _ = mimetypes.guess_type(filename)
118
+ artifact = types.Part.from_bytes(
119
+ data=artifact_bytes, mime_type=mime_type
120
+ )
121
+ return artifact
122
+
123
+ @override
124
+ async def list_artifact_keys(
125
+ self, *, app_name: str, user_id: str, session_id: str
126
+ ) -> list[str]:
127
+ filenames = set()
128
+
129
+ session_prefix = f"{app_name}/{user_id}/{session_id}/"
130
+ keys = self.storage.list(session_prefix)
131
+ for key in keys:
132
+ _, _, _, filename, _ = key.split("/")[-5:]
133
+ filenames.add(filename)
134
+
135
+ user_namespace_prefix = f"{app_name}/{user_id}/user/"
136
+ user_namespace_keys = self.storage.list(user_namespace_prefix)
137
+ for key in user_namespace_keys:
138
+ _, _, _, filename, _ = key.split("/")[-5:]
139
+ filenames.add(filename)
140
+
141
+ return sorted(list(filenames))
142
+
143
+ @override
144
+ async def delete_artifact(
145
+ self, *, app_name: str, user_id: str, session_id: str, filename: str
146
+ ) -> None:
147
+ raise NotImplementedError()
148
+
149
+ @override
150
+ async def list_versions(
151
+ self, *, app_name: str, user_id: str, session_id: str, filename: str
152
+ ) -> list[int]:
153
+ prefix = self._get_key(app_name, user_id, session_id, filename, "")
154
+ keys = self.storage.list(prefix)
155
+ versions = []
156
+ for key in keys:
157
+ _, _, _, _, version = key.split("/")[-5:]
158
+ versions.append(int(version))
159
+ return versions
160
+
161
+ async def get_permanent_read_url(
162
+ self,
163
+ *,
164
+ app_name: str,
165
+ user_id: str,
166
+ session_id: str,
167
+ filename: str,
168
+ version: Optional[int] = None,
169
+ ) -> str:
170
+ if version is None:
171
+ versions = await self.list_versions(
172
+ app_name=app_name,
173
+ user_id=user_id,
174
+ session_id=session_id,
175
+ filename=filename,
176
+ )
177
+ if not versions:
178
+ return None
179
+ version = max(versions)
180
+
181
+ key = self._get_key(
182
+ app_name, user_id, session_id, filename, version
183
+ )
184
+ return self.storage.get_http_url(key)
@@ -50,9 +50,9 @@ def login(username=None, phone=None, password=None, bohrium_url=None):
50
50
  password = config["password"]
51
51
  if bohrium_url is None:
52
52
  bohrium_url = config["bohrium_url"]
53
- config["authorization"] = _login(
53
+ authorization = _login(
54
54
  bohrium_url + "/account/login", username, phone, password)
55
- return config["authorization"]
55
+ return authorization
56
56
 
57
57
 
58
58
  def _login(login_url=None, username=None, phone=None, password=None):
@@ -256,6 +256,7 @@ class BohriumStorage(BaseStorage):
256
256
  return meta["entityTag"] if "entityTag" in meta else ""
257
257
 
258
258
  def get_http_url(self, key):
259
+ key = self.prefixing(key)
259
260
  url = self.tiefblue_url + "/api/setacl"
260
261
  headers = {
261
262
  "Content-type": "application/json",