@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,257 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright 2025 AgentUnion Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
from typing import Union
|
|
16
|
+
import uuid
|
|
17
|
+
import time
|
|
18
|
+
import requests
|
|
19
|
+
from cryptography import x509
|
|
20
|
+
from cryptography.hazmat.primitives import serialization, hashes
|
|
21
|
+
from cryptography.hazmat.primitives.asymmetric import ec
|
|
22
|
+
from cryptography.x509.oid import NameOID
|
|
23
|
+
from agentcp.ca.ca_root import CARoot
|
|
24
|
+
from agentcp.base.log import log_error, log_exception, log_info, log_warning
|
|
25
|
+
from cryptography.hazmat.backends import default_backend
|
|
26
|
+
import os
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AuthClient:
|
|
30
|
+
|
|
31
|
+
success_crt_list = []
|
|
32
|
+
|
|
33
|
+
# HTTP 请求超时配置 (连接超时, 读取超时)
|
|
34
|
+
HTTP_TIMEOUT = (3, 10)
|
|
35
|
+
|
|
36
|
+
def __init__(self, agent_id: str, server_url: str, aid_path: str, seed_password: str):
|
|
37
|
+
"""认证客户端类
|
|
38
|
+
Args:
|
|
39
|
+
agent_id: 代理ID
|
|
40
|
+
server_url: 服务器URL
|
|
41
|
+
"""
|
|
42
|
+
self.agent_id = agent_id
|
|
43
|
+
self.server_url = server_url
|
|
44
|
+
self.signature = None
|
|
45
|
+
self.aid_path = aid_path
|
|
46
|
+
self.seed_password = seed_password
|
|
47
|
+
|
|
48
|
+
def sign_in(self, max_retry_num: int = 10) -> Union[dict, None]:
|
|
49
|
+
"""登录方法,使用循环重试,失败返回 None"""
|
|
50
|
+
for retry_count in range(max_retry_num + 1):
|
|
51
|
+
try:
|
|
52
|
+
if retry_count > 0:
|
|
53
|
+
# 指数退避:2s, 4s, 6s, ..., 最大 30s
|
|
54
|
+
backoff = min(2 * retry_count, 30)
|
|
55
|
+
log_info(f"Sign in retry {retry_count}/{max_retry_num}, waiting {backoff}s...")
|
|
56
|
+
time.sleep(backoff)
|
|
57
|
+
|
|
58
|
+
hb_url = self.server_url + "/sign_in"
|
|
59
|
+
log_info(f"Sign in: {hb_url}")
|
|
60
|
+
request_id = uuid.uuid4().hex
|
|
61
|
+
data = {
|
|
62
|
+
"agent_id": self.agent_id,
|
|
63
|
+
"request_id": request_id,
|
|
64
|
+
}
|
|
65
|
+
headers = {
|
|
66
|
+
'User-Agent': f'AgentCP/{__import__("agentcp").__version__} (AuthClient; {self.agent_id})'
|
|
67
|
+
}
|
|
68
|
+
response = requests.post(hb_url, json=data, verify=False, headers=headers, proxies={}, timeout=self.HTTP_TIMEOUT)
|
|
69
|
+
|
|
70
|
+
if response.status_code == 200:
|
|
71
|
+
log_info(f"Sign in url: {hb_url}, response: {response.json()}")
|
|
72
|
+
aid_path = os.path.join(self.aid_path, self.agent_id + ".key")
|
|
73
|
+
private_key = self.__load_private_key(aid_path)
|
|
74
|
+
if private_key is None:
|
|
75
|
+
raise Exception("私钥加载失败,请检查加密种子是否一致")
|
|
76
|
+
|
|
77
|
+
aid_path = os.path.join(self.aid_path, self.agent_id + ".crt")
|
|
78
|
+
with open(aid_path, "rb") as f:
|
|
79
|
+
certificate_pem = f.read().decode('utf-8')
|
|
80
|
+
|
|
81
|
+
cert = x509.load_pem_x509_certificate(certificate_pem.encode('utf-8'))
|
|
82
|
+
public_key = cert.public_key()
|
|
83
|
+
public_key_pem = public_key.public_bytes(
|
|
84
|
+
encoding=serialization.Encoding.PEM,
|
|
85
|
+
format=serialization.PublicFormat.SubjectPublicKeyInfo
|
|
86
|
+
).decode('utf-8')
|
|
87
|
+
|
|
88
|
+
if "nonce" in response.json():
|
|
89
|
+
nonce = response.json()["nonce"]
|
|
90
|
+
server_cert_valid = True
|
|
91
|
+
|
|
92
|
+
if "cert" in response.json() and "signature" in response.json():
|
|
93
|
+
server_cert_valid = False
|
|
94
|
+
try:
|
|
95
|
+
cert_data = response.json()["cert"].encode('utf-8')
|
|
96
|
+
server_cert = x509.load_pem_x509_certificate(cert_data, default_backend())
|
|
97
|
+
server_public_key = server_cert.public_key()
|
|
98
|
+
data_to_verify = (self.agent_id + str(request_id)).lower().encode('utf-8')
|
|
99
|
+
signature_bytes = bytes.fromhex(response.json()["signature"])
|
|
100
|
+
server_public_key.verify(
|
|
101
|
+
signature_bytes,
|
|
102
|
+
data_to_verify,
|
|
103
|
+
ec.ECDSA(hashes.SHA256())
|
|
104
|
+
)
|
|
105
|
+
log_info("服务器签名验证成功")
|
|
106
|
+
server_cert_valid = self.__check_server_cert(server_cert)
|
|
107
|
+
if not server_cert_valid:
|
|
108
|
+
raise Exception("服务器证书验证失败")
|
|
109
|
+
except Exception as e:
|
|
110
|
+
server_cert_valid = False
|
|
111
|
+
raise Exception(f"{e}")
|
|
112
|
+
|
|
113
|
+
if not server_cert_valid:
|
|
114
|
+
raise Exception("服务器证书是无效证书,请注意通信安全")
|
|
115
|
+
|
|
116
|
+
if nonce:
|
|
117
|
+
signature = private_key.sign(
|
|
118
|
+
nonce.encode('utf-8'),
|
|
119
|
+
ec.ECDSA(hashes.SHA256())
|
|
120
|
+
)
|
|
121
|
+
data = {
|
|
122
|
+
"agent_id": self.agent_id,
|
|
123
|
+
"request_id": request_id,
|
|
124
|
+
"nonce": nonce,
|
|
125
|
+
"public_key": public_key_pem,
|
|
126
|
+
"cert": certificate_pem,
|
|
127
|
+
"signature": signature.hex(),
|
|
128
|
+
}
|
|
129
|
+
response = requests.post(hb_url, json=data, verify=False, headers=headers, proxies={}, timeout=self.HTTP_TIMEOUT)
|
|
130
|
+
if response.status_code == 200:
|
|
131
|
+
result = response.json()
|
|
132
|
+
self.signature = result.get("signature")
|
|
133
|
+
log_info("Sign in successful")
|
|
134
|
+
return result
|
|
135
|
+
else:
|
|
136
|
+
log_error(f"Sign in FAILED: {response.status_code} - {response.json().get('error', '')}")
|
|
137
|
+
else:
|
|
138
|
+
log_error(f"Sign in failed: {response.status_code} - {response.json().get('error', '')}")
|
|
139
|
+
|
|
140
|
+
except Exception as e:
|
|
141
|
+
log_warning(f"Sign in exception (retry {retry_count}/{max_retry_num}): {e}")
|
|
142
|
+
|
|
143
|
+
# 所有重试都失败
|
|
144
|
+
log_error(f"Sign in failed after {max_retry_num} retries, please check network connection")
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def __load_private_key(self, aid_path):
|
|
149
|
+
try:
|
|
150
|
+
with open(aid_path, "rb") as f:
|
|
151
|
+
private_key = serialization.load_pem_private_key(
|
|
152
|
+
f.read(),
|
|
153
|
+
password=self.seed_password.encode('utf-8'),
|
|
154
|
+
)
|
|
155
|
+
return private_key
|
|
156
|
+
except Exception as e:
|
|
157
|
+
# 兼容性代码,按照不加密获取 private_key
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
def sign_out(self) -> None:
|
|
161
|
+
"""登出方法"""
|
|
162
|
+
try:
|
|
163
|
+
if self.signature is None:
|
|
164
|
+
return
|
|
165
|
+
hb_url = self.server_url + "/sign_out"
|
|
166
|
+
data = {
|
|
167
|
+
"agent_id": self.agent_id,
|
|
168
|
+
"signature": self.signature,
|
|
169
|
+
}
|
|
170
|
+
headers = {
|
|
171
|
+
'User-Agent': f'AgentCP/{__import__("agentcp").__version__} (AuthClient; {self.agent_id})'
|
|
172
|
+
}
|
|
173
|
+
response = requests.post(hb_url, json=data, verify=False, headers=headers, proxies={}, timeout=self.HTTP_TIMEOUT)
|
|
174
|
+
if response.status_code == 200:
|
|
175
|
+
log_info(f"Sign out OK: {response.json()}")
|
|
176
|
+
else:
|
|
177
|
+
log_error(f"Sign out failed: {response.json()}")
|
|
178
|
+
except Exception as e:
|
|
179
|
+
log_exception("Sign out exception")
|
|
180
|
+
|
|
181
|
+
def __check_server_cert(self, server_cert):
|
|
182
|
+
try:
|
|
183
|
+
# 尝试获取主体的组织及 common name
|
|
184
|
+
try:
|
|
185
|
+
organization = server_cert.subject.get_attributes_for_oid(NameOID.ORGANIZATION_NAME)
|
|
186
|
+
common_name = server_cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)
|
|
187
|
+
if organization:
|
|
188
|
+
log_info(f"__check_server_cert 证书的组织名称为: {organization[0].value}")
|
|
189
|
+
else:
|
|
190
|
+
log_info("__check_server_cert 未找到证书的组织名称")
|
|
191
|
+
if common_name:
|
|
192
|
+
log_info(f"__check_server_cert 证书的通用名称为: {common_name[0].value}")
|
|
193
|
+
else:
|
|
194
|
+
log_info("__check_server_cert 未找到证书的通用名称")
|
|
195
|
+
except AttributeError:
|
|
196
|
+
log_error("获取证书主体信息时出错,可能证书对象不存在或格式不正确。")
|
|
197
|
+
return False
|
|
198
|
+
aia_ext = server_cert.extensions.get_extension_for_class(x509.AuthorityInformationAccess)
|
|
199
|
+
log_info(f"aia_ext:{aia_ext}")
|
|
200
|
+
issuer_url = None
|
|
201
|
+
for desc in aia_ext.value:
|
|
202
|
+
if desc.access_method == x509.oid.AuthorityInformationAccessOID.CA_ISSUERS:
|
|
203
|
+
issuer_url = desc.access_location.value
|
|
204
|
+
break
|
|
205
|
+
|
|
206
|
+
if issuer_url:
|
|
207
|
+
log_info(f"证书颁发者 URL: {issuer_url}")
|
|
208
|
+
if issuer_url in AuthClient.success_crt_list:
|
|
209
|
+
log_info(f"证书之前验证成功 {issuer_url}")
|
|
210
|
+
return True
|
|
211
|
+
try:
|
|
212
|
+
issuer_response = requests.get(issuer_url, verify=False, proxies={}, timeout=self.HTTP_TIMEOUT)
|
|
213
|
+
issuer_response.raise_for_status()
|
|
214
|
+
#TODO:将证书内存以issuer_url为键值缓存在本地,避免重复下载和验证证书
|
|
215
|
+
issuer_cert = x509.load_pem_x509_certificate(issuer_response.content, default_backend())
|
|
216
|
+
# 验证服务器证书的有效性
|
|
217
|
+
issuer_public_key = issuer_cert.public_key()
|
|
218
|
+
issuer_public_key.verify(
|
|
219
|
+
server_cert.signature,
|
|
220
|
+
server_cert.tbs_certificate_bytes,
|
|
221
|
+
ec.ECDSA(server_cert.signature_hash_algorithm)
|
|
222
|
+
)
|
|
223
|
+
#TODO标记证书是受信任的
|
|
224
|
+
log_info(f"证书验证成功 {issuer_url}")
|
|
225
|
+
AuthClient.success_crt_list.append(issuer_url)
|
|
226
|
+
return self.__check_server_cert(issuer_cert)
|
|
227
|
+
except requests.RequestException as e:
|
|
228
|
+
log_error(f"下载证书颁发者证书时出错: {e}")
|
|
229
|
+
return False
|
|
230
|
+
except Exception as e:
|
|
231
|
+
log_error(f"验证证书时出错: {e}")
|
|
232
|
+
return False
|
|
233
|
+
else:
|
|
234
|
+
log_error("未找到证书颁发者信息")
|
|
235
|
+
return False
|
|
236
|
+
except x509.ExtensionNotFound:
|
|
237
|
+
log_error("证书中未包含 AIA 扩展信息")
|
|
238
|
+
try:
|
|
239
|
+
root_cert_pem = CARoot().get_ca_root_crt()
|
|
240
|
+
root_cert = x509.load_pem_x509_certificate(root_cert_pem.encode('utf-8'), default_backend())
|
|
241
|
+
root_public_key = root_cert.public_key()
|
|
242
|
+
root_public_key.verify(
|
|
243
|
+
server_cert.signature,
|
|
244
|
+
server_cert.tbs_certificate_bytes,
|
|
245
|
+
ec.ECDSA(server_cert.signature_hash_algorithm)
|
|
246
|
+
)
|
|
247
|
+
log_info("用root.crt 证书进行验证成功")
|
|
248
|
+
return True
|
|
249
|
+
except FileNotFoundError:
|
|
250
|
+
log_error("未找到 root.crt 文件,请检查文件路径。")
|
|
251
|
+
return False
|
|
252
|
+
except Exception as e:
|
|
253
|
+
log_error(f"加载 root.crt 证书时出错: {e}")
|
|
254
|
+
return False
|
|
255
|
+
except Exception as e:
|
|
256
|
+
log_error(f"服务器证书验证失败: {e}")
|
|
257
|
+
return False
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright 2025 AgentUnion Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
import abc
|
|
16
|
+
import requests
|
|
17
|
+
|
|
18
|
+
from agentcp.base.log import log_error, log_info
|
|
19
|
+
from agentcp.utils.proxy_bypass import ensure_no_proxy_for_local_env, get_requests_proxies
|
|
20
|
+
|
|
21
|
+
ensure_no_proxy_for_local_env()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class IClient(abc.ABC):
|
|
25
|
+
def __init__(self):
|
|
26
|
+
self._agent_id_ref = None
|
|
27
|
+
|
|
28
|
+
def set_agent_id_ref(self, agent_id_ref):
|
|
29
|
+
"""设置AgentID引用,用于获取代理配置"""
|
|
30
|
+
self._agent_id_ref = agent_id_ref
|
|
31
|
+
|
|
32
|
+
def _get_proxies(self, url: str):
|
|
33
|
+
"""获取 requests 代理配置;agentcp 内部本地/远程一律直连。"""
|
|
34
|
+
return get_requests_proxies(False, url)
|
|
35
|
+
|
|
36
|
+
@abc.abstractmethod
|
|
37
|
+
def sign_in(self) -> bool:
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
@abc.abstractmethod
|
|
41
|
+
def get_headers(self) -> dict:
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
@abc.abstractmethod
|
|
45
|
+
def sign_out(self):
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_request(self,url: str, params: dict = None, headers: dict = None,is_retry=True) -> requests.Response:
|
|
50
|
+
"""
|
|
51
|
+
发送GET请求的通用方法
|
|
52
|
+
Args:
|
|
53
|
+
url (str): 请求的URL
|
|
54
|
+
params (dict, optional): 请求参数. Defaults to None.
|
|
55
|
+
headers (dict, optional): 请求头. Defaults to None.
|
|
56
|
+
Returns:
|
|
57
|
+
requests.Response: 响应对象
|
|
58
|
+
"""
|
|
59
|
+
try:
|
|
60
|
+
common_headers = self.get_headers()
|
|
61
|
+
if headers:
|
|
62
|
+
common_headers = {**common_headers, **headers}
|
|
63
|
+
proxies = self._get_proxies(url)
|
|
64
|
+
response = requests.get(url, params=params, headers=common_headers, verify=False, proxies=proxies)
|
|
65
|
+
response.raise_for_status()
|
|
66
|
+
if response.status_code == 200:
|
|
67
|
+
return response
|
|
68
|
+
else:
|
|
69
|
+
error = response.json().get("error", "")
|
|
70
|
+
log_error(f"请求失败,错误详情: {error}")
|
|
71
|
+
if response.status_code == 401 and is_retry:
|
|
72
|
+
log_info("尝试重新登录...")
|
|
73
|
+
if self.sign_in():
|
|
74
|
+
return self.get_request(url, params=params, headers=common_headers, is_retry=False)
|
|
75
|
+
return response
|
|
76
|
+
except requests.exceptions.RequestException as e:
|
|
77
|
+
log_error(f"请求失败: {e}")
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def post_request(self, url: str, data: dict = None, json: dict = None, headers: dict = None, is_retry=True) -> requests.Response:
|
|
82
|
+
"""
|
|
83
|
+
发送POST请求的通用方法
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
url (str): 请求的URL
|
|
87
|
+
data (dict, optional): 表单数据. Defaults to None.
|
|
88
|
+
json (dict, optional): JSON数据. Defaults to None.
|
|
89
|
+
headers (dict, optional): 请求头. Defaults to None.
|
|
90
|
+
is_retry (bool, optional): 是否重试. Defaults to True.
|
|
91
|
+
Returns:
|
|
92
|
+
requests.Response: 响应对象
|
|
93
|
+
"""
|
|
94
|
+
try:
|
|
95
|
+
common_headers = self.get_headers()
|
|
96
|
+
if headers:
|
|
97
|
+
common_headers = {**common_headers, **headers}
|
|
98
|
+
proxies = self._get_proxies(url)
|
|
99
|
+
response = requests.post(url, data=data, json=json, headers=common_headers, verify=False, proxies=proxies)
|
|
100
|
+
if response.status_code == 200:
|
|
101
|
+
return response
|
|
102
|
+
else:
|
|
103
|
+
error = response.json().get("error", "")
|
|
104
|
+
log_error(f"请求失败,错误详情: {error}")
|
|
105
|
+
if response.status_code == 401 and is_retry:
|
|
106
|
+
log_info("尝试重新登录...")
|
|
107
|
+
if self.sign_in():
|
|
108
|
+
return self.post_request(url, data=data, json=json, headers=common_headers, is_retry=False)
|
|
109
|
+
return response
|
|
110
|
+
except requests.exceptions.RequestException as e:
|
|
111
|
+
log_error(f"请求失败: {e}")
|
|
112
|
+
raise
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright 2025 AgentUnion Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
import enum
|
|
16
|
+
import os
|
|
17
|
+
|
|
18
|
+
class Environ(enum.Enum):
|
|
19
|
+
"""
|
|
20
|
+
Environment for the agent.
|
|
21
|
+
"""
|
|
22
|
+
# Define the environments
|
|
23
|
+
ENTRY_SERVER = "ENTRY_SERVER"
|
|
24
|
+
LOG_LEVEL = "LOG_LEVEL"
|
|
25
|
+
CA_SERVER = "CA_SERVER"
|
|
26
|
+
|
|
27
|
+
def __str__(self):
|
|
28
|
+
return self.value
|
|
29
|
+
|
|
30
|
+
def get(self, default=None):
|
|
31
|
+
"""
|
|
32
|
+
Get the environment variable value.
|
|
33
|
+
"""
|
|
34
|
+
return os.environ.get(self.value, default)
|