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.
- bohr_agent_sdk-0.1.103.dist-info/METADATA +292 -0
- bohr_agent_sdk-0.1.103.dist-info/RECORD +80 -0
- dp/agent/cli/cli.py +126 -25
- dp/agent/cli/templates/__init__.py +1 -0
- dp/agent/cli/templates/calculation/simple.py.template +15 -0
- dp/agent/cli/templates/device/tescan_device.py.template +158 -0
- dp/agent/cli/templates/main.py.template +67 -0
- dp/agent/cli/templates/ui/__init__.py +1 -0
- dp/agent/cli/templates/ui/api/__init__.py +1 -0
- dp/agent/cli/templates/ui/api/config.py +32 -0
- dp/agent/cli/templates/ui/api/constants.py +61 -0
- dp/agent/cli/templates/ui/api/debug.py +257 -0
- dp/agent/cli/templates/ui/api/files.py +469 -0
- dp/agent/cli/templates/ui/api/files_upload.py +115 -0
- dp/agent/cli/templates/ui/api/files_user.py +50 -0
- dp/agent/cli/templates/ui/api/messages.py +161 -0
- dp/agent/cli/templates/ui/api/projects.py +146 -0
- dp/agent/cli/templates/ui/api/sessions.py +93 -0
- dp/agent/cli/templates/ui/api/utils.py +161 -0
- dp/agent/cli/templates/ui/api/websocket.py +184 -0
- dp/agent/cli/templates/ui/config/__init__.py +1 -0
- dp/agent/cli/templates/ui/config/agent_config.py +257 -0
- dp/agent/cli/templates/ui/frontend/index.html +13 -0
- dp/agent/cli/templates/ui/frontend/package.json +46 -0
- dp/agent/cli/templates/ui/frontend/tsconfig.json +26 -0
- dp/agent/cli/templates/ui/frontend/tsconfig.node.json +10 -0
- dp/agent/cli/templates/ui/frontend/ui-static/assets/index-DdAmKhul.js +105 -0
- dp/agent/cli/templates/ui/frontend/ui-static/assets/index-DfN2raU9.css +1 -0
- dp/agent/cli/templates/ui/frontend/ui-static/index.html +14 -0
- dp/agent/cli/templates/ui/frontend/vite.config.ts +37 -0
- dp/agent/cli/templates/ui/scripts/build_ui.py +56 -0
- dp/agent/cli/templates/ui/server/__init__.py +0 -0
- dp/agent/cli/templates/ui/server/app.py +98 -0
- dp/agent/cli/templates/ui/server/connection.py +210 -0
- dp/agent/cli/templates/ui/server/file_watcher.py +85 -0
- dp/agent/cli/templates/ui/server/middleware.py +43 -0
- dp/agent/cli/templates/ui/server/models.py +53 -0
- dp/agent/cli/templates/ui/server/session_manager.py +1158 -0
- dp/agent/cli/templates/ui/server/user_files.py +85 -0
- dp/agent/cli/templates/ui/server/utils.py +50 -0
- dp/agent/cli/templates/ui/test_download.py +98 -0
- dp/agent/cli/templates/ui/ui_utils.py +260 -0
- dp/agent/cli/templates/ui/websocket-server.py +87 -0
- dp/agent/server/storage/http_storage.py +1 -1
- bohr_agent_sdk-0.1.101.dist-info/METADATA +0 -224
- bohr_agent_sdk-0.1.101.dist-info/RECORD +0 -40
- {bohr_agent_sdk-0.1.101.dist-info → bohr_agent_sdk-0.1.103.dist-info}/WHEEL +0 -0
- {bohr_agent_sdk-0.1.101.dist-info → bohr_agent_sdk-0.1.103.dist-info}/entry_points.txt +0 -0
- {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)
|