refine(usage): enhance query robustness and error handling

Backend improvements:
- Add InvalidHttpMethod error enum for better error semantics
- Clamp HTTP timeout to 2-30s to prevent config abuse
- Strict HTTP method validation instead of silent fallback to GET

Frontend improvements:
- Add i18n support for usage query errors (en/zh)
- Improve error handling with type-safe unknown instead of any
- Optimize i18n import (direct import instead of dynamic)
- Disable auto-retry for usage queries to avoid API stampede

Additional changes:
- Apply prettier formatting to affected files

Files changed:
- src-tauri/src/error.rs (+2)
- src-tauri/src/usage_script.rs (+8 -2)
- src/i18n/locales/{en,zh}.json (+4 -1 each)
- src/lib/api/usage.ts (+21 -4)
- src/lib/query/queries.ts (+1)
- style: prettier formatting on 6 other files
This commit is contained in:
Jason
2025-11-03 10:24:59 +08:00
parent ab2833e626
commit 85334d8dce
12 changed files with 94 additions and 36 deletions

View File

@@ -166,7 +166,9 @@ export function ClaudeFormFields({
id="claudeModel"
type="text"
value={claudeModel}
onChange={(e) => onModelChange("ANTHROPIC_MODEL", e.target.value)}
onChange={(e) =>
onModelChange("ANTHROPIC_MODEL", e.target.value)
}
placeholder={t("providerForm.modelPlaceholder", {
defaultValue: "claude-3-7-sonnet-20250219",
})}
@@ -177,7 +179,9 @@ export function ClaudeFormFields({
{/* 默认 Haiku */}
<div className="space-y-2">
<FormLabel htmlFor="claudeDefaultHaikuModel">
{t("providerForm.anthropicDefaultHaikuModel", { defaultValue: "Haiku 默认模型" })}
{t("providerForm.anthropicDefaultHaikuModel", {
defaultValue: "Haiku 默认模型",
})}
</FormLabel>
<Input
id="claudeDefaultHaikuModel"
@@ -196,14 +200,19 @@ export function ClaudeFormFields({
{/* 默认 Sonnet */}
<div className="space-y-2">
<FormLabel htmlFor="claudeDefaultSonnetModel">
{t("providerForm.anthropicDefaultSonnetModel", { defaultValue: "Sonnet 默认模型" })}
{t("providerForm.anthropicDefaultSonnetModel", {
defaultValue: "Sonnet 默认模型",
})}
</FormLabel>
<Input
id="claudeDefaultSonnetModel"
type="text"
value={defaultSonnetModel}
onChange={(e) =>
onModelChange("ANTHROPIC_DEFAULT_SONNET_MODEL", e.target.value)
onModelChange(
"ANTHROPIC_DEFAULT_SONNET_MODEL",
e.target.value,
)
}
placeholder={t("providerForm.modelPlaceholder", {
defaultValue: "claude-3-7-sonnet-20250219",
@@ -215,7 +224,9 @@ export function ClaudeFormFields({
{/* 默认 Opus */}
<div className="space-y-2">
<FormLabel htmlFor="claudeDefaultOpusModel">
{t("providerForm.anthropicDefaultOpusModel", { defaultValue: "Opus 默认模型" })}
{t("providerForm.anthropicDefaultOpusModel", {
defaultValue: "Opus 默认模型",
})}
</FormLabel>
<Input
id="claudeDefaultOpusModel"
@@ -233,7 +244,8 @@ export function ClaudeFormFields({
</div>
<p className="text-xs text-muted-foreground">
{t("providerForm.modelHelper", {
defaultValue: "可选:指定默认使用的 Claude 模型,留空则使用系统默认。",
defaultValue:
"可选:指定默认使用的 Claude 模型,留空则使用系统默认。",
})}
</p>
</div>

View File

@@ -7,7 +7,10 @@ import { Form } from "@/components/ui/form";
import { providerSchema, type ProviderFormData } from "@/lib/schemas/provider";
import type { AppId } from "@/lib/api";
import type { ProviderCategory, ProviderMeta } from "@/types";
import { providerPresets, type ProviderPreset } from "@/config/claudeProviderPresets";
import {
providerPresets,
type ProviderPreset,
} from "@/config/claudeProviderPresets";
import {
codexProviderPresets,
type CodexProviderPreset,

View File

@@ -9,7 +9,10 @@ interface UseModelStateProps {
* 管理模型选择状态
* 支持 ANTHROPIC_MODEL 和 ANTHROPIC_SMALL_FAST_MODEL
*/
export function useModelState({ settingsConfig, onConfigChange }: UseModelStateProps) {
export function useModelState({
settingsConfig,
onConfigChange,
}: UseModelStateProps) {
const [claudeModel, setClaudeModel] = useState("");
const [defaultHaikuModel, setDefaultHaikuModel] = useState("");
const [defaultSonnetModel, setDefaultSonnetModel] = useState("");
@@ -24,9 +27,12 @@ export function useModelState({ settingsConfig, onConfigChange }: UseModelStateP
try {
const cfg = settingsConfig ? JSON.parse(settingsConfig) : {};
const env = cfg?.env || {};
const model = typeof env.ANTHROPIC_MODEL === "string" ? env.ANTHROPIC_MODEL : "";
const model =
typeof env.ANTHROPIC_MODEL === "string" ? env.ANTHROPIC_MODEL : "";
const small =
typeof env.ANTHROPIC_SMALL_FAST_MODEL === "string" ? env.ANTHROPIC_SMALL_FAST_MODEL : "";
typeof env.ANTHROPIC_SMALL_FAST_MODEL === "string"
? env.ANTHROPIC_SMALL_FAST_MODEL
: "";
const haiku =
typeof env.ANTHROPIC_DEFAULT_HAIKU_MODEL === "string"
? env.ANTHROPIC_DEFAULT_HAIKU_MODEL
@@ -59,12 +65,16 @@ export function useModelState({ settingsConfig, onConfigChange }: UseModelStateP
value: string,
) => {
if (field === "ANTHROPIC_MODEL") setClaudeModel(value);
if (field === "ANTHROPIC_DEFAULT_HAIKU_MODEL") setDefaultHaikuModel(value);
if (field === "ANTHROPIC_DEFAULT_SONNET_MODEL") setDefaultSonnetModel(value);
if (field === "ANTHROPIC_DEFAULT_HAIKU_MODEL")
setDefaultHaikuModel(value);
if (field === "ANTHROPIC_DEFAULT_SONNET_MODEL")
setDefaultSonnetModel(value);
if (field === "ANTHROPIC_DEFAULT_OPUS_MODEL") setDefaultOpusModel(value);
try {
const currentConfig = settingsConfig ? JSON.parse(settingsConfig) : { env: {} };
const currentConfig = settingsConfig
? JSON.parse(settingsConfig)
: { env: {} };
if (!currentConfig.env) currentConfig.env = {};
// 新键仅写入;旧键不再写入