fix(proxy): bill route-takeover traffic by the real upstream model

The model mapped for takeover (env mapping, Claude Desktop routes,
Copilot normalization, Codex chat override) was discarded inside the
forwarder, so usage attribution depended entirely on the upstream
echoing it back. When the upstream omitted the model or mirrored the
client alias, kimi/glm tokens were recorded and priced as claude-*
(roughly 5-25x overstatement).

- capture the final outbound model in forward(), return it via
  ForwardResult, and store it on the request context
- attribution fallback order is now: upstream echo (empty string
  treated as missing) -> outbound model -> client-requested model
- 'request' pricing mode anchors to the outbound model instead of the
  pre-mapping client alias; unchanged when no mapping applies
- persist the resolved pricing_model on every usage row
- Claude Desktop rows now log app_type "claude-desktop" on streaming
  and transform paths too (was hardcoded "claude", silently dropping
  desktop provider pricing overrides and splitting the cost basis by
  the stream flag); its global pricing defaults inherit the claude
  config since proxy_config only allows claude/codex/gemini rows
This commit is contained in:
Jason
2026-06-10 11:56:54 +08:00
parent 4282856683
commit feea81e5bb
6 changed files with 305 additions and 62 deletions
+6
View File
@@ -48,6 +48,11 @@ pub struct RequestContext {
pub current_provider_id: String,
/// 请求中的模型名称
pub request_model: String,
/// 实际发往上游的模型名(路由接管/模型映射后的真值,forward 成功后回填)。
///
/// usage 归因的兜底顺序:上游响应回显 → outbound_model → request_model。
/// 不能直接用 request_model 兜底:接管场景下它是映射前的客户端别名。
pub outbound_model: Option<String>,
/// 日志标签(如 "Claude"、"Codex"、"Gemini"
pub tag: &'static str,
/// 应用类型字符串(如 "claude"、"codex"、"gemini"
@@ -159,6 +164,7 @@ impl RequestContext {
providers,
current_provider_id,
request_model,
outbound_model: None,
tag,
app_type_str,
app_type,