Add AI test, doctor, and interactive setup wizard
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QKxGW1raAWaqeU8WdHsMsp
This commit is contained in:
Executable
+47
@@ -0,0 +1,47 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# omarchy:summary=Check AI harness installation, credentials, and endpoint health
|
||||||
|
# omarchy:examples=omarchycn ai doctor
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$OMARCHY_PATH/cn/lib/ai.sh"
|
||||||
|
|
||||||
|
failures=0
|
||||||
|
|
||||||
|
profile=$(cn_ai_current_profile 2>/dev/null || true)
|
||||||
|
if [[ -z $profile ]]; then
|
||||||
|
echo "INFO ai: 未设置默认 Profile (omarchycn ai profile use <name>)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "INFO ai: current profile $profile"
|
||||||
|
|
||||||
|
harness=$(cn_ai_profile_field "$profile" harness)
|
||||||
|
provider=$(cn_ai_profile_field "$profile" provider)
|
||||||
|
command=$(cn_ai_harness_field "$harness" command)
|
||||||
|
proto=$(cn_ai_harness_field "$harness" protocol)
|
||||||
|
|
||||||
|
if command -v "$command" > /dev/null 2>&1; then
|
||||||
|
echo "PASS ai: harness $harness installed ($command)"
|
||||||
|
else
|
||||||
|
echo "WARN ai: harness $harness 未安装,首次 launch 时自动安装"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if omarchy-cn-ai-secret get "$provider" > /dev/null 2>&1; then
|
||||||
|
echo "PASS ai: $provider API Key stored"
|
||||||
|
else
|
||||||
|
echo "FAIL ai: $provider API Key 未存储 (omarchycn ai secret set $provider)"
|
||||||
|
failures=$((failures + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $proto != "native" ]]; then
|
||||||
|
base=$(cn_ai_endpoint "$provider" "$proto")
|
||||||
|
host=$(sed -E 's|https?://([^/]+).*|\1|' <<<"$base")
|
||||||
|
if getent hosts "$host" > /dev/null 2>&1; then
|
||||||
|
echo "PASS ai: endpoint DNS resolves ($host)"
|
||||||
|
else
|
||||||
|
echo "FAIL ai: endpoint DNS 无法解析 ($host)"
|
||||||
|
failures=$((failures + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit $((failures > 0 ? 1 : 0))
|
||||||
Executable
+46
@@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# omarchy:summary=Interactive wizard: pick harness, provider, model, store key, test
|
||||||
|
# omarchy:examples=omarchycn ai setup
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$OMARCHY_PATH/cn/lib/ai.sh"
|
||||||
|
|
||||||
|
if [[ ! -t 0 ]]; then
|
||||||
|
echo "omarchycn ai setup 需要交互终端;非交互场景用 omarchycn ai profile create" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
harness=$(cn_ai_harness_ids | gum choose --header "选择 Harness")
|
||||||
|
|
||||||
|
mapfile -t providers < <(jq -r --arg h "$harness" '.combos[$h] | keys[]' "$CN_AI_COMPAT")
|
||||||
|
if (( ${#providers[@]} == 0 )); then
|
||||||
|
echo "兼容矩阵中没有 $harness 的 Provider 组合" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
provider=$(printf '%s\n' "${providers[@]}" | gum choose --header "选择 Provider(兼容级别见 docs)")
|
||||||
|
|
||||||
|
allowlist=$(cn_ai_combo_models "$harness" "$provider")
|
||||||
|
if [[ -n $allowlist ]]; then
|
||||||
|
model=$(gum choose --header "选择模型" <<<"$allowlist")
|
||||||
|
else
|
||||||
|
model=$(cn_ai_models "$provider" | gum choose --header "选择模型")
|
||||||
|
fi
|
||||||
|
|
||||||
|
default_name="$harness-$provider"
|
||||||
|
name=$(gum input --header "Profile 名称" --value "$default_name")
|
||||||
|
|
||||||
|
if ! omarchy-cn-ai-secret get "$provider" > /dev/null 2>&1; then
|
||||||
|
key=$(gum input --password --header "$provider API Key(获取: $(jq -r --arg p "$provider" '.providers[$p].key_url' "$CN_AI_PROVIDERS"))")
|
||||||
|
printf '%s' "$key" | omarchy-cn-ai-secret set "$provider"
|
||||||
|
fi
|
||||||
|
|
||||||
|
omarchy-cn-ai-profile-create "$name" "$harness" "$provider" "$model"
|
||||||
|
omarchy-cn-ai-profile-use "$name"
|
||||||
|
|
||||||
|
proto=$(cn_ai_harness_field "$harness" protocol)
|
||||||
|
if [[ $proto != "native" ]] && gum confirm "运行连接测试?"; then
|
||||||
|
omarchy-cn-ai-test "$name"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "完成。启动: omarchycn ai launch"
|
||||||
Executable
+82
@@ -0,0 +1,82 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# omarchy:summary=Test connectivity, auth, and model availability for an AI profile
|
||||||
|
# omarchy:args=[profile]
|
||||||
|
# omarchy:examples=omarchycn ai test | omarchycn ai test work
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$OMARCHY_PATH/cn/lib/ai.sh"
|
||||||
|
|
||||||
|
profile="${1:-$(cn_ai_current_profile)}"
|
||||||
|
|
||||||
|
if [[ ! -f $CN_AI_PROFILE_DIR/$profile.toml ]]; then
|
||||||
|
echo "No such profile: $profile" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
harness=$(cn_ai_profile_field "$profile" harness)
|
||||||
|
provider=$(cn_ai_profile_field "$profile" provider)
|
||||||
|
model=$(cn_ai_profile_field "$profile" model)
|
||||||
|
proto=$(cn_ai_harness_field "$harness" protocol)
|
||||||
|
failures=0
|
||||||
|
|
||||||
|
if [[ $proto == "native" ]]; then
|
||||||
|
echo "INFO ai-test: $harness 自管鉴权,本测试仅覆盖 env/config 型 Harness"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Endpoint override for mock-server tests
|
||||||
|
base="${OMARCHYCN_AI_TEST_BASE_URL:-$(cn_ai_endpoint "$provider" "$proto")}"
|
||||||
|
echo "INFO ai-test: $profile ($harness x $provider x $model) -> $base"
|
||||||
|
|
||||||
|
if ! key=$(omarchy-cn-ai-secret get "$provider" 2>/dev/null); then
|
||||||
|
echo "FAIL ai-test: 未存储 $provider 的 API Key (omarchycn ai secret set $provider)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$proto" in
|
||||||
|
anthropic)
|
||||||
|
code=$(curl -sS -o /tmp/omarchycn-ai-test-body -w '%{http_code}' -m 30 --connect-timeout 8 \
|
||||||
|
-X POST "${base%/}/v1/messages" \
|
||||||
|
-H "x-api-key: $key" -H "authorization: Bearer $key" \
|
||||||
|
-H "anthropic-version: 2023-06-01" -H "content-type: application/json" \
|
||||||
|
-d "{\"model\":\"$model\",\"max_tokens\":8,\"messages\":[{\"role\":\"user\",\"content\":\"ping\"}]}" || echo 000)
|
||||||
|
;;
|
||||||
|
openai)
|
||||||
|
code=$(curl -sS -o /tmp/omarchycn-ai-test-body -w '%{http_code}' -m 30 --connect-timeout 8 \
|
||||||
|
-X POST "${base%/}/chat/completions" \
|
||||||
|
-H "Authorization: Bearer $key" -H "content-type: application/json" \
|
||||||
|
-d "{\"model\":\"$model\",\"max_tokens\":8,\"messages\":[{\"role\":\"user\",\"content\":\"ping\"}]}" || echo 000)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "FAIL ai-test: unknown protocol $proto"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$code" in
|
||||||
|
200)
|
||||||
|
echo "PASS ai-test: 连接、鉴权与模型调用成功 (HTTP 200)"
|
||||||
|
;;
|
||||||
|
401 | 403)
|
||||||
|
echo "FAIL ai-test: 鉴权失败 (HTTP $code),检查 API Key"
|
||||||
|
failures=$((failures + 1))
|
||||||
|
;;
|
||||||
|
404 | 400 | 422)
|
||||||
|
echo "FAIL ai-test: 端点可达但请求被拒 (HTTP $code),可能是模型名问题"
|
||||||
|
head -c 200 /tmp/omarchycn-ai-test-body 2>/dev/null && echo
|
||||||
|
failures=$((failures + 1))
|
||||||
|
;;
|
||||||
|
000)
|
||||||
|
echo "FAIL ai-test: 无法连接 $base (DNS/TLS/网络)"
|
||||||
|
failures=$((failures + 1))
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "FAIL ai-test: HTTP $code"
|
||||||
|
head -c 200 /tmp/omarchycn-ai-test-body 2>/dev/null && echo
|
||||||
|
failures=$((failures + 1))
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
rm -f /tmp/omarchycn-ai-test-body
|
||||||
|
exit $((failures > 0 ? 1 : 0))
|
||||||
Reference in New Issue
Block a user