@agentunion/kite 1.4.0 → 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 (235) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/cli.js +44 -5
  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/server.py +33 -17
  7. package/extensions/channels/acp_channel/server.py +33 -17
  8. package/extensions/services/backup/entry.py +23 -16
  9. package/extensions/services/evol/auth_manager.py +443 -0
  10. package/extensions/services/evol/config.yaml +149 -0
  11. package/extensions/services/evol/config_loader.py +117 -0
  12. package/extensions/services/evol/entry.py +406 -0
  13. package/extensions/services/evol/evol_api.py +173 -0
  14. package/extensions/services/evol/evol_config.json5 +29 -0
  15. package/extensions/services/evol/migrate_tokens.py +122 -0
  16. package/extensions/services/evol/module.md +32 -0
  17. package/extensions/services/evol/pairing.py +250 -0
  18. package/extensions/services/evol/pairing_codes.jsonl +1 -0
  19. package/extensions/services/evol/relay.py +682 -0
  20. package/extensions/services/evol/relay_config.json5 +67 -0
  21. package/extensions/services/evol/routes/__init__.py +1 -0
  22. package/extensions/services/evol/routes/routes_management_ws.py +127 -0
  23. package/extensions/services/evol/routes/routes_rpc.py +89 -0
  24. package/extensions/services/evol/routes/routes_test.py +61 -0
  25. package/extensions/services/evol/server.py +875 -0
  26. package/extensions/services/evol/static/css/style.css +1200 -0
  27. package/extensions/services/evol/static/index.html +781 -0
  28. package/extensions/services/evol/static/index_evol.html +14 -0
  29. package/extensions/services/evol/static/js/app.js +6304 -0
  30. package/extensions/services/evol/static/js/auth.js +326 -0
  31. package/extensions/services/evol/static/js/dialog.js +285 -0
  32. package/extensions/services/evol/static/js/evol-app-fixed.js +50 -0
  33. package/extensions/services/evol/static/js/evol-app.js +1949 -0
  34. package/extensions/services/evol/static/js/evol-app.js.bak +1800 -0
  35. package/extensions/services/evol/static/js/kernel-client-example.js +228 -0
  36. package/extensions/services/evol/static/js/kernel-client.js +396 -0
  37. package/extensions/services/evol/static/js/main.js +141 -0
  38. package/extensions/services/evol/static/js/registry-tests.js +585 -0
  39. package/extensions/services/evol/static/js/stats.js +217 -0
  40. package/extensions/services/evol/static/js/token-manager.js +175 -0
  41. package/extensions/services/evol/static/pairing.html +248 -0
  42. package/extensions/services/evol/static/test_registry.html +262 -0
  43. package/extensions/services/evol/static/test_relay.html +462 -0
  44. package/extensions/services/evol/stats_manager.py +240 -0
  45. package/extensions/services/model_service/entry.py +23 -1
  46. package/extensions/services/proxy/.claude/settings.local.json +13 -0
  47. package/extensions/services/proxy/CHANGELOG_20260308.md +258 -0
  48. package/extensions/services/proxy/_fix_prints.py +133 -0
  49. package/extensions/services/proxy/_fix_prints2.py +87 -0
  50. package/extensions/services/proxy/agentcp/LICENCE +178 -0
  51. package/extensions/services/proxy/agentcp/README copy.md +85 -0
  52. package/extensions/services/proxy/agentcp/README.md +260 -0
  53. package/extensions/services/proxy/agentcp/__init__.py +16 -0
  54. package/extensions/services/proxy/agentcp/agent.py +4 -0
  55. package/extensions/services/proxy/agentcp/agentcp.py +2494 -0
  56. package/extensions/services/proxy/agentcp/agentprofile.json +89 -0
  57. package/extensions/services/proxy/agentcp/ap/__init__.py +16 -0
  58. package/extensions/services/proxy/agentcp/ap/ap_client.py +316 -0
  59. package/extensions/services/proxy/agentcp/assets/images/wechat_qr.png +0 -0
  60. package/extensions/services/proxy/agentcp/backup/metrics.json +31 -0
  61. package/extensions/services/proxy/agentcp/base/__init__.py +20 -0
  62. package/extensions/services/proxy/agentcp/base/auth_client.py +257 -0
  63. package/extensions/services/proxy/agentcp/base/client.py +112 -0
  64. package/extensions/services/proxy/agentcp/base/env.py +34 -0
  65. package/extensions/services/proxy/agentcp/base/html_util.py +336 -0
  66. package/extensions/services/proxy/agentcp/base/log.py +98 -0
  67. package/extensions/services/proxy/agentcp/ca/__init__.py +17 -0
  68. package/extensions/services/proxy/agentcp/ca/ca_client.py +414 -0
  69. package/extensions/services/proxy/agentcp/ca/ca_root.py +74 -0
  70. package/extensions/services/proxy/agentcp/context/__init__.py +20 -0
  71. package/extensions/services/proxy/agentcp/context/context.py +73 -0
  72. package/extensions/services/proxy/agentcp/context/exceptions.py +114 -0
  73. package/extensions/services/proxy/agentcp/create_profile.py +125 -0
  74. package/extensions/services/proxy/agentcp/create_profile_weather.py +125 -0
  75. package/extensions/services/proxy/agentcp/db/__init__.py +15 -0
  76. package/extensions/services/proxy/agentcp/db/db_mananger.py +550 -0
  77. package/extensions/services/proxy/agentcp/docs/UDP_HEARTBEAT_FIX_REPORT.md +265 -0
  78. package/extensions/services/proxy/agentcp/docs/heartbeat_issue_analysis.md +291 -0
  79. package/extensions/services/proxy/agentcp/file/__init__.py +16 -0
  80. package/extensions/services/proxy/agentcp/file/file_client.py +141 -0
  81. package/extensions/services/proxy/agentcp/file/wss_binary_message.py +137 -0
  82. package/extensions/services/proxy/agentcp/hcp.py +299 -0
  83. package/extensions/services/proxy/agentcp/heartbeat/__init__.py +16 -0
  84. package/extensions/services/proxy/agentcp/heartbeat/heartbeat_client.py +360 -0
  85. package/extensions/services/proxy/agentcp/improved_scheduler.py +498 -0
  86. package/extensions/services/proxy/agentcp/llm_agent_utils.py +249 -0
  87. package/extensions/services/proxy/agentcp/llm_server.py +172 -0
  88. package/extensions/services/proxy/agentcp/mermaid.py +210 -0
  89. package/extensions/services/proxy/agentcp/message.py +149 -0
  90. package/extensions/services/proxy/agentcp/metrics.py +256 -0
  91. package/extensions/services/proxy/agentcp/monitoring/__init__.py +20 -0
  92. package/extensions/services/proxy/agentcp/monitoring/global_monitor.py +27 -0
  93. package/extensions/services/proxy/agentcp/monitoring/metrics_store.py +325 -0
  94. package/extensions/services/proxy/agentcp/monitoring/monitoring_service.py +269 -0
  95. package/extensions/services/proxy/agentcp/monitoring/sliding_window.py +222 -0
  96. package/extensions/services/proxy/agentcp/monitoring/standalone_reader.py +224 -0
  97. package/extensions/services/proxy/agentcp/msg/__init__.py +21 -0
  98. package/extensions/services/proxy/agentcp/msg/connection_manager.py +456 -0
  99. package/extensions/services/proxy/agentcp/msg/message_client.py +2058 -0
  100. package/extensions/services/proxy/agentcp/msg/message_serialize.py +263 -0
  101. package/extensions/services/proxy/agentcp/msg/open_ai_message.py +88 -0
  102. package/extensions/services/proxy/agentcp/msg/session_manager.py +1062 -0
  103. package/extensions/services/proxy/agentcp/msg/stream_client.py +267 -0
  104. package/extensions/services/proxy/agentcp/msg/websocket_file_receiver.py +89 -0
  105. package/extensions/services/proxy/agentcp/msg/ws_logger.py +685 -0
  106. package/extensions/services/proxy/agentcp/msg/wss_binary_message.py +137 -0
  107. package/extensions/services/proxy/agentcp/requirements.txt +7 -0
  108. package/extensions/services/proxy/agentcp/samples/agent_graph/README.md +37 -0
  109. package/extensions/services/proxy/agentcp/samples/agent_graph/agentprofile.json +89 -0
  110. package/extensions/services/proxy/agentcp/samples/agent_graph/create_profile.py +138 -0
  111. package/extensions/services/proxy/agentcp/samples/agent_graph/main.py +164 -0
  112. package/extensions/services/proxy/agentcp/samples/agent_use/create_profile.py +123 -0
  113. package/extensions/services/proxy/agentcp/samples/agent_use/llm/create_profile.py +129 -0
  114. package/extensions/services/proxy/agentcp/samples/agent_use/llm/env.json +5 -0
  115. package/extensions/services/proxy/agentcp/samples/agent_use/llm/main.py +146 -0
  116. package/extensions/services/proxy/agentcp/samples/agent_use/main.py +123 -0
  117. package/extensions/services/proxy/agentcp/samples/agent_use/readme.md +379 -0
  118. package/extensions/services/proxy/agentcp/samples/agent_use/search/create_profile.py +129 -0
  119. package/extensions/services/proxy/agentcp/samples/agent_use/search/main.py +28 -0
  120. package/extensions/services/proxy/agentcp/samples/agent_use/tool/create_profile.py +129 -0
  121. package/extensions/services/proxy/agentcp/samples/agent_use/tool/main.py +20 -0
  122. package/extensions/services/proxy/agentcp/samples/ali_amap/README.md +97 -0
  123. package/extensions/services/proxy/agentcp/samples/ali_amap/amap_agent.py +88 -0
  124. package/extensions/services/proxy/agentcp/samples/ali_amap/create_profile.py +125 -0
  125. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/powershell.py +228 -0
  126. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/software.py +63 -0
  127. package/extensions/services/proxy/agentcp/samples/compute_agent/agent/tools.py +36 -0
  128. package/extensions/services/proxy/agentcp/samples/compute_agent/browser_user.py +41 -0
  129. package/extensions/services/proxy/agentcp/samples/deepseek/README.md +79 -0
  130. package/extensions/services/proxy/agentcp/samples/deepseek/create_profile.py +126 -0
  131. package/extensions/services/proxy/agentcp/samples/deepseek/deepseek.py +42 -0
  132. package/extensions/services/proxy/agentcp/samples/dify_chat/README.md +78 -0
  133. package/extensions/services/proxy/agentcp/samples/dify_chat/create_profile.py +126 -0
  134. package/extensions/services/proxy/agentcp/samples/dify_chat/dify_chat.py +47 -0
  135. package/extensions/services/proxy/agentcp/samples/dify_workflow/README.md +78 -0
  136. package/extensions/services/proxy/agentcp/samples/dify_workflow/create_profile.py +126 -0
  137. package/extensions/services/proxy/agentcp/samples/dify_workflow/dify_workflow.py +46 -0
  138. package/extensions/services/proxy/agentcp/samples/executor/README.md +44 -0
  139. package/extensions/services/proxy/agentcp/samples/executor/agentprofile.json +89 -0
  140. package/extensions/services/proxy/agentcp/samples/executor/create_profile.py +139 -0
  141. package/extensions/services/proxy/agentcp/samples/executor/main.py +160 -0
  142. package/extensions/services/proxy/agentcp/samples/filereader/README.md +45 -0
  143. package/extensions/services/proxy/agentcp/samples/filereader/agentprofile.json +90 -0
  144. package/extensions/services/proxy/agentcp/samples/filereader/create_profile.py +137 -0
  145. package/extensions/services/proxy/agentcp/samples/filereader/main.py +253 -0
  146. package/extensions/services/proxy/agentcp/samples/filewriter/README.md +38 -0
  147. package/extensions/services/proxy/agentcp/samples/filewriter/agentprofile.json +91 -0
  148. package/extensions/services/proxy/agentcp/samples/filewriter/create_profile.py +138 -0
  149. package/extensions/services/proxy/agentcp/samples/filewriter/main.py +289 -0
  150. package/extensions/services/proxy/agentcp/samples/hcp/README.md +85 -0
  151. package/extensions/services/proxy/agentcp/samples/hcp/acp_weather_agent.zip +0 -0
  152. package/extensions/services/proxy/agentcp/samples/hcp/create_profile.py +125 -0
  153. package/extensions/services/proxy/agentcp/samples/hcp/hcp.py +237 -0
  154. package/extensions/services/proxy/agentcp/samples/helloworld/README.md +68 -0
  155. package/extensions/services/proxy/agentcp/samples/helloworld/hello_world.py +40 -0
  156. package/extensions/services/proxy/agentcp/samples/llm_agent/MEADME.md +117 -0
  157. package/extensions/services/proxy/agentcp/samples/llm_agent/create_profile.py +125 -0
  158. package/extensions/services/proxy/agentcp/samples/llm_agent/qwen_agent.py +136 -0
  159. package/extensions/services/proxy/agentcp/samples/local_llm_agent/README.md +90 -0
  160. package/extensions/services/proxy/agentcp/samples/local_llm_agent/create_profile.py +125 -0
  161. package/extensions/services/proxy/agentcp/samples/local_llm_agent/main.py +49 -0
  162. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/README.md +55 -0
  163. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/create_profile.py +125 -0
  164. package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/main.py +23 -0
  165. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/README.md +103 -0
  166. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/create_profile.py +125 -0
  167. package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/main.py +69 -0
  168. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/README.md +58 -0
  169. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/create_profile.py +125 -0
  170. package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/main.py +25 -0
  171. package/extensions/services/proxy/agentcp/samples/qwen3/README.md +71 -0
  172. package/extensions/services/proxy/agentcp/samples/qwen3/create_profile.py +126 -0
  173. package/extensions/services/proxy/agentcp/samples/qwen3/qwen3.py +37 -0
  174. package/extensions/services/proxy/agentcp/samples/qwen3_tools/README.md +133 -0
  175. package/extensions/services/proxy/agentcp/samples/qwen3_tools/create_profile.py +126 -0
  176. package/extensions/services/proxy/agentcp/samples/qwen3_tools/qwen3_tools.py +98 -0
  177. package/extensions/services/proxy/agentcp/samples/search/create_profile_qwen.py +125 -0
  178. package/extensions/services/proxy/agentcp/samples/search/create_profile_search.py +125 -0
  179. package/extensions/services/proxy/agentcp/samples/search/qwen_agent.py +136 -0
  180. package/extensions/services/proxy/agentcp/samples/search/search_agent.py +170 -0
  181. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/README.md +89 -0
  182. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/create_profile.py +125 -0
  183. package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/main.py +44 -0
  184. package/extensions/services/proxy/agentcp/utils/__init__.py +15 -0
  185. package/extensions/services/proxy/agentcp/utils/file_util.py +117 -0
  186. package/extensions/services/proxy/agentcp/utils/proxy_bypass.py +99 -0
  187. package/extensions/services/proxy/agentcp/workflow.py +203 -0
  188. package/extensions/services/proxy/console_auth.py +109 -0
  189. package/extensions/services/proxy/evol/__init__.py +1 -0
  190. package/extensions/services/proxy/evol/config.py +37 -0
  191. package/extensions/services/proxy/evol/http/__init__.py +1 -0
  192. package/extensions/services/proxy/evol/http/async_http.py +551 -0
  193. package/extensions/services/proxy/evol/log.py +28 -0
  194. package/extensions/services/proxy/evol/presenter/__init__.py +2 -0
  195. package/extensions/services/proxy/evol/presenter/agentIdPresenter.py +1031 -0
  196. package/extensions/services/proxy/evol/presenter/apikeyPresenter.py +106 -0
  197. package/extensions/services/proxy/evol/presenter/configPresenter.py +1281 -0
  198. package/extensions/services/proxy/evol/presenter/userPresenter.py +477 -0
  199. package/extensions/services/proxy/evol/server/__init__.py +1 -0
  200. package/extensions/services/proxy/evol/server/claude_proxy_async.py +3430 -0
  201. package/extensions/services/proxy/evol/server/openclaw_proxy.py +1861 -0
  202. package/extensions/services/proxy/evol/server/proxy_config.py +15 -0
  203. package/extensions/services/proxy/evol/server/proxy_engine.py +501 -0
  204. package/extensions/services/proxy/evol/version.py +24 -0
  205. package/extensions/services/proxy/logs/websocket.log +260 -0
  206. package/extensions/services/proxy/main.py +240 -0
  207. package/extensions/services/proxy/requirements.txt +13 -0
  208. package/extensions/services/proxy/server.py +271 -0
  209. package/extensions/services/watchdog/entry.py +42 -16
  210. package/extensions/services/watchdog/module.md +1 -0
  211. package/extensions/services/watchdog/monitor.py +34 -4
  212. package/extensions/services/web/module.md +1 -1
  213. package/extensions/services/web/server.py +30 -18
  214. package/extensions/services/web/static/js/token-manager.js +10 -10
  215. package/kernel/entry.py +1 -1
  216. package/kernel/module.md +25 -1
  217. package/kernel/registry_store.py +2 -26
  218. package/kernel/rpc_router.py +36 -10
  219. package/kernel/server.py +106 -17
  220. package/kite_cli/commands/deps_install.py +67 -0
  221. package/kite_cli/commands/env_check.py +45 -0
  222. package/kite_cli/commands/prepare.py +49 -0
  223. package/kite_cli/commands/venv_setup.py +56 -0
  224. package/kite_cli/main.py +29 -1
  225. package/launcher/entry.py +306 -21
  226. package/launcher/module.md +9 -0
  227. package/launcher/module_scanner.py +11 -1
  228. package/main.py +4 -1
  229. package/package.json +8 -1
  230. package/python_version.json +4 -0
  231. package/requirements.txt +38 -0
  232. package/scripts/env-manager.js +328 -0
  233. package/scripts/python-env.js +79 -0
  234. package/scripts/scan_dependencies.py +461 -0
  235. package/scripts/setup-python-env.js +191 -0
