Skip to content

feat(my-usage): cache statistics and timezone fixes#623

Merged
ding113 merged 6 commits intoding113:devfrom
miraserver:my-usage-fix
Jan 19, 2026
Merged

feat(my-usage): cache statistics and timezone fixes#623
ding113 merged 6 commits intoding113:devfrom
miraserver:my-usage-fix

Conversation

@miraserver
Copy link
Contributor

@miraserver miraserver commented Jan 17, 2026

Summary

This PR improves the my-usage page with cache token statistics and timezone-related fixes:

Changes

  1. Cache Token Statistics (b0f6f896)

    • Add cache creation and read token fields to model breakdown
    • Display cache hit rate in statistics summary modal
    • i18n support for 5 languages
  2. Timezone Fixes (3a66813c)

    • Use server timezone (TZ config) instead of browser locale for date filtering
    • Fixes discrepancy between Daily Quota and Statistics Summary for users in different timezones
    • Affects getMyStatsSummary and getTimeRangeForPeriod
  3. UI Cleanup (a6b972d1)

    • Remove duplicate expiration displays (Key Expires chip, "Expiring Soon" warnings)
    • Improve ExpirationInfo component with Clock icon, larger font, color coding
    • Single source of truth for expiration data
  4. Cache Hit Rate Formula Fix (bc8f0d2f)

    • Exclude output tokens from cache hit rate calculation (output tokens are never cached)
    • Formula changed from cacheRead / (input + output + cacheCreate + cacheRead) to cacheRead / (input + cacheCreate + cacheRead)
    • Affects my-usage and leaderboard displays

Testing

  • bun run lint - Biome formatting applied
  • bun run typecheck - Type checks passed
  • bun run build - Production build successful

