diff --git a/README.md b/README.md index 02f9007..95847ab 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Open **Providers**, click **Add Provider**, then choose a built-in preset or **O ### 2. Configure routing -Open **Routing** to choose the default route, add conditional rules, configure request rewrites, and set fallback behavior. +Open **Routing** to add conditional rules, configure request rewrites, and set fallback behavior. Use **Add Routing Rule** for request conditions, model-prefix routing, or rule-level fallback targets. diff --git a/README_zh.md b/README_zh.md index 3963630..15bdb68 100644 --- a/README_zh.md +++ b/README_zh.md @@ -24,7 +24,7 @@ Claude Code Router Desktop 是一个本地网关和桌面控制台,用来把 C - **概览仪表盘**:查看系统状态、用量组件、账号余额、模型分布和分享卡片。 - **Provider 管理**:添加预设或自定义端点,探测协议支持,检测模型连通性,管理凭据,并在可用时查看账号余额。 -- **路由规则**:配置默认路由、条件路由、模型前缀规则、失败降级和请求改写。 +- **路由规则**:配置条件路由、模型前缀规则、失败降级和请求改写。 - **Agent配置**:为 Claude Code、Codex 和 ZCode 配置启动入口、模型、作用范围和多开 App 配置。 - **网关兼容层**:通过本地 CCR 模型网关转换支持的客户端请求。 - **代理模式**:通过本地代理捕获支持的 API 流量,可选系统代理和网络捕获。 @@ -61,7 +61,7 @@ CCR 可以完全通过桌面 UI 完成配置。首次使用建议按下面顺序 ### 2. 设置路由 -打开 **路由**,选择默认路由,添加条件规则,配置请求改写和失败降级。 +打开 **路由**,添加条件规则,配置请求改写和失败降级。 如果需要更细粒度控制,使用 **添加路由规则** 添加模型前缀、请求条件或规则级失败降级目标。 diff --git a/docs/src/content/docs/en/configuration/routing.md b/docs/src/content/docs/en/configuration/routing.md index 5c534d2..a378c56 100644 --- a/docs/src/content/docs/en/configuration/routing.md +++ b/docs/src/content/docs/en/configuration/routing.md @@ -9,9 +9,9 @@ lead: Choose the model for a request, then automatically retry or switch to fall ### Claude Code -The built-in Claude Code route detects requests from Claude Code and routes main requests to the Claude Code Agent Config model or the default route model. +The built-in Claude Code route detects requests from Claude Code and routes main requests to the Claude Code Agent Config model. -Claude Code **main requests** use the Claude Code Agent Config model by default; if it is unset, they use the Routing page default model. CCR also automatically removes the first `x-anthropic-billing-header` system message injected by Claude Code so that billing helper messages do not affect later routing decisions. Claude Code Subagent, Task, and Workflow-created agents can still choose different models through the tag mechanism below. +Claude Code **main requests** use the Claude Code Agent Config model. If that model is unset, the built-in route remains inactive. CCR also automatically removes the first `x-anthropic-billing-header` system message injected by Claude Code so that billing helper messages do not affect later routing decisions. Claude Code Subagent, Task, and Workflow-created agents can still choose different models through the tag mechanism below. #### Subagent / Workflow Auto-Routing @@ -176,7 +176,7 @@ Configure **Default on failure** at the top of the Routing page: 2. If you choose **Retry**, set `Retries`. 3. If you choose **Fallback targets**, add backup models in priority order. -Global Fallback applies to the default route and to rules that do not define their own Fallback. +Global Fallback applies to routing rules that do not define their own Fallback. ### Rule-Level Fallback diff --git a/docs/src/content/docs/zh/configuration.md b/docs/src/content/docs/zh/configuration.md index 26df10a..6515d0f 100644 --- a/docs/src/content/docs/zh/configuration.md +++ b/docs/src/content/docs/zh/configuration.md @@ -16,7 +16,7 @@ lead: 深入配置概览仪表盘、API 密钥、服务、供应商、路由、A | 服务配置 | Host、Port、代理模式、系统代理、网络捕获和 CA 证书 | | 供应商配置 | 上游服务、协议、基础 URL、模型列表和凭据 | | 一键导入供应商 | Provider deeplink 协议、Manifest 导入、一键导入按钮和安全边界 | -| 路由配置 | 默认路由、条件规则、fallback 和请求改写 | +| 路由配置 | 条件规则、fallback 和请求改写 | | 日志&观测 | 请求日志、Agent 执行追踪、工具调用和工具结果 | | Fusion 组合模型 | 把基础模型与视觉、搜索、MCP 工具组合成新的可选模型 | | Agent配置 | Agent 启动方式、模型、作用范围、多开和 Bot 绑定 | diff --git a/docs/src/content/docs/zh/configuration/routing.md b/docs/src/content/docs/zh/configuration/routing.md index 32fb625..c00f069 100644 --- a/docs/src/content/docs/zh/configuration/routing.md +++ b/docs/src/content/docs/zh/configuration/routing.md @@ -9,9 +9,9 @@ lead: 设置请求如何选择模型,并在失败时通过 Fallback 自动重 ### Claude Code -Claude Code 内置路由的作用是识别 Claude Code 发来的请求,并把主请求路由到 Claude Code Agent 配置或默认路由中的模型。 +Claude Code 内置路由的作用是识别 Claude Code 发来的请求,并把主请求路由到 Claude Code Agent 配置中的模型。 -Claude Code **主请求** 默认使用 Claude Code Agent 配置中的模型;如果未设置,则使用路由页的默认模型。CCR 也会自动删除 Claude Code 注入的第一条 `x-anthropic-billing-header` system 消息,避免这类计费辅助消息影响后续路由判断。Claude Code 创建的 Subagent、Task 或 Workflow 内部 Agent 可以继续用下面的标签机制自动选择不同模型。 +Claude Code **主请求** 使用 Claude Code Agent 配置中的模型;如果未设置,该内置路由不会生效。CCR 也会自动删除 Claude Code 注入的第一条 `x-anthropic-billing-header` system 消息,避免这类计费辅助消息影响后续路由判断。Claude Code 创建的 Subagent、Task 或 Workflow 内部 Agent 可以继续用下面的标签机制自动选择不同模型。 #### Subagent / Workflow 自动路由 @@ -176,7 +176,7 @@ Fallback 处理请求失败后的降级。第一次选模型由路由完成; 2. 如果选择 **继续重试**,填写 `Retries`。 3. 如果选择 **失败降级目标**,按优先级添加备用模型。 -全局 Fallback 会应用到默认路由,以及没有单独配置 Fallback 的规则。 +全局 Fallback 会应用到没有单独配置 Fallback 的规则。 ### 规则级失败降级 diff --git a/docs/src/content/docs/zh/troubleshooting.md b/docs/src/content/docs/zh/troubleshooting.md index da049b7..f37bc12 100644 --- a/docs/src/content/docs/zh/troubleshooting.md +++ b/docs/src/content/docs/zh/troubleshooting.md @@ -13,7 +13,7 @@ A: 服务运行状态、Agent 启动方式、配置应用状态和作用范围 ### Q: 请求命中了错误模型怎么办? -A: 请求日志会展示 `request model`、`resolved provider` 和 `resolved model`。路由配置页包含默认路由、规则顺序、匹配条件和 fallback。 +A: 请求日志会展示 `request model`、`resolved provider` 和 `resolved model`。路由配置页包含规则顺序、匹配条件和 fallback。 ### Q: 供应商返回 401 或 403 怎么处理? diff --git a/src/main/config.ts b/src/main/config.ts index 89a9c4d..bccbc7d 100644 --- a/src/main/config.ts +++ b/src/main/config.ts @@ -1190,10 +1190,6 @@ function parseRouter(value: unknown): Partial | undefined { } const router: Partial = {}; - const defaultRoute = readString(value.default); - if (defaultRoute) { - router.default = defaultRoute; - } const builtInRules = parseRouterBuiltInRules(value.builtInRules ?? value.builtinRules ?? value.agentRules); if (builtInRules) { router.builtInRules = builtInRules; diff --git a/src/main/profile-launch-service.ts b/src/main/profile-launch-service.ts index cd2d01a..8aecd07 100644 --- a/src/main/profile-launch-service.ts +++ b/src/main/profile-launch-service.ts @@ -514,11 +514,7 @@ function profileGatewayConfigWithToken(config: AppConfig, profile: ReturnType provider.name === config.preferredProvider) ?? config.Providers[0]; if (preferred?.name && preferred.models[0]) { return `${preferred.name}/${preferred.models[0]}`; diff --git a/src/main/zcode-profile-config.ts b/src/main/zcode-profile-config.ts index 8ac037c..9e62c65 100644 --- a/src/main/zcode-profile-config.ts +++ b/src/main/zcode-profile-config.ts @@ -282,10 +282,6 @@ function gatewayEndpoint(config: AppConfig): string { } function defaultClientModel(config: AppConfig): string { - const configuredDefault = normalizeClientModel(config.Router.default); - if (configuredDefault) { - return configuredDefault; - } const preferred = config.Providers.find((provider) => provider.name === config.preferredProvider) ?? config.Providers[0]; if (preferred?.name && preferred.models[0]) { return `${preferred.name}/${preferred.models[0]}`; diff --git a/src/renderer/components/ui/switch.tsx b/src/renderer/components/ui/switch.tsx index 5440546..616f640 100644 --- a/src/renderer/components/ui/switch.tsx +++ b/src/renderer/components/ui/switch.tsx @@ -6,8 +6,8 @@ export interface SwitchProps extends Omit( - ({ checked = false, className, disabled, onChange, onCheckedChange, ...props }, ref) => ( - + ({ checked = false, className, disabled, onChange, onCheckedChange, title, ...props }, ref) => ( + ( }} ref={ref} role="switch" + title={title} type="checkbox" {...props} /> diff --git a/src/renderer/pages/home/components/routing.tsx b/src/renderer/pages/home/components/routing.tsx index 1d702f8..4f54c8e 100644 --- a/src/renderer/pages/home/components/routing.tsx +++ b/src/renderer/pages/home/components/routing.tsx @@ -4,11 +4,11 @@ import { CardHeader, Check, CircleAlert, clampNumber, cn, createRouteModelOptions, createRoutingRewriteDraftRow, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, disclosureSpringTransition, Field, formatRouterRuleCondition, formatRouterRuleTarget, GatewayProviderConfig, Input, - Info, motion, normalizeRouterFallbackConfig, Pencil, Plus, Route, RouterFallbackConfig, + AppI18nContext, appCopy, ExternalLink, Info, motion, normalizeRouterFallbackConfig, Pencil, Plus, Route, RouterFallbackConfig, RouterBuiltInAgentRuleId, RouterFallbackMode, routerConditionSourceOptions, routerFallbackModeOptions, RouterRule, routerRewriteOperationOptions, routerRuleOperatorOptions, RouterBuiltInAgentRuleConfig, RouteTargetControl, routingRuleRowMatchesQuery, Search, SelectControl, Toggle, translateOptions, - Trash2, uniqueStrings, useAppText, useMemo, useState, X + Trash2, uniqueStrings, useAppText, useContext, useMemo, useState, X } from "../shared"; import { ROUTER_FALLBACK_MAX_RETRY_COUNT } from "../../../../shared/app"; export function RoutingView({ @@ -100,6 +100,7 @@ export function RoutingView({ {visibleRules.map((row) => { const rowSourceLabel = row.builtInAgent ? t(row.sourceLabel) : row.sourceLabel; const rowTarget = row.target === "Profile model unset" ? t(row.target) : row.target; + const toggleDisabledReason = row.toggleDisabledReason ? t(row.toggleDisabledReason) : undefined; return (
{row.name || t("Unnamed")}
- {row.builtInAgent ? : null} + {row.builtInAgent ? : null} {row.builtInAgent ? {t("Built-in")} : row.readonly ? {t("Plugin")} : null}
@@ -129,17 +130,28 @@ export function RoutingView({ {row.builtInAgent ? null : rowTarget}
- { - if (row.builtInAgent) { - updateBuiltInRule(row.builtInAgent, { enabled }); - } else if (row.index !== undefined) { - updateRule(row.index, { enabled }); - } - }} - /> + + { + if (row.builtInAgent) { + updateBuiltInRule(row.builtInAgent, { enabled }); + } else if (row.index !== undefined) { + updateRule(row.index, { enabled }); + } + }} + /> + {toggleDisabledReason ? ( + + {toggleDisabledReason} + + ) : null} +
{!row.builtInAgent ? ( @@ -185,22 +197,55 @@ export function RoutingView({ ); } -function BuiltInRouteInfoIcon({ description }: { description: string }) { +function BuiltInRouteInfoIcon({ agent }: { agent: RouterBuiltInAgentRuleId }) { + const t = useAppText(); + const copy = useContext(AppI18nContext); + const description = builtInRouteDescription(agent, t); + const docsUrl = builtInRouteDocsUrl(agent, copy === appCopy.zh ? "zh" : "en"); + return ( - +