@agentunion/kite 1.3.2 → 1.5.0

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 (293) hide show
  1. package/CHANGELOG.md +302 -0
  2. package/cli.js +119 -4
  3. package/core/dependency_checker.py +250 -0
  4. package/core/env_checker.py +490 -0
  5. package/dependencies_lock.json +128 -0
  6. package/extensions/agents/assistant/entry.py +111 -1
  7. package/extensions/agents/assistant/server.py +279 -215
  8. package/extensions/channels/acp_channel/entry.py +111 -1
  9. package/extensions/channels/acp_channel/module.md +23 -22
  10. package/extensions/channels/acp_channel/server.py +279 -215
  11. package/extensions/event_hub_bench/entry.py +107 -1
  12. package/extensions/services/backup/entry.py +306 -21
  13. package/extensions/services/backup/module.md +24 -22
  14. package/extensions/services/evol/auth_manager.py +443 -0
  15. package/extensions/services/evol/config.yaml +149 -0
  16. package/extensions/services/evol/config_loader.py +117 -0
  17. package/extensions/services/evol/entry.py +406 -0
  18. package/extensions/services/evol/evol_api.py +173 -0
  19. package/extensions/services/evol/evol_config.json5 +29 -0
  20. package/extensions/services/evol/migrate_tokens.py +122 -0
  21. package/extensions/services/evol/module.md +32 -0
  22. package/extensions/services/evol/pairing.py +250 -0
  23. package/extensions/services/evol/pairing_codes.jsonl +1 -0
  24. package/extensions/services/evol/relay.py +682 -0
  25. package/extensions/services/evol/relay_config.json5 +67 -0
  26. package/extensions/services/evol/routes/__init__.py +1 -0
  27. package/extensions/services/evol/routes/routes_management_ws.py +127 -0
  28. package/extensions/services/evol/routes/routes_rpc.py +89 -0
  29. package/extensions/services/evol/routes/routes_test.py +61 -0
  30. package/extensions/services/evol/server.py +875 -0
  31. package/extensions/services/evol/static/css/style.css +1200 -0
  32. package/extensions/services/evol/static/index.html +781 -0
  33. package/extensions/services/evol/static/index_evol.html +14 -0
  34. package/extensions/services/evol/static/js/app.js +6304 -0
  35. package/extensions/services/evol/static/js/auth.js +326 -0
  36. package/extensions/services/evol/static/js/dialog.js +285 -0
  37. package/extensions/services/evol/static/js/evol-app-fixed.js +50 -0
  38. package/extensions/services/evol/static/js/evol-app.js +1949 -0
  39. package/extensions/services/evol/static/js/evol-app.js.bak +1800 -0
  40. package/extensions/services/evol/static/js/kernel-client-example.js +228 -0
  41. package/extensions/services/evol/static/js/kernel-client.js +396 -0
  42. package/extensions/services/evol/static/js/main.js +141 -0
  43. package/extensions/services/evol/static/js/registry-tests.js +585 -0
  44. package/extensions/services/evol/static/js/stats.js +217 -0
  45. package/extensions/services/evol/static/js/token-manager.js +175 -0
  46. package/extensions/services/evol/static/pairing.html +248 -0
  47. package/extensions/services/evol/static/test_registry.html +262 -0
  48. package/extensions/services/evol/static/test_relay.html +462 -0
  49. package/extensions/services/evol/stats_manager.py +240 -0
  50. package/extensions/services/model_service/entry.py +167 -19
  51. package/extensions/services/model_service/module.md +21 -22
  52. package/extensions/services/proxy/.claude/settings.local.json +13 -0
  53. package/extensions/services/proxy/CHANGELOG_20260308.md +258 -0
  54. package/extensions/services/proxy/_fix_prints.py +133 -0
  55. package/extensions/services/proxy/_fix_prints2.py +87 -0
  56. package/extensions/services/proxy/agentcp/LICENCE +178 -0
  57. package/extensions/services/proxy/agentcp/README copy.md +85 -0
  58. package/extensions/services/proxy/agentcp/README.md +260 -0
  59. package/extensions/services/proxy/agentcp/__init__.py +16 -0
  60. package/extensions/services/proxy/agentcp/agent.py +4 -0
  61. package/extensions/services/proxy/agentcp/agentcp.py +2494 -0
  62. package/extensions/services/proxy/agentcp/agentprofile.json +89 -0
  63. package/extensions/services/proxy/agentcp/ap/__init__.py +16 -0
  64. package/extensions/services/proxy/agentcp/ap/ap_client.py +316 -0
  65. package/extensions/services/proxy/agentcp/assets/images/wechat_qr.png +0 -0
  66. package/extensions/services/proxy/agentcp/backup/metrics.json +31 -0
  67. package/extensions/services/proxy/agentcp/base/__init__.py +20 -0
  68. package/extensions/services/proxy/agentcp/base/auth_client.py +257 -0
  69. package/extensions/services/proxy/agentcp/base/client.py +112 -0
  70. package/extensions/services/proxy/agentcp/base/env.py +34 -0
  71. package/extensions/services/proxy/agentcp/base/html_util.py +336 -0
  72. package/extensions/services/proxy/agentcp/base/log.py +98 -0
  73. package/extensions/services/proxy/agentcp/ca/__init__.py +17 -0
  74. package/extensions/services/proxy/agentcp/ca/ca_client.py +414 -0
  75. package/extensions/services/proxy/agentcp/ca/ca_root.py +74 -0
  76. package/extensions/services/proxy/agentcp/context/__init__.py +20 -0
  77. package/extensions/services/proxy/agentcp/context/context.py +73 -0
  78. package/extensions/services/proxy/agentcp/context/exceptions.py +114 -0
  79. package/extensions/services/proxy/agentcp/create_profile.py +125 -0
  80. package/extensions/services/proxy/agentcp/create_profile_weather.py +125 -0
  81. package/extensions/services/proxy/agentcp/db/__init__.py +15 -0
  82. package/extensions/services/proxy/agentcp/db/db_mananger.py +550 -0
  83. package/extensions/services/proxy/agentcp/docs/UDP_HEARTBEAT_FIX_REPORT.md +265 -0
  84. package/extensions/services/proxy/agentcp/docs/heartbeat_issue_analysis.md +291 -0
  85. package/extensions/services/proxy/agentcp/file/__init__.py +16 -0
  86. package/extensions/services/proxy/agentcp/file/file_client.py +141 -0
  87. package/extensions/services/proxy/agentcp/file/wss_binary_message.py +137 -0
  88. package/extensions/services/proxy/agentcp/hcp.py +299 -0
  89. package/extensions/services/proxy/agentcp/heartbeat/__init__.py +16 -0
  90. package/extensions/services/proxy/agentcp/heartbeat/heartbeat_client.py +360 -0
  91. package/extensions/services/proxy/agentcp/improved_scheduler.py +498 -0
  92. package/extensions/services/proxy/agentcp/llm_agent_utils.py +249 -0
  93. package/extensions/services/proxy/agentcp/llm_server.py +172 -0
  94. package/extensions/services/proxy/agentcp/mermaid.py +210 -0
  95. package/extensions/services/proxy/agentcp/message.py +149 -0
  96. package/extensions/services/proxy/agentcp/metrics.py +256 -0
  97. package/extensions/services/proxy/agentcp/monitoring/__init__.py +20 -0
  98. package/extensions/services/proxy/agentcp/monitoring/global_monitor.py +27 -0
  99. package/extensions/services/proxy/agentcp/monitoring/metrics_store.py +325 -0
  100. package/extensions/services/proxy/agentcp/monitoring/monitoring_service.py +269 -0
  101. package/extensions/services/proxy/agentcp/monitoring/sliding_window.py +222 -0
  102. package/extensions/services/proxy/agentcp/monitoring/standalone_reader.py +224 -0
  103. package/extensions/services/proxy/agentcp/msg/__init__.py +21 -0
  104. package/extensions/services/proxy/agentcp/msg/connection_manager.py +456 -0
  105. package/extensions/services/proxy/agentcp/msg/message_client.py +2058 -0
  106. package/extensions/services/proxy/agentcp/msg/message_serialize.py +263 -0
  107. package/extensions/services/proxy/agentcp/msg/open_ai_message.py +88 -0
  108. package/extensions/services/proxy/agentcp/msg/session_manager.py +1062 -0
  109. package/extensions/services/proxy/agentcp/msg/stream_client.py +267 -0
  110. package/extensions/services/proxy/agentcp/msg/websocket_file_receiver.py +89 -0
  111. package/extensions/services/proxy/agentcp/msg/ws_logger.py +685 -0
  112. package/extensions/services/proxy/agentcp/msg/wss_binary_message.py +137 -0
  113. package/extensions/services/proxy/agentcp/requirements.txt +7 -0
  114. package/extensions/services/proxy/agentcp/samples/agent_graph/README.md +37 -0
  115. package/extensions/services/proxy/agentcp/samples/agent_graph/agentprofile.json +89 -0
  116. package/extensions/services/proxy/agentcp/samples/agent_graph/create_profile.py +138 -0
  117. package/extensions/services/proxy/agentcp/samples/agent_graph/main.py +164 -0
  118. package/extensions/services/proxy/agentcp/samples/agent_use/create_profile.py +123 -0
  119. package/extensions/services/proxy/agentcp/samples/agent_use/llm/create_profile.py +129 -0
  120. package/extensions/services/proxy/agentcp/samples/agent_use/llm/env.json +5 -0
  121. package/extensions/services/proxy/agentcp/samples/agent_use/llm/main.py +146 -0
  122. package/extensions/services/proxy/agentcp/samples/agent_use/main.py +123 -0
  123. package/extensions/services/proxy/agentcp/samples/agent_use/readme.md +379 -0
  124. package/extensions/services/proxy/agentcp/samples/agent_use/search/create_profile.py +129 -0
  125. package/extensions/services/proxy/agentcp/samples/agent_use/search/main.py +28 -0
  126. package/extensions/services/proxy/agentcp/samples/agent_use/tool/create_profile.py +129 -0
  127. package/extensions/services/proxy/agentcp/samples/agent_use/tool/main.py +20 -0
  128. package/extensions/services/proxy/agentcp/samples/ali_amap/README.md +97 -0
  129. package/extensions/services/proxy/agentcp/samples/ali_amap/amap_agent.py +88 -0
  130. package/extensions/services/proxy/agentcp/samples/ali_amap/create_profile.py +125 -0
  131. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/powershell.py +228 -0
  132. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/software.py +63 -0
  133. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/tools.py +36 -0
  134. package/extensions/services/proxy/agentcp/samples/compute_agent/browser_user.py +41 -0
  135. package/extensions/services/proxy/agentcp/samples/deepseek/README.md +79 -0
  136. package/extensions/services/proxy/agentcp/samples/deepseek/create_profile.py +126 -0
  137. package/extensions/services/proxy/agentcp/samples/deepseek/deepseek.py +42 -0
  138. package/extensions/services/proxy/agentcp/samples/dify_chat/README.md +78 -0
  139. package/extensions/services/proxy/agentcp/samples/dify_chat/create_profile.py +126 -0
  140. package/extensions/services/proxy/agentcp/samples/dify_chat/dify_chat.py +47 -0
  141. package/extensions/services/proxy/agentcp/samples/dify_workflow/README.md +78 -0
  142. package/extensions/services/proxy/agentcp/samples/dify_workflow/create_profile.py +126 -0
  143. package/extensions/services/proxy/agentcp/samples/dify_workflow/dify_workflow.py +46 -0
  144. package/extensions/services/proxy/agentcp/samples/executor/README.md +44 -0
  145. package/extensions/services/proxy/agentcp/samples/executor/agentprofile.json +89 -0
  146. package/extensions/services/proxy/agentcp/samples/executor/create_profile.py +139 -0
  147. package/extensions/services/proxy/agentcp/samples/executor/main.py +160 -0
  148. package/extensions/services/proxy/agentcp/samples/filereader/README.md +45 -0
  149. package/extensions/services/proxy/agentcp/samples/filereader/agentprofile.json +90 -0
  150. package/extensions/services/proxy/agentcp/samples/filereader/create_profile.py +137 -0
  151. package/extensions/services/proxy/agentcp/samples/filereader/main.py +253 -0
  152. package/extensions/services/proxy/agentcp/samples/filewriter/README.md +38 -0
  153. package/extensions/services/proxy/agentcp/samples/filewriter/agentprofile.json +91 -0
  154. package/extensions/services/proxy/agentcp/samples/filewriter/create_profile.py +138 -0
  155. package/extensions/services/proxy/agentcp/samples/filewriter/main.py +289 -0
  156. package/extensions/services/proxy/agentcp/samples/hcp/README.md +85 -0
  157. package/extensions/services/proxy/agentcp/samples/hcp/acp_weather_agent.zip +0 -0
  158. package/extensions/services/proxy/agentcp/samples/hcp/create_profile.py +125 -0
  159. package/extensions/services/proxy/agentcp/samples/hcp/hcp.py +237 -0
  160. package/extensions/services/proxy/agentcp/samples/helloworld/README.md +68 -0
  161. package/extensions/services/proxy/agentcp/samples/helloworld/hello_world.py +40 -0
  162. package/extensions/services/proxy/agentcp/samples/llm_agent/MEADME.md +117 -0
  163. package/extensions/services/proxy/agentcp/samples/llm_agent/create_profile.py +125 -0
  164. package/extensions/services/proxy/agentcp/samples/llm_agent/qwen_agent.py +136 -0
  165. package/extensions/services/proxy/agentcp/samples/local_llm_agent/README.md +90 -0
  166. package/extensions/services/proxy/agentcp/samples/local_llm_agent/create_profile.py +125 -0
  167. package/extensions/services/proxy/agentcp/samples/local_llm_agent/main.py +49 -0
  168. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/README.md +55 -0
  169. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/create_profile.py +125 -0
  170. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/main.py +23 -0
  171. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/README.md +103 -0
  172. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/create_profile.py +125 -0
  173. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/main.py +69 -0
  174. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/README.md +58 -0
  175. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/create_profile.py +125 -0
  176. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/main.py +25 -0
  177. package/extensions/services/proxy/agentcp/samples/qwen3/README.md +71 -0
  178. package/extensions/services/proxy/agentcp/samples/qwen3/create_profile.py +126 -0
  179. package/extensions/services/proxy/agentcp/samples/qwen3/qwen3.py +37 -0
  180. package/extensions/services/proxy/agentcp/samples/qwen3_tools/README.md +133 -0
  181. package/extensions/services/proxy/agentcp/samples/qwen3_tools/create_profile.py +126 -0
  182. package/extensions/services/proxy/agentcp/samples/qwen3_tools/qwen3_tools.py +98 -0
  183. package/extensions/services/proxy/agentcp/samples/search/create_profile_qwen.py +125 -0
  184. package/extensions/services/proxy/agentcp/samples/search/create_profile_search.py +125 -0
  185. package/extensions/services/proxy/agentcp/samples/search/qwen_agent.py +136 -0
  186. package/extensions/services/proxy/agentcp/samples/search/search_agent.py +170 -0
  187. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/README.md +89 -0
  188. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/create_profile.py +125 -0
  189. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/main.py +44 -0
  190. package/extensions/services/proxy/agentcp/utils/__init__.py +15 -0
  191. package/extensions/services/proxy/agentcp/utils/file_util.py +117 -0
  192. package/extensions/services/proxy/agentcp/utils/proxy_bypass.py +99 -0
  193. package/extensions/services/proxy/agentcp/workflow.py +203 -0
  194. package/extensions/services/proxy/console_auth.py +109 -0
  195. package/extensions/services/proxy/evol/__init__.py +1 -0
  196. package/extensions/services/proxy/evol/config.py +37 -0
  197. package/extensions/services/proxy/evol/http/__init__.py +1 -0
  198. package/extensions/services/proxy/evol/http/async_http.py +551 -0
  199. package/extensions/services/proxy/evol/log.py +28 -0
  200. package/extensions/services/proxy/evol/presenter/__init__.py +2 -0
  201. package/extensions/services/proxy/evol/presenter/agentIdPresenter.py +1031 -0
  202. package/extensions/services/proxy/evol/presenter/apikeyPresenter.py +106 -0
  203. package/extensions/services/proxy/evol/presenter/configPresenter.py +1281 -0
  204. package/extensions/services/proxy/evol/presenter/userPresenter.py +477 -0
  205. package/extensions/services/proxy/evol/server/__init__.py +1 -0
  206. package/extensions/services/proxy/evol/server/claude_proxy_async.py +3430 -0
  207. package/extensions/services/proxy/evol/server/openclaw_proxy.py +1861 -0
  208. package/extensions/services/proxy/evol/server/proxy_config.py +15 -0
  209. package/extensions/services/proxy/evol/server/proxy_engine.py +501 -0
  210. package/extensions/services/proxy/evol/version.py +24 -0
  211. package/extensions/services/proxy/logs/websocket.log +260 -0
  212. package/extensions/services/proxy/main.py +240 -0
  213. package/extensions/services/proxy/requirements.txt +13 -0
  214. package/extensions/services/proxy/server.py +271 -0
  215. package/extensions/services/watchdog/entry.py +215 -26
  216. package/extensions/services/watchdog/module.md +1 -0
  217. package/extensions/services/watchdog/monitor.py +178 -38
  218. package/extensions/services/web/WEBSOCKET_STATUS.md +143 -0
  219. package/extensions/services/web/config_example.py +35 -0
  220. package/extensions/services/web/config_loader.py +110 -0
  221. package/extensions/services/web/entry.py +114 -26
  222. package/extensions/services/web/module.md +35 -24
  223. package/extensions/services/web/pairing.py +250 -0
  224. package/extensions/services/web/pairing_codes.jsonl +16 -0
  225. package/extensions/services/web/relay.py +643 -0
  226. package/extensions/services/web/relay_config.json5 +67 -0
  227. package/extensions/services/web/routes/routes_management_ws.py +127 -0
  228. package/extensions/services/web/routes/routes_rpc.py +89 -0
  229. package/extensions/services/web/routes/routes_test.py +61 -0
  230. package/extensions/services/web/routes/schemas.py +0 -22
  231. package/extensions/services/web/server.py +434 -99
  232. package/extensions/services/web/static/css/style.css +67 -28
  233. package/extensions/services/web/static/index.html +234 -44
  234. package/extensions/services/web/static/js/app.js +1335 -48
  235. package/extensions/services/web/static/js/kernel-client-example.js +161 -0
  236. package/extensions/services/web/static/js/kernel-client.js +383 -0
  237. package/extensions/services/web/static/js/registry-tests.js +558 -0
  238. package/extensions/services/web/static/js/token-manager.js +175 -0
  239. package/extensions/services/web/static/pairing.html +248 -0
  240. package/extensions/services/web/static/test_registry.html +262 -0
  241. package/extensions/services/web/web_config.json5 +29 -0
  242. package/kernel/entry.py +120 -32
  243. package/kernel/event_hub.py +141 -16
  244. package/kernel/module.md +60 -33
  245. package/kernel/registry_store.py +45 -36
  246. package/kernel/rpc_router.py +152 -59
  247. package/kernel/server.py +322 -26
  248. package/kite_cli/__init__.py +3 -0
  249. package/kite_cli/__main__.py +5 -0
  250. package/kite_cli/commands/__init__.py +1 -0
  251. package/kite_cli/commands/clean.py +101 -0
  252. package/kite_cli/commands/deps_install.py +67 -0
  253. package/kite_cli/commands/doctor.py +35 -0
  254. package/kite_cli/commands/env_check.py +45 -0
  255. package/kite_cli/commands/history.py +111 -0
  256. package/kite_cli/commands/info.py +96 -0
  257. package/kite_cli/commands/install.py +313 -0
  258. package/kite_cli/commands/list.py +143 -0
  259. package/kite_cli/commands/log.py +81 -0
  260. package/kite_cli/commands/prepare.py +49 -0
  261. package/kite_cli/commands/rollback.py +88 -0
  262. package/kite_cli/commands/search.py +73 -0
  263. package/kite_cli/commands/uninstall.py +85 -0
  264. package/kite_cli/commands/update.py +118 -0
  265. package/kite_cli/commands/venv_setup.py +56 -0
  266. package/kite_cli/core/__init__.py +1 -0
  267. package/kite_cli/core/checker.py +142 -0
  268. package/kite_cli/core/dependency.py +229 -0
  269. package/kite_cli/core/downloader.py +209 -0
  270. package/kite_cli/core/install_info.py +40 -0
  271. package/kite_cli/core/tool_installer.py +397 -0
  272. package/kite_cli/core/validator.py +78 -0
  273. package/kite_cli/main.py +317 -0
  274. package/kite_cli/utils/__init__.py +1 -0
  275. package/kite_cli/utils/i18n.py +252 -0
  276. package/kite_cli/utils/interactive.py +63 -0
  277. package/kite_cli/utils/operation_log.py +77 -0
  278. package/kite_cli/utils/paths.py +34 -0
  279. package/kite_cli/utils/version.py +308 -0
  280. package/launcher/entry.py +1124 -178
  281. package/launcher/logging_setup.py +104 -0
  282. package/launcher/module.md +46 -37
  283. package/launcher/module_scanner.py +11 -1
  284. package/main.py +4 -1
  285. package/package.json +9 -1
  286. package/python_version.json +4 -0
  287. package/requirements.txt +38 -0
  288. package/scripts/env-manager.js +328 -0
  289. package/scripts/plan_manager.py +315 -0
  290. package/scripts/python-env.js +79 -0
  291. package/scripts/scan_dependencies.py +461 -0
  292. package/scripts/setup-python-env.js +191 -0
  293. package/extensions/services/web/routes/routes_modules.py +0 -249
