@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
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""Management WebSocket — 实时推送模块状态变更到前端管理页面"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import json
|
|
7
|
+
import logging
|
|
8
|
+
from datetime import datetime, timezone
|
|
9
|
+
|
|
10
|
+
from fastapi import APIRouter, WebSocket, WebSocketDisconnect
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
router = APIRouter()
|
|
15
|
+
|
|
16
|
+
# 全局连接池 — 所有连接的管理客户端
|
|
17
|
+
_management_clients: set[WebSocket] = set()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@router.websocket("/ws/management")
|
|
21
|
+
async def management_websocket(ws: WebSocket):
|
|
22
|
+
"""
|
|
23
|
+
管理后台实时状态推送 WebSocket.
|
|
24
|
+
|
|
25
|
+
前端连接后会收到:
|
|
26
|
+
- 初始 connected 消息
|
|
27
|
+
- 模块状态变更事件(module.started, module.stopped, module.crashed 等)
|
|
28
|
+
- 健康检查结果(module.health)
|
|
29
|
+
- Kernel 连接状态(module.connected, module.registered)
|
|
30
|
+
"""
|
|
31
|
+
await ws.accept()
|
|
32
|
+
_management_clients.add(ws)
|
|
33
|
+
client_id = id(ws)
|
|
34
|
+
logger.info(f"Management WS: client connected (id={client_id}, total={len(_management_clients)})")
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
# 发送初始连接确认
|
|
38
|
+
await ws.send_json({
|
|
39
|
+
"type": "connected",
|
|
40
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
# 保持连接,接收心跳和客户端消息
|
|
44
|
+
while True:
|
|
45
|
+
try:
|
|
46
|
+
raw = await asyncio.wait_for(ws.receive_text(), timeout=60.0)
|
|
47
|
+
msg = json.loads(raw)
|
|
48
|
+
|
|
49
|
+
# 心跳响应
|
|
50
|
+
if msg.get("type") == "ping":
|
|
51
|
+
await ws.send_json({
|
|
52
|
+
"type": "pong",
|
|
53
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
except asyncio.TimeoutError:
|
|
57
|
+
# 60 秒无消息,发送 ping 检测连接
|
|
58
|
+
try:
|
|
59
|
+
await ws.send_json({"type": "ping"})
|
|
60
|
+
except Exception:
|
|
61
|
+
break
|
|
62
|
+
|
|
63
|
+
except WebSocketDisconnect:
|
|
64
|
+
logger.info(f"Management WS: client disconnected (id={client_id})")
|
|
65
|
+
except Exception as e:
|
|
66
|
+
logger.warning(f"Management WS: client error (id={client_id}): {e}")
|
|
67
|
+
finally:
|
|
68
|
+
_management_clients.discard(ws)
|
|
69
|
+
logger.info(f"Management WS: client removed (id={client_id}, remaining={len(_management_clients)})")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
async def broadcast_event(event_type: str, data: dict):
|
|
73
|
+
"""
|
|
74
|
+
广播事件到所有连接的管理客户端.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
event_type: 事件类型(如 module.started, module.stopped)
|
|
78
|
+
data: 事件数据(通常包含 module_id 等字段)
|
|
79
|
+
"""
|
|
80
|
+
if not _management_clients:
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
message = {
|
|
84
|
+
"type": event_type,
|
|
85
|
+
"data": data,
|
|
86
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
message_str = json.dumps(message)
|
|
90
|
+
dead_clients = []
|
|
91
|
+
|
|
92
|
+
# 并发发送到所有客户端
|
|
93
|
+
for ws in list(_management_clients):
|
|
94
|
+
try:
|
|
95
|
+
await ws.send_text(message_str)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
logger.debug(f"Management WS: failed to send to client {id(ws)}: {e}")
|
|
98
|
+
dead_clients.append(ws)
|
|
99
|
+
|
|
100
|
+
# 清理失败的连接
|
|
101
|
+
for ws in dead_clients:
|
|
102
|
+
_management_clients.discard(ws)
|
|
103
|
+
|
|
104
|
+
if dead_clients:
|
|
105
|
+
logger.info(f"Management WS: removed {len(dead_clients)} dead clients, remaining={len(_management_clients)}")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def get_client_count() -> int:
|
|
109
|
+
"""返回当前连接的管理客户端数量"""
|
|
110
|
+
return len(_management_clients)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
async def close_all_clients():
|
|
114
|
+
"""优雅关闭所有管理客户端(用于 shutdown)"""
|
|
115
|
+
if not _management_clients:
|
|
116
|
+
return
|
|
117
|
+
|
|
118
|
+
logger.info(f"Management WS: closing {len(_management_clients)} clients...")
|
|
119
|
+
|
|
120
|
+
for ws in list(_management_clients):
|
|
121
|
+
try:
|
|
122
|
+
await ws.close(code=1001, reason="Server shutting down")
|
|
123
|
+
except Exception as e:
|
|
124
|
+
logger.debug(f"Management WS: error closing client {id(ws)}: {e}")
|
|
125
|
+
|
|
126
|
+
_management_clients.clear()
|
|
127
|
+
logger.info("Management WS: all clients closed")
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""RPC forwarding routes — forward HTTP requests to Kernel RPC."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import json
|
|
7
|
+
import logging
|
|
8
|
+
import uuid
|
|
9
|
+
|
|
10
|
+
from fastapi import APIRouter, HTTPException, Request
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
router = APIRouter(tags=["rpc"])
|
|
15
|
+
|
|
16
|
+
# Global reference to WebServer instance (set by server.py)
|
|
17
|
+
_web_server = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def set_web_server(server):
|
|
21
|
+
"""Set the WebServer instance for RPC forwarding."""
|
|
22
|
+
global _web_server
|
|
23
|
+
_web_server = server
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@router.post("/rpc/{method:path}")
|
|
27
|
+
async def forward_rpc(method: str, request: Request):
|
|
28
|
+
"""
|
|
29
|
+
Forward RPC call to Kernel via WebSocket.
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
POST /api/rpc/launcher.start_module
|
|
33
|
+
Body: {"name": "watchdog"}
|
|
34
|
+
"""
|
|
35
|
+
if not _web_server:
|
|
36
|
+
raise HTTPException(503, "Web 模块未初始化")
|
|
37
|
+
|
|
38
|
+
if not _web_server._ws:
|
|
39
|
+
raise HTTPException(503, "Web 模块未连接到 Kernel,请检查 Kernel 是否正常运行")
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
body = await request.json()
|
|
43
|
+
except Exception:
|
|
44
|
+
body = {}
|
|
45
|
+
|
|
46
|
+
# Generate unique request ID
|
|
47
|
+
rpc_id = str(uuid.uuid4())
|
|
48
|
+
|
|
49
|
+
# Create RPC request
|
|
50
|
+
rpc_request = {
|
|
51
|
+
"jsonrpc": "2.0",
|
|
52
|
+
"id": rpc_id,
|
|
53
|
+
"method": method,
|
|
54
|
+
"params": body,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Create a future to wait for response
|
|
58
|
+
response_future = asyncio.Future()
|
|
59
|
+
|
|
60
|
+
# Store the future in a dict (keyed by rpc_id)
|
|
61
|
+
if not hasattr(_web_server, '_rpc_futures'):
|
|
62
|
+
_web_server._rpc_futures = {}
|
|
63
|
+
_web_server._rpc_futures[rpc_id] = response_future
|
|
64
|
+
|
|
65
|
+
# Send RPC request
|
|
66
|
+
try:
|
|
67
|
+
await _web_server._ws.send(json.dumps(rpc_request))
|
|
68
|
+
except Exception as e:
|
|
69
|
+
_web_server._rpc_futures.pop(rpc_id, None)
|
|
70
|
+
raise HTTPException(503, f"发送 RPC 请求失败: {str(e)}")
|
|
71
|
+
|
|
72
|
+
# Wait for response (with timeout)
|
|
73
|
+
try:
|
|
74
|
+
response = await asyncio.wait_for(response_future, timeout=30.0)
|
|
75
|
+
except asyncio.TimeoutError:
|
|
76
|
+
_web_server._rpc_futures.pop(rpc_id, None)
|
|
77
|
+
raise HTTPException(504, f"RPC 请求超时(30秒),目标服务可能未响应")
|
|
78
|
+
finally:
|
|
79
|
+
_web_server._rpc_futures.pop(rpc_id, None)
|
|
80
|
+
|
|
81
|
+
# Check for RPC error
|
|
82
|
+
if "error" in response:
|
|
83
|
+
error = response["error"]
|
|
84
|
+
error_msg = error.get('message', '未知错误')
|
|
85
|
+
error_code = error.get('code', -1)
|
|
86
|
+
raise HTTPException(500, f"RPC 调用失败: {error_msg} (code: {error_code})")
|
|
87
|
+
|
|
88
|
+
# Return result
|
|
89
|
+
return response.get("result", {})
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""
|
|
2
|
+
测试日志 API 路由
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from fastapi import APIRouter, HTTPException
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
|
|
10
|
+
router = APIRouter()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestLogRequest(BaseModel):
|
|
14
|
+
"""测试日志请求"""
|
|
15
|
+
content: str
|
|
16
|
+
test_name: str = "registry_test"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@router.post("/save_test_log")
|
|
20
|
+
async def save_test_log(req: TestLogRequest):
|
|
21
|
+
"""
|
|
22
|
+
保存测试日志到服务器
|
|
23
|
+
|
|
24
|
+
日志保存路径: {KITE_MODULE_DATA}/log/registry_test.log (每次覆盖)
|
|
25
|
+
"""
|
|
26
|
+
try:
|
|
27
|
+
# 获取模块数据目录
|
|
28
|
+
module_data = os.environ.get("KITE_MODULE_DATA")
|
|
29
|
+
if not module_data:
|
|
30
|
+
raise HTTPException(status_code=500, detail="KITE_MODULE_DATA not set")
|
|
31
|
+
|
|
32
|
+
# 日志保存到 log 目录(与 latest.log 同级)
|
|
33
|
+
log_dir = Path(module_data) / "log"
|
|
34
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
35
|
+
|
|
36
|
+
# 固定文件名,每次覆盖
|
|
37
|
+
log_file = log_dir / "registry_test.log"
|
|
38
|
+
|
|
39
|
+
# 写入日志(覆盖模式)
|
|
40
|
+
now = datetime.now()
|
|
41
|
+
with open(log_file, "w", encoding="utf-8") as f:
|
|
42
|
+
f.write(f"# Kite 注册中心测试日志\n")
|
|
43
|
+
f.write(f"# 测试时间: {now.isoformat()}\n")
|
|
44
|
+
f.write(f"# {'=' * 70}\n\n")
|
|
45
|
+
f.write(req.content)
|
|
46
|
+
|
|
47
|
+
# 输出到控制台(会被 Launcher 捕获)
|
|
48
|
+
print(f"\n{'=' * 70}")
|
|
49
|
+
print(f"[web] 测试日志已保存")
|
|
50
|
+
print(f"[web] 路径: {log_file}")
|
|
51
|
+
print(f"[web] 时间: {now.strftime('%Y-%m-%d %H:%M:%S')}")
|
|
52
|
+
print(f"{'=' * 70}\n")
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
"success": True,
|
|
56
|
+
"log_path": str(log_file),
|
|
57
|
+
"timestamp": now.isoformat()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
except Exception as e:
|
|
61
|
+
raise HTTPException(status_code=500, detail=f"Failed to save log: {str(e)}")
|
|
@@ -214,25 +214,3 @@ class ConfigUpdate(BaseModel):
|
|
|
214
214
|
"""Arbitrary config update payload — accepts any key/value pairs."""
|
|
215
215
|
|
|
216
216
|
model_config = {"extra": "allow"}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
# ---------------------------------------------------------------------------
|
|
220
|
-
# Modules
|
|
221
|
-
# ---------------------------------------------------------------------------
|
|
222
|
-
|
|
223
|
-
class ModuleMetadataUpdate(BaseModel):
|
|
224
|
-
"""可更新的 module.md frontmatter 字段."""
|
|
225
|
-
display_name: Optional[str] = None
|
|
226
|
-
version: Optional[str] = None
|
|
227
|
-
state: Optional[str] = None # enabled | manual | disabled
|
|
228
|
-
preferred_port: Optional[int] = None
|
|
229
|
-
advertise_ip: Optional[str] = None
|
|
230
|
-
monitor: Optional[bool] = None
|
|
231
|
-
events: Optional[list[str]] = None
|
|
232
|
-
subscriptions: Optional[list[str]] = None
|
|
233
|
-
depends_on: Optional[list[str]] = None
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
class ModuleConfigUpdate(BaseModel):
|
|
237
|
-
"""config.yaml 更新,接受任意 key/value."""
|
|
238
|
-
model_config = {"extra": "allow"}
|