From d2ccc47bc18d5740a163fa7e35131d34ad4980e4 Mon Sep 17 00:00:00 2001 From: CYJiang Date: Fri, 22 May 2026 13:23:21 +0800 Subject: [PATCH 1/2] =?UTF-8?q?install:=20=E5=AE=89=E8=A3=85=E5=89=8D?= =?UTF-8?q?=E6=8E=A2=E6=B5=8B=E4=B8=80=E4=B8=8B=20routing=20=E5=92=8C=20up?= =?UTF-8?q?stream=20model=20=E6=98=AF=E5=90=A6=E8=83=BD=E9=80=9A=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E9=80=9A=E5=B0=B1=E6=8F=90=E7=A4=BA=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E7=BB=A7=E7=BB=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/install.sh | 122 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/scripts/install.sh b/scripts/install.sh index e9a0053..314100b 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -40,6 +40,110 @@ prompt_required() { done } +probe_model_endpoint() { + local label="$1" + local base_url="$2" + local api_key="$3" + local model="$4" + local with_tools="$5" + local output + output=$(LABEL="$label" BASE_URL="$base_url" API_KEY="$api_key" MODEL="$model" WITH_TOOLS="$with_tools" python3 - <<'PY' +import json +import os +import re +import socket +import sys +import urllib.error +import urllib.request + +base_url = os.environ["BASE_URL"].rstrip("/") +raw_key = os.environ["API_KEY"] +model = os.environ["MODEL"] +with_tools = os.environ["WITH_TOOLS"] == "1" + +m = re.fullmatch(r"\$\{([A-Z_][A-Z0-9_]*)\}", raw_key) +if m: + resolved = os.environ.get(m.group(1)) + if resolved is None: + sys.stderr.write(f"warning: API key references {raw_key} but it is not set in this shell\n") + key = raw_key + else: + key = resolved +elif raw_key == "" or raw_key.lower() == "any": + key = "any" +else: + key = raw_key + +url = f"{base_url}/chat/completions" +body = { + "model": model, + "messages": [{"role": "user", "content": "ping"}], + "max_tokens": 1, +} +if with_tools: + body["tools"] = [{ + "type": "function", + "function": { + "name": "ping", + "description": "connectivity probe", + "parameters": {"type": "object", "properties": {}}, + }, + }] + +req = urllib.request.Request( + url, + data=json.dumps(body).encode("utf-8"), + headers={ + "Content-Type": "application/json", + "Authorization": f"Bearer {key}", + }, + method="POST", +) + +def emit(status, detail): + print(f"{status}\t{url}\t{detail}") + +try: + with urllib.request.urlopen(req, timeout=10) as resp: + code = resp.getcode() + raw = resp.read(2048).decode("utf-8", errors="replace") + if 200 <= code < 300: + emit("OK", model) + sys.exit(0) + emit("FAIL", f"HTTP {code}: {raw[:200]}") + sys.exit(1) +except urllib.error.HTTPError as e: + raw = "" + try: + raw = e.read(2048).decode("utf-8", errors="replace") + except Exception: + pass + emit("FAIL", f"HTTP {e.code}: {raw[:200]}") + sys.exit(1) +except socket.timeout: + emit("FAIL", "Timed out after 10s") + sys.exit(1) +except urllib.error.URLError as e: + emit("FAIL", f"Connection error: {e.reason!r}") + sys.exit(1) +except Exception as e: + emit("FAIL", f"Unexpected error: {e!r}") + sys.exit(1) +PY +) + local probe_exit=$? + local status_field url_field detail_field + IFS=$'\t' read -r status_field url_field detail_field <<< "$output" + if [ "$probe_exit" -eq 0 ] && [ "$status_field" = "OK" ]; then + printf ' \u2713 %s model reachable: %s\n' "$label" "$detail_field" + return 0 + fi + printf ' \u2717 %s model check failed:\n' "$label" + printf ' URL: %s\n' "$url_field" + printf ' %s\n' "$detail_field" + return 1 +} + prompt_yes_no() { local prompt_en="$1" local prompt_zh="$2" @@ -267,6 +371,24 @@ echo " 示例值: /home/mt/tools" TOOLS_BASE_DIR=$(prompt_default " Tools base directory" " 工具根目录" "$HOME/.function-router/scripts") OPENCLAW_CONFIG=$(prompt_default " OpenClaw config path" " OpenClaw 配置路径" "$DEFAULT_OPENCLAW_CONFIG") +echo +echo "── Verifying model endpoints / 验证模型连通性 ──" +ROUTING_OK=1 +UPSTREAM_OK=1 +probe_model_endpoint "Routing" "$ROUTING_BASE_URL" "$ROUTING_API_KEY" "$ROUTING_MODEL" 1 || ROUTING_OK=0 +probe_model_endpoint "Upstream" "$UPSTREAM_BASE_URL" "$UPSTREAM_API_KEY" "$UPSTREAM_MODEL" 0 || UPSTREAM_OK=0 + +if [ "$ROUTING_OK" -ne 1 ] || [ "$UPSTREAM_OK" -ne 1 ]; then + echo + CONTINUE_ANYWAY=$(prompt_yes_no "One or more model checks failed. Continue install anyway?" "一个或多个模型检测失败,是否仍要继续安装?" "N") + if [ "$CONTINUE_ANYWAY" != "yes" ]; then + echo "Aborted. No files were modified." + echo "已中止,未修改任何文件。" + exit 1 + fi +fi +echo + mkdir -p "$TARGET_DIR" "$SCRIPTS_DIR" "$LOGS_DIR" cp "$REPO_ROOT/examples/config.example.json" "$CONFIG_PATH" cp "$REPO_ROOT/examples/functions.example.jsonl" "$FUNCTIONS_PATH" From e6fef1bd30d1a1889f722836f6768cb3a7b9563f Mon Sep 17 00:00:00 2001 From: CYJiang Date: Mon, 25 May 2026 13:44:07 +0800 Subject: [PATCH 2/2] =?UTF-8?q?install:=20=E9=85=8D=E5=AE=8C=E6=AF=8F?= =?UTF-8?q?=E4=B8=AA=20model=20=E7=AB=8B=E5=88=BB=E6=8E=A2=E6=B5=8B?= =?UTF-8?q?=E4=B8=80=E6=AC=A1=EF=BC=8C=E8=AE=A9=E7=94=A8=E6=88=B7=E5=8D=B3?= =?UTF-8?q?=E6=97=B6=E7=9C=8B=E5=88=B0=20provider=20=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E5=8F=AF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- scripts/install.sh | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/scripts/install.sh b/scripts/install.sh index 314100b..c22620a 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -325,6 +325,16 @@ ROUTING_BASE_URL=$(prompt_default " Base URL (OpenAI-compatible endpoint)" " ROUTING_MODEL=$(prompt_default " Model name" " 模型名" "your-tool-calling-model") ROUTING_API_KEY=$(prompt_default " API key (use 'any' if no auth needed)" " API key(如果不需要鉴权可填 any)" "${ROUTING_API_KEY:-any}") +echo +if ! probe_model_endpoint "Routing" "$ROUTING_BASE_URL" "$ROUTING_API_KEY" "$ROUTING_MODEL" 1; then + CONTINUE_ANYWAY=$(prompt_yes_no "Routing model check failed. Continue install anyway?" "路由模型检测失败,是否仍要继续安装?" "N") + if [ "$CONTINUE_ANYWAY" != "yes" ]; then + echo "Aborted. No files were modified." + echo "已中止,未修改任何文件。" + exit 1 + fi +fi + echo if [ "$USE_OPENCLAW_DEFAULT" = "yes" ]; then echo "── Upstream LLM (main response model) ──" @@ -352,6 +362,16 @@ else UPSTREAM_MODEL=$(prompt_default " Model name" " 模型名" "$DEFAULT_UPSTREAM_MODEL") fi +echo +if ! probe_model_endpoint "Upstream" "$UPSTREAM_BASE_URL" "$UPSTREAM_API_KEY" "$UPSTREAM_MODEL" 0; then + CONTINUE_ANYWAY=$(prompt_yes_no "Upstream model check failed. Continue install anyway?" "上游模型检测失败,是否仍要继续安装?" "N") + if [ "$CONTINUE_ANYWAY" != "yes" ]; then + echo "Aborted. No files were modified." + echo "已中止,未修改任何文件。" + exit 1 + fi +fi + echo echo "── General ──" @@ -371,22 +391,6 @@ echo " 示例值: /home/mt/tools" TOOLS_BASE_DIR=$(prompt_default " Tools base directory" " 工具根目录" "$HOME/.function-router/scripts") OPENCLAW_CONFIG=$(prompt_default " OpenClaw config path" " OpenClaw 配置路径" "$DEFAULT_OPENCLAW_CONFIG") -echo -echo "── Verifying model endpoints / 验证模型连通性 ──" -ROUTING_OK=1 -UPSTREAM_OK=1 -probe_model_endpoint "Routing" "$ROUTING_BASE_URL" "$ROUTING_API_KEY" "$ROUTING_MODEL" 1 || ROUTING_OK=0 -probe_model_endpoint "Upstream" "$UPSTREAM_BASE_URL" "$UPSTREAM_API_KEY" "$UPSTREAM_MODEL" 0 || UPSTREAM_OK=0 - -if [ "$ROUTING_OK" -ne 1 ] || [ "$UPSTREAM_OK" -ne 1 ]; then - echo - CONTINUE_ANYWAY=$(prompt_yes_no "One or more model checks failed. Continue install anyway?" "一个或多个模型检测失败,是否仍要继续安装?" "N") - if [ "$CONTINUE_ANYWAY" != "yes" ]; then - echo "Aborted. No files were modified." - echo "已中止,未修改任何文件。" - exit 1 - fi -fi echo mkdir -p "$TARGET_DIR" "$SCRIPTS_DIR" "$LOGS_DIR"