Files Changed

  • 5 i18n files (messages/*/myUsage.json)
  • 7 TypeScript files (actions, components, repository)

All changes are scoped to the my-usage module.

🤖 Generated with Claude Code

Greptile Summary

This PR enhances the my-usage page with cache token statistics and fixes timezone-related issues for accurate date filtering.

Key Improvements:

  • Cache Statistics Feature: Added comprehensive cache token tracking (cacheCreationTokens and cacheReadTokens) to model breakdowns with a detailed modal showing cache hit rates, color-coded performance indicators (green ≥85%, yellow ≥60%, orange <60%), and token breakdowns across 5 languages.

  • Timezone Fix: Replaced browser-based date parsing with server timezone (TZ config) using fromZonedTime in getMyStatsSummary and getMyUsageLogs. This ensures consistent date filtering across different user timezones, fixing discrepancies between Daily Quota and Statistics Summary displays.

  • Cache Hit Rate Formula Correction: Updated formula to exclude output tokens (which are never cached) from cacheRead / (input + output + cacheCreate + cacheRead) to cacheRead / (input + cacheCreate + cacheRead). Applied consistently across my-usage and leaderboard modules.

  • UI Cleanup: Removed duplicate expiration displays (chips and warnings) from quota cards. Enhanced ExpirationInfo component with Clock icon, larger font, and status-based color coding for a single, improved source of truth.

Testing: All changes passed linting, type checking, and production build validation. Changes are well-scoped to the my-usage module with proper i18n support.

Confidence Score: 4/5

  • This PR is safe to merge with one minor documentation fix needed
  • The implementation is solid with correct logic for timezone handling and cache statistics. The only issue found is an outdated comment in leaderboard.ts that still references the old formula including output tokens. The code itself is correct, well-tested (lint, typecheck, build all passed), and properly scoped to the my-usage module with complete i18n coverage.
  • src/repository/leaderboard.ts requires a comment update to match the corrected cache hit rate formula

Important Files Changed

Filename Overview
src/repository/leaderboard.ts Updated cache hit rate formula to exclude output tokens (code correct, comment outdated)
src/actions/my-usage.ts Added timezone-aware date parsing and cache token fields to statistics queries
src/app/[locale]/my-usage/_components/statistics-summary-card.tsx Added detailed cache statistics modal with hit rate visualization and color coding
src/app/[locale]/my-usage/_components/quota-cards.tsx Removed duplicate expiration warnings, cleaned up expiration props
src/app/[locale]/my-usage/_components/expiration-info.tsx Enhanced expiration display with Clock icon, color coding, and improved typography

Sequence Diagram

sequenceDiagram
    participant User
    participant StatsSummaryCard
    participant getMyStatsSummary
    participant DB
    participant ModelBreakdownRow
    
    User->>StatsSummaryCard: View statistics (select date)
    StatsSummaryCard->>StatsSummaryCard: Format date with date-fns
    StatsSummaryCard->>getMyStatsSummary: Request stats with date range
    
    Note over getMyStatsSummary: Use fromZonedTime to convert<br/>date string to timestamp<br/>in configured timezone (TZ)
    
    getMyStatsSummary->>DB: Query message_request table
    Note over DB: Aggregate by model:<br/>- inputTokens<br/>- outputTokens<br/>- cacheCreationTokens<br/>- cacheReadTokens<br/>- cost
    
    DB-->>getMyStatsSummary: Return aggregated data
    getMyStatsSummary-->>StatsSummaryCard: Return ModelBreakdownItem[]
    
    StatsSummaryCard->>ModelBreakdownRow: Display each model
    
    Note over ModelBreakdownRow: Calculate cache hit rate:<br/>cacheReadTokens / <br/>(inputTokens + cacheCreationTokens<br/>+ cacheReadTokens)
    
    ModelBreakdownRow->>ModelBreakdownRow: Apply color coding<br/>(green/yellow/orange)
    
    User->>ModelBreakdownRow: Click to view details
    ModelBreakdownRow->>ModelBreakdownRow: Open modal with detailed<br/>token breakdown and<br/>cache statistics
Loading

John Doe and others added 4 commits January 16, 2026 23:00
Add cacheCreationTokens and cacheReadTokens fields to ModelBreakdownItem
interface and related DB queries for displaying cache statistics in the
statistics summary card modal.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use server timezone (TZ config) instead of browser locale when:
- Filtering statistics by date (getMyStatsSummary)
- Calculating daily quota time ranges (getTimeRangeForPeriod)

This ensures consistent date interpretation across different client
timezones. Fixes discrepancy between Daily Quota and Statistics
Summary when user is in a different timezone than the server.

Added comprehensive unit tests covering:
- Date parsing in configured timezone
- Timezone offset calculations
- Day boundary edge cases
Remove duplicate expiration information:
- Remove Key Expires chip from Welcome header (keep User Expires only)
- Remove "Expiring Soon" warning block from Quota Usage cards

Improve countdown display in ExpirationInfo component:
- Add Clock icon
- Increase font size to match date display
- Use monospace font for better readability
- Color-coded by status (emerald/amber/red)

ExpirationInfo remains the single source of expiration data.
Output tokens are never cached (per Anthropic docs), so they should not be
included in cache hit rate calculation. Changed formula from:
  cacheReadTokens / (input + output + cacheCreate + cacheRead)
to:
  cacheReadTokens / (input + cacheCreate + cacheRead)

Affects:
- /my-usage model breakdown cache hit rate display
- /dashboard/leaderboard provider cache hit rate ranking

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

在多语言使用统计中新增每模型详情模态本地化标签,扩展后端模型以采集缓存相关令牌(创建/读取),引入时区感知的日期解析,移除过期时间显示相关 props/逻辑,并调整缓存命中率的分母为“总输入令牌”。

Changes

变更组 / 文件(s) 变更总结
本地化消息
messages/en/myUsage.json, messages/ja/myUsage.json, messages/ru/myUsage.json, messages/zh-CN/myUsage.json, messages/zh-TW/myUsage.json
stats 下添加 modal 对象,包含 requests, tokens, totalTokens, cost, inputTokens, outputTokens, cacheWrite, cacheRead, cacheHitRate, cacheTokens, performanceHigh/Medium/Low 本地化键;为新增块在前一项后添加逗号(每文件 +16/-1 行)。
后端/数据聚合
src/actions/my-usage.ts
引入时区感知的日期解析(使用 env TZ 和 date-fns-tz),ModelBreakdownItem 增加 cacheCreationTokenscacheReadTokens,并在 getMyStatsSummary/getMyUsageLogs 中填充/返回这些字段(+40/-20 行)。
统计卡 & 模态
src/app/[locale]/my-usage/_components/statistics-summary-card.tsx
将每模型行改为可打开的 Dialog 详情模态,展示缓存创建/读取令牌、缓存命中率、总令牌计算与成本占比等衍生指标;ModelBreakdownRow 接口/签名扩展接受 cacheCreationTokens, cacheReadTokens, totalCost(+209/-12 行)。
移除过期时间 UI
src/app/[locale]/my-usage/_components/my-usage-header.tsx, src/app/[locale]/my-usage/_components/collapsible-quota-card.tsx, src/app/[locale]/my-usage/_components/quota-cards.tsx, src/app/[locale]/my-usage/page.tsx
从组件 props 中移除 keyExpiresAt/userExpiresAt,删除相关倒计时计算与渲染逻辑,更新调用点以不再传递这些参数(多处文件,删去若干导入与渲染分支)。
过期显示替换
src/app/[locale]/my-usage/_components/expiration-info.tsx
用时钟图标与内联单行倒计时替换 QuotaCountdownCompact,添加颜色映射并调整渲染布局(+14/-4 行)。
排行榜计算调整
src/repository/leaderboard.ts, src/app/[locale]/dashboard/leaderboard/_components/leaderboard-view.tsx
ProviderCacheHitRateLeaderboardEntry 暴露 totalInputTokens(等于 input + cacheCreation + cacheRead),在聚合表达式中以 totalInputTokens 作为 cache hit rate 的分母;前端列由 totalTokens 切换为 totalInputTokens 用于显示与排序(+10/-7、+3/-3 行)。

Estimated code review effort

🎯 3 (中等) | ⏱️ ~25 分钟

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR标题准确总结了主要变更:缓存统计和时区修复,与提交内容完全匹配。
Description check ✅ Passed PR描述详细说明了所有更改,包括缓存令牌统计、时区修复、UI清理和缓存命中率公式修正,与文件变更完全对应。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @miraserver, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the "my-usage" page by introducing detailed cache token statistics and addressing critical timezone-related issues. It also refines the user interface for expiration information and corrects the cache hit rate calculation for improved accuracy across the application.

Highlights

  • Cache Token Statistics: Added cache creation and read token fields to model breakdown and displayed cache hit rate in the statistics summary modal, with i18n support for 5 languages.
  • Timezone Fixes: Implemented server timezone (TZ config) for date filtering in usage logs and stats summary, resolving discrepancies between daily quota and statistics summary for users in different timezones.
  • UI Cleanup: Streamlined expiration displays by removing redundant elements (Key Expires chip, 'Expiring Soon' warnings) and enhancing the 'ExpirationInfo' component with a clock icon, larger font, and color coding for a single source of truth.
  • Cache Hit Rate Formula Fix: Adjusted the cache hit rate calculation to exclude output tokens, as they are never cached, affecting both my-usage and leaderboard displays for improved accuracy.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several significant improvements, including the addition of cache token statistics, crucial timezone-related fixes for date filtering, and a substantial UI cleanup that centralizes expiration information. The correction to the cache hit rate formula is also a key fix. The code is well-written and the changes are well-documented. I have one suggestion to improve the clarity of a field name in the leaderboard logic to prevent potential confusion in the future.

cacheReadTokens: sumCacheReadTokens,
cacheCreationCost: sumCacheCreationCost,
totalTokens: sumTotalTokens,
totalTokens: sumTotalInputTokens,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The field totalTokens is assigned the value of sumTotalInputTokens, which correctly excludes output tokens for the cache hit rate calculation. However, the name totalTokens is misleading as it no longer represents the sum of all tokens. This could cause confusion for future developers using this data.

To improve clarity and maintainability, I recommend renaming this field to totalInputTokens to accurately reflect its contents. This change should be applied here, in the ProviderCacheHitRateLeaderboardEntry interface, and in the final mapping that returns the data.

Suggested change
totalTokens: sumTotalInputTokens,
totalInputTokens: sumTotalInputTokens,

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (1)

  1. src/repository/leaderboard.ts, line 430 (link)

    syntax: Update comment to match the corrected formula - should be cache_read / (input + cache_creation + cache_read) without output tokens

13 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/app/`[locale]/my-usage/_components/statistics-summary-card.tsx:
- Around line 326-351: The clickable summary row uses a div with onClick but
lacks keyboard accessibility; update the root div (the element with onClick={()
=> setOpen(true)}) to add role="button", tabIndex={0}, and an onKeyDown handler
that triggers setOpen(true) when Enter or Space is pressed (handle Space by
preventing default to avoid page scroll), keeping existing classes like
cursor-pointer; ensure you reference the onClick target in the handler so
setOpen is invoked consistently.

In `@src/repository/leaderboard.ts`:
- Line 474: The ProviderCacheHitRateLeaderboardEntry currently sets totalTokens
to sumTotalInputTokens which only includes input-related tokens, causing
inconsistency with other leaderboards; rename the field to totalInputTokens
(update the ProviderCacheHitRateLeaderboardEntry type/interface and the place
where totalTokens is assigned to use totalInputTokens = sumTotalInputTokens) and
update all consumers/tests to reference totalInputTokens, or alternatively add a
clear JSDoc/comment on ProviderCacheHitRateLeaderboardEntry.totalTokens stating
it only includes input tokens if you prefer not to rename—ensure the symbol
names updated are ProviderCacheHitRateLeaderboardEntry, totalTokens (or new
totalInputTokens), and sumTotalInputTokens.
🧹 Nitpick comments (3)
src/app/[locale]/my-usage/_components/expiration-info.tsx (1)

59-65: 新增的倒计时样式映射实现合理

颜色编码与状态类型一致(正常为翠绿色、警告为琥珀色、危险为红色),且与 statusStyles 保持语义对齐。

可选优化:warningdangerexpired 的样式与 statusStyles 重复,可考虑提取公共映射以减少重复代码。

src/repository/leaderboard.ts (1)

56-58: 接口注释需要更新

接口 ProviderCacheHitRateLeaderboardEntrytotalTokens 字段的含义已变更(现仅包含输入 token),建议添加注释说明以避免混淆。

建议的修改
 export interface ProviderCacheHitRateLeaderboardEntry {
   providerId: number;
   providerName: string;
   totalRequests: number;
   cacheReadTokens: number;
   totalCost: number;
   cacheCreationCost: number;
-  totalTokens: number;
+  totalTokens: number; // 仅包含输入相关 token (input + cacheCreation + cacheRead),用于计算缓存命中率
   cacheHitRate: number; // 0-1 之间的小数,UI 层负责格式化为百分比
 }
src/actions/my-usage.ts (1)

550-561: 建议提取日期解析逻辑为复用函数。

此处的时区感知日期解析逻辑与 getMyUsageLogs(行 400-411)几乎相同。考虑提取为公共辅助函数以减少重复,例如:

function parseDateRangeWithTimezone(startDate?: string, endDate?: string) {
  const timezone = getEnvConfig().TZ;
  const parsedStart = startDate
    ? fromZonedTime(`${startDate}T00:00:00`, timezone).getTime()
    : Number.NaN;
  const parsedEnd = endDate
    ? fromZonedTime(`${endDate}T00:00:00`, timezone).getTime()
    : Number.NaN;
  return {
    startTime: Number.isFinite(parsedStart) ? parsedStart : undefined,
    endTime: Number.isFinite(parsedEnd) ? parsedEnd + 24 * 60 * 60 * 1000 : undefined,
  };
}

- Fix outdated cache hit rate comment (leaderboard.ts:430)
- Add keyboard accessibility to model breakdown rows (a11y)
- Rename totalTokens -> totalInputTokens in ProviderCacheHitRateLeaderboardEntry
- Extract parseDateRangeInServerTimezone helper to reduce duplication

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@miraserver
Copy link
Contributor Author

Review feedback addressed

Fixed all 4 issues from the code review:

1. Outdated comment (leaderboard.ts:430)

  • Removed + output from cache hit rate formula in comment

2. Accessibility (statistics-summary-card.tsx)

  • Added role="button", tabIndex={0}, and onKeyDown handler for keyboard navigation

3. Field naming (ProviderCacheHitRateLeaderboardEntry)

  • Renamed totalTokens -> totalInputTokens with JSDoc clarifying it excludes output tokens
  • Updated all references in leaderboard-view.tsx

4. Code duplication (my-usage.ts)

  • Extracted parseDateRangeInServerTimezone() helper function
  • Replaced duplicate code in getMyUsageLogs and getMyStatsSummary

Breaking change: API response for /api/leaderboard?scope=providerCacheHitRate now returns totalInputTokens instead of totalTokens

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/actions/my-usage.ts`:
- Around line 28-46: The parseDateRangeInServerTimezone function uses
date-fns-tz.fromZonedTime which is buggy for non-UTC system timezones; replace
calls to fromZonedTime in parseDateRangeInServerTimezone with
date-fns-tz.zonedTimeToUtc (or an equivalent safe function) so you convert the
local zone midnight string to a UTC timestamp using the configured timezone from
getEnvConfig().TZ, and keep the existing logic that returns startTime as the
midnight timestamp and endTime as that timestamp plus 24*60*60*1000 when endDate
is provided.

In `@src/app/`[locale]/dashboard/leaderboard/_components/leaderboard-view.tsx:
- Around line 299-305: The column header currently uses t("columns.totalTokens")
but the cell/getValue use ProviderCacheHitRateEntry.totalInputTokens so update
the i18n key to reflect input-only tokens: add a new key (e.g.
"columns.totalInputTokens") to all language files and change the column header
invocation to t("columns.totalInputTokens"); ensure the new translations (e.g.
"总输入 Token 数"/"Total Input Tokens") are present in each locale and leave the
cell/getValue/sortKey referencing totalInputTokens unchanged.

Comment on lines +28 to +46
/**
* Parse date range strings to timestamps using server timezone (TZ config).
* Returns startTime as midnight and endTime as next day midnight (exclusive upper bound).
*/
function parseDateRangeInServerTimezone(
startDate?: string,
endDate?: string
): { startTime?: number; endTime?: number } {
const timezone = getEnvConfig().TZ;
const parsedStart = startDate
? fromZonedTime(`${startDate}T00:00:00`, timezone).getTime()
: Number.NaN;
const parsedEnd = endDate ? fromZonedTime(`${endDate}T00:00:00`, timezone).getTime() : Number.NaN;

return {
startTime: Number.isFinite(parsedStart) ? parsedStart : undefined,
endTime: Number.isFinite(parsedEnd) ? parsedEnd + 24 * 60 * 60 * 1000 : undefined,
};
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

date-fns-tz fromZonedTime undefined timezone behavior

💡 Result:

Short answer: fromZonedTime has a known implementation issue — it reads date parts with getHours()/getFullYear() (local-time getters) and then builds a UTC Date from those parts, so the result is only correct if the environment's system time zone is UTC. That makes conversions wrong when your system TZ ≠ UTC (including cases where you pass undefined/omit a timeZone). See the GitHub issue describing the problem and the library docs for the intended behavior. [1][2]

What to do:

  • Always pass an explicit IANA time zone (e.g. "America/New_York"), and prefer toZonedTime / zonedTimeToUtc or formatInTimeZone for most flows. [2]
  • If you need a safe conversion regardless of the environment, convert/parse with explicit offsets or use functions that operate on UTC inputs instead. [2][1]

Sources:
[1] GitHub issue describing the fromZonedTime bug.
[2] date-fns-tz README / docs (function descriptions: fromZonedTime, toZonedTime, formatInTimeZone).


🏁 Script executed:

# Check the function definition and export type in the file
cat -n src/actions/my-usage.ts | sed -n '25,50p'

Repository: ding113/claude-code-hub

Length of output: 1184


🏁 Script executed:

# Find and examine getEnvConfig implementation
fd config -t f | grep -E "(config|lib)" | head -20

Repository: ding113/claude-code-hub

Length of output: 772


🏁 Script executed:

# Check imports and overall structure
head -n 50 src/actions/my-usage.ts

Repository: ding113/claude-code-hub

Length of output: 1963


🏁 Script executed:

# Find where parseDateRangeInServerTimezone is exported
grep -n "export.*parseDateRangeInServerTimezone" src/actions/my-usage.ts

Repository: ding113/claude-code-hub

Length of output: 49


🏁 Script executed:

# Check getEnvConfig implementation and TZ default value
cat -n src/lib/config/config.ts | head -100

Repository: ding113/claude-code-hub

Length of output: 367


🏁 Script executed:

# Verify export statement nearby
grep -n "export" src/actions/my-usage.ts | head -20

Repository: ding113/claude-code-hub

Length of output: 954


🏁 Script executed:

# Check env.schema for TZ configuration
fd env.schema -t f

Repository: ding113/claude-code-hub

Length of output: 95


🏁 Script executed:

# Look for TZ in the config files
rg "TZ" src/lib/config/ -A 3 -B 1

Repository: ding113/claude-code-hub

Length of output: 547


🏁 Script executed:

# Check if parseDateRangeInServerTimezone is used in getMyUsageLogs and getMyStatsSummary
sed -n '407,430p' src/actions/my-usage.ts

Repository: ding113/claude-code-hub

Length of output: 878


🏁 Script executed:

# Check if there are any comments or issues about timezone handling
rg "fromZonedTime\|zonedTimeToUtc\|toZonedTime" src/ -t ts -t tsx

Repository: ding113/claude-code-hub

Length of output: 94


🏁 Script executed:

# Verify the code structure around the function to understand context
sed -n '550,570p' src/actions/my-usage.ts

Repository: ding113/claude-code-hub

Length of output: 762


🏁 Script executed:

# Check if there are any other timezone-related utilities or fixes in the codebase
rg "timezone\|toZonedTime\|zonedTimeToUtc" src/ --type ts -C 2

Repository: ding113/claude-code-hub

Length of output: 49


🏁 Script executed:

# Verify the specific issue: understand how fromZonedTime is being used and what the expected behavior is
cat -n src/actions/my-usage.ts | sed -n '1,10p'

Repository: ding113/claude-code-hub

Length of output: 548


fromZonedTime 存在已知 Bug,会导致时区转换错误。

date-fns-tz 中的 fromZonedTime 函数存在实现缺陷:它使用本地时间的 getter 方法(getHours()getFullYear() 等)而非正确的 UTC 转换,只在系统时区为 UTC 时才能正常工作。即使配置了 TZ: "Asia/Shanghai",如果部署环境的系统时区不是 UTC,该函数返回的时间戳仍会错误。这会导致 getMyUsageLogsgetMyStatsSummary 返回的日期范围查询结果不准确。

改用 zonedTimeToUtc 或其他库提供的安全函数替代 fromZonedTime

🤖 Prompt for AI Agents
In `@src/actions/my-usage.ts` around lines 28 - 46, The
parseDateRangeInServerTimezone function uses date-fns-tz.fromZonedTime which is
buggy for non-UTC system timezones; replace calls to fromZonedTime in
parseDateRangeInServerTimezone with date-fns-tz.zonedTimeToUtc (or an equivalent
safe function) so you convert the local zone midnight string to a UTC timestamp
using the configured timezone from getEnvConfig().TZ, and keep the existing
logic that returns startTime as the midnight timestamp and endTime as that
timestamp plus 24*60*60*1000 when endDate is provided.

Comment on lines 299 to 305
{
header: t("columns.totalTokens"),
className: "text-right",
cell: (row) => formatTokenAmount((row as ProviderCacheHitRateEntry).totalTokens),
sortKey: "totalTokens",
getValue: (row) => (row as ProviderCacheHitRateEntry).totalTokens,
cell: (row) => formatTokenAmount((row as ProviderCacheHitRateEntry).totalInputTokens),
sortKey: "totalInputTokens",
getValue: (row) => (row as ProviderCacheHitRateEntry).totalInputTokens,
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the specific file and lines
cat -n src/app/[locale]/dashboard/leaderboard/_components/leaderboard-view.tsx | sed -n '295,310p'

Repository: ding113/claude-code-hub

Length of output: 774


🏁 Script executed:

# Find and check the i18n message files for the columns.totalTokens key
fd -type f -name "*.json" -path "*/messages/*" | head -20

Repository: ding113/claude-code-hub

Length of output: 237


🏁 Script executed:

# Search for columns.totalTokens in i18n files
rg "totalTokens" -t json src/

Repository: ding113/claude-code-hub

Length of output: 49


🏁 Script executed:

# Find all message/i18n JSON files
find . -type f -name "*.json" -path "*messages*" | head -20

Repository: ding113/claude-code-hub

Length of output: 705


🏁 Script executed:

# Search for totalTokens more broadly, not just in src/
rg "totalTokens" --type json

Repository: ding113/claude-code-hub

Length of output: 1600


🏁 Script executed:

# Check what changed in the PR by looking at git diff for i18n files
git diff --name-only | grep -i messages

Repository: ding113/claude-code-hub

Length of output: 49


🏁 Script executed:

# Check the structure of dashboard.json files, specifically looking for columns key
rg -A 2 -B 2 "columns" messages/en/dashboard.json | head -50

Repository: ding113/claude-code-hub

Length of output: 1045


🏁 Script executed:

# Let's look at the actual JSON structure around totalTokens in dashboard files
python3 << 'EOF'
import json
import glob

for file in glob.glob("messages/*/dashboard.json"):
    try:
        with open(file, 'r', encoding='utf-8') as f:
            data = json.load(f)
        # Check if 'columns' key exists
        if 'columns' in data:
            print(f"\n=== {file} ===")
            print("columns keys:", list(data['columns'].keys()))
            if 'totalTokens' in data['columns']:
                print(f"columns.totalTokens = {data['columns']['totalTokens']}")
        # Also check leaderboard section
        if 'leaderboard' in data and isinstance(data['leaderboard'], dict):
            if 'columns' in data['leaderboard']:
                print(f"\n=== {file} (leaderboard.columns) ===")
                print("leaderboard.columns keys:", list(data['leaderboard']['columns'].keys())[:10])
                if 'totalTokens' in data['leaderboard']['columns']:
                    print(f"leaderboard.columns.totalTokens = {data['leaderboard']['columns']['totalTokens']}")
    except Exception as e:
        print(f"Error reading {file}: {e}")
EOF

Repository: ding113/claude-code-hub

Length of output: 153


🏁 Script executed:

# Extract just the leaderboard section from one dashboard file
jq '.leaderboard' messages/en/dashboard.json 2>/dev/null | head -100

Repository: ding113/claude-code-hub

Length of output: 2567


🏁 Script executed:

# Search for both totalTokens and totalInputTokens in the message files
rg "totalInputTokens" messages/

Repository: ding113/claude-code-hub

Length of output: 49


🏁 Script executed:

# Check the exact structure - look for where columns.totalTokens is defined
rg -B 5 "totalTokens" messages/en/dashboard.json | grep -E "(leaderboard|columns|totalTokens)" | head -20

Repository: ding113/claude-code-hub

Length of output: 140


列标题与实际数据语义不匹配,需要更新国际化 key

逻辑变更正确:将 totalInputTokens 用于缓存命中率计算符合 PR 目标,与已有经验一致(缓存计算仅包含输入相关令牌)。

但存在 UX 问题:第 300 行的列标题使用 t("columns.totalTokens"),该 i18n key 在所有语言文件中均定义为"总 Token 数"/"Total Tokens",隐含包含所有 Token 类型(输入+输出)。而实际显示的数据仅为 totalInputTokens(输入令牌),造成语义不符。

需修复

  • 创建新的 i18n key(如 columns.totalInputTokens),在 5 个语言文件中定义为"总输入 Token 数"等
  • 或更新列标题代码为 t("columns.totalInputTokens")

否则用户会误解为该列显示全部 Token。

🤖 Prompt for AI Agents
In `@src/app/`[locale]/dashboard/leaderboard/_components/leaderboard-view.tsx
around lines 299 - 305, The column header currently uses
t("columns.totalTokens") but the cell/getValue use
ProviderCacheHitRateEntry.totalInputTokens so update the i18n key to reflect
input-only tokens: add a new key (e.g. "columns.totalInputTokens") to all
language files and change the column header invocation to
t("columns.totalInputTokens"); ensure the new translations (e.g. "总输入 Token
数"/"Total Input Tokens") are present in each locale and leave the
cell/getValue/sortKey referencing totalInputTokens unchanged.

Keep returning totalTokens (deprecated) alongside totalInputTokens
for API consumers that haven't migrated yet.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/repository/leaderboard.ts (1)

477-500: deprecated 的 totalTokens 语义已变更,兼容性不完整

当前 totalTokens 直接等于 totalInputTokens,会让旧消费方拿到更小的值(不含 outputTokens),与“向后兼容”的预期不一致。建议保留旧 totalTokens 计算(含 outputTokens),同时新增 totalInputTokens 供新分母使用。

Proposed fix
   const totalInputTokensExpr = sql<number>`(
     COALESCE(${messageRequest.inputTokens}, 0) +
     COALESCE(${messageRequest.cacheCreationInputTokens}, 0) +
     COALESCE(${messageRequest.cacheReadInputTokens}, 0)
   )`;
+  const totalTokensExpr = sql<number>`(
+    COALESCE(${messageRequest.inputTokens}, 0) +
+    COALESCE(${messageRequest.outputTokens}, 0) +
+    COALESCE(${messageRequest.cacheCreationInputTokens}, 0) +
+    COALESCE(${messageRequest.cacheReadInputTokens}, 0)
+  )`;

   const sumTotalInputTokens = sql<number>`COALESCE(sum(${totalInputTokensExpr})::double precision, 0::double precision)`;
+  const sumTotalTokens = sql<number>`COALESCE(sum(${totalTokensExpr})::double precision, 0::double precision)`;

   const rankings = await db
     .select({
       providerId: messageRequest.providerId,
       providerName: providers.name,
       totalRequests: sql<number>`count(*)::double precision`,
       totalCost: sql<string>`COALESCE(sum(${messageRequest.costUsd}), 0)`,
       cacheReadTokens: sumCacheReadTokens,
       cacheCreationCost: sumCacheCreationCost,
       totalInputTokens: sumTotalInputTokens,
+      totalTokens: sumTotalTokens,
       cacheHitRate: cacheHitRateExpr,
     })

   return rankings.map((entry) => ({
     providerId: entry.providerId,
     providerName: entry.providerName,
     totalRequests: entry.totalRequests,
     totalCost: parseFloat(entry.totalCost),
     cacheReadTokens: entry.cacheReadTokens,
     cacheCreationCost: parseFloat(entry.cacheCreationCost),
     totalInputTokens: entry.totalInputTokens,
-    totalTokens: entry.totalInputTokens, // deprecated, for backward compatibility
+    totalTokens: entry.totalTokens, // deprecated, for backward compatibility
     cacheHitRate: Math.min(Math.max(entry.cacheHitRate ?? 0, 0), 1),
   }));

@ding113
Copy link
Owner

ding113 commented Jan 18, 2026

Regarding the timezone issue, can we modify .env.example to explicitly add a TZ variable and use it in the system?
This would make future maintenance easier.

@miraserver
Copy link
Contributor Author

miraserver commented Jan 18, 2026

Regarding the timezone issue, can we modify .env.example to explicitly add a TZ variable and use it in the system?
This would make future maintenance easier.

I've already thought about this and tried it, but I still decided not to include it in this PR.

I'll try to explain
there are too many fixes everywhere. There are some issues, namely a performance issue when defining such a variable and reading from env.

But the main issue is too many fixes - admin logs, my-usage logs and etc.
It turns out that rate limits are strictly tied to server time. Meanwhile, the admins log dashboard's TODAY button shows a data based on the user's browser time. But I set my-usage TODAY to server time, otherwise the data won't match the daily rate limit data.

admin dashboard logs TODAY - based on browser user time
my-usage logs and stats - TODAY - based on server time
rate limits per user (example daytime limit) - based on server time

I think we should leave the server time and just write it in UI (make a tooltip) so that the user and the admin understand what time the TODAY/YESTERDAY button refers to

I suggest moving the timezome variable to a separate PR later.

@ding113 ding113 merged commit 745df9b into ding113:dev Jan 19, 2026
7 of 9 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in Claude Code Hub Roadmap Jan 19, 2026
@github-actions github-actions bot mentioned this pull request Jan 19, 2026
9 tasks
ding113 added a commit that referenced this pull request Jan 20, 2026
* fix: 清理 usage-doc / big-screen i18n 硬编码 + 修复 Next.js params Promise 报错

* feat(leaderboard): add user tag and group filters for user ranking (#607)

* feat(leaderboard): add user tag and group filters for user ranking (#606)

Add filtering capability to the leaderboard user ranking by:
- userTags: filter users by their tags (OR logic)
- userGroups: filter users by their providerGroup (OR logic)

Changes:
- Repository: Add UserLeaderboardFilters interface and SQL filtering
- Cache: Extend LeaderboardFilters and include filters in cache key
- API: Parse userTags/userGroups query params (CSV format, max 20)
- Frontend: Add TagInput filters (admin-only, user scope only)
- i18n: Add translation keys for 5 languages

Closes #606

* refactor: apply reviewer suggestions for leaderboard filters

- Use JSONB ? operator instead of @> for better performance
- Extract parseListParam helper to reduce code duplication

* feat(leaderboard): add tag/group suggestions dropdown for better UX

- Fetch all user tags and groups via getAllUserTags/getAllUserKeyGroups
- Pass suggestions to TagInput for autocomplete dropdown
- Validate input against available suggestions
- Consistent with /dashboard/users filter behavior

* docs: update Privnode offer details in README files

* fix: 修复 1M 上下文标头兼容问题

* fix: resolve container name conflicts in multi-user environments (#625)

* fix: resolve container name conflicts in multi-user environments

- Add top-level `name` field with COMPOSE_PROJECT_NAME env var support
- Remove hardcoded container_name from all services
- Users can now set COMPOSE_PROJECT_NAME in .env for complete isolation

Closes #624

* fix: add top-level name field for project isolation

Add `name: ${COMPOSE_PROJECT_NAME:-claude-code-hub}` to enable
complete project isolation via environment variable.

* feat(dashboard): improve user management, statistics reset, and i18n (#610)

* fix(dashboard/logs): add reset options to filters and use short time format

- Add "All keys" SelectItem to API Key filter dropdown
- Add "All status codes" SelectItem to Status Code filter dropdown
- Use __all__ value instead of empty string (Radix Select requirement)
- Add formatDateDistanceShort() for compact time display (2h ago, 3d ago)
- Update RelativeTime component to use short format

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(providers): add Auto Sort button to dashboard and fix i18n

- Add AutoSortPriorityDialog to dashboard/providers page
- EN: "Auto Sort Priority" -> "Auto Sort"
- RU: "Авто сортировка приоритета" -> "Автосорт"
- RU: "Добавить провайдера" -> "Добавить поставщика"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(i18n): improve Russian localization and fix login errors

Russian localization improvements:
- Menu: "Управление поставщиками" -> "Поставщики"
- Menu: "Доступность" -> "Мониторинг"
- Filters: "Последние 7/30 дней" -> "7д/30д"
- Dashboard: "Статистика использования" -> "Статистика"
- Dashboard: "Показать статистику..." -> "Только ваши ключи"
- Quota: add missing translations (manageNotice, withQuotas, etc.)

Login error localization:
- Fix issue where login errors displayed in Chinese ("无效或已过期") regardless of locale
- Add locale detection from NEXT_LOCALE cookie and Accept-Language header
- Add 3 new error keys: apiKeyRequired, apiKeyInvalidOrExpired, serverError
- Support all 5 languages: EN, JA, RU, ZH-CN, ZH-TW
- Remove product name from login privacyNote for all locales

Files changed:
- messages/*/auth.json: new error keys, update privacyNote
- messages/ru/dashboard.json, messages/ru/quota.json: Russian improvements
- src/app/api/auth/login/route.ts: add getLocaleFromRequest()

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* feat(dashboard/users): improve user management with key quotas and tokens

- Add access/model restrictions support (allowedClients/allowedModels)
- Add tokens column and refresh button to users table
- Add todayTokens calculation in repository layer (sum all token types)
- Add visual status indicators with color-coded icons (active/disabled/expiring/expired)
- Allow users to view their own key quota (was admin-only)
- Fix React Query cache invalidation on status toggle
- Fix filter logic: change tag/keyGroup from OR to AND
- Refactor time display: move formatDateDistanceShort to component with i18n
- Add fixed header/footer to key dialogs for better UX

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* feat(dashboard/users): add reset statistics with optimized Redis pipeline

- Implement reset all statistics functionality for admins
- Optimize Redis operations: replace sequential redis.keys() with parallel SCAN
- Add scanPattern() helper for production-safe key scanning
- Comprehensive error handling and performance metrics logging
- 50-100x performance improvement with no Redis blocking

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(lint): apply biome formatting and fix React hooks dependencies

- Fix useEffect dependencies in RelativeTime component (wrap formatShortDistance in useCallback)
- Remove unused effectiveGroupText variable in key-row-item.tsx
- Apply consistent LF line endings across modified files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: address code review feedback from PR #610

- Remove duplicate max-h class in edit-key-dialog.tsx (keep max-h-[90dvh] only)
- Add try-catch fallback for getTranslations in login route catch block

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: translate Russian comments to English for consistency

Addresses Gemini Code Assist review feedback.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(users): add unit tests for resetUserAllStatistics function

Cover all requirement scenarios:
- Permission check (admin-only)
- User not found handling
- Success path with DB + Redis cleanup
- Redis not ready graceful handling
- Redis partial failure warning
- scanPattern failure warning
- pipeline.exec failure error logging
- Unexpected error handling
- Empty keys list handling

10 test cases with full mock coverage.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: John Doe <johndoe@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* feat(my-usage): cache statistics and timezone fixes (#623)

* feat(my-usage): add cache token statistics to model breakdown

Add cacheCreationTokens and cacheReadTokens fields to ModelBreakdownItem
interface and related DB queries for displaying cache statistics in the
statistics summary card modal.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(my-usage): use configured timezone for date filtering

Use server timezone (TZ config) instead of browser locale when:
- Filtering statistics by date (getMyStatsSummary)
- Calculating daily quota time ranges (getTimeRangeForPeriod)

This ensures consistent date interpretation across different client
timezones. Fixes discrepancy between Daily Quota and Statistics
Summary when user is in a different timezone than the server.

Added comprehensive unit tests covering:
- Date parsing in configured timezone
- Timezone offset calculations
- Day boundary edge cases

* refactor(my-usage): clean up expiration displays

Remove duplicate expiration information:
- Remove Key Expires chip from Welcome header (keep User Expires only)
- Remove "Expiring Soon" warning block from Quota Usage cards

Improve countdown display in ExpirationInfo component:
- Add Clock icon
- Increase font size to match date display
- Use monospace font for better readability
- Color-coded by status (emerald/amber/red)

ExpirationInfo remains the single source of expiration data.

* fix: correct cache hit rate formula to exclude output tokens

Output tokens are never cached (per Anthropic docs), so they should not be
included in cache hit rate calculation. Changed formula from:
  cacheReadTokens / (input + output + cacheCreate + cacheRead)
to:
  cacheReadTokens / (input + cacheCreate + cacheRead)

Affects:
- /my-usage model breakdown cache hit rate display
- /dashboard/leaderboard provider cache hit rate ranking

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: address PR #623 review feedback

- Fix outdated cache hit rate comment (leaderboard.ts:430)
- Add keyboard accessibility to model breakdown rows (a11y)
- Rename totalTokens -> totalInputTokens in ProviderCacheHitRateLeaderboardEntry
- Extract parseDateRangeInServerTimezone helper to reduce duplication

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: add backward compatibility for totalTokens field

Keep returning totalTokens (deprecated) alongside totalInputTokens
for API consumers that haven't migrated yet.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: John Doe <johndoe@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* fix: Set HOSTNAME environment variable in Dockerfile (#622)

Add HOSTNAME environment variable for container

* fix: inherit 1M flag from client

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* fix(my-usage): make date range DST-safe

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* test(api): cover leaderboard comma-list parsing

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix(auth): avoid hardcoded server error fallback

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix(actions): localize key quota permission errors

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* docs: clarify context 1M inherit behavior

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* test(settings): fix model multi-select messages loader

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* test(dashboard): provide QueryClientProvider in edit key form test

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* chore(scripts): avoid hardcoded docker container names

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix(i18n): replace fullwidth parentheses in ja dashboard

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix(ui): add a11y label and clean up dialog styles

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* chore: ignore tmp scratch directory

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* feat: Dashboard Logs:秒级时间筛选 + Session ID 精确筛选/联想/展示(含回归修复) (#611)

* feat: add sessionId filter for usage logs

* feat: add seconds-level time filters for logs

* feat: wire sessionId into logs URL filters

* chore: add i18n keys for logs sessionId

* feat: add sessionId column to logs tables

* feat: add sessionId suggestions for logs

* docs: document dashboard logs call chain

* test: add logs sessionId/time filter coverage config

* fix: keep sessionId search input focused

* fix: drop leaked page param on logs apply

* fix: reload sessionId suggestions on scope change

* fix: harden logs url params and time parsing

* fix: avoid keys join for sessionId suggestions

* test: strengthen empty sessionId filter assertions

* chore: format logs sessionId suggestions test

* Update src/actions/usage-logs.ts

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* feat: 补充公共静态变量 SESSION_ID_SUGGESTION_LIMIT

* fix: use prefix LIKE for sessionId suggestions

* refactor: centralize usage logs sessionId suggestion constants

* refactor: simplify logs url filters parsing

* refactor: reuse clipboard util for sessionId copy

* chore(db): add sessionId prefix index

* docs: clarify sessionId suggestion semantics

* test: add escapeLike unit tests

* chore: apply biome fixes for sessionId search

* feat: include session id in error responses

* test: add coverage suite for session id errors

* docs: add guide for error session id

* chore: format code (feat-logs-sessionid-time-filter-233f96a)

* feat(dashboard/logs): add fullscreen mode (#632)

* Fix provider exhaustion after model redirect (refs #629) (#633)

* Fix provider fallback after model redirect

Use original model for provider selection during failover and tolerate tool_result blocks in non-stream converters to prevent premature provider exhaustion. References #629.

* Add regression test for model redirect provider selection

Ensures provider selection uses original model even when current model is redirected (refs #629).

* chore: format code (fix-629-provider-fallback-toolresult-b17f671)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

---------

Co-authored-by: YangQing-Lin <56943790+YangQing-Lin@users.noreply.github.com>
Co-authored-by: SaladDay <92240037+SaladDay@users.noreply.github.com>
Co-authored-by: miraserver <20286838+miraserver@users.noreply.github.com>
Co-authored-by: John Doe <johndoe@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: hwa <yll2002mail@gmail.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Ding <ding113@users.noreply.github.com>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants