From 07568286fc606a392444ba11a4777efc54dd70c3 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 3 Mar 2026 21:49:57 +0800 Subject: [PATCH] feat: add first-run confirmation dialog for stream check Show an informational dialog when users first click the health check button, explaining its limitations (OAuth providers, relay services, Bedrock). The dialog persists the confirmation in settings so it only appears once per device. --- src-tauri/src/settings.rs | 4 ++ src/components/providers/ProviderList.tsx | 48 ++++++++++++++++++++++- src/i18n/locales/en.json | 5 +++ src/i18n/locales/ja.json | 5 +++ src/i18n/locales/zh.json | 5 +++ src/types.ts | 2 + 6 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/settings.rs b/src-tauri/src/settings.rs index 8ee07e60b..a972d5131 100644 --- a/src-tauri/src/settings.rs +++ b/src-tauri/src/settings.rs @@ -196,6 +196,9 @@ pub struct AppSettings { /// User has confirmed the usage query first-run notice #[serde(default, skip_serializing_if = "Option::is_none")] pub usage_confirmed: Option, + /// User has confirmed the stream check first-run notice + #[serde(default, skip_serializing_if = "Option::is_none")] + pub stream_check_confirmed: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub language: Option, @@ -282,6 +285,7 @@ impl Default for AppSettings { enable_local_proxy: false, proxy_confirmed: None, usage_confirmed: None, + stream_check_confirmed: None, language: None, visible_apps: None, claude_config_dir: None, diff --git a/src/components/providers/ProviderList.tsx b/src/components/providers/ProviderList.tsx index b95576d8c..6b8c8f453 100644 --- a/src/components/providers/ProviderList.tsx +++ b/src/components/providers/ProviderList.tsx @@ -41,6 +41,8 @@ import { import { useCallback } from "react"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; +import { ConfirmDialog } from "@/components/ConfirmDialog"; +import { settingsApi } from "@/lib/api/settings"; interface ProviderListProps { providers: Record; @@ -176,14 +178,43 @@ export function ProviderList({ const [searchTerm, setSearchTerm] = useState(""); const [isSearchOpen, setIsSearchOpen] = useState(false); const searchInputRef = useRef(null); + const [showStreamCheckConfirm, setShowStreamCheckConfirm] = useState(false); + const [pendingTestProvider, setPendingTestProvider] = useState(null); + + // Query settings for streamCheckConfirmed flag + const { data: settings } = useQuery({ + queryKey: ["settings"], + queryFn: () => settingsApi.get(), + }); const handleTest = useCallback( (provider: Provider) => { - checkProvider(provider.id, provider.name); + if (!settings?.streamCheckConfirmed) { + setPendingTestProvider(provider); + setShowStreamCheckConfirm(true); + } else { + checkProvider(provider.id, provider.name); + } }, - [checkProvider], + [checkProvider, settings?.streamCheckConfirmed], ); + const handleStreamCheckConfirm = async () => { + setShowStreamCheckConfirm(false); + try { + if (settings) { + await settingsApi.save({ ...settings, streamCheckConfirmed: true }); + await queryClient.invalidateQueries({ queryKey: ["settings"] }); + } + } catch (error) { + console.error("Failed to save stream check confirmed:", error); + } + if (pendingTestProvider) { + checkProvider(pendingTestProvider.id, pendingTestProvider.name); + setPendingTestProvider(null); + } + }; + // Import current live config as default provider const queryClient = useQueryClient(); const importMutation = useMutation({ @@ -417,6 +448,19 @@ export function ProviderList({ ) : ( renderProviderList() )} + + void handleStreamCheckConfirm()} + onCancel={() => { + setShowStreamCheckConfirm(false); + setPendingTestProvider(null); + }} + /> ); } diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index fccbaa456..0a540232e 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -191,6 +191,11 @@ "title": "Configure Usage Query", "message": "Usage query requires a custom script or API parameters. Please make sure you have obtained the necessary information from your provider.\n\nIf unsure how to configure, please consult your provider's documentation first.", "confirm": "I understand, configure" + }, + "streamCheck": { + "title": "Model Health Check", + "message": "Health check tests provider connectivity by sending a direct API request. The following may cause check failures:\n\n• Official providers (uses OAuth login, no standalone API Key)\n• Some relay services (verify requests come from Claude Code CLI)\n• AWS Bedrock (uses IAM signature authentication)\n\nA failed check does not mean the provider is unusable — it only means it cannot be verified via a standalone request. Please refer to actual behavior within the application.", + "confirm": "I understand, proceed" } }, "settings": { diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index f6b5508d6..0e0fc72b1 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -191,6 +191,11 @@ "title": "使用量クエリの設定", "message": "使用量クエリにはカスタムスクリプトまたは API パラメータが必要です。プロバイダーから必要な情報を取得していることをご確認ください。\n\n設定方法が不明な場合は、プロバイダーのドキュメントを先にご確認ください。", "confirm": "理解しました、設定する" + }, + "streamCheck": { + "title": "モデルヘルスチェック", + "message": "ヘルスチェックは API リクエストを直接送信してプロバイダーの接続性をテストします。以下の場合、チェックが失敗する可能性があります:\n\n• 公式プロバイダー(OAuth ログイン使用、独立した API キーなし)\n• 一部の中継サービス(リクエストが Claude Code CLI からのものか検証)\n• AWS Bedrock(IAM 署名認証を使用)\n\nチェック失敗はプロバイダーが使用不能であることを意味しません。独立したリクエストでの検証ができないことを示すだけです。アプリ内の実際の動作を基準にしてください。", + "confirm": "理解しました、続行する" } }, "settings": { diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index 0fe3901c3..f18782cd1 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -191,6 +191,11 @@ "title": "配置用量查询", "message": "用量查询需要配置专用的查询脚本或 API 参数,请确保您已从供应商处获取相关信息。\n\n如不确定如何配置,请先查阅供应商文档。", "confirm": "我已了解,继续配置" + }, + "streamCheck": { + "title": "模型健康检测", + "message": "健康检测通过直接发送 API 请求来测试供应商连通性,以下情况可能导致检测失败:\n\n• 官方供应商(使用 OAuth 登录,无独立 API Key)\n• 部分中转服务(会校验请求是否来自 Claude Code CLI)\n• AWS Bedrock(使用 IAM 签名认证)\n\n检测失败不代表供应商不可用,仅表示无法通过独立请求验证。请以应用内的实际情况为准。", + "confirm": "我已了解,继续检测" } }, "settings": { diff --git a/src/types.ts b/src/types.ts index eda850887..72d25e08f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -219,6 +219,8 @@ export interface Settings { proxyConfirmed?: boolean; // User has confirmed the usage query first-run notice usageConfirmed?: boolean; + // User has confirmed the stream check first-run notice + streamCheckConfirmed?: boolean; // 首选语言(可选,默认中文) language?: "en" | "zh" | "ja";