@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.
- package/CHANGELOG.md +302 -0
- package/cli.js +119 -4
- package/core/dependency_checker.py +250 -0
- package/core/env_checker.py +490 -0
- package/dependencies_lock.json +128 -0
- package/extensions/agents/assistant/entry.py +111 -1
- package/extensions/agents/assistant/server.py +279 -215
- package/extensions/channels/acp_channel/entry.py +111 -1
- package/extensions/channels/acp_channel/module.md +23 -22
- package/extensions/channels/acp_channel/server.py +279 -215
- package/extensions/event_hub_bench/entry.py +107 -1
- package/extensions/services/backup/entry.py +306 -21
- package/extensions/services/backup/module.md +24 -22
- package/extensions/services/evol/auth_manager.py +443 -0
- package/extensions/services/evol/config.yaml +149 -0
- package/extensions/services/evol/config_loader.py +117 -0
- package/extensions/services/evol/entry.py +406 -0
- package/extensions/services/evol/evol_api.py +173 -0
- package/extensions/services/evol/evol_config.json5 +29 -0
- package/extensions/services/evol/migrate_tokens.py +122 -0
- package/extensions/services/evol/module.md +32 -0
- package/extensions/services/evol/pairing.py +250 -0
- package/extensions/services/evol/pairing_codes.jsonl +1 -0
- package/extensions/services/evol/relay.py +682 -0
- package/extensions/services/evol/relay_config.json5 +67 -0
- package/extensions/services/evol/routes/__init__.py +1 -0
- package/extensions/services/evol/routes/routes_management_ws.py +127 -0
- package/extensions/services/evol/routes/routes_rpc.py +89 -0
- package/extensions/services/evol/routes/routes_test.py +61 -0
- package/extensions/services/evol/server.py +875 -0
- package/extensions/services/evol/static/css/style.css +1200 -0
- package/extensions/services/evol/static/index.html +781 -0
- package/extensions/services/evol/static/index_evol.html +14 -0
- package/extensions/services/evol/static/js/app.js +6304 -0
- package/extensions/services/evol/static/js/auth.js +326 -0
- package/extensions/services/evol/static/js/dialog.js +285 -0
- package/extensions/services/evol/static/js/evol-app-fixed.js +50 -0
- package/extensions/services/evol/static/js/evol-app.js +1949 -0
- package/extensions/services/evol/static/js/evol-app.js.bak +1800 -0
- package/extensions/services/evol/static/js/kernel-client-example.js +228 -0
- package/extensions/services/evol/static/js/kernel-client.js +396 -0
- package/extensions/services/evol/static/js/main.js +141 -0
- package/extensions/services/evol/static/js/registry-tests.js +585 -0
- package/extensions/services/evol/static/js/stats.js +217 -0
- package/extensions/services/evol/static/js/token-manager.js +175 -0
- package/extensions/services/evol/static/pairing.html +248 -0
- package/extensions/services/evol/static/test_registry.html +262 -0
- package/extensions/services/evol/static/test_relay.html +462 -0
- package/extensions/services/evol/stats_manager.py +240 -0
- package/extensions/services/model_service/entry.py +167 -19
- package/extensions/services/model_service/module.md +21 -22
- package/extensions/services/proxy/.claude/settings.local.json +13 -0
- package/extensions/services/proxy/CHANGELOG_20260308.md +258 -0
- package/extensions/services/proxy/_fix_prints.py +133 -0
- package/extensions/services/proxy/_fix_prints2.py +87 -0
- package/extensions/services/proxy/agentcp/LICENCE +178 -0
- package/extensions/services/proxy/agentcp/README copy.md +85 -0
- package/extensions/services/proxy/agentcp/README.md +260 -0
- package/extensions/services/proxy/agentcp/__init__.py +16 -0
- package/extensions/services/proxy/agentcp/agent.py +4 -0
- package/extensions/services/proxy/agentcp/agentcp.py +2494 -0
- package/extensions/services/proxy/agentcp/agentprofile.json +89 -0
- package/extensions/services/proxy/agentcp/ap/__init__.py +16 -0
- package/extensions/services/proxy/agentcp/ap/ap_client.py +316 -0
- package/extensions/services/proxy/agentcp/assets/images/wechat_qr.png +0 -0
- package/extensions/services/proxy/agentcp/backup/metrics.json +31 -0
- package/extensions/services/proxy/agentcp/base/__init__.py +20 -0
- package/extensions/services/proxy/agentcp/base/auth_client.py +257 -0
- package/extensions/services/proxy/agentcp/base/client.py +112 -0
- package/extensions/services/proxy/agentcp/base/env.py +34 -0
- package/extensions/services/proxy/agentcp/base/html_util.py +336 -0
- package/extensions/services/proxy/agentcp/base/log.py +98 -0
- package/extensions/services/proxy/agentcp/ca/__init__.py +17 -0
- package/extensions/services/proxy/agentcp/ca/ca_client.py +414 -0
- package/extensions/services/proxy/agentcp/ca/ca_root.py +74 -0
- package/extensions/services/proxy/agentcp/context/__init__.py +20 -0
- package/extensions/services/proxy/agentcp/context/context.py +73 -0
- package/extensions/services/proxy/agentcp/context/exceptions.py +114 -0
- package/extensions/services/proxy/agentcp/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/create_profile_weather.py +125 -0
- package/extensions/services/proxy/agentcp/db/__init__.py +15 -0
- package/extensions/services/proxy/agentcp/db/db_mananger.py +550 -0
- package/extensions/services/proxy/agentcp/docs/UDP_HEARTBEAT_FIX_REPORT.md +265 -0
- package/extensions/services/proxy/agentcp/docs/heartbeat_issue_analysis.md +291 -0
- package/extensions/services/proxy/agentcp/file/__init__.py +16 -0
- package/extensions/services/proxy/agentcp/file/file_client.py +141 -0
- package/extensions/services/proxy/agentcp/file/wss_binary_message.py +137 -0
- package/extensions/services/proxy/agentcp/hcp.py +299 -0
- package/extensions/services/proxy/agentcp/heartbeat/__init__.py +16 -0
- package/extensions/services/proxy/agentcp/heartbeat/heartbeat_client.py +360 -0
- package/extensions/services/proxy/agentcp/improved_scheduler.py +498 -0
- package/extensions/services/proxy/agentcp/llm_agent_utils.py +249 -0
- package/extensions/services/proxy/agentcp/llm_server.py +172 -0
- package/extensions/services/proxy/agentcp/mermaid.py +210 -0
- package/extensions/services/proxy/agentcp/message.py +149 -0
- package/extensions/services/proxy/agentcp/metrics.py +256 -0
- package/extensions/services/proxy/agentcp/monitoring/__init__.py +20 -0
- package/extensions/services/proxy/agentcp/monitoring/global_monitor.py +27 -0
- package/extensions/services/proxy/agentcp/monitoring/metrics_store.py +325 -0
- package/extensions/services/proxy/agentcp/monitoring/monitoring_service.py +269 -0
- package/extensions/services/proxy/agentcp/monitoring/sliding_window.py +222 -0
- package/extensions/services/proxy/agentcp/monitoring/standalone_reader.py +224 -0
- package/extensions/services/proxy/agentcp/msg/__init__.py +21 -0
- package/extensions/services/proxy/agentcp/msg/connection_manager.py +456 -0
- package/extensions/services/proxy/agentcp/msg/message_client.py +2058 -0
- package/extensions/services/proxy/agentcp/msg/message_serialize.py +263 -0
- package/extensions/services/proxy/agentcp/msg/open_ai_message.py +88 -0
- package/extensions/services/proxy/agentcp/msg/session_manager.py +1062 -0
- package/extensions/services/proxy/agentcp/msg/stream_client.py +267 -0
- package/extensions/services/proxy/agentcp/msg/websocket_file_receiver.py +89 -0
- package/extensions/services/proxy/agentcp/msg/ws_logger.py +685 -0
- package/extensions/services/proxy/agentcp/msg/wss_binary_message.py +137 -0
- package/extensions/services/proxy/agentcp/requirements.txt +7 -0
- package/extensions/services/proxy/agentcp/samples/agent_graph/README.md +37 -0
- package/extensions/services/proxy/agentcp/samples/agent_graph/agentprofile.json +89 -0
- package/extensions/services/proxy/agentcp/samples/agent_graph/create_profile.py +138 -0
- package/extensions/services/proxy/agentcp/samples/agent_graph/main.py +164 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/create_profile.py +123 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/llm/create_profile.py +129 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/llm/env.json +5 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/llm/main.py +146 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/main.py +123 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/readme.md +379 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/search/create_profile.py +129 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/search/main.py +28 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/tool/create_profile.py +129 -0
- package/extensions/services/proxy/agentcp/samples/agent_use/tool/main.py +20 -0
- package/extensions/services/proxy/agentcp/samples/ali_amap/README.md +97 -0
- package/extensions/services/proxy/agentcp/samples/ali_amap/amap_agent.py +88 -0
- package/extensions/services/proxy/agentcp/samples/ali_amap/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/compute_agent/agent/powershell.py +228 -0
- package/extensions/services/proxy/agentcp/samples/compute_agent/agent/software.py +63 -0
- package/extensions/services/proxy/agentcp/samples/compute_agent/agent/tools.py +36 -0
- package/extensions/services/proxy/agentcp/samples/compute_agent/browser_user.py +41 -0
- package/extensions/services/proxy/agentcp/samples/deepseek/README.md +79 -0
- package/extensions/services/proxy/agentcp/samples/deepseek/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/deepseek/deepseek.py +42 -0
- package/extensions/services/proxy/agentcp/samples/dify_chat/README.md +78 -0
- package/extensions/services/proxy/agentcp/samples/dify_chat/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/dify_chat/dify_chat.py +47 -0
- package/extensions/services/proxy/agentcp/samples/dify_workflow/README.md +78 -0
- package/extensions/services/proxy/agentcp/samples/dify_workflow/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/dify_workflow/dify_workflow.py +46 -0
- package/extensions/services/proxy/agentcp/samples/executor/README.md +44 -0
- package/extensions/services/proxy/agentcp/samples/executor/agentprofile.json +89 -0
- package/extensions/services/proxy/agentcp/samples/executor/create_profile.py +139 -0
- package/extensions/services/proxy/agentcp/samples/executor/main.py +160 -0
- package/extensions/services/proxy/agentcp/samples/filereader/README.md +45 -0
- package/extensions/services/proxy/agentcp/samples/filereader/agentprofile.json +90 -0
- package/extensions/services/proxy/agentcp/samples/filereader/create_profile.py +137 -0
- package/extensions/services/proxy/agentcp/samples/filereader/main.py +253 -0
- package/extensions/services/proxy/agentcp/samples/filewriter/README.md +38 -0
- package/extensions/services/proxy/agentcp/samples/filewriter/agentprofile.json +91 -0
- package/extensions/services/proxy/agentcp/samples/filewriter/create_profile.py +138 -0
- package/extensions/services/proxy/agentcp/samples/filewriter/main.py +289 -0
- package/extensions/services/proxy/agentcp/samples/hcp/README.md +85 -0
- package/extensions/services/proxy/agentcp/samples/hcp/acp_weather_agent.zip +0 -0
- package/extensions/services/proxy/agentcp/samples/hcp/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/hcp/hcp.py +237 -0
- package/extensions/services/proxy/agentcp/samples/helloworld/README.md +68 -0
- package/extensions/services/proxy/agentcp/samples/helloworld/hello_world.py +40 -0
- package/extensions/services/proxy/agentcp/samples/llm_agent/MEADME.md +117 -0
- package/extensions/services/proxy/agentcp/samples/llm_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/llm_agent/qwen_agent.py +136 -0
- package/extensions/services/proxy/agentcp/samples/local_llm_agent/README.md +90 -0
- package/extensions/services/proxy/agentcp/samples/local_llm_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/local_llm_agent/main.py +49 -0
- package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/README.md +55 -0
- package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/query_llm_from_agent/main.py +23 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/README.md +103 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_api_agent/main.py +69 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/README.md +58 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/query_weather_from_agent/main.py +25 -0
- package/extensions/services/proxy/agentcp/samples/qwen3/README.md +71 -0
- package/extensions/services/proxy/agentcp/samples/qwen3/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/qwen3/qwen3.py +37 -0
- package/extensions/services/proxy/agentcp/samples/qwen3_tools/README.md +133 -0
- package/extensions/services/proxy/agentcp/samples/qwen3_tools/create_profile.py +126 -0
- package/extensions/services/proxy/agentcp/samples/qwen3_tools/qwen3_tools.py +98 -0
- package/extensions/services/proxy/agentcp/samples/search/create_profile_qwen.py +125 -0
- package/extensions/services/proxy/agentcp/samples/search/create_profile_search.py +125 -0
- package/extensions/services/proxy/agentcp/samples/search/qwen_agent.py +136 -0
- package/extensions/services/proxy/agentcp/samples/search/search_agent.py +170 -0
- package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/README.md +89 -0
- package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/create_profile.py +125 -0
- package/extensions/services/proxy/agentcp/samples/wrapper_agently_to_agent/main.py +44 -0
- package/extensions/services/proxy/agentcp/utils/__init__.py +15 -0
- package/extensions/services/proxy/agentcp/utils/file_util.py +117 -0
- package/extensions/services/proxy/agentcp/utils/proxy_bypass.py +99 -0
- package/extensions/services/proxy/agentcp/workflow.py +203 -0
- package/extensions/services/proxy/console_auth.py +109 -0
- package/extensions/services/proxy/evol/__init__.py +1 -0
- package/extensions/services/proxy/evol/config.py +37 -0
- package/extensions/services/proxy/evol/http/__init__.py +1 -0
- package/extensions/services/proxy/evol/http/async_http.py +551 -0
- package/extensions/services/proxy/evol/log.py +28 -0
- package/extensions/services/proxy/evol/presenter/__init__.py +2 -0
- package/extensions/services/proxy/evol/presenter/agentIdPresenter.py +1031 -0
- package/extensions/services/proxy/evol/presenter/apikeyPresenter.py +106 -0
- package/extensions/services/proxy/evol/presenter/configPresenter.py +1281 -0
- package/extensions/services/proxy/evol/presenter/userPresenter.py +477 -0
- package/extensions/services/proxy/evol/server/__init__.py +1 -0
- package/extensions/services/proxy/evol/server/claude_proxy_async.py +3430 -0
- package/extensions/services/proxy/evol/server/openclaw_proxy.py +1861 -0
- package/extensions/services/proxy/evol/server/proxy_config.py +15 -0
- package/extensions/services/proxy/evol/server/proxy_engine.py +501 -0
- package/extensions/services/proxy/evol/version.py +24 -0
- package/extensions/services/proxy/logs/websocket.log +260 -0
- package/extensions/services/proxy/main.py +240 -0
- package/extensions/services/proxy/requirements.txt +13 -0
- package/extensions/services/proxy/server.py +271 -0
- package/extensions/services/watchdog/entry.py +215 -26
- package/extensions/services/watchdog/module.md +1 -0
- package/extensions/services/watchdog/monitor.py +178 -38
- package/extensions/services/web/WEBSOCKET_STATUS.md +143 -0
- package/extensions/services/web/config_example.py +35 -0
- package/extensions/services/web/config_loader.py +110 -0
- package/extensions/services/web/entry.py +114 -26
- package/extensions/services/web/module.md +35 -24
- package/extensions/services/web/pairing.py +250 -0
- package/extensions/services/web/pairing_codes.jsonl +16 -0
- package/extensions/services/web/relay.py +643 -0
- package/extensions/services/web/relay_config.json5 +67 -0
- package/extensions/services/web/routes/routes_management_ws.py +127 -0
- package/extensions/services/web/routes/routes_rpc.py +89 -0
- package/extensions/services/web/routes/routes_test.py +61 -0
- package/extensions/services/web/routes/schemas.py +0 -22
- package/extensions/services/web/server.py +434 -99
- package/extensions/services/web/static/css/style.css +67 -28
- package/extensions/services/web/static/index.html +234 -44
- package/extensions/services/web/static/js/app.js +1335 -48
- package/extensions/services/web/static/js/kernel-client-example.js +161 -0
- package/extensions/services/web/static/js/kernel-client.js +383 -0
- package/extensions/services/web/static/js/registry-tests.js +558 -0
- package/extensions/services/web/static/js/token-manager.js +175 -0
- package/extensions/services/web/static/pairing.html +248 -0
- package/extensions/services/web/static/test_registry.html +262 -0
- package/extensions/services/web/web_config.json5 +29 -0
- package/kernel/entry.py +120 -32
- package/kernel/event_hub.py +141 -16
- package/kernel/module.md +60 -33
- package/kernel/registry_store.py +45 -36
- package/kernel/rpc_router.py +152 -59
- package/kernel/server.py +322 -26
- package/kite_cli/__init__.py +3 -0
- package/kite_cli/__main__.py +5 -0
- package/kite_cli/commands/__init__.py +1 -0
- package/kite_cli/commands/clean.py +101 -0
- package/kite_cli/commands/deps_install.py +67 -0
- package/kite_cli/commands/doctor.py +35 -0
- package/kite_cli/commands/env_check.py +45 -0
- package/kite_cli/commands/history.py +111 -0
- package/kite_cli/commands/info.py +96 -0
- package/kite_cli/commands/install.py +313 -0
- package/kite_cli/commands/list.py +143 -0
- package/kite_cli/commands/log.py +81 -0
- package/kite_cli/commands/prepare.py +49 -0
- package/kite_cli/commands/rollback.py +88 -0
- package/kite_cli/commands/search.py +73 -0
- package/kite_cli/commands/uninstall.py +85 -0
- package/kite_cli/commands/update.py +118 -0
- package/kite_cli/commands/venv_setup.py +56 -0
- package/kite_cli/core/__init__.py +1 -0
- package/kite_cli/core/checker.py +142 -0
- package/kite_cli/core/dependency.py +229 -0
- package/kite_cli/core/downloader.py +209 -0
- package/kite_cli/core/install_info.py +40 -0
- package/kite_cli/core/tool_installer.py +397 -0
- package/kite_cli/core/validator.py +78 -0
- package/kite_cli/main.py +317 -0
- package/kite_cli/utils/__init__.py +1 -0
- package/kite_cli/utils/i18n.py +252 -0
- package/kite_cli/utils/interactive.py +63 -0
- package/kite_cli/utils/operation_log.py +77 -0
- package/kite_cli/utils/paths.py +34 -0
- package/kite_cli/utils/version.py +308 -0
- package/launcher/entry.py +1124 -178
- package/launcher/logging_setup.py +104 -0
- package/launcher/module.md +46 -37
- package/launcher/module_scanner.py +11 -1
- package/main.py +4 -1
- package/package.json +9 -1
- package/python_version.json +4 -0
- package/requirements.txt +38 -0
- package/scripts/env-manager.js +328 -0
- package/scripts/plan_manager.py +315 -0
- package/scripts/python-env.js +79 -0
- package/scripts/scan_dependencies.py +461 -0
- package/scripts/setup-python-env.js +191 -0
- package/extensions/services/web/routes/routes_modules.py +0 -249
|
@@ -23,7 +23,113 @@ import websockets
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
# ── Module configuration ──
|
|
26
|
-
|
|
26
|
+
|
|
27
|
+
def _load_module_config() -> dict:
|
|
28
|
+
"""Load module configuration from module.md frontmatter.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Dict with keys: name, preferred_port, advertise_ip
|
|
32
|
+
|
|
33
|
+
Raises:
|
|
34
|
+
SystemExit: If module.md is invalid or name is non-compliant
|
|
35
|
+
"""
|
|
36
|
+
_this_dir = os.path.dirname(os.path.abspath(__file__))
|
|
37
|
+
module_md = os.path.join(_this_dir, "module.md")
|
|
38
|
+
|
|
39
|
+
# Calculate relative path for error messages
|
|
40
|
+
project_root = os.environ.get("KITE_PROJECT", "")
|
|
41
|
+
if project_root and _this_dir.startswith(project_root):
|
|
42
|
+
rel_path = os.path.relpath(_this_dir, project_root)
|
|
43
|
+
else:
|
|
44
|
+
rel_path = _this_dir
|
|
45
|
+
|
|
46
|
+
# Default values (will be overridden if valid config exists)
|
|
47
|
+
result = {
|
|
48
|
+
"name": "",
|
|
49
|
+
"preferred_port": 0,
|
|
50
|
+
"advertise_ip": "0.0.0.0"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Check if module.md exists
|
|
54
|
+
if not os.path.exists(module_md):
|
|
55
|
+
print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
|
|
56
|
+
print(f" Path: {rel_path}/module.md")
|
|
57
|
+
print(f" Reason: File not found")
|
|
58
|
+
sys.exit(1)
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
with open(module_md, encoding="utf-8") as f:
|
|
62
|
+
text = f.read()
|
|
63
|
+
|
|
64
|
+
# Extract YAML frontmatter (between --- markers)
|
|
65
|
+
import re
|
|
66
|
+
m = re.match(r'^---\s*\n(.*?)\n---', text, re.DOTALL)
|
|
67
|
+
if not m:
|
|
68
|
+
print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
|
|
69
|
+
print(f" Path: {rel_path}/module.md")
|
|
70
|
+
print(f" Reason: Missing YAML frontmatter")
|
|
71
|
+
sys.exit(1)
|
|
72
|
+
|
|
73
|
+
# Parse YAML frontmatter
|
|
74
|
+
try:
|
|
75
|
+
import yaml
|
|
76
|
+
fm = yaml.safe_load(m.group(1)) or {}
|
|
77
|
+
except ImportError:
|
|
78
|
+
print(f"[{rel_path}] ERROR: PyYAML not installed, cannot parse module.md")
|
|
79
|
+
sys.exit(1)
|
|
80
|
+
except Exception as e:
|
|
81
|
+
print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
|
|
82
|
+
print(f" Path: {rel_path}/module.md")
|
|
83
|
+
print(f" Reason: YAML parse error: {e}")
|
|
84
|
+
sys.exit(1)
|
|
85
|
+
|
|
86
|
+
# Validate 'name' field (required)
|
|
87
|
+
if "name" not in fm:
|
|
88
|
+
print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
|
|
89
|
+
print(f" Path: {rel_path}/module.md")
|
|
90
|
+
print(f" Reason: Missing 'name' field")
|
|
91
|
+
sys.exit(1)
|
|
92
|
+
|
|
93
|
+
raw_name = str(fm["name"]).strip()
|
|
94
|
+
|
|
95
|
+
if not raw_name:
|
|
96
|
+
print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
|
|
97
|
+
print(f" Path: {rel_path}/module.md")
|
|
98
|
+
print(f" Reason: Empty module name")
|
|
99
|
+
sys.exit(1)
|
|
100
|
+
|
|
101
|
+
# Validate name characters
|
|
102
|
+
sanitized = re.sub(r'[^a-zA-Z0-9_\-]', '', raw_name)
|
|
103
|
+
|
|
104
|
+
if sanitized != raw_name:
|
|
105
|
+
invalid_chars = ''.join(sorted(set(c for c in raw_name if c not in sanitized)))
|
|
106
|
+
print(f"[{rel_path}] ERROR: Invalid module configuration in module.md")
|
|
107
|
+
print(f" Path: {rel_path}/module.md")
|
|
108
|
+
print(f" Reason: Invalid characters in name '{raw_name}': {repr(invalid_chars)}")
|
|
109
|
+
sys.exit(1)
|
|
110
|
+
|
|
111
|
+
result["name"] = sanitized
|
|
112
|
+
|
|
113
|
+
# Extract optional fields
|
|
114
|
+
if "preferred_port" in fm:
|
|
115
|
+
try:
|
|
116
|
+
result["preferred_port"] = int(fm["preferred_port"])
|
|
117
|
+
except (ValueError, TypeError):
|
|
118
|
+
pass
|
|
119
|
+
|
|
120
|
+
if "advertise_ip" in fm:
|
|
121
|
+
result["advertise_ip"] = str(fm["advertise_ip"])
|
|
122
|
+
|
|
123
|
+
except SystemExit:
|
|
124
|
+
raise # Re-raise exit to prevent catching by outer except
|
|
125
|
+
except Exception as e:
|
|
126
|
+
print(f"[{rel_path}] ERROR: Failed to read module.md: {e}")
|
|
127
|
+
sys.exit(1)
|
|
128
|
+
|
|
129
|
+
return result
|
|
130
|
+
|
|
131
|
+
_module_config = _load_module_config()
|
|
132
|
+
MODULE_NAME = _module_config["name"]
|
|
27
133
|
|
|
28
134
|
|
|
29
135
|
class _SafeWriter:
|
|
@@ -264,6 +370,7 @@ def _read_stdin_kite_message(expected_type: str, timeout: float = 10) -> dict |
|
|
|
264
370
|
# Global WS reference for publish_event callback
|
|
265
371
|
_ws_global = None
|
|
266
372
|
_shutting_down = False
|
|
373
|
+
_exit_code = 0 # Exit code for main() to use
|
|
267
374
|
|
|
268
375
|
|
|
269
376
|
def _is_auth_failure(e: Exception) -> bool:
|
|
@@ -333,7 +440,7 @@ async def main():
|
|
|
333
440
|
|
|
334
441
|
async def _ws_loop(token: str, kernel_port: int, _t0: float):
|
|
335
442
|
"""Connect to Kernel with exponential backoff reconnection."""
|
|
336
|
-
global _shutting_down
|
|
443
|
+
global _shutting_down, _exit_code
|
|
337
444
|
retry_delay = 0.3
|
|
338
445
|
max_delay = 5.0
|
|
339
446
|
max_retries = 10
|
|
@@ -349,10 +456,14 @@ async def _ws_loop(token: str, kernel_port: int, _t0: float):
|
|
|
349
456
|
attempt += 1
|
|
350
457
|
if _is_auth_failure(e):
|
|
351
458
|
print(f"[model_service] Kernel 认证失败,退出")
|
|
352
|
-
|
|
459
|
+
_exit_code = 1
|
|
460
|
+
_shutting_down = True
|
|
461
|
+
return
|
|
353
462
|
if attempt >= max_retries:
|
|
354
463
|
print(f"[model_service] 重连失败 {max_retries} 次,退出")
|
|
355
|
-
|
|
464
|
+
_exit_code = 1
|
|
465
|
+
_shutting_down = True
|
|
466
|
+
return
|
|
356
467
|
_write_crash(type(e), e, e.__traceback__, severity="error", handled=True)
|
|
357
468
|
print(f"[model_service] 连接错误: {e}, {retry_delay:.1f}s 后重试 ({attempt}/{max_retries})")
|
|
358
469
|
_ws_global_clear()
|
|
@@ -374,7 +485,7 @@ async def _ws_connect(token: str, kernel_port: int, _t0: float):
|
|
|
374
485
|
ws_url = f"ws://127.0.0.1:{kernel_port}/ws?token={token}&id=model_service"
|
|
375
486
|
print(f"[model_service] Connecting to Kernel: {ws_url}")
|
|
376
487
|
|
|
377
|
-
async with websockets.connect(ws_url, open_timeout=5, ping_interval=None,
|
|
488
|
+
async with websockets.connect(ws_url, open_timeout=5, ping_interval=None, close_timeout=10) as ws:
|
|
378
489
|
_ws_global = ws
|
|
379
490
|
print(f"[model_service] Connected to Kernel ({_fmt_elapsed(_t0)})")
|
|
380
491
|
|
|
@@ -393,7 +504,9 @@ async def _ws_connect(token: str, kernel_port: int, _t0: float):
|
|
|
393
504
|
"module_id": "model_service",
|
|
394
505
|
"module_type": "service",
|
|
395
506
|
"events_publish": {
|
|
396
|
-
"model_service
|
|
507
|
+
"model_service": {
|
|
508
|
+
"test": {"description": "Test event from model_service module"},
|
|
509
|
+
}
|
|
397
510
|
},
|
|
398
511
|
"events_subscribe": [
|
|
399
512
|
"module.started",
|
|
@@ -405,12 +518,14 @@ async def _ws_connect(token: str, kernel_port: int, _t0: float):
|
|
|
405
518
|
|
|
406
519
|
# Publish module.ready (every reconnect)
|
|
407
520
|
if not _shutting_down:
|
|
521
|
+
startup_time = time.monotonic() - _t0
|
|
408
522
|
await _rpc_call(ws, "event.publish", {
|
|
409
523
|
"event_id": str(uuid.uuid4()),
|
|
410
524
|
"event": "module.ready",
|
|
411
525
|
"data": {
|
|
412
526
|
"module_id": "model_service",
|
|
413
527
|
"graceful_shutdown": True,
|
|
528
|
+
"startup_time": startup_time,
|
|
414
529
|
},
|
|
415
530
|
})
|
|
416
531
|
print(f"[model_service] module.ready published ({_fmt_elapsed(_t0)})")
|
|
@@ -419,6 +534,11 @@ async def _ws_connect(token: str, kernel_port: int, _t0: float):
|
|
|
419
534
|
test_task = asyncio.create_task(_test_event_loop(ws))
|
|
420
535
|
|
|
421
536
|
# Message loop: handle incoming RPC + events
|
|
537
|
+
# CRITICAL: RPC 死锁防范
|
|
538
|
+
# - 入站 RPC 请求必须用 create_task() 异步执行,不可 await
|
|
539
|
+
# - 原因:如果 handler 内部调用 rpc_call() 发出站请求,出站响应需要本接收循环来分发
|
|
540
|
+
# - 如果接收循环被 await handler 阻塞,出站响应永远收不到 → 超时死锁
|
|
541
|
+
# - 事件通知和 RPC 响应可以同步处理(它们不会反向调用 rpc_call)
|
|
422
542
|
async for raw in ws:
|
|
423
543
|
try:
|
|
424
544
|
msg = json.loads(raw)
|
|
@@ -433,8 +553,8 @@ async def _ws_connect(token: str, kernel_port: int, _t0: float):
|
|
|
433
553
|
# Event Notification
|
|
434
554
|
await _handle_event_notification(msg)
|
|
435
555
|
elif has_method and has_id:
|
|
436
|
-
# Incoming RPC request
|
|
437
|
-
|
|
556
|
+
# Incoming RPC request — run in background to prevent deadlock
|
|
557
|
+
asyncio.create_task(_handle_rpc_request(ws, msg))
|
|
438
558
|
# Ignore RPC responses (we don't await them in this simple impl)
|
|
439
559
|
except Exception as e:
|
|
440
560
|
print(f"[model_service] 消息处理异常(已忽略): {e}")
|
|
@@ -457,12 +577,32 @@ async def _publish_event(ws, event: dict):
|
|
|
457
577
|
})
|
|
458
578
|
|
|
459
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
|
+
|
|
460
595
|
async def _handle_event_notification(msg: dict):
|
|
461
596
|
"""Handle an event notification (JSON-RPC 2.0 Notification with method='event')."""
|
|
462
597
|
params = msg.get("params", {})
|
|
463
598
|
event_type = params.get("event", "")
|
|
464
599
|
data = params.get("data", {})
|
|
465
600
|
|
|
601
|
+
# Handle system.ping event
|
|
602
|
+
if event_type == "system.ping":
|
|
603
|
+
await _handle_ping_event(data)
|
|
604
|
+
return
|
|
605
|
+
|
|
466
606
|
# Special handling for module.shutdown
|
|
467
607
|
if event_type == "module.shutdown":
|
|
468
608
|
target = data.get("module_id", "")
|
|
@@ -523,29 +663,37 @@ async def _rpc_status() -> dict:
|
|
|
523
663
|
|
|
524
664
|
|
|
525
665
|
async def _handle_shutdown():
|
|
526
|
-
"""Handle module.shutdown event —
|
|
666
|
+
"""Handle module.shutdown event — ack → exiting → cleanup → ready → exit."""
|
|
527
667
|
global _shutting_down
|
|
528
668
|
print("[model_service] Received shutdown request")
|
|
529
669
|
_shutting_down = True
|
|
530
|
-
# Step
|
|
670
|
+
# Step 1: Send ack (立即确认收到)
|
|
531
671
|
await _publish_event(_ws_global, {
|
|
532
|
-
"event": "module.
|
|
533
|
-
"data": {"module_id": "model_service"
|
|
672
|
+
"event": "module.shutdown.ack",
|
|
673
|
+
"data": {"module_id": "model_service"},
|
|
534
674
|
})
|
|
535
|
-
# Step
|
|
675
|
+
# Step 2: Send module.exiting (开始清理)
|
|
536
676
|
await _publish_event(_ws_global, {
|
|
537
|
-
"event": "module.
|
|
538
|
-
"data": {
|
|
677
|
+
"event": "module.exiting",
|
|
678
|
+
"data": {
|
|
679
|
+
"module_id": "model_service",
|
|
680
|
+
"type": "passive",
|
|
681
|
+
"reason": "shutdown_requested",
|
|
682
|
+
"restart": "auto",
|
|
683
|
+
"action": "none",
|
|
684
|
+
"timeout": 2.0,
|
|
685
|
+
"restart_delay": 0.0,
|
|
686
|
+
},
|
|
539
687
|
})
|
|
540
|
-
# Step
|
|
541
|
-
# Step
|
|
688
|
+
# Step 3: Cleanup (nothing to clean up for model_service)
|
|
689
|
+
# Step 4: Send ready (清理完成)
|
|
542
690
|
await _publish_event(_ws_global, {
|
|
543
691
|
"event": "module.shutdown.ready",
|
|
544
692
|
"data": {"module_id": "model_service"},
|
|
545
693
|
})
|
|
546
694
|
print("[model_service] Shutdown ready, exiting")
|
|
547
|
-
# Step
|
|
548
|
-
sys.exit(
|
|
695
|
+
# Step 5: Exit
|
|
696
|
+
sys.exit(_exit_code)
|
|
549
697
|
|
|
550
698
|
|
|
551
699
|
async def _test_event_loop(ws):
|
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: model_service
|
|
3
|
-
display_name: Model Service
|
|
4
|
-
version:
|
|
5
|
-
type: service
|
|
6
|
-
state:
|
|
7
|
-
runtime: python
|
|
8
|
-
entry: entry.py
|
|
9
|
-
events:
|
|
10
|
-
|
|
11
|
-
subscriptions:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
- 事件通知 — 通过 Event Hub 发布模型服务状态事件
|
|
1
|
+
---
|
|
2
|
+
name: model_service
|
|
3
|
+
display_name: Model Service
|
|
4
|
+
version: '1.0'
|
|
5
|
+
type: service
|
|
6
|
+
state: manual
|
|
7
|
+
runtime: python
|
|
8
|
+
entry: entry.py
|
|
9
|
+
events:
|
|
10
|
+
- model_service.test
|
|
11
|
+
subscriptions:
|
|
12
|
+
- module.started
|
|
13
|
+
- module.stopped
|
|
14
|
+
- module.shutdown
|
|
15
|
+
---
|
|
16
|
+
# Model Service(大模型服务)
|
|
17
|
+
|
|
18
|
+
大模型服务模块,提供统一的 LLM 调用接口。
|
|
19
|
+
|
|
20
|
+
- 模型调用 — 封装多种大模型 API 的统一调用接口
|
|
21
|
+
- 事件通知 — 通过 Event Hub 发布模型服务状态事件
|
|
@@ -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
|
+
**审核者:** 待审核
|