@@ -0,0 +1,456 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright 2025 AgentUnion Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ """
17
+ ConnectionManager - WebSocket 连接管理器
18
+
19
+ 提供 MessageClient 的生命周期管理,支持:
20
+ 1. 连接状态查询
21
+ 2. 主动销毁和重建连接
22
+ 3. 断开/恢复回调
23
+ 4. 连接健康监控
24
+
25
+ 每个 AgentID 对应一个 ConnectionManager,管理该 Agent 的所有 MessageClient。
26
+ """
27
+
28
+ import threading
29
+ import time
30
+ from typing import Dict, Optional, Callable, List
31
+ from dataclasses import dataclass, field
32
+ from enum import Enum
33
+
34
+ from agentcp.base.log import log_info, log_error, log_warning, log_debug
35
+ from agentcp.msg.message_client import MessageClient, MessageClientConfig, ConnectionState
36
+
37
+
38
+ class ConnectionEvent(Enum):
39
+ """连接事件类型"""
40
+ CONNECTED = "connected" # 连接建立
41
+ DISCONNECTED = "disconnected" # 连接断开
42
+ RECONNECTING = "reconnecting" # 正在重连
43
+ RECONNECTED = "reconnected" # 重连成功
44
+ DESTROYED = "destroyed" # 连接销毁
45
+ CREATED = "created" # 连接创建
46
+
47
+
48
+ @dataclass
49
+ class ConnectionInfo:
50
+ """连接信息"""
51
+ server_url: str
52
+ message_client: Optional[MessageClient] = None
53
+ created_at: float = 0.0
54
+ last_connected_at: float = 0.0
55
+ last_disconnected_at: float = 0.0
56
+ disconnect_count: int = 0
57
+ reconnect_count: int = 0
58
+ is_destroyed: bool = False
59
+
60
+
61
+ class ConnectionManager:
62
+ """WebSocket 连接管理器
63
+
64
+ 管理一个 AgentID 下的所有 MessageClient 连接。
65
+
66
+ 主要功能:
67
+ 1. 连接生命周期管理(创建、销毁、重建)
68
+ 2. 连接状态查询
69
+ 3. 事件回调(断开、恢复)
70
+ 4. 健康监控
71
+
72
+ 使用示例:
73
+ ```python
74
+ # 创建连接管理器
75
+ conn_mgr = ConnectionManager(agent_id, aid_path, seed_password)
76
+
77
+ # 设置回调
78
+ conn_mgr.set_event_callback(on_connection_event)
79
+
80
+ # 获取或创建连接
81
+ mc = conn_mgr.get_or_create_connection(server_url)
82
+
83
+ # 查询连接状态
84
+ if conn_mgr.is_healthy(server_url):
85
+ mc.send_msg(...)
86
+
87
+ # 销毁并重建连接
88
+ conn_mgr.rebuild_connection(server_url)
89
+
90
+ # 关闭所有连接
91
+ conn_mgr.destroy_all()
92
+ ```
93
+ """
94
+
95
+ def __init__(
96
+ self,
97
+ agent_id: str,
98
+ aid_path: str,
99
+ seed_password: str,
100
+ config: Optional[MessageClientConfig] = None
101
+ ):
102
+ """初始化连接管理器
103
+
104
+ Args:
105
+ agent_id: Agent ID
106
+ aid_path: AID 证书路径
107
+ seed_password: 种子密码
108
+ config: MessageClient 配置(可选,不传则使用默认配置)
109
+ """
110
+ self.agent_id = agent_id
111
+ self.aid_path = aid_path
112
+ self.seed_password = seed_password
113
+ self.config = config or MessageClientConfig()
114
+
115
+ # 连接映射:server_url -> ConnectionInfo
116
+ self._connections: Dict[str, ConnectionInfo] = {}
117
+ self._lock = threading.RLock()
118
+
119
+ # 事件回调
120
+ self._event_callback: Optional[Callable[[str, ConnectionEvent, dict], None]] = None
121
+
122
+ # 是否已关闭
123
+ self._shutdown = False
124
+
125
+ log_info(f"[ConnectionManager] 初始化: agent_id={agent_id}")
126
+
127
+ def set_event_callback(self, callback: Callable[[str, ConnectionEvent, dict], None]) -> None:
128
+ """设置连接事件回调
129
+
130
+ 回调函数签名: callback(server_url: str, event: ConnectionEvent, info: dict)
131
+
132
+ Args:
133
+ callback: 事件回调函数
134
+ """
135
+ self._event_callback = callback
136
+ log_info(f"[ConnectionManager] 已设置事件回调")
137
+
138
+ def _fire_event(self, server_url: str, event: ConnectionEvent, extra_info: dict = None) -> None:
139
+ """触发事件回调"""
140
+ if self._event_callback:
141
+ try:
142
+ info = extra_info or {}
143
+ info["agent_id"] = self.agent_id
144
+ info["server_url"] = server_url
145
+ info["timestamp"] = time.time()
146
+ self._event_callback(server_url, event, info)
147
+ except Exception as e:
148
+ log_error(f"[ConnectionManager] 事件回调异常: {e}")
149
+
150
+ def get_or_create_connection(
151
+ self,
152
+ server_url: str,
153
+ cache_auth_client=None,
154
+ message_handler=None
155
+ ) -> Optional[MessageClient]:
156
+ """获取或创建连接
157
+
158
+ 如果连接已存在且未销毁,返回现有连接。
159
+ 如果连接不存在或已销毁,创建新连接。
160
+
161
+ Args:
162
+ server_url: 消息服务器 URL
163
+ cache_auth_client: 缓存的认证客户端(可选)
164
+ message_handler: 消息处理器(可选)
165
+
166
+ Returns:
167
+ MessageClient 实例,失败返回 None
168
+ """
169
+ if self._shutdown:
170
+ log_warning(f"[ConnectionManager] 已关闭,无法创建连接")
171
+ return None
172
+
173
+ server_url = server_url.rstrip("/")
174
+
175
+ with self._lock:
176
+ conn_info = self._connections.get(server_url)
177
+
178
+ # 已存在且未销毁,复用
179
+ if conn_info and not conn_info.is_destroyed and conn_info.message_client:
180
+ log_debug(f"[ConnectionManager] 复用现有连接: {server_url}")
181
+ return conn_info.message_client
182
+
183
+ # 需要创建新连接
184
+ log_info(f"[ConnectionManager] 创建新连接: {server_url}")
185
+
186
+ try:
187
+ mc = MessageClient(
188
+ agent_id=self.agent_id,
189
+ server_url=server_url,
190
+ aid_path=self.aid_path,
191
+ seed_password=self.seed_password,
192
+ cache_auth_client=cache_auth_client,
193
+ config=self.config
194
+ )
195
+ mc.initialize()
196
+
197
+ if message_handler:
198
+ mc.set_message_handler(message_handler)
199
+
200
+ # 设置回调
201
+ mc.set_disconnect_callback(self._on_disconnect)
202
+ mc.set_reconnect_callback(self._on_reconnect)
203
+
204
+ # 记录连接信息
205
+ conn_info = ConnectionInfo(
206
+ server_url=server_url,
207
+ message_client=mc,
208
+ created_at=time.time(),
209
+ is_destroyed=False
210
+ )
211
+ self._connections[server_url] = conn_info
212
+
213
+ self._fire_event(server_url, ConnectionEvent.CREATED)
214
+ return mc
215
+
216
+ except Exception as e:
217
+ log_error(f"[ConnectionManager] 创建连接失败: {server_url}, error={e}")
218
+ return None
219
+
220
+ def get_connection(self, server_url: str) -> Optional[MessageClient]:
221
+ """获取现有连接(不创建)
222
+
223
+ Args:
224
+ server_url: 消息服务器 URL
225
+
226
+ Returns:
227
+ MessageClient 实例,不存在返回 None
228
+ """
229
+ server_url = server_url.rstrip("/")
230
+ with self._lock:
231
+ conn_info = self._connections.get(server_url)
232
+ if conn_info and not conn_info.is_destroyed:
233
+ return conn_info.message_client
234
+ return None
235
+
236
+ def is_healthy(self, server_url: str) -> bool:
237
+ """检查连接是否健康
238
+
239
+ Args:
240
+ server_url: 消息服务器 URL
241
+
242
+ Returns:
243
+ True: 连接健康可用
244
+ False: 连接不可用
245
+ """
246
+ mc = self.get_connection(server_url)
247
+ if mc:
248
+ return mc.is_healthy()
249
+ return False
250
+
251
+ def get_connection_info(self, server_url: str) -> Optional[dict]:
252
+ """获取连接详细信息
253
+
254
+ Args:
255
+ server_url: 消息服务器 URL
256
+
257
+ Returns:
258
+ 连接信息字典,不存在返回 None
259
+ """
260
+ server_url = server_url.rstrip("/")
261
+ with self._lock:
262
+ conn_info = self._connections.get(server_url)
263
+ if not conn_info:
264
+ return None
265
+
266
+ mc = conn_info.message_client
267
+ mc_info = mc.get_connection_info() if mc else {}
268
+
269
+ return {
270
+ "server_url": server_url,
271
+ "created_at": conn_info.created_at,
272
+ "last_connected_at": conn_info.last_connected_at,
273
+ "last_disconnected_at": conn_info.last_disconnected_at,
274
+ "disconnect_count": conn_info.disconnect_count,
275
+ "reconnect_count": conn_info.reconnect_count,
276
+ "is_destroyed": conn_info.is_destroyed,
277
+ **mc_info
278
+ }
279
+
280
+ def get_all_connections_info(self) -> List[dict]:
281
+ """获取所有连接的信息
282
+
283
+ Returns:
284
+ 连接信息列表
285
+ """
286
+ with self._lock:
287
+ result = []
288
+ for server_url in self._connections:
289
+ info = self.get_connection_info(server_url)
290
+ if info:
291
+ result.append(info)
292
+ return result
293
+
294
+ def get_health_summary(self) -> dict:
295
+ """获取健康状态摘要
296
+
297
+ Returns:
298
+ 健康状态摘要字典
299
+ """
300
+ with self._lock:
301
+ total = len(self._connections)
302
+ healthy = sum(1 for url in self._connections if self.is_healthy(url))
303
+ destroyed = sum(1 for info in self._connections.values() if info.is_destroyed)
304
+
305
+ return {
306
+ "agent_id": self.agent_id,
307
+ "total_connections": total,
308
+ "healthy_connections": healthy,
309
+ "unhealthy_connections": total - healthy - destroyed,
310
+ "destroyed_connections": destroyed,
311
+ "is_all_healthy": healthy == total and total > 0
312
+ }
313
+
314
+ def destroy_connection(self, server_url: str, wait: bool = True) -> bool:
315
+ """销毁指定连接
316
+
317
+ Args:
318
+ server_url: 消息服务器 URL
319
+ wait: 是否等待连接完全关闭
320
+
321
+ Returns:
322
+ True: 销毁成功
323
+ False: 连接不存在
324
+ """
325
+ server_url = server_url.rstrip("/")
326
+
327
+ with self._lock:
328
+ conn_info = self._connections.get(server_url)
329
+ if not conn_info:
330
+ log_warning(f"[ConnectionManager] 连接不存在: {server_url}")
331
+ return False
332
+
333
+ if conn_info.is_destroyed:
334
+ log_debug(f"[ConnectionManager] 连接已销毁: {server_url}")
335
+ return True
336
+
337
+ log_info(f"[ConnectionManager] 销毁连接: {server_url}")
338
+
339
+ mc = conn_info.message_client
340
+ if mc:
341
+ try:
342
+ mc.stop_websocket_client()
343
+ except Exception as e:
344
+ log_error(f"[ConnectionManager] 停止 WebSocket 异常: {e}")
345
+
346
+ conn_info.is_destroyed = True
347
+ conn_info.message_client = None
348
+
349
+ self._fire_event(server_url, ConnectionEvent.DESTROYED)
350
+ return True
351
+
352
+ def rebuild_connection(
353
+ self,
354
+ server_url: str,
355
+ cache_auth_client=None,
356
+ message_handler=None
357
+ ) -> Optional[MessageClient]:
358
+ """销毁并重建连接
359
+
360
+ Args:
361
+ server_url: 消息服务器 URL
362
+ cache_auth_client: 缓存的认证客户端(可选)
363
+ message_handler: 消息处理器(可选)
364
+
365
+ Returns:
366
+ 新的 MessageClient 实例,失败返回 None
367
+ """
368
+ log_info(f"[ConnectionManager] 重建连接: {server_url}")
369
+
370
+ # 先销毁
371
+ self.destroy_connection(server_url, wait=True)
372
+
373
+ # 短暂等待确保资源释放
374
+ time.sleep(0.3)
375
+
376
+ # 再创建
377
+ return self.get_or_create_connection(server_url, cache_auth_client, message_handler)
378
+
379
+ def destroy_all(self, wait: bool = True) -> None:
380
+ """销毁所有连接
381
+
382
+ Args:
383
+ wait: 是否等待所有连接完全关闭
384
+ """
385
+ log_info(f"[ConnectionManager] 销毁所有连接...")
386
+ self._shutdown = True
387
+
388
+ with self._lock:
389
+ for server_url in list(self._connections.keys()):
390
+ self.destroy_connection(server_url, wait=wait)
391
+
392
+ log_info(f"[ConnectionManager] 所有连接已销毁")
393
+
394
+ def force_reconnect(self, server_url: str) -> bool:
395
+ """强制触发重连
396
+
397
+ 不销毁连接,而是触发 MessageClient 的重连逻辑。
398
+
399
+ Args:
400
+ server_url: 消息服务器 URL
401
+
402
+ Returns:
403
+ True: 触发成功
404
+ False: 连接不存在
405
+ """
406
+ mc = self.get_connection(server_url)
407
+ if not mc:
408
+ return False
409
+
410
+ log_info(f"[ConnectionManager] 强制重连: {server_url}")
411
+
412
+ # 停止当前连接
413
+ mc.stop_websocket_client()
414
+
415
+ # 短暂等待
416
+ time.sleep(0.2)
417
+
418
+ # 重新启动
419
+ return mc.start_websocket_client()
420
+
421
+ def _on_disconnect(self, agent_id: str, server_url: str, code: int, reason: str) -> None:
422
+ """连接断开回调"""
423
+ server_url = server_url.rstrip("/")
424
+ log_warning(f"[ConnectionManager] 连接断开: {server_url}, code={code}, reason={reason}")
425
+
426
+ with self._lock:
427
+ conn_info = self._connections.get(server_url)
428
+ if conn_info:
429
+ conn_info.last_disconnected_at = time.time()
430
+ conn_info.disconnect_count += 1
431
+
432
+ self._fire_event(server_url, ConnectionEvent.DISCONNECTED, {
433
+ "code": code,
434
+ "reason": reason
435
+ })
436
+
437
+ def _on_reconnect(self, agent_id: str, server_url: str) -> None:
438
+ """连接恢复回调"""
439
+ server_url = server_url.rstrip("/")
440
+ log_info(f"[ConnectionManager] 连接恢复: {server_url}")
441
+
442
+ with self._lock:
443
+ conn_info = self._connections.get(server_url)
444
+ if conn_info:
445
+ conn_info.last_connected_at = time.time()
446
+ conn_info.reconnect_count += 1
447
+
448
+ self._fire_event(server_url, ConnectionEvent.RECONNECTED)
449
+
450
+ def __del__(self):
451
+ """析构时清理"""
452
+ try:
453
+ if not self._shutdown:
454
+ self.destroy_all(wait=False)
455
+ except Exception:
456
+ pass