bohr-agent-sdk 0.1.101__py3-none-any.whl → 0.1.103__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.
Files changed (49) hide show
  1. bohr_agent_sdk-0.1.103.dist-info/METADATA +292 -0
  2. bohr_agent_sdk-0.1.103.dist-info/RECORD +80 -0
  3. dp/agent/cli/cli.py +126 -25
  4. dp/agent/cli/templates/__init__.py +1 -0
  5. dp/agent/cli/templates/calculation/simple.py.template +15 -0
  6. dp/agent/cli/templates/device/tescan_device.py.template +158 -0
  7. dp/agent/cli/templates/main.py.template +67 -0
  8. dp/agent/cli/templates/ui/__init__.py +1 -0
  9. dp/agent/cli/templates/ui/api/__init__.py +1 -0
  10. dp/agent/cli/templates/ui/api/config.py +32 -0
  11. dp/agent/cli/templates/ui/api/constants.py +61 -0
  12. dp/agent/cli/templates/ui/api/debug.py +257 -0
  13. dp/agent/cli/templates/ui/api/files.py +469 -0
  14. dp/agent/cli/templates/ui/api/files_upload.py +115 -0
  15. dp/agent/cli/templates/ui/api/files_user.py +50 -0
  16. dp/agent/cli/templates/ui/api/messages.py +161 -0
  17. dp/agent/cli/templates/ui/api/projects.py +146 -0
  18. dp/agent/cli/templates/ui/api/sessions.py +93 -0
  19. dp/agent/cli/templates/ui/api/utils.py +161 -0
  20. dp/agent/cli/templates/ui/api/websocket.py +184 -0
  21. dp/agent/cli/templates/ui/config/__init__.py +1 -0
  22. dp/agent/cli/templates/ui/config/agent_config.py +257 -0
  23. dp/agent/cli/templates/ui/frontend/index.html +13 -0
  24. dp/agent/cli/templates/ui/frontend/package.json +46 -0
  25. dp/agent/cli/templates/ui/frontend/tsconfig.json +26 -0
  26. dp/agent/cli/templates/ui/frontend/tsconfig.node.json +10 -0
  27. dp/agent/cli/templates/ui/frontend/ui-static/assets/index-DdAmKhul.js +105 -0
  28. dp/agent/cli/templates/ui/frontend/ui-static/assets/index-DfN2raU9.css +1 -0
  29. dp/agent/cli/templates/ui/frontend/ui-static/index.html +14 -0
  30. dp/agent/cli/templates/ui/frontend/vite.config.ts +37 -0
  31. dp/agent/cli/templates/ui/scripts/build_ui.py +56 -0
  32. dp/agent/cli/templates/ui/server/__init__.py +0 -0
  33. dp/agent/cli/templates/ui/server/app.py +98 -0
  34. dp/agent/cli/templates/ui/server/connection.py +210 -0
  35. dp/agent/cli/templates/ui/server/file_watcher.py +85 -0
  36. dp/agent/cli/templates/ui/server/middleware.py +43 -0
  37. dp/agent/cli/templates/ui/server/models.py +53 -0
  38. dp/agent/cli/templates/ui/server/session_manager.py +1158 -0
  39. dp/agent/cli/templates/ui/server/user_files.py +85 -0
  40. dp/agent/cli/templates/ui/server/utils.py +50 -0
  41. dp/agent/cli/templates/ui/test_download.py +98 -0
  42. dp/agent/cli/templates/ui/ui_utils.py +260 -0
  43. dp/agent/cli/templates/ui/websocket-server.py +87 -0
  44. dp/agent/server/storage/http_storage.py +1 -1
  45. bohr_agent_sdk-0.1.101.dist-info/METADATA +0 -224
  46. bohr_agent_sdk-0.1.101.dist-info/RECORD +0 -40
  47. {bohr_agent_sdk-0.1.101.dist-info → bohr_agent_sdk-0.1.103.dist-info}/WHEEL +0 -0
  48. {bohr_agent_sdk-0.1.101.dist-info → bohr_agent_sdk-0.1.103.dist-info}/entry_points.txt +0 -0
  49. {bohr_agent_sdk-0.1.101.dist-info → bohr_agent_sdk-0.1.103.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,158 @@
1
+ """
2
+ Tescan device implementation.
3
+
4
+ This module contains the implementation of a Tescan device with
5
+ specific parameter and result types.
6
+ """
7
+ import time
8
+ from typing import Dict, TypedDict
9
+ from dp.agent.device.device.types import SuccessResult, BaseParams, ErrorResult
10
+ from dp.agent.device.device.device import Device, action
11
+
12
+ class TakePictureParams(BaseParams):
13
+ """Parameters for take_picture action."""
14
+ horizontal_width: str
15
+
16
+ class GetStagePositionParams(BaseParams):
17
+ """Parameters for get_stage_position action."""
18
+ pass
19
+
20
+ class MoveStageParams(BaseParams):
21
+ """Parameters for move_stage action."""
22
+ x: float
23
+ y: float
24
+ z: float
25
+
26
+ class StagePosition(TypedDict):
27
+ """Stage position data."""
28
+ x: float
29
+ y: float
30
+ z: float
31
+
32
+ class PictureData(TypedDict):
33
+ """Picture data."""
34
+ image_id: str
35
+
36
+
37
+ class SleepParams(BaseParams):
38
+ """Parameters for sleep action."""
39
+ seconds: int
40
+
41
+ class StagePositionResult(SuccessResult):
42
+ """Result for get_stage_position action."""
43
+ data: StagePosition
44
+
45
+ class PictureResult(SuccessResult):
46
+ """Result for take_picture action."""
47
+ data: PictureData
48
+
49
+ class MoveStageResult(SuccessResult):
50
+ """Result for move_stage action."""
51
+ data: Dict[str, float]
52
+
53
+ class TescanDevice(Device):
54
+ """Tescan device implementation."""
55
+ device_name = "tescan"
56
+
57
+ @action("start_electron_beam")
58
+ def start_electron_beam(self, params: BaseParams):
59
+ print("start electron beam")
60
+
61
+ @action("start_ion_beam")
62
+ def start_ion_beam(self, params: BaseParams):
63
+ print("start ion beam")
64
+
65
+ @action("toggle_electron_scanning")
66
+ def toggle_electron_scanning(self, params: BaseParams):
67
+ """start scanning, this will cost 5 seconds to finish. call sleep(5) after toggle this.
68
+ """
69
+ print("toggle electron scanning")
70
+
71
+ @action("toggle_ion_scanning")
72
+ def toggle_ion_scanning(self, params: BaseParams):
73
+ print("toggle ion scanning")
74
+
75
+ @action("sleep")
76
+ def sleep(self, params: SleepParams):
77
+ time.sleep(params.get("seconds", 0))
78
+
79
+ @action("take_picture")
80
+ def take_picture(self, params: TakePictureParams) -> PictureResult:
81
+ """Take a picture with the microscope.
82
+
83
+ Args:
84
+ params: Parameters for the action
85
+ - horizontal_width: Horizontal width of the image
86
+
87
+ Returns:
88
+ Result of the action
89
+ """
90
+ time.sleep(1)
91
+
92
+ hw = params.get("horizontal_width", "default")
93
+
94
+ return PictureResult(
95
+ message=f"Picture taken with {self.device_name} (width: {hw})",
96
+ data={"image_id": "mock_image_123"}
97
+ )
98
+
99
+ @action("get_stage_position")
100
+ def get_stage_position(self, params: GetStagePositionParams) -> StagePositionResult:
101
+ """Get the stage position.
102
+
103
+ Args:
104
+ params: Parameters for the action (none required)
105
+
106
+ Returns:
107
+ Result of the action with x, y, z coordinates
108
+ """
109
+ time.sleep(0.5)
110
+
111
+ return StagePositionResult(
112
+ message=f"Stage position retrieved for {self.device_name}",
113
+ data=StagePosition(
114
+ x=10.5,
115
+ y=20.3,
116
+ z=5.1
117
+ )
118
+ )
119
+
120
+ @action("move_stage")
121
+ def move_stage(self, params: MoveStageParams) -> MoveStageResult:
122
+ """Move the stage to a new position.
123
+
124
+ Args:
125
+ params: Parameters for the action
126
+ - x: X coordinate
127
+ - y: Y coordinate
128
+ - z: Z coordinate
129
+
130
+ Returns:
131
+ Result of the action
132
+ """
133
+ time.sleep(2)
134
+
135
+ if not all(k in params for k in ["x", "y", "z"]):
136
+ # Use a proper MoveStageResult with error status instead of ErrorResult
137
+ return MoveStageResult(
138
+ message=f"Missing required parameters: x, y, z",
139
+ data={}
140
+ )
141
+
142
+ try:
143
+ new_position = {
144
+ "x": float(params["x"]),
145
+ "y": float(params["y"]),
146
+ "z": float(params["z"])
147
+ }
148
+
149
+ return MoveStageResult(
150
+ message=f"Stage moved for {self.device_name}",
151
+ data=new_position
152
+ )
153
+ except (KeyError, TypeError, ValueError):
154
+ # Use a proper MoveStageResult with error status instead of ErrorResult
155
+ return MoveStageResult(
156
+ message=f"Invalid parameters: x, y, z must be numeric values",
157
+ data={}
158
+ )
@@ -0,0 +1,67 @@
1
+ import sys
2
+ import signal
3
+ from pathlib import Path
4
+ import os
5
+
6
+ # 从SDK包中导入所需模块
7
+ from dp.agent.cloud.mcp import mcp
8
+ from dp.agent.cloud.mqtt import get_mqtt_cloud_instance
9
+ from dp.agent.device.mqtt_device_twin import DeviceTwin
10
+ # 从本地导入 TescanDevice
11
+
12
+ def run_cloud():
13
+ """Run in cloud environment"""
14
+ mqtt_instance = get_mqtt_cloud_instance()
15
+ from dp.agent.device.device.device import register_mcp_tools
16
+ from device.tescan_device import TescanDevice
17
+ register_mcp_tools(mcp, TescanDevice())
18
+ def signal_handler(sig, frame):
19
+ """Handle SIGINT signal to gracefully shutdown."""
20
+ print("Shutting down...")
21
+ mqtt_instance.stop()
22
+ sys.exit(0)
23
+
24
+ # Register signal handler for graceful shutdown
25
+ signal.signal(signal.SIGINT, signal_handler)
26
+
27
+ # Start MCP server
28
+ print("Starting MCP server...")
29
+ mcp.run(transport="sse")
30
+ def run_device():
31
+ """Run in lab environment"""
32
+ # Initialize device and twin
33
+ from device.tescan_device import TescanDevice
34
+ tescan_device = TescanDevice()
35
+ device_twin = DeviceTwin(tescan_device)
36
+
37
+ # Run device twin
38
+ try:
39
+ device_twin.run()
40
+ except KeyboardInterrupt:
41
+ print("\nShutting down lab environment...")
42
+ sys.exit(0)
43
+
44
+ def run_calculation():
45
+ """Run in calculation environment"""
46
+ # 在此实现你自己的计算环境逻辑
47
+ print("Running calculation task...")
48
+ # 模拟任务处理逻辑
49
+ from calculation import simple
50
+ simple.run()
51
+
52
+ if __name__ == "__main__":
53
+ if len(sys.argv) != 2:
54
+ print("Usage: python main.py [device|cloud|calculation]")
55
+ sys.exit(1)
56
+
57
+ mode = sys.argv[1]
58
+ if mode == "device":
59
+ run_device()
60
+ elif mode == "cloud":
61
+ run_cloud()
62
+ elif mode == "calculation":
63
+ run_calculation()
64
+ else:
65
+ print(f"Unknown mode: {mode}")
66
+ print("Usage: python main.py [device|cloud|calculation]")
67
+ sys.exit(1)
@@ -0,0 +1 @@
1
+ # UI 模板包
@@ -0,0 +1 @@
1
+ # API !W
@@ -0,0 +1,32 @@
1
+ # Configuration API
2
+ from fastapi import Request
3
+ from fastapi.responses import JSONResponse
4
+
5
+ from server.utils import get_ak_info_from_request
6
+ from config.agent_config import agentconfig
7
+
8
+
9
+ async def get_config(request: Request):
10
+ """Get frontend configuration"""
11
+ access_key, _ = get_ak_info_from_request(request.headers)
12
+ return JSONResponse(content={
13
+ "agent": agentconfig.config.get("agent", {}),
14
+ "ui": agentconfig.get_ui_config(),
15
+ "files": agentconfig.get_files_config(),
16
+ "websocket": agentconfig.get_websocket_config(),
17
+ "user_type": "registered" if access_key else "temporary"
18
+ })
19
+
20
+
21
+ async def status():
22
+ """API status"""
23
+ return {
24
+ "message": f"{agentconfig.config.get('agent', {}).get('name', 'Agent')} WebSocket 服务器正在运行",
25
+ "mode": "session",
26
+ "endpoints": {
27
+ "websocket": "/ws",
28
+ "files": "/api/files",
29
+ "file_tree": "/api/files/tree",
30
+ "config": "/api/config"
31
+ }
32
+ }
@@ -0,0 +1,61 @@
1
+ """
2
+ Constants for API modules
3
+ """
4
+
5
+ # File upload limits
6
+ MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
7
+ MAX_FILES_PER_UPLOAD = 10
8
+
9
+ # Allowed file extensions for upload
10
+ ALLOWED_EXTENSIONS = {
11
+ 'txt', 'pdf', 'csv', 'json', 'xml',
12
+ 'png', 'jpg', 'jpeg', 'gif', 'svg',
13
+ 'py', 'js', 'ts', 'java', 'cpp', 'c',
14
+ 'md', 'rst', 'yaml', 'yml', 'log',
15
+ 'html', 'htm', 'css', 'scss',
16
+ 'sh', 'bash', 'sql', 'toml'
17
+ }
18
+
19
+ # WebSocket message types
20
+ WS_MESSAGE_TYPES = {
21
+ 'MESSAGE': 'message',
22
+ 'CREATE_SESSION': 'create_session',
23
+ 'SWITCH_SESSION': 'switch_session',
24
+ 'GET_SESSIONS': 'get_sessions',
25
+ 'DELETE_SESSION': 'delete_session',
26
+ 'SET_PROJECT_ID': 'set_project_id',
27
+ 'ERROR': 'error',
28
+ 'PROJECT_ID_SET': 'project_id_set',
29
+ 'SESSION_MESSAGES': 'session_messages'
30
+ }
31
+
32
+ # Session states
33
+ SESSION_STATES = {
34
+ 'ACTIVE': 'active',
35
+ 'INACTIVE': 'inactive',
36
+ 'DELETED': 'deleted'
37
+ }
38
+
39
+ # API endpoints
40
+ API_ENDPOINTS = {
41
+ 'WEBSOCKET': '/ws',
42
+ 'FILES': '/api/files',
43
+ 'FILE_TREE': '/api/files/tree',
44
+ 'CONFIG': '/api/config',
45
+ 'PROJECTS': '/api/projects',
46
+ 'SESSIONS': '/api/sessions',
47
+ 'DEBUG': '/api/debug'
48
+ }
49
+
50
+ # File operations
51
+ FILE_OPS = {
52
+ 'DOWNLOAD': 'download',
53
+ 'UPLOAD': 'upload',
54
+ 'DELETE': 'delete',
55
+ 'LIST': 'list'
56
+ }
57
+
58
+ # Default values
59
+ DEFAULT_WORKSPACE_NAME = "Workspace"
60
+ DEFAULT_SESSION_LIMIT = 50
61
+ DEFAULT_MESSAGE_LIMIT = 100
@@ -0,0 +1,257 @@
1
+ """
2
+ Debug API endpoints for troubleshooting
3
+ """
4
+ import os
5
+ from fastapi import HTTPException
6
+ from fastapi.responses import JSONResponse
7
+ from config.agent_config import agentconfig
8
+ from api.websocket import manager
9
+
10
+ async def get_runner_status():
11
+ """
12
+ Get status of all runners
13
+ """
14
+ try:
15
+ runner_status = {}
16
+
17
+ # Get status of all runners
18
+ for runner_key, runner in manager.runners.items():
19
+ runner_status[runner_key] = {
20
+ "exists": True,
21
+ "type": type(runner).__name__,
22
+ "created": True
23
+ }
24
+
25
+ # Get all runner errors
26
+ runner_errors = getattr(manager, '_runner_errors', {})
27
+ for error_key, error_msg in runner_errors.items():
28
+ runner_status[error_key] = {
29
+ "exists": False,
30
+ "error": error_msg,
31
+ "created": False
32
+ }
33
+
34
+ return JSONResponse({
35
+ "success": True,
36
+ "runners": runner_status,
37
+ "total_runners": len(manager.runners),
38
+ "total_errors": len(runner_errors),
39
+ "active_connections": len(manager.active_connections)
40
+ })
41
+ except Exception as e:
42
+ return JSONResponse({
43
+ "success": False,
44
+ "error": str(e)
45
+ }, status_code=500)
46
+
47
+ async def get_config_status():
48
+ """
49
+ Get configuration status
50
+ """
51
+ try:
52
+ config = agentconfig.config
53
+
54
+ # Get agent configuration
55
+ agent_config = config.get("agent", {})
56
+
57
+ # Test if agent can be loaded
58
+ test_result = {
59
+ "can_load": False,
60
+ "error": None,
61
+ "agent_type": None
62
+ }
63
+
64
+ try:
65
+ # Try to load agent (without parameters)
66
+ test_agent = agentconfig.get_agent()
67
+ test_result["can_load"] = True
68
+ test_result["agent_type"] = type(test_agent).__name__
69
+ except Exception as e:
70
+ test_result["error"] = str(e)
71
+
72
+ return JSONResponse({
73
+ "success": True,
74
+ "config": {
75
+ "agent_name": agent_config.get("name"),
76
+ "agent_module": agent_config.get("module"),
77
+ "root_agent": agent_config.get("rootAgent"),
78
+ "config_path": str(agentconfig.config_path),
79
+ "config_exists": agentconfig.config_path.exists()
80
+ },
81
+ "test_result": test_result,
82
+ "environment": {
83
+ "user_working_dir": os.environ.get('USER_WORKING_DIR', os.getcwd()),
84
+ "bohr_project_id": os.environ.get('BOHR_PROJECT_ID'),
85
+ "agent_config_path": os.environ.get('AGENT_CONFIG_PATH')
86
+ }
87
+ })
88
+ except Exception as e:
89
+ return JSONResponse({
90
+ "success": False,
91
+ "error": str(e)
92
+ }, status_code=500)
93
+
94
+ async def get_session_status():
95
+ """
96
+ Get session status
97
+ """
98
+ try:
99
+ session_info = {}
100
+
101
+ # Get session information for each user
102
+ for user_id, session_service in manager.session_services.items():
103
+ try:
104
+ response = await session_service.list_sessions(
105
+ app_name=manager.app_name,
106
+ user_id=user_id
107
+ )
108
+ sessions = response.sessions if hasattr(response, 'sessions') else []
109
+ session_info[user_id] = {
110
+ "session_count": len(sessions),
111
+ "sessions": [
112
+ {
113
+ "id": s.id,
114
+ "state": s.state if hasattr(s, 'state') else {}
115
+ } for s in sessions[:3] # Only show first 3
116
+ ]
117
+ }
118
+ except Exception as e:
119
+ session_info[user_id] = {
120
+ "error": str(e)
121
+ }
122
+
123
+ return JSONResponse({
124
+ "success": True,
125
+ "users": len(manager.session_services),
126
+ "session_info": session_info,
127
+ "active_connections": [
128
+ {
129
+ "user": ctx.get_user_identifier(),
130
+ "project_id": ctx.project_id,
131
+ "current_session": ctx.current_session_id,
132
+ "is_registered": ctx.is_registered_user()
133
+ }
134
+ for ctx in manager.active_connections.values()
135
+ ]
136
+ })
137
+ except Exception as e:
138
+ return JSONResponse({
139
+ "success": False,
140
+ "error": str(e)
141
+ }, status_code=500)
142
+
143
+ async def test_agent_creation():
144
+ """
145
+ Test agent creation process
146
+ """
147
+ try:
148
+ steps = []
149
+
150
+ # Step 1: Load configuration
151
+ steps.append({
152
+ "step": "Load configuration",
153
+ "success": True,
154
+ "details": {
155
+ "config_path": str(agentconfig.config_path),
156
+ "agent_module": agentconfig.config.get("agent", {}).get("module")
157
+ }
158
+ })
159
+
160
+ # Step 2: Create agent (without parameters)
161
+ try:
162
+ agent = agentconfig.get_agent()
163
+ steps.append({
164
+ "step": "Create agent (no parameters)",
165
+ "success": True,
166
+ "details": {
167
+ "agent_type": type(agent).__name__,
168
+ "has_run_method": hasattr(agent, 'run') or hasattr(agent, '__call__')
169
+ }
170
+ })
171
+ except Exception as e:
172
+ steps.append({
173
+ "step": "Create agent (no parameters)",
174
+ "success": False,
175
+ "error": str(e)
176
+ })
177
+
178
+ # Step 3: Create agent (with project_id)
179
+ try:
180
+ project_id = os.environ.get('BOHR_PROJECT_ID')
181
+ if project_id:
182
+ agent_with_project = agentconfig.get_agent(
183
+ ak="",
184
+ app_key="",
185
+ project_id=int(project_id)
186
+ )
187
+ steps.append({
188
+ "step": f"Create agent (project_id={project_id})",
189
+ "success": True,
190
+ "details": {
191
+ "agent_type": type(agent_with_project).__name__
192
+ }
193
+ })
194
+ except Exception as e:
195
+ steps.append({
196
+ "step": f"创建 Agent (project_id={project_id})",
197
+ "success": False,
198
+ "error": str(e)
199
+ })
200
+
201
+ # Step 4: Check SessionService
202
+ try:
203
+ from google.adk.sessions import InMemorySessionService
204
+ test_service = InMemorySessionService()
205
+ steps.append({
206
+ "step": "Create SessionService",
207
+ "success": True,
208
+ "details": {
209
+ "service_type": type(test_service).__name__
210
+ }
211
+ })
212
+ except Exception as e:
213
+ steps.append({
214
+ "step": "Create SessionService",
215
+ "success": False,
216
+ "error": str(e)
217
+ })
218
+
219
+ # Step 5: Create Runner
220
+ try:
221
+ from google.adk import Runner
222
+ if 'agent' in locals() and 'test_service' in locals():
223
+ test_runner = Runner(
224
+ agent=agent,
225
+ session_service=test_service,
226
+ app_name="TestApp"
227
+ )
228
+ steps.append({
229
+ "step": "Create Runner",
230
+ "success": True,
231
+ "details": {
232
+ "runner_type": type(test_runner).__name__
233
+ }
234
+ })
235
+ except Exception as e:
236
+ steps.append({
237
+ "step": "创建 Runner",
238
+ "success": False,
239
+ "error": str(e)
240
+ })
241
+
242
+ all_success = all(step.get("success", False) for step in steps)
243
+
244
+ return JSONResponse({
245
+ "success": all_success,
246
+ "steps": steps,
247
+ "summary": {
248
+ "total_steps": len(steps),
249
+ "successful": sum(1 for s in steps if s.get("success", False)),
250
+ "failed": sum(1 for s in steps if not s.get("success", False))
251
+ }
252
+ })
253
+ except Exception as e:
254
+ return JSONResponse({
255
+ "success": False,
256
+ "error": str(e)
257
+ }, status_code=500)