@@ -485,7 +485,7 @@ async def _ws_connect(token: str, kernel_port: int, _t0: float):
485
485
  ws_url = f"ws://127.0.0.1:{kernel_port}/ws?token={token}&id=model_service"
486
486
  print(f"[model_service] Connecting to Kernel: {ws_url}")
487
487
 
488
- async with websockets.connect(ws_url, open_timeout=5, ping_interval=20, ping_timeout=20, close_timeout=10) as ws:
488
+ async with websockets.connect(ws_url, open_timeout=5, ping_interval=None, close_timeout=10) as ws:
489
489
  _ws_global = ws
490
490
  print(f"[model_service] Connected to Kernel ({_fmt_elapsed(_t0)})")
491
491
 
@@ -518,12 +518,14 @@ async def _ws_connect(token: str, kernel_port: int, _t0: float):
518
518
 
519
519
  # Publish module.ready (every reconnect)
520
520
  if not _shutting_down:
521
+ startup_time = time.monotonic() - _t0
521
522
  await _rpc_call(ws, "event.publish", {
522
523
  "event_id": str(uuid.uuid4()),
523
524
  "event": "module.ready",
524
525
  "data": {
525
526
  "module_id": "model_service",
526
527
  "graceful_shutdown": True,
528
+ "startup_time": startup_time,
527
529
  },
528
530
  })
