diff --git a/src/components/usage/RequestDetailPanel.tsx b/src/components/usage/RequestDetailPanel.tsx index f39547198..9cbb80bf8 100644 --- a/src/components/usage/RequestDetailPanel.tsx +++ b/src/components/usage/RequestDetailPanel.tsx @@ -111,6 +111,28 @@ export function RequestDetailPanel({ {t("usage.model", "模型")}
{request.model}
+ {request.requestModel && + request.requestModel !== request.model && ( + <> +
+ {t("usage.requestModel", "请求模型")} +
+
+ {request.requestModel} +
+ + )} + {request.pricingModel && + request.pricingModel !== request.model && ( + <> +
+ {t("usage.pricingModel", "计价模型")} +
+
+ {request.pricingModel} +
+ + )}
diff --git a/src/components/usage/UsageHero.tsx b/src/components/usage/UsageHero.tsx index 3ade773f1..e99db9e1f 100644 --- a/src/components/usage/UsageHero.tsx +++ b/src/components/usage/UsageHero.tsx @@ -49,6 +49,11 @@ const TITLE_THEMES: Record = { accent: "text-amber-600 dark:text-amber-400", iconBg: "bg-amber-500/10", }, + "claude-desktop": { + // 与 Claude Code 同属 Anthropic 品牌,用更深的 orange 区分 + accent: "text-orange-600 dark:text-orange-400", + iconBg: "bg-orange-500/10", + }, codex: { // OpenAI/Codex 走黑白单色调;中性灰在深浅模式都能透出方块底色, // 不像纯黑 bg-black/10 在深色背景下会糊掉。 diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index ad461bc75..f29569c34 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -1373,6 +1373,7 @@ "appFilter": { "all": "All", "claude": "Claude Code", + "claude-desktop": "Claude Desktop", "codex": "Codex", "gemini": "Gemini", "opencode": "OpenCode" @@ -1403,6 +1404,7 @@ "modelPricingDesc": "Configure token costs for each model", "noPricingData": "No pricing data. Click \"Add\" to add model pricing configuration.", "model": "Model", + "pricingModel": "Pricing Model", "displayName": "Display Name", "inputCost": "Input Cost", "outputCost": "Output Cost", diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 0abf87721..858067d78 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -1373,6 +1373,7 @@ "appFilter": { "all": "すべて", "claude": "Claude Code", + "claude-desktop": "Claude Desktop", "codex": "Codex", "gemini": "Gemini", "opencode": "OpenCode" @@ -1403,6 +1404,7 @@ "modelPricingDesc": "各モデルのトークンコストを設定", "noPricingData": "料金データがありません。「追加」をクリックしてモデル料金を設定してください。", "model": "モデル", + "pricingModel": "課金モデル", "displayName": "表示名", "inputCost": "入力コスト", "outputCost": "出力コスト", diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json index 4b866ed53..5dfe8fd15 100644 --- a/src/i18n/locales/zh-TW.json +++ b/src/i18n/locales/zh-TW.json @@ -1318,6 +1318,7 @@ "appFilter": { "all": "全部", "claude": "Claude Code", + "claude-desktop": "Claude Desktop", "codex": "Codex", "gemini": "Gemini", "opencode": "OpenCode" @@ -1348,6 +1349,7 @@ "modelPricingDesc": "設定各模型的 Token 成本", "noPricingData": "暫無定價資料。點擊「新增」加入模型定價設定。", "model": "模型", + "pricingModel": "計價模型", "displayName": "顯示名稱", "inputCost": "輸入成本", "outputCost": "輸出成本", diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index 675b2cd85..59b6be3fd 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -1373,6 +1373,7 @@ "appFilter": { "all": "全部", "claude": "Claude Code", + "claude-desktop": "Claude Desktop", "codex": "Codex", "gemini": "Gemini", "opencode": "OpenCode" @@ -1403,6 +1404,7 @@ "modelPricingDesc": "配置各模型的 Token 成本", "noPricingData": "暂无定价数据。点击\"新增\"添加模型定价配置。", "model": "模型", + "pricingModel": "计价模型", "displayName": "显示名称", "inputCost": "输入成本", "outputCost": "输出成本", diff --git a/src/types/usage.ts b/src/types/usage.ts index efb885088..cde1958b5 100644 --- a/src/types/usage.ts +++ b/src/types/usage.ts @@ -14,6 +14,8 @@ export interface RequestLog { appType: string; model: string; requestModel?: string; + /** 写入时实际用于计价的模型名;路由接管 + request 计价模式下可能与 model 不同 */ + pricingModel?: string; costMultiplier: string; inputTokens: number; outputTokens: number; @@ -141,17 +143,26 @@ export interface UsageRangeSelection { /** * App types whose token usage is reliably collected by the proxy. * - * The proxy has handlers for `claude-desktop` too, but in practice those - * requests overwhelmingly fail (500/503) and contribute near-zero tokens, so - * it is hidden from the Dashboard. `opencode` / `openclaw` / `hermes` have - * no proxy handler at all — they appear only as managed apps elsewhere. + * `claude-desktop` was previously hidden because its rows looked like pure + * failure noise — that was an accounting bug: streaming/transform usage of + * the Desktop gateway was logged under app_type "claude", leaving only + * edge-case rows under "claude-desktop". The backend now attributes all + * Desktop traffic to "claude-desktop", so it is a first-class filter option. + * `opencode` / `openclaw` / `hermes` have no proxy handler at all — they + * appear only as managed apps elsewhere. */ -export type AppType = "claude" | "codex" | "gemini" | "opencode"; +export type AppType = + | "claude" + | "claude-desktop" + | "codex" + | "gemini" + | "opencode"; export type AppTypeFilter = "all" | AppType; export const KNOWN_APP_TYPES: ReadonlyArray = [ "claude", + "claude-desktop", "codex", "gemini", "opencode",