Ollama v0.14+ speaks the Anthropic Messages API natively, so the registry drives it with a fixed 'ollama' token and runtime-listed models: static_token skips secret storage everywhere keys resolve, models_dynamic defers model validation to the live /api/tags list, and the setup wizard installs the right GPU variant and starts the service before listing local models. Doctor stops treating the endpoint port as part of the hostname. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019hLK3wsDuKVAC37GgDqg6H
95 lines
3.0 KiB
Bash
Executable File
95 lines
3.0 KiB
Bash
Executable File
#!/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)
|
|
# Codex speaks the Responses API (wire_api=responses), not chat/completions
|
|
[[ $harness == "codex" ]] && proto="openai-responses"
|
|
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%-responses}")}"
|
|
echo "INFO ai-test: $profile ($harness x $provider x $model) -> $base"
|
|
|
|
if ! key=$(cn_ai_resolve_key "$provider" 2>/dev/null); then
|
|
echo "FAIL ai-test: 未存储 $provider 的 API Key (omarchycn ai secret set $provider)"
|
|
exit 1
|
|
fi
|
|
|
|
body=$(mktemp)
|
|
trap 'rm -f "$body"' EXIT
|
|
|
|
case "$proto" in
|
|
anthropic)
|
|
code=$(curl -sS -o "$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\"}]}" || true)
|
|
;;
|
|
openai)
|
|
code=$(curl -sS -o "$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\"}]}" || true)
|
|
;;
|
|
openai-responses)
|
|
code=$(curl -sS -o "$body" -w '%{http_code}' -m 30 --connect-timeout 8 \
|
|
-X POST "${base%/}/responses" \
|
|
-H "Authorization: Bearer $key" -H "content-type: application/json" \
|
|
-d "{\"model\":\"$model\",\"input\":\"ping\",\"max_output_tokens\":16}" || true)
|
|
;;
|
|
*)
|
|
echo "FAIL ai-test: unknown protocol $proto"
|
|
exit 1
|
|
;;
|
|
esac
|
|
[[ -z $code ]] && code=000
|
|
|
|
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 "$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 "$body" 2>/dev/null && echo
|
|
failures=$((failures + 1))
|
|
;;
|
|
esac
|
|
|
|
rm -f $body
|
|
exit $((failures > 0 ? 1 : 0))
|