diff --git a/CHANGELOG.md b/CHANGELOG.md index e8d1c35ed..fd5580930 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,24 @@ --- +## [v0.3.28](https://github.com/ding113/claude-code-hub/releases/tag/v0.3.28) - 2025-12-10 + +### 新增 + +- 日志页面新增快速日期筛选器(今日/昨日/近7天/近30天)和 CSV 导出功能 (#314) +- Session 监控页面新增分页功能,支持分别对活跃和非活跃 Session 进行分页浏览 (#314) + +### 优化 + +- 每日排行榜改用滚动 24 小时窗口计算,替代原先基于日历日的统计方式 (#314) +- 上游 404 错误现在触发供应商故障切换而不计入熔断器,提升中转服务兼容性 (#314) + +### 修复 + +- 修复 Anthropic SSE 流式响应中 output_tokens 提取问题,现在从 message_delta 事件正确获取 (#313) + +--- + ## [v0.3.27](https://github.com/ding113/claude-code-hub/releases/tag/v0.3.27) - 2025-12-10 ### 新增 diff --git a/src/app/v1/_lib/gemini/types.ts b/src/app/v1/_lib/gemini/types.ts index 076a03819..dd409fddc 100644 --- a/src/app/v1/_lib/gemini/types.ts +++ b/src/app/v1/_lib/gemini/types.ts @@ -51,11 +51,21 @@ export interface GeminiRequest { }; } +export interface GeminiTokenDetail { + modality: "TEXT" | "IMAGE" | "AUDIO" | "VIDEO"; + tokenCount: number; +} + export interface GeminiUsageMetadata { promptTokenCount: number; candidatesTokenCount: number; totalTokenCount: number; - cachedContentTokenCount?: number; // Gemini 缓存支持 + cachedContentTokenCount?: number; // Gemini 缓存命中的 token 数 + thoughtsTokenCount?: number; // Gemini 思考模型的推理 token + // 详细信息(按 modality 分类) + promptTokensDetails?: GeminiTokenDetail[]; + cacheTokensDetails?: GeminiTokenDetail[]; + candidatesTokensDetails?: GeminiTokenDetail[]; } export interface GeminiCandidate { diff --git a/src/app/v1/_lib/proxy/response-handler.ts b/src/app/v1/_lib/proxy/response-handler.ts index 21e9c048a..45fc79f29 100644 --- a/src/app/v1/_lib/proxy/response-handler.ts +++ b/src/app/v1/_lib/proxy/response-handler.ts @@ -1206,6 +1206,11 @@ function extractUsageMetrics(value: unknown): UsageMetrics | null { result.cache_read_input_tokens = usage.cachedContentTokenCount; hasAny = true; } + // Gemini 思考/推理 token:直接累加到 output_tokens(思考价格与输出价格相同) + if (typeof usage.thoughtsTokenCount === "number" && usage.thoughtsTokenCount > 0) { + result.output_tokens = (result.output_tokens ?? 0) + usage.thoughtsTokenCount; + hasAny = true; + } if (typeof usage.output_tokens === "number") { result.output_tokens = usage.output_tokens;