Skip to content

Commit 5e962db

Browse files
committed
feat: v0.14.0 - 添加 Provider 图标支持和修复 API 测试模型
## 新功能 - 为所有 Provider 按钮添加图标支持(Kiro、Gemini、Claude、OpenAI 等) - API Server 页面的默认 Provider 按钮现在显示对应图标 - 配置管理页面的应用类型标签页(Claude Code、Codex、Gemini)显示图标 ## 修复 - 修复 API 测试中的模型名称,使用 claude-opus-4-5-20251101 - 修复 TypeScript 编译错误 - 修复 ESLint 警告 ## 构建 - 添加 Intel Mac (x86_64-apple-darwin) 构建支持
1 parent b94fc6e commit 5e962db

17 files changed

Lines changed: 307 additions & 42 deletions

File tree

.github/workflows/release.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ jobs:
2323
- platform: macos-latest
2424
target: aarch64-apple-darwin
2525
name: macOS-arm64
26+
- platform: macos-latest
27+
target: x86_64-apple-darwin
28+
name: macOS-x64
2629
- platform: windows-latest
2730
target: x86_64-pc-windows-msvc
2831
name: Windows-x64
@@ -73,6 +76,7 @@ jobs:
7376
7477
### Downloads
7578
- **macOS (Apple Silicon)**: `proxycast_*_aarch64.dmg`
79+
- **macOS (Intel)**: `proxycast_*_x64.dmg`
7680
- **Windows (64-bit)**: `proxycast_*_x64-setup.exe`
7781
7882
### macOS 首次安装

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "proxycast",
33
"private": true,
4-
"version": "0.13.0",
4+
"version": "0.14.0",
55
"type": "module",
66
"scripts": {
77
"dev": "vite",

src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "proxycast"
3-
version = "0.13.0"
3+
version = "0.14.0"
44
description = "AI API Proxy Desktop App"
55
authors = ["you"]
66
edition = "2021"

src-tauri/tauri.conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://schema.tauri.app/config/2",
33
"productName": "ProxyCast",
4-
"version": "0.13.0",
4+
"version": "0.14.0",
55
"identifier": "com.proxycast.app",
66
"build": {
77
"beforeDevCommand": "npm run dev",

src/components/api-server/ApiServerPage.tsx

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
import { LogsTab } from "./LogsTab";
1616
import { RoutesTab } from "./RoutesTab";
1717
import { HelpTip } from "@/components/HelpTip";
18+
import { ProviderIcon } from "@/icons/providers";
1819
import {
1920
startServer,
2021
stopServer,
@@ -260,7 +261,7 @@ export function ApiServerPage() {
260261
path: "/v1/chat/completions",
261262
needsAuth: true,
262263
body: JSON.stringify({
263-
model: "claude-sonnet-4-5",
264+
model: "claude-opus-4-5-20251101",
264265
messages: [{ role: "user", content: "Say hi in one word" }],
265266
}),
266267
},
@@ -271,7 +272,7 @@ export function ApiServerPage() {
271272
path: "/v1/messages",
272273
needsAuth: true,
273274
body: JSON.stringify({
274-
model: "claude-sonnet-4-5",
275+
model: "claude-opus-4-5-20251101",
275276
max_tokens: 100,
276277
messages: [
277278
{
@@ -555,12 +556,24 @@ export function ApiServerPage() {
555556
<div className="flex flex-wrap gap-2">
556557
{(
557558
[
558-
{ id: "kiro", label: "Kiro (AWS)" },
559-
{ id: "gemini", label: "Gemini (Google)" },
560-
{ id: "qwen", label: "Qwen (阿里)" },
561-
{ id: "antigravity", label: "Antigravity (Gemini 3 Pro)" },
562-
{ id: "openai", label: "OpenAI" },
563-
{ id: "claude", label: "Claude (Anthropic)" },
559+
{ id: "kiro", label: "Kiro (AWS)", iconType: "kiro" },
560+
{
561+
id: "gemini",
562+
label: "Gemini (Google)",
563+
iconType: "gemini",
564+
},
565+
{ id: "qwen", label: "Qwen (阿里)", iconType: "qwen" },
566+
{
567+
id: "antigravity",
568+
label: "Antigravity (Gemini 3 Pro)",
569+
iconType: "gemini",
570+
},
571+
{ id: "openai", label: "OpenAI", iconType: "openai" },
572+
{
573+
id: "claude",
574+
label: "Claude (Anthropic)",
575+
iconType: "claude",
576+
},
564577
] as const
565578
).map((p) => {
566579
const overview = poolOverview.find(
@@ -572,12 +585,13 @@ export function ApiServerPage() {
572585
key={p.id}
573586
onClick={() => handleSetDefaultProvider(p.id)}
574587
disabled={loading}
575-
className={`rounded-lg px-4 py-2 text-sm font-medium ${
588+
className={`flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium ${
576589
defaultProvider === p.id
577590
? "bg-primary text-primary-foreground"
578591
: "border hover:bg-muted"
579592
} disabled:opacity-50`}
580593
>
594+
<ProviderIcon providerType={p.iconType} size={16} />
581595
{p.label}
582596
{count > 0 && (
583597
<span className="ml-1 text-xs opacity-70">({count})</span>

src/components/clients/AppTabs.tsx

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,36 @@
11
import { cn } from "@/lib/utils";
22
import { AppType } from "@/lib/api/switch";
3+
import { ProviderIcon } from "@/icons/providers";
34

45
interface AppTabsProps {
56
activeApp: AppType;
67
onAppChange: (app: AppType) => void;
78
}
89

9-
const apps: { id: AppType; label: string; description: string }[] = [
10-
{ id: "claude", label: "Claude Code", description: "Claude CLI 配置" },
11-
{ id: "codex", label: "Codex", description: "OpenAI Codex CLI" },
12-
{ id: "gemini", label: "Gemini", description: "Google Gemini CLI" },
10+
const apps: {
11+
id: AppType;
12+
label: string;
13+
description: string;
14+
iconType: string;
15+
}[] = [
16+
{
17+
id: "claude",
18+
label: "Claude Code",
19+
description: "Claude CLI 配置",
20+
iconType: "claude",
21+
},
22+
{
23+
id: "codex",
24+
label: "Codex",
25+
description: "OpenAI Codex CLI",
26+
iconType: "openai",
27+
},
28+
{
29+
id: "gemini",
30+
label: "Gemini",
31+
description: "Google Gemini CLI",
32+
iconType: "gemini",
33+
},
1334
];
1435

1536
export function AppTabs({ activeApp, onAppChange }: AppTabsProps) {
@@ -20,13 +41,14 @@ export function AppTabs({ activeApp, onAppChange }: AppTabsProps) {
2041
key={app.id}
2142
onClick={() => onAppChange(app.id)}
2243
className={cn(
23-
"px-4 py-2 rounded-t-lg text-sm font-medium transition-colors",
44+
"flex items-center gap-2 px-4 py-2 rounded-t-lg text-sm font-medium transition-colors",
2445
activeApp === app.id
2546
? "bg-primary text-primary-foreground"
2647
: "hover:bg-muted text-muted-foreground",
2748
)}
2849
title={app.description}
2950
>
51+
<ProviderIcon providerType={app.iconType} size={16} />
3052
{app.label}
3153
</button>
3254
))}

src/components/clients/ProviderCard.tsx

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,39 @@
11
import { Check, Edit2, Trash2, Zap } from "lucide-react";
22
import { Provider } from "@/lib/api/switch";
33
import { cn } from "@/lib/utils";
4+
import { ProviderIcon } from "@/icons/providers";
5+
6+
// 从供应商名称和分类推断图标类型
7+
function getProviderTypeFromName(name: string, category: string): string {
8+
const lowerName = name.toLowerCase();
9+
10+
// 精确匹配
11+
if (lowerName.includes("智谱") || lowerName.includes("glm")) return "zhipu";
12+
if (lowerName.includes("proxycast")) return "proxycast";
13+
if (lowerName.includes("deepseek")) return "deepseek";
14+
if (lowerName.includes("kimi")) return "kimi";
15+
if (lowerName.includes("minimax")) return "minimax";
16+
if (lowerName.includes("doubao") || lowerName.includes("豆包"))
17+
return "doubao";
18+
if (lowerName.includes("qwen") || lowerName.includes("通义")) return "qwen";
19+
if (lowerName.includes("claude")) return "claude";
20+
if (lowerName.includes("anthropic")) return "anthropic";
21+
if (lowerName.includes("openai")) return "openai";
22+
if (lowerName.includes("gemini")) return "gemini";
23+
if (lowerName.includes("google")) return "google";
24+
if (lowerName.includes("kiro")) return "kiro";
25+
if (lowerName.includes("azure")) return "azure";
26+
if (lowerName.includes("alibaba") || lowerName.includes("阿里"))
27+
return "alibaba";
28+
if (lowerName.includes("copilot")) return "copilot";
29+
30+
// 根据分类推断
31+
if (category === "custom") return "custom";
32+
if (category === "proxy") return "amp";
33+
34+
// 默认回退
35+
return lowerName.replace(/\s+/g, "");
36+
}
437

538
interface ProviderCardProps {
639
provider: Provider;
@@ -34,11 +67,15 @@ export function ProviderCard({
3467

3568
<div className="flex items-start justify-between">
3669
<div className="flex items-center gap-2">
37-
<div
38-
className="h-8 w-8 rounded-lg flex items-center justify-center text-lg"
39-
style={{ backgroundColor: provider.icon_color || "#6366f1" }}
40-
>
41-
{provider.icon || provider.name.charAt(0).toUpperCase()}
70+
<div className="h-8 w-8 rounded-lg flex items-center justify-center">
71+
<ProviderIcon
72+
providerType={getProviderTypeFromName(
73+
provider.name,
74+
provider.category || "",
75+
)}
76+
size={24}
77+
showFallback={true}
78+
/>
4279
</div>
4380
<div>
4481
<h3 className="font-medium">{provider.name}</h3>

src/components/clients/ProviderForm.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { X, ExternalLink, Wand2, Eye, EyeOff, Database } from "lucide-react";
33
import { Provider, AppType } from "@/lib/api/switch";
44
import { getConfig } from "@/hooks/useTauri";
55
import { cn } from "@/lib/utils";
6+
import { ProviderIcon } from "@/icons/providers";
67
import {
78
providerPoolApi,
89
CredentialDisplay,
@@ -372,7 +373,6 @@ export function ProviderForm({
372373
const generateJsonFromFields = useCallback(() => {
373374
const env: Record<string, string> = {};
374375
if (apiKey) {
375-
env.ANTHROPIC_AUTH_TOKEN = apiKey;
376376
env.ANTHROPIC_API_KEY = apiKey;
377377
}
378378
if (baseUrl) env.ANTHROPIC_BASE_URL = baseUrl;
@@ -790,10 +790,7 @@ export function ProviderForm({
790790
: "border-border hover:border-muted-foreground/50",
791791
)}
792792
>
793-
<span
794-
className="w-4 h-4 rounded"
795-
style={{ backgroundColor: preset.iconColor }}
796-
/>
793+
<ProviderIcon providerType={preset.id} size={16} />
797794
{preset.name}
798795
</button>
799796
))}

src/components/provider-pool/ProviderPoolPage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { getConfig, saveConfig, Config } from "@/hooks/useTauri";
1919
import { GeminiApiKeySection } from "./GeminiApiKeySection";
2020
import { VertexAISection } from "./VertexAISection";
2121
import { AmpConfigSection } from "./AmpConfigSection";
22+
import { ProviderIcon } from "@/icons/providers";
2223
import type {
2324
PoolProviderType,
2425
CredentialDisplay,
@@ -381,6 +382,7 @@ export const ProviderPoolPage = forwardRef<ProviderPoolPageRef>(
381382
: "border-transparent text-muted-foreground hover:text-foreground"
382383
}`}
383384
>
385+
<ProviderIcon providerType={providerType} size={16} />
384386
{providerLabels[providerType]}
385387
{count > 0 && (
386388
<span className="rounded-full bg-muted px-1.5 py-0.5 text-xs">

src/components/switch/AppTabs.tsx

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,36 @@
11
import { cn } from "@/lib/utils";
22
import { AppType } from "@/lib/api/switch";
3+
import { ProviderIcon } from "@/icons/providers";
34

45
interface AppTabsProps {
56
activeApp: AppType;
67
onAppChange: (app: AppType) => void;
78
}
89

9-
const apps: { id: AppType; label: string; description: string }[] = [
10-
{ id: "claude", label: "Claude Code", description: "Claude CLI 配置" },
11-
{ id: "codex", label: "Codex", description: "OpenAI Codex CLI" },
12-
{ id: "gemini", label: "Gemini", description: "Google Gemini CLI" },
10+
const apps: {
11+
id: AppType;
12+
label: string;
13+
description: string;
14+
iconType: string;
15+
}[] = [
16+
{
17+
id: "claude",
18+
label: "Claude Code",
19+
description: "Claude CLI 配置",
20+
iconType: "claude",
21+
},
22+
{
23+
id: "codex",
24+
label: "Codex",
25+
description: "OpenAI Codex CLI",
26+
iconType: "openai",
27+
},
28+
{
29+
id: "gemini",
30+
label: "Gemini",
31+
description: "Google Gemini CLI",
32+
iconType: "gemini",
33+
},
1334
];
1435

1536
export function AppTabs({ activeApp, onAppChange }: AppTabsProps) {
@@ -20,13 +41,14 @@ export function AppTabs({ activeApp, onAppChange }: AppTabsProps) {
2041
key={app.id}
2142
onClick={() => onAppChange(app.id)}
2243
className={cn(
23-
"px-4 py-2 rounded-t-lg text-sm font-medium transition-colors",
44+
"flex items-center gap-2 px-4 py-2 rounded-t-lg text-sm font-medium transition-colors",
2445
activeApp === app.id
2546
? "bg-primary text-primary-foreground"
2647
: "hover:bg-muted text-muted-foreground",
2748
)}
2849
title={app.description}
2950
>
51+
<ProviderIcon providerType={app.iconType} size={16} />
3052
{app.label}
3153
</button>
3254
))}

0 commit comments

Comments
 (0)