bohr-agent-sdk 0.1.101__py3-none-any.whl → 0.1.102__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 (48) hide show
  1. {bohr_agent_sdk-0.1.101.dist-info → bohr_agent_sdk-0.1.102.dist-info}/METADATA +6 -2
  2. bohr_agent_sdk-0.1.102.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/RECORD +0 -40
  46. {bohr_agent_sdk-0.1.101.dist-info → bohr_agent_sdk-0.1.102.dist-info}/WHEEL +0 -0
  47. {bohr_agent_sdk-0.1.101.dist-info → bohr_agent_sdk-0.1.102.dist-info}/entry_points.txt +0 -0
  48. {bohr_agent_sdk-0.1.101.dist-info → bohr_agent_sdk-0.1.102.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bohr-agent-sdk
3
- Version: 0.1.101
3
+ Version: 0.1.102
4
4
  Summary: SDK for scientific agents
5
5
  Home-page: https://github.com/dptech-corp/bohr-agent-sdk/
6
6
  Author: DP Technology
@@ -30,6 +30,9 @@ Requires-Dist: paho-mqtt>=2.1.0
30
30
  Requires-Dist: redis>=6.2.0
31
31
  Requires-Dist: twine>=6.1.0
32
32
  Requires-Dist: build>=1.2.2.post1
33
+ Requires-Dist: watchdog>=6.0.0
34
+ Requires-Dist: fastapi>=0.116.0
35
+ Requires-Dist: bohrium-open-sdk==0.1.5
33
36
  Provides-Extra: device
34
37
  Requires-Dist: pywinauto-recorder>=0.1.0; extra == "device"
35
38
  Provides-Extra: cloud
@@ -44,6 +47,7 @@ Requires-Dist: black>=23.11.0; extra == "dev"
44
47
  Requires-Dist: isort>=5.12.0; extra == "dev"
45
48
  Requires-Dist: mypy>=1.7.0; extra == "dev"
46
49
  Requires-Dist: pylint>=3.0.0; extra == "dev"
50
+ Requires-Dist: google-adk; extra == "dev"
47
51
  Provides-Extra: docs
48
52
  Requires-Dist: sphinx>=7.2.0; extra == "docs"
49
53
  Requires-Dist: sphinx-rtd-theme>=1.3.0; extra == "docs"
@@ -92,7 +96,7 @@ dp-agent run tool cloud
92
96
  dp-agent run tool calculation
93
97
 
94
98
  # 运行代理
95
- dp-agent run agent
99
+ dp-agent run agent --config config.json
96
100
 
97
101
  # 调试模式
98
102
  dp-agent run debug
@@ -0,0 +1,80 @@
1
+ dp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ dp/agent/__init__.py,sha256=4kwF1khocxEkqJjnVhBV5cCsWkR_MBGrUthuHk44pT8,153
3
+ dp/agent/adapter/adk/__init__.py,sha256=mxX2SxGgDjwQ7WjfKMw9mQkq4ddl8XlCA6gnUinCW0w,493
4
+ dp/agent/adapter/adk/storage_artifact_service.py,sha256=Hd1CmEB8HgEz3x_riHVSSmYdw6W2bDYYa3c5ySCqmCE,5414
5
+ dp/agent/adapter/adk/utils.py,sha256=Hf6zZOmNi0YSI9t5acmR5kzowWaYr-UfyPiN8fefPkI,7359
6
+ dp/agent/adapter/adk/client/__init__.py,sha256=F1xfFNa4ZG8jV9adeGI2D3YBiSX-5RkvqEdTqNdJce4,209
7
+ dp/agent/adapter/adk/client/calculation_mcp_tool.py,sha256=8_uBP12SLaYUiQL6c0vysVsePEZS_r0YMogvW93ZFHo,12188
8
+ dp/agent/adapter/camel/__init__.py,sha256=RN1NhdmsJyN43fTxTXFld4UKZksjpSV0b2QvFn5gK7o,77
9
+ dp/agent/adapter/camel/client/__init__.py,sha256=ld-r0_WsZLFv6yyrmxjWmR8JgnrQzOw4fX0hwVHzciY,93
10
+ dp/agent/adapter/camel/client/calculation_mcp_client.py,sha256=JZZUYYfMgXvHzK4f6IJp-ia33wn3aYZqDSDVa5yKtdc,1860
11
+ dp/agent/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ dp/agent/cli/cli.py,sha256=3CPdZW3nn_n5-1Ohak_LOOHqNQJbnYZHoTXIVjI19VU,12367
13
+ dp/agent/cli/templates/__init__.py,sha256=h5__iNn8QzUyYpCUORJO9GTd42tga_BFQ3ZjA3QtSCI,15
14
+ dp/agent/cli/templates/main.py.template,sha256=gEv_naKkBKUmVY1aGM_RZPWqXhkYDIrk4eu7uQFpWrA,1986
15
+ dp/agent/cli/templates/calculation/simple.py.template,sha256=AkOrMWZf9YKQuLnl5yRgl2V-fepFuZJ1qDcTc9S5Gj0,395
16
+ dp/agent/cli/templates/device/tescan_device.py.template,sha256=c7RIwWhfwp5WiPy1S6puqnEJm7ClaZtic6ndv2WE7o8,4663
17
+ dp/agent/cli/templates/ui/__init__.py,sha256=QgYZneX7gKyajZIEvbHIEMD3av3bKj64E_eeDPBeuvY,14
18
+ dp/agent/cli/templates/ui/test_download.py,sha256=RzZ59pVd-4fYIbUbW6ZO1b1Twbycu5G6yb5yLFuT0oI,3002
19
+ dp/agent/cli/templates/ui/ui_utils.py,sha256=OMgQxZ-UvIJB_a58YBMypQKTI7N9B3AQBOR7kOTudRE,9774
20
+ dp/agent/cli/templates/ui/websocket-server.py,sha256=YLVnXyBelrZLo9EcU-17_qts4-UVscMM8-cX08X6XYY,2809
21
+ dp/agent/cli/templates/ui/api/__init__.py,sha256=eq1djuBJYvWlGTgxXvT9A386Eu21FNCcB7gV2lU46dU,8
22
+ dp/agent/cli/templates/ui/api/config.py,sha256=ZhHApcXDrmO1JjI-Ok09ETYB-BVis390ZrMRt140DhQ,1018
23
+ dp/agent/cli/templates/ui/api/constants.py,sha256=mHY81zf4ksfKEOsSiVsWD_A_KcQ6wveLvAImCay_kVM,1391
24
+ dp/agent/cli/templates/ui/api/debug.py,sha256=URC1k429s84Ue7ElcK7jFh73QeK04IlRyXEjVgLXnbY,8490
25
+ dp/agent/cli/templates/ui/api/files.py,sha256=DDqU8-u5yQmHz2sd9vuEURpdgTkQVlBjAyv7dhWz-mA,16469
26
+ dp/agent/cli/templates/ui/api/files_upload.py,sha256=SOPy7GdQQG4grj5DvuJt3p1_HHJYdk6EuehqtKMAcqs,4411
27
+ dp/agent/cli/templates/ui/api/files_user.py,sha256=mEFCpZChHzxNUxYUM7A3VqyMbgM3cR0M9FdT93wXJR8,1718
28
+ dp/agent/cli/templates/ui/api/messages.py,sha256=umIkjfVA5rlXIonWQP7JRLqpfjDdvOc046gBFidMk5A,4992
29
+ dp/agent/cli/templates/ui/api/projects.py,sha256=KOMRAPrfsbBKNBPotKHEFIKyBypQpox4lSO3ocnjA_M,5008
30
+ dp/agent/cli/templates/ui/api/sessions.py,sha256=Mi_Sq4mfW163oZ2K0lRFiSgE7MpvVArmmSItDL2fBFo,2994
31
+ dp/agent/cli/templates/ui/api/utils.py,sha256=6oTf1P105GEGcwDct-TB3v2pt2iQezTmywfniwrlOqM,4728
32
+ dp/agent/cli/templates/ui/api/websocket.py,sha256=kPc9ZArxHSpvEZHl8So5vAH7rWaKNcfTk2O5_61wYUg,9013
33
+ dp/agent/cli/templates/ui/config/__init__.py,sha256=F7JR_fnXNnZDHeqRCdEiWtVMy03_qFr8cOilIQ6XLUk,14
34
+ dp/agent/cli/templates/ui/config/agent_config.py,sha256=WFpukdBuZ0t-QQKnhE7NQ6tYPl98FP6fmweRpNbOZQM,11255
35
+ dp/agent/cli/templates/ui/frontend/index.html,sha256=QKDypXDFg72KI3dPq8uJ9dA0WG0XmkiZNSKCSu7_bTc,362
36
+ dp/agent/cli/templates/ui/frontend/package.json,sha256=JGICM80tJ1Jvroi-D5RcBjBbCoqqQF_ARFl5qyci-wc,1270
37
+ dp/agent/cli/templates/ui/frontend/tsconfig.json,sha256=1WbW4SvrlJDyfu1pkDY5-53AwTqqs1c8y7FTPEC3Rlw,664
38
+ dp/agent/cli/templates/ui/frontend/tsconfig.node.json,sha256=aEcXXaWrgHnbZYO5LCCfeaiuOdNfOwh23fsHF7dS1Mg,212
39
+ dp/agent/cli/templates/ui/frontend/vite.config.ts,sha256=YFMZLo35W8b0SgLQ0xPxMWk8byraKEpd4gCDdag34v8,930
40
+ dp/agent/cli/templates/ui/frontend/ui-static/index.html,sha256=lUvP2GnHOhP3hDzXh-lUYjE8P6sFJBPdZ9pXpYu26M4,460
41
+ dp/agent/cli/templates/ui/frontend/ui-static/assets/index-DdAmKhul.js,sha256=v6CrzD6cvbf6QiUwdpngBlkhOwGBAlKbEdm11uB7KIs,1174176
42
+ dp/agent/cli/templates/ui/frontend/ui-static/assets/index-DfN2raU9.css,sha256=Ks6tewLxZv00LYmBf_U8CNUr-pPDSqGXFBiIJ5HaES0,68144
43
+ dp/agent/cli/templates/ui/scripts/build_ui.py,sha256=zoK6agl1dt-InaYQyXSABxjtJj24gtCbm0KKVv0RTSA,1661
44
+ dp/agent/cli/templates/ui/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
+ dp/agent/cli/templates/ui/server/app.py,sha256=ZX7ZA_qJyA-Ur7BODICzSn_S4FwGnRWcQP_qq2MZJhw,3803
46
+ dp/agent/cli/templates/ui/server/connection.py,sha256=huet_WWxGjo_J9ozj-G8tEYSiEYTsgxOTgjEEJ6CubU,6457
47
+ dp/agent/cli/templates/ui/server/file_watcher.py,sha256=t0e7IMgf4E1y0CxeboCqsVeZPBo1CGSw_qoO8wG6Wy4,2923
48
+ dp/agent/cli/templates/ui/server/middleware.py,sha256=bNR5aFqKjxv2einQ0e26aq6tiUW4SMses3IHkrmHDCk,1474
49
+ dp/agent/cli/templates/ui/server/models.py,sha256=obfMkFFB9qZZXDdwoC25u3tBlUC6Rz7sjeyuh7a_UWk,1680
50
+ dp/agent/cli/templates/ui/server/session_manager.py,sha256=ZbNHGCFvswa-LKWn6c6RMHWDdfeOvY5L6A8CfrsF0OE,46536
51
+ dp/agent/cli/templates/ui/server/user_files.py,sha256=khkiyY2UOOysHqO6JgCPUDqtrInp83G1M62i3Lj-0aY,2995
52
+ dp/agent/cli/templates/ui/server/utils.py,sha256=f4NfwFBq_RdZyFn_KCW6ZThYW8TvQyVruK7PJZ-DA80,1530
53
+ dp/agent/cloud/__init__.py,sha256=e16ymCZX2f-S8DyGB5jSK8gnQqVObRIsvtLXLALIKxQ,441
54
+ dp/agent/cloud/main.py,sha256=5QIEjpZ1RxWnR8wyLf-vlgz1bn9oOnxCYn158LBaLN4,727
55
+ dp/agent/cloud/mcp.py,sha256=tsAwC3doVMLYr6Oh8PxVqF-qCygYkDZJTIhoF_h8eGQ,4537
56
+ dp/agent/cloud/mqtt.py,sha256=e8Dz1Wffzjj8V0Xrr6LukwfdiPrj9VsVXatD3u4NpkQ,23036
57
+ dp/agent/device/__init__.py,sha256=G3i0zG7orCgMcXBEEhm7dufDeKY0QgFdQinOjDh8zSg,400
58
+ dp/agent/device/mqtt_device_twin.py,sha256=xHQFi2WQxrL5KqSEU2DeRSBiaPT5FLXvgszinyanQ_Q,8671
59
+ dp/agent/device/device/__init__.py,sha256=w7_1S16S1vWUq0RGl0GFgjq2vFkc5oNvy8cQTnvPm24,319
60
+ dp/agent/device/device/device.py,sha256=9ZRIJth-4qMO-i-u_b_cO3d6a4eTbTQjPaxFsV_zEkc,9643
61
+ dp/agent/device/device/types.py,sha256=JuxB-hjf1CjjvfBxCLwRAXVFlYS-nPEdiJpBWLFVCzo,1924
62
+ dp/agent/server/__init__.py,sha256=rckaYd8pbYyB4ENEhgjXKeGMXjdnrgcJpdM1gu5u1Wc,508
63
+ dp/agent/server/calculation_mcp_server.py,sha256=eClRP7A-t5hMGyTh81KC3GAKjSPNJIylOrOKyzqwo8o,11459
64
+ dp/agent/server/preprocessor.py,sha256=XUWu7QOwo_sIDMYS2b1OTrM33EXEVH_73vk-ju1Ok8A,1264
65
+ dp/agent/server/utils.py,sha256=8jgYZEW4XBp86AF2Km6QkwHltBmrnS-soTpHov7ZEJw,4501
66
+ dp/agent/server/executor/__init__.py,sha256=s95M5qKQk39Yi9qaVJZhk_nfj54quSf7EDghR3OCFUA,248
67
+ dp/agent/server/executor/base_executor.py,sha256=EFJBsYVYAvuRbiLAbLOwLTw3h7ScjN025xnSP4uJHrQ,2052
68
+ dp/agent/server/executor/dispatcher_executor.py,sha256=urpzmKH_tBOgblBdJEa3y8eEhXqUDrdcdWCnUdJpfZk,9420
69
+ dp/agent/server/executor/local_executor.py,sha256=wYCclNZFkLb3v7KpW1nCnupO8piBES-esYlDAuz86zk,6120
70
+ dp/agent/server/storage/__init__.py,sha256=Sgsyp5hb0_hhIGugAPfQFzBHt_854rS_MuMuE3sn8Gs,389
71
+ dp/agent/server/storage/base_storage.py,sha256=728-oNG6N8isV95gZVnyi4vTznJPJhSjxw9Gl5Y_y5o,2356
72
+ dp/agent/server/storage/bohrium_storage.py,sha256=EsKX4dWWvZTn2TEhZv4zsvihfDK0mmPFecrln-Ytk40,10488
73
+ dp/agent/server/storage/http_storage.py,sha256=w0lY95wQqKmjXTGFRhEG2hLu8GBFwgqG8ocm5lJ_fYc,1470
74
+ dp/agent/server/storage/local_storage.py,sha256=t1wfjByjXew9ws3PuUxWxmZQ0-Wt1a6t4wmj3fW62GI,1352
75
+ dp/agent/server/storage/oss_storage.py,sha256=pgjmi7Gir3Y5wkMDCvU4fvSls15fXT7Ax-h9MYHFPK0,3359
76
+ bohr_agent_sdk-0.1.102.dist-info/METADATA,sha256=7FQMW--VfxyMkPlKfbj9_j5oMWFExoM_0cpxTG1a4-Y,6495
77
+ bohr_agent_sdk-0.1.102.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
78
+ bohr_agent_sdk-0.1.102.dist-info/entry_points.txt,sha256=5n5kneF5IbDQtoQ2WfF-QuBjDtsimJte9Rv9baSGgc0,86
79
+ bohr_agent_sdk-0.1.102.dist-info/top_level.txt,sha256=87xLUDhu_1nQHoGLwlhJ6XlO7OsjILh6i1nX6ljFzDo,3
80
+ bohr_agent_sdk-0.1.102.dist-info/RECORD,,
dp/agent/cli/cli.py CHANGED
@@ -8,7 +8,18 @@ import signal
8
8
  import uuid
9
9
  import requests
10
10
 
11
+ try:
12
+ from dotenv import load_dotenv
13
+ env_file = Path('.env')
14
+ if not env_file.exists():
15
+ env_file = Path(__file__).parent.parent.parent.parent.parent / '.env'
16
+ if env_file.exists():
17
+ load_dotenv(env_file)
18
+ except ImportError:
19
+ pass
20
+
11
21
  from ..server.storage import storage_dict
22
+ from .templates.ui.ui_utils import UIConfigManager, UIProcessManager
12
23
 
13
24
  @click.group()
14
25
  def cli():
@@ -29,37 +40,34 @@ def scaffolding(type):
29
40
  """Fetch scaffolding for the science agent."""
30
41
  click.echo(f"Generating {type} project scaffold...")
31
42
 
32
- # 获取模板目录路径
33
43
  templates_dir = Path(__file__).parent / 'templates'
34
-
35
- # 获取用户当前工作目录
36
44
  current_dir = Path.cwd()
37
45
 
38
46
 
39
- # 创建必要的目录结构
47
+ # Create necessary directory structure
40
48
  if type == 'device':
41
- project_dirs = project_dirs = ['cloud', 'device']
49
+ project_dirs = ['cloud', 'device']
42
50
  elif type == 'calculation':
43
- project_dirs = project_dirs = ['calculation']
51
+ project_dirs = ['calculation']
44
52
 
45
53
  for dir_name in project_dirs:
46
54
  dst_dir = current_dir / dir_name
47
55
 
48
56
  if dst_dir.exists():
49
- click.echo(f"Warning: {dir_name} already existsskipping...")
50
- click.echo(f"If you want to create a new scaffold, please delete the existing project folder first.")
57
+ click.echo(f"Warning: {dir_name} already exists, skipping...")
58
+ click.echo(f"To create a new scaffold, please delete the existing folder first.")
51
59
  continue
52
60
 
53
- # 只创建目录,不复制SDK文件
61
+ # Create directory only
54
62
  dst_dir.mkdir(parents=True, exist_ok=True)
55
63
 
56
- # 创建__init__.py文件以使目录成为Python
64
+ # Create __init__.py files to make directories Python packages
57
65
  for dir_name in project_dirs:
58
66
  init_file = current_dir / dir_name / '__init__.py'
59
67
  if not init_file.exists():
60
68
  init_file.write_text('')
61
69
 
62
- # 从模板创建main.py文件
70
+ # Create main.py from template
63
71
  main_template = templates_dir / 'main.py.template'
64
72
  main_file = current_dir / 'main.py'
65
73
  if not main_file.exists():
@@ -78,11 +86,11 @@ def scaffolding(type):
78
86
  calculation_file = current_dir / 'calculation' / 'simple.py'
79
87
  if not calculation_file.exists():
80
88
  shutil.copy2(calculation_template, calculation_file)
81
- click.echo("\nCreated calculation example implementation in calculation/calculation.py")
82
- click.echo("Please modify this file according to your actual calculation control requirements.")
89
+ click.echo("\nCreated calculation example implementation in calculation/simple.py")
90
+ click.echo("Please modify this file according to your actual calculation requirements.")
83
91
 
84
- click.echo("\nSucceed for fetching scaffold!")
85
- click.echo("Now you can use dp-agent run-cloud or dp-agent run-device to run this project!")
92
+ click.echo("\nSuccessfully created scaffold!")
93
+ click.echo("Now you can use dp-agent run tool cloud/device/calculation to run this project!")
86
94
 
87
95
  @fetch.command()
88
96
  def config():
@@ -104,7 +112,6 @@ def config():
104
112
  response = requests.get(remote_env_url)
105
113
  with open(env_file, 'w') as f:
106
114
  f.write(response.text)
107
- #shutil.copy2(env_template, env_file)
108
115
  click.echo("Configuration file .env has been created.")
109
116
  click.echo("\nIMPORTANT: Please update the following configurations in your .env file:")
110
117
  click.echo("1. MQTT_INSTANCE_ID - Your Aliyun MQTT instance ID")
@@ -172,16 +179,109 @@ def calculation():
172
179
  sys.exit(1)
173
180
 
174
181
  @run.command()
175
- def agent():
176
- """Run the science agent."""
177
- click.echo("Starting agent...")
178
- click.echo("Agent started.")
182
+ @click.option('--ui/--no-ui', default=True, help='Enable/disable Web UI interface')
183
+ @click.option('--config', help='Configuration file path (default: agent-config.json)')
184
+ @click.option('--port', type=int, help='Server port (default from config)')
185
+ @click.option('--module', help='Agent module path (default: agent)')
186
+ @click.option('--agent-name', help='Agent variable name (default: root_agent)')
187
+ @click.option('--dev/--prod', default=False, help='Development mode (default: production)')
188
+ def agent(ui, config, port, module, agent_name, dev):
189
+ """Run the science agent with optional UI interface."""
190
+ if not ui:
191
+ click.echo("Starting agent in console mode...")
192
+ click.echo("Console mode not yet implemented.")
193
+ return
194
+
195
+ current_dir = Path.cwd()
196
+ config_path = Path(config) if config else current_dir / "agent-config.json"
197
+ config_manager = UIConfigManager(config_path if config_path.exists() else None)
198
+
199
+ if module:
200
+ config_manager.config['agent']['module'] = module
201
+
202
+ agent_module = config_manager.config['agent']['module']
203
+
204
+ if '/' in agent_module or '\\' in agent_module or agent_module.endswith('.py'):
205
+ file_path = Path(agent_module)
206
+
207
+ if not file_path.is_absolute():
208
+ file_path = current_dir / file_path
209
+
210
+ if not file_path.exists():
211
+ click.echo(f"Error: Agent file not found: {file_path}")
212
+ click.echo("\nPlease ensure:")
213
+ click.echo("1. File path is correct")
214
+ click.echo("2. File exists and is accessible")
215
+ sys.exit(1)
216
+ else:
217
+ module_parts = agent_module.split('.')
218
+ module_dir = current_dir / Path(*module_parts[:-1])
219
+ module_file = current_dir / Path(*module_parts[:-1]) / f"{module_parts[-1]}.py"
220
+ module_init = module_dir / "__init__.py"
221
+
222
+ if not (module_dir.exists() or module_file.exists()):
223
+ click.echo(f"Error: Module {agent_module} not found.")
224
+ click.echo(f"Tried to find: {module_dir} or {module_file}")
225
+ click.echo("\nPlease ensure:")
226
+ click.echo("1. You have created the agent module")
227
+ click.echo("2. The 'agent.module' path is correctly configured in config.json")
228
+ click.echo("3. Or use --module parameter to specify the correct module path")
229
+ sys.exit(1)
230
+
231
+ if os.environ.get('UI_TEMPLATE_DIR'):
232
+ ui_dir = Path(os.environ.get('UI_TEMPLATE_DIR'))
233
+ else:
234
+ try:
235
+ current_file = Path(__file__).resolve()
236
+
237
+ if 'site-packages' in str(current_file):
238
+ ui_dir = Path(__file__).parent / "templates" / "ui"
239
+ else:
240
+ ui_dir = current_file.parent / "templates" / "ui"
241
+ click.echo(f"🔧 Development mode detected, using source path: {ui_dir}")
242
+
243
+ except Exception:
244
+ ui_dir = Path(__file__).parent / "templates" / "ui"
245
+
246
+ if not ui_dir.exists():
247
+ click.echo(f"Error: UI template directory not found: {ui_dir}")
248
+ click.echo("Tip: You can specify template path via UI_TEMPLATE_DIR environment variable")
249
+ sys.exit(1)
250
+
251
+ if agent_name:
252
+ config_manager.config['agent']['rootAgent'] = agent_name
253
+ if port:
254
+ config_manager.config['server']['port'] = port
255
+
256
+ temp_config = ui_dir / "config" / "agent-config.temp.json"
257
+ config_manager.save_config(temp_config)
258
+
259
+ os.environ['AGENT_CONFIG_PATH'] = str(temp_config)
260
+ os.environ['PYTHONPATH'] = f"{current_dir}:{os.environ.get('PYTHONPATH', '')}"
261
+
262
+ try:
263
+ process_manager = UIProcessManager(ui_dir, config_manager.config)
264
+
265
+ process_manager.start_websocket_server()
266
+ process_manager.start_frontend_server(dev_mode=dev)
267
+
268
+ click.echo("\nPress Ctrl+C to stop the service...")
269
+ process_manager.wait_for_processes()
270
+
271
+ except KeyboardInterrupt:
272
+ click.echo("\nShutting down services...")
273
+ if 'process_manager' in locals():
274
+ process_manager.cleanup()
275
+ sys.exit(0)
276
+ except Exception as e:
277
+ click.echo(f"Error: {e}")
278
+ if 'process_manager' in locals():
279
+ process_manager.cleanup()
280
+ sys.exit(1)
281
+ finally:
282
+ if 'temp_config' in locals() and temp_config.exists():
283
+ temp_config.unlink()
179
284
 
180
- @run.command()
181
- def debug():
182
- """Debug the science agent in cloud environment."""
183
- click.echo("Starting cloud environment in debug mode...")
184
- click.echo("Cloud environment debug mode started.")
185
285
 
186
286
  @cli.group()
187
287
  def artifact():
@@ -229,6 +329,7 @@ def download(**kwargs):
229
329
  path = storage.download(key, path)
230
330
  click.echo("%s has been downloaded to %s" % (uri, path))
231
331
 
332
+
232
333
  def main():
233
334
  cli()
234
335
 
@@ -0,0 +1 @@
1
+ # CLI 模板包
@@ -0,0 +1,15 @@
1
+ from dp.agent.server import CalculationMCPServer
2
+
3
+ # 创建 MCP Server 实例
4
+ mcp = CalculationMCPServer("Demo", host="0.0.0.0", port=5001)
5
+
6
+ # 用装饰器注册远程调用函数
7
+ @mcp.tool()
8
+ def add_numbers(a: int, b: int) -> int:
9
+ """Add two numbers."""
10
+ return a + b
11
+
12
+ def run():
13
+ print("Starting MCP server on http://127.0.0.1:5001 ...")
14
+ mcp.run(transport="streamable-http")
15
+
@@ -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
+ }