529
531
  print(f"[model_service] module.ready published ({_fmt_elapsed(_t0)})")
@@ -575,12 +577,32 @@ async def _publish_event(ws, event: dict):
575
577
  })
576
578
 
577
579
 
580
+ async def _handle_ping_event(data: dict):
581
+ """Handle system.ping event and reply with system.pong."""
582
+ t1 = data.get("ping_time")
583
+ t2 = time.time()
584
+
585
+ await _publish_event(_ws_global, {
586
+ "event": "system.pong",
587
+ "data": {
588
+ "module_id": MODULE_NAME,
589
+ "ping_time": t1,
590
+ "pong_time": t2,
591
+ },
592
+ })
593
+
594
+
578
595
  async def _handle_event_notification(msg: dict):
579
596
  """Handle an event notification (JSON-RPC 2.0 Notification with method='event')."""
580
597
  params = msg.get("params", {})
581
598
  event_type = params.get("event", "")
582
599
  data = params.get("data", {})
583
600
 
601
+ # Handle system.ping event
602
+ if event_type == "system.ping":
603
+ await _handle_ping_event(data)
604
+ return
605
+
584
606
  # Special handling for module.shutdown
585
607
  if event_type == "module.shutdown":
586
608
  target = data.get("module_id", "")
@@ -0,0 +1,13 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(echo agentcp not found directly:*)",
5
+ "Bash(grep:*)",
6
+ "Bash(head:*)",
7
+ "Bash(find H:\\\\project\\\\evol_main\\\\evol-electron-app\\\\python_sample_backend:*)",
8
+ "Bash(python3:*)",
9
+ "Bash(python:*)",
10
+ "Bash(cd H:\\\\project\\\\evol_main\\\\evol-electron-app\\\\python_sample_backend:*)"
11
+ ]
12
+ }
13
+ }
@@ -0,0 +1,258 @@
1
+ # Evol Proxy 服务修改说明
2
+
3
+ ## 修改日期
4
+ 2026-03-08
5
+
6
+ ## 修改内容
7
+
8
+ ### 1. 端口改为系统自动分配
9
+
10
+ **修改文件:**
11
+ - `main.py`
12
+ - `server.py`
13
+
14
+ **改动说明:**
15
+
16
+ 原来使用固定端口 12655,容易导致端口冲突。现在改为:
17
+ - 使用 `port=0` 让系统自动分配可用端口
18
+ - 在启动前先获取一个可用端口
19
+ - 启动后显示实际使用的端口号
20
+
21
+ **实现方式:**
22
+
23
+ ```python
24
+ # 获取系统分配的可用端口
25
+ import socket
26
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
27
+ sock.bind(('', 0))
28
+ actual_port = sock.getsockname()[1]
29
+ sock.close()
30
+
31
+ # 使用该端口启动服务器
32
+ await run_server(port=actual_port)
33
+ ```
34
+
35
+ ### 2. 登录后自动拉取模型列表和用户信息
36
+
37
+ **修改文件:**
38
+ - `main.py`
39
+
40
+ **新增功能:**
41
+
42
+ 在 AID 上线成功后,自动执行以下操作:
43
+
44
+ 1. **拉取模型列表**
45
+ - 调用 `get_models_list()` 获取可用模型
46
+ - 显示模型数量和前 5 个模型名称
47
+ - 示例输出:
48
+ ```
49
+ [Models] Found 15 available models:
50
+ - gpt-4
51
+ - gpt-3.5-turbo
52
+ - claude-3-opus
53
+ - claude-3-sonnet
54
+ - gemini-pro
55
+ ... and 10 more
56
+ ```
57
+
58
+ 2. **获取用户信息**
59
+ - 调用 `userPresenter.get_user_info()` 获取用户信息
60
+ - 显示手机号和用户 ID
61
+ - 示例输出:
62
+ ```
63
+ [User] Logged in as: 138****1234
64
+ [User] User ID: user_abc123
65
+ ```
66
+
67
+ **代码位置:**
68
+
69
+ 在 `async_main()` 函数中,Step 3.6 部分:
70
+
71
+ ```python
72
+ # Step 3.6: 拉取模型列表和用户信息
73
+ print("\n[Info] Fetching models and user info...")
74
+ try:
75
+ # 拉取模型列表
76
+ from evol.server.openclaw_proxy import get_models_list
77
+ models_data = get_models_list()
78
+ model_count = len(models_data.get("data", []))
79
+ print(f"[Models] Found {model_count} available models:")
80
+ for model in models_data.get("data", [])[:5]:
81
+ print(f" - {model.get('id', 'unknown')}")
82
+ if model_count > 5:
83
+ print(f" ... and {model_count - 5} more")
84
+
85
+ # 获取用户信息
86
+ from evol.presenter.userPresenter import userPresenter
87
+ user_info = userPresenter.get_user_info()
88
+ if user_info:
89
+ print(f"[User] Logged in as: {user_info.get('phone', 'unknown')}")
90
+ print(f"[User] User ID: {user_info.get('id', 'unknown')}")
91
+
92
+ except Exception as e:
93
+ print(f"[Info] Warning: 获取信息失败: {e}")
94
+ ```
95
+
96
+ ## 启动流程变化
97
+
98
+ ### 修改前
99
+
100
+ ```
101
+ 1. 初始化配置目录
102
+ 2. 检查本地 token
103
+ 3. 若无有效 token → 控制台登录
104
+ 4. 同步用户信息 & AID 上线
105
+ 5. 获取 Evol 本地密钥
106
+ 6. 启动 FastAPI 服务器(固定端口 12655)
107
+ ```
108
+
109
+ ### 修改后
110
+
111
+ ```
112
+ 1. 初始化配置目录
113
+ 2. 检查本地 token
114
+ 3. 若无有效 token → 控制台登录
115
+ 4. 同步用户信息 & AID 上线
116
+ 5. 获取 Evol 本地密钥
117
+ 6. 拉取模型列表和用户信息 ← 新增
118
+ 7. 启动 FastAPI 服务器(系统自动分配端口)← 修改
119
+ ```
120
+
121
+ ## 输出示例
122
+
123
+ ### 修改前
124
+
125
+ ```
126
+ ============================================================
127
+ Evol Sample Backend
128
+ Port: 12655
129
+ ============================================================
130
+
131
+ [Init] Config dir: C:\Users\xxx\.evol
132
+ [Auth] Token valid, skip login
133
+ [AID] Starting AID login...
134
+ Evol: aid_xxx is online
135
+ [Key] Evol API Key: evol-xxx
136
+
137
+ [Server] Starting on port 12655...
138
+ [Server] ANTHROPIC_BASE_URL = http://127.0.0.1:12655/claude-proxy
139
+ [Server] OPENAI_BASE_URL = http://127.0.0.1:12655/openclaw-proxy/v1
140
+ [Server] Health check = http://127.0.0.1:12655/health
141
+ [Server] Evol API Key = evol-xxx
142
+
143
+ Press Ctrl+C to stop.
144
+ ```
145
+
146
+ ### 修改后
147
+
148
+ ```
149
+ ============================================================
150
+ Evol Sample Backend
151
+ Port: Auto-assigned by system
152
+ ============================================================
153
+
154
+ [Init] Config dir: C:\Users\xxx\.evol
155
+ [Auth] Token valid, skip login
156
+ [AID] Starting AID login...
157
+ Evol: aid_xxx is online
158
+ [Key] Evol API Key: evol-xxx
159
+
160
+ [Info] Fetching models and user info...
161
+ [Models] Found 15 available models:
162
+ - gpt-4
163
+ - gpt-3.5-turbo
164
+ - claude-3-opus
165
+ - claude-3-sonnet
166
+ - gemini-pro
167
+ ... and 10 more
168
+ [User] Logged in as: 138****1234
169
+ [User] User ID: user_abc123
170
+
171
+ [Server] Starting server...
172
+
173
+ [Server] Server will start on port 54321
174
+ [Server] ANTHROPIC_BASE_URL = http://127.0.0.1:54321/claude-proxy
175
+ [Server] OPENAI_BASE_URL = http://127.0.0.1:54321/openclaw-proxy/v1
176
+ [Server] Health check = http://127.0.0.1:54321/health
177
+ [Server] Evol API Key = evol-xxx
178
+
179
+ Press Ctrl+C to stop.
180
+ ```
181
+
182
+ ## 优点
183
+
184
+ ### 1. 端口自动分配
185
+
186
+ - **避免端口冲突** - 不会与其他服务冲突
187
+ - **支持多实例** - 可以同时运行多个代理服务
188
+ - **更灵活** - 适应不同的部署环境
189
+
190
+ ### 2. 自动拉取信息
191
+
192
+ - **验证登录状态** - 确认模型列表可以正常获取
193
+ - **显示可用模型** - 用户一目了然有哪些模型可用
194
+ - **确认用户身份** - 显示当前登录的用户信息
195
+ - **便于调试** - 启动时就能发现配置问题
196
+
197
+ ## 注意事项
198
+
199
+ 1. **端口号变化** - 每次启动端口可能不同,需要从启动日志中获取
200
+ 2. **防火墙规则** - 如果需要外部访问,需要动态配置防火墙
201
+ 3. **错误处理** - 如果拉取模型列表失败,只会显示警告,不会中断启动
202
+
203
+ ## 测试建议
204
+
205
+ 1. **基本功能测试**
206
+ ```bash
207
+ # 启动服务
208
+ python main.py
209
+
210
+ # 查看启动日志,获取实际端口(假设是 54321)
211
+ # 测试健康检查
212
+ curl http://127.0.0.1:54321/health
213
+
214
+ # 测试模型列表
215
+ curl http://127.0.0.1:54321/openclaw-proxy/v1/models \
216
+ -H "Authorization: Bearer evol-xxx"
217
+ ```
218
+
219
+ 2. **多实例测试**
220
+ ```bash
221
+ # 同时启动多个实例,验证端口不冲突
222
+ python main.py &
223
+ python main.py &
224
+ ```
225
+
226
+ 3. **端口冲突测试**
227
+ ```bash
228
+ # 验证不会出现端口占用错误
229
+ # 之前固定端口时可能出现的问题现在应该不会发生
230
+ ```
231
+
232
+ ## 回滚方案
233
+
234
+ 如果需要回滚到固定端口模式,修改 `main.py`:
235
+
236
+ ```python
237
+ # 改回固定端口
238
+ PORT = 12655 # 或其他固定端口
239
+
240
+ # 恢复端口清理逻辑
241
+ kill_port(PORT)
242
+
243
+ # 直接使用固定端口启动
244
+ await run_server(port=PORT)
245
+ ```
246
+
247
+ ## 相关文件
248
+
249
+ - `main.py` - 主程序入口
250
+ - `server.py` - FastAPI 服务器
251
+ - `console_auth.py` - 控制台认证
252
+ - `evol/server/openclaw_proxy.py` - OpenClaw 代理实现
253
+ - `evol/presenter/userPresenter.py` - 用户信息管理
254
+
255
+ ---
256
+
257
+ **修改者:** Claude (Kite Assistant)
258
+ **审核者:** 待审核
@@ -0,0 +1,133 @@
1
+ """
2
+ Temporary script to replace print() with logger calls in openclaw_proxy.py and claude_proxy_async.py.
3
+ Delete this file after running.
4
+ """
5
+ import re
6
+ import sys
7
+
8
+ def classify_message(msg_text):
9
+ """Classify a print message into logger level based on content."""
10
+ error_keywords = ['❌', '失败', '异常', 'error', 'Error', '严重错误', '错误']
11
+ warning_keywords = ['⚠️', '警告']
12
+ info_keywords = ['成功', '已初始化', '已启动', '已停止', '已注册', '已禁用', '已清理',
13
+ '刷新完成', '加载成功', '上线', '完成']
14
+
15
+ for kw in error_keywords:
16
+ if kw in msg_text:
17
+ return 'error'
18
+ for kw in warning_keywords:
19
+ if kw in msg_text:
20
+ return 'warning'
21
+ for kw in info_keywords:
22
+ if kw in msg_text:
23
+ return 'info'
24
+ return 'debug'
25
+
26
+
27
+ def remove_emojis(text):
28
+ """Remove common emoji characters from text."""
29
+ emojis = ['🧹', '🚀', '🛑', '✅', '❌', '⚠️', '✓', '🔧']
30
+ for e in emojis:
31
+ text = text.replace(e, '')
32
+ # Clean up extra spaces left by emoji removal
33
+ text = re.sub(r' +', ' ', text)
34
+ return text
35
+
36
+
37
+ def process_file(filepath):
38
+ with open(filepath, 'r', encoding='utf-8') as f:
39
+ content = f.read()
40
+
41
+ lines = content.split('\n')
42
+ new_lines = []
43
+ i = 0
44
+ replacements = 0
45
+
46
+ while i < len(lines):
47
+ line = lines[i]
48
+ stripped = line.lstrip()
49
+ indent = line[:len(line) - len(stripped)]
50
+
51
+ # Handle traceback.print_exc()
52
+ if 'traceback.print_exc()' in stripped and stripped.strip() == 'traceback.print_exc()':
53
+ new_lines.append(f'{indent}logger.debug(traceback.format_exc())')
54
+ replacements += 1
55
+ i += 1
56
+ continue
57
+
58
+ # Skip non-print lines
59
+ if not stripped.startswith('print(') and not stripped.startswith('print ('):
60
+ new_lines.append(line)
61
+ i += 1
62
+ continue
63
+
64
+ # Gather the full print statement (may span multiple lines)
65
+ full_print = line
66
+ # Count open/close parens to handle multi-line prints
67
+ open_count = full_print.count('(') - full_print.count(')')
68
+ while open_count > 0 and i + 1 < len(lines):
69
+ i += 1
70
+ full_print += '\n' + lines[i]
71
+ open_count = full_print.count('(') - full_print.count(')')
72
+
73
+ # Extract the content inside print(...)
74
+ # Find the print( and matching )
75
+ full_stripped = full_print.lstrip()
76
+
77
+ # Match print(...) - extract inner content
78
+ # Simple approach: replace 'print(' with 'logger.X(' and keep everything else
79
+
80
+ # Determine the level based on content
81
+ level = classify_message(full_stripped)
82
+
83
+ # Clean emojis from the content
84
+ cleaned = remove_emojis(full_print)
85
+ cleaned_stripped = cleaned.lstrip()
86
+
87
+ # Handle special case: print("\n" + "=" * 80) and print("=" * 80 + "\n")
88
+ # These are separator lines - skip them entirely
89
+ if re.match(r'print\(\s*"\\n"\s*\+\s*"="\s*\*\s*\d+\s*\)', cleaned_stripped):
90
+ replacements += 1
91
+ i += 1
92
+ continue
93
+ if re.match(r'print\(\s*"="\s*\*\s*\d+\s*\+\s*"\\n"\s*\)', cleaned_stripped):
94
+ replacements += 1
95
+ i += 1
96
+ continue
97
+ if re.match(r'print\(\s*"="\s*\*\s*\d+\s*\)', cleaned_stripped):
98
+ replacements += 1
99
+ i += 1
100
+ continue
101
+
102
+ # Replace print( with logger.level(
103
+ # Handle the indentation properly for multi-line
104
+ cleaned_lines = cleaned.split('\n')
105
+ first_line = cleaned_lines[0]
106
+ first_stripped = first_line.lstrip()
107
+ first_indent = first_line[:len(first_line) - len(first_stripped)]
108
+
109
+ # Replace print( with logger.level(
110
+ new_first = re.sub(r'^print\s*\(', f'logger.{level}(', first_stripped)
111
+ cleaned_lines[0] = first_indent + new_first
112
+
113
+ for cl in cleaned_lines:
114
+ new_lines.append(cl)
115
+
116
+ replacements += 1
117
+ i += 1
118
+ continue
119
+
120
+ result = '\n'.join(new_lines)
121
+
122
+ with open(filepath, 'w', encoding='utf-8') as f:
123
+ f.write(result)
124
+
125
+ return replacements
126
+
127
+
128
+ # Process both files
129
+ r1 = process_file('evol/server/openclaw_proxy.py')
130
+ print(f"openclaw_proxy.py: {r1} replacements made")
131
+
132
+ r2 = process_file('evol/server/claude_proxy_async.py')
133
+ print(f"claude_proxy_async.py: {r2} replacements made")
@@ -0,0 +1,87 @@
1
+ """
2
+ Fix indentation issues caused by the previous script's emoji removal.
3
+ The problem: removing multi-byte emoji chars from lines messes up indentation
4
+ when the emoji is at the start of a string, not in the indentation itself.
5
+
6
+ Actually, the real issue is simpler: the 'remove_emojis' function was applied to
7
+ the ENTIRE line including indentation whitespace, and the `re.sub(r' +', ' ', text)`
8
+ collapsed double spaces in the indentation.
9
+
10
+ This script fixes the indentation by re-reading the current (broken) files and
11
+ fixing any lines where logger.X( has wrong indentation.
12
+ """
13
+ import re
14
+
15
+ def fix_indentation(filepath):
16
+ """
17
+ The previous script broke indentation because:
18
+ 1. Emojis in Chinese text like '✅' '❌' were removed
19
+ 2. The cleanup regex `re.sub(r' +', ' ', text)` collapsed ALL multi-spaces,
20
+ including indentation whitespace
21
+
22
+ Strategy: We can't easily reverse this. Instead, let's look at each logger.X()
23
+ line and infer the correct indentation from its surrounding context.
24
+ """
25
+ with open(filepath, 'r', encoding='utf-8') as f:
26
+ lines = f.readlines()
27
+
28
+ fixed = 0
29
+ new_lines = []
30
+
31
+ for i, line in enumerate(lines):
32
+ stripped = line.lstrip()
33
+ current_indent = len(line) - len(line.lstrip())
34
+
35
+ # Check if this is a logger line with potentially wrong indentation
36
+ if stripped.startswith('logger.'):
37
+ # Look at the previous non-empty line to determine expected indentation
38
+ expected_indent = None
39
+ for j in range(i - 1, max(0, i - 5), -1):
40
+ prev = lines[j]
41
+ prev_stripped = prev.lstrip()
42
+ if not prev_stripped or prev_stripped.startswith('#'):
43
+ continue
44
+ prev_indent = len(prev) - len(prev.lstrip())
45
+
46
+ # If previous line ends with ':', this line should be indented more
47
+ if prev_stripped.rstrip().endswith(':'):
48
+ expected_indent = prev_indent + 4
49
+ # If previous line is at same block level
50
+ elif prev_stripped.startswith(('logger.', 'log_info', 'log_error',
51
+ 'return', 'if ', 'elif ', 'else:', 'try:', 'except', 'finally:',
52
+ 'for ', 'while ', 'async ', 'await ', 'with ', 'raise',
53
+ 'self.', 'del ', 'pass', 'break', 'continue',
54
+ 'result', 'response', 'session', 'error', 'cleanup',
55
+ 'old_', 'new_', 'first_', 'aid_', 'evol_', 'agentcp_',
56
+ 'remaining', 'time_since', 'current_', 'message', 'proxy_',
57
+ 'trace_id', 'model', 'request', 'body', 'api_', 'user_',
58
+ 'is_', 'async_session', 'openclaw', 'shared_', '_register',
59
+ 'full_rebuild', 'rebuild_thread', 'login_result',
60
+ 'fetch_result', 'balance', 'credits', 'users_count',
61
+ 'inner_data', 'data', 'api_key', 'cached_key', 'success',
62
+ 'stale_trace', 'age_', 'content', 'stream_url', 'openai_',
63
+ 'response_body', 'http_status', 'error_message',
64
+ 'global ', 'import ', '_rebuild', '_last_full', '_agentcp')):
65
+ expected_indent = prev_indent
66
+ else:
67
+ expected_indent = prev_indent
68
+ break
69
+
70
+ if expected_indent is not None and current_indent != expected_indent:
71
+ # Fix the indentation
72
+ line = ' ' * expected_indent + stripped
73
+ fixed += 1
74
+
75
+ new_lines.append(line)
76
+
77
+ with open(filepath, 'w', encoding='utf-8') as f:
78
+ f.writelines(new_lines)
79
+
80
+ return fixed
81
+
82
+
83
+ f1 = fix_indentation('evol/server/openclaw_proxy.py')
84
+ print(f"openclaw_proxy.py: {f1} lines fixed")
85
+
86
+ f2 = fix_indentation('evol/server/claude_proxy_async.py')
87
+ print(f"claude_proxy_async.py: {f2} lines fixed")