Conversation
- Extend ErrorDetectionResult with ruleId and description fields - Add matchedRule field to ProviderChainItem.errorDetails - Record matched error rule info in client_error_non_retryable branch - Add client_error_non_retryable formatting in provider-chain-formatter - Add getProviderStatus and isActualRequest handling for new reason type - Add i18n translations for all 5 locales Closes #416 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Non-admin users could see "Quotas" nav but were redirected away. Now they see "My Quota" nav linking to a read-only quota view. - Add /dashboard/my-quota page reusing QuotaCards component - Update nav to show role-specific labels and routes - Unify redirect targets for non-admin users - Add i18n keys for all 5 languages Closes #412 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add headersToSanitizedObject and parseHeaderRecord helpers in session-manager.ts - Store sanitized request/response headers to Redis with SESSION_TTL - Extend getSessionDetails API to return requestHeaders/responseHeaders - Refactor session details UI from vertical layout to 4-tab layout - Add i18n keys for 5 locales (en, ja, ru, zh-CN, zh-TW) - Add input validation for seq URL parameter to prevent NaN issues Closes #417 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add error state handling in my-quota page (show Alert instead of empty state) - Fix quotas/keys redirect to /dashboard/my-quota for consistency Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Address PR review feedback from Gemini Code Assist: replace truthiness checks with explicit !== undefined comparisons for pattern, matchType, and category fields. This prevents potential false negatives when these fields contain empty strings. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat(error-rules): record matched rule details in decision chain (#416)
Simplifies the JSX structure by removing unnecessary inner div elements in both the error state and success state render paths. Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
fix: add my-quota page for non-admin users
- Add ProviderGroupSelect for admin user/key editing - Support multi-select for non-admin key creation with TagInputField - Auto-remove 'default' group when selecting other groups - Keep dropdown open during multi-selection (tag-input) - Display user provider group as read-only badges - Adjust key row grid layout for better group/expiry column balance - Show +N for remaining groups when >1 group exists 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ttfb_ms field to message_request table for Time To First Byte tracking - Record TTFB at first chunk arrival (streaming) or use durationMs fallback (non-streaming) - Add performance section to ErrorDetailsDialog showing TTFB, duration, and output rate - Update provider leaderboard: replace avgResponseTime with avgTtfbMs and avgTokensPerSecond - Add i18n support for all 5 locales (en, zh-CN, zh-TW, ja, ru) Implementation details: - ProxySession.recordTtfb() method with idempotent design - Gemini passthrough records TTFB at response received time - Output rate calculated as outputTokens / ((durationMs - ttfbMs) / 1000) - Display "-" for null/zero values instead of misleading "0" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ection feat: enhance provider group selection in users page [#423]
… and add JSON parse logging - Extract normalizeRequestSequence to src/lib/utils/request-sequence.ts (DRY) - Use Number.isSafeInteger() for stronger validation (per Codex review) - Add logger.warn in parseHeaderRecord catch block for JSON parse failures - Unify return type to number | null Addresses PR #420 review feedback: - Gemini: duplicate normalizeRequestSequence functions - GitHub Actions: silent JSON parse error in parseHeaderRecord Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat(session): add request/response headers logging with Tab UI
feat(perf): add TTFB and output rate tracking (#421)
- Add tests for normalizeRequestSequence (edge cases, type errors) - Add tests for parseHeaderRecord (JSON parsing, logger.warn verification) - Add tests for headersToSanitizedObject (header conversion, colon handling) - Export helper functions from session-manager.ts for testing 12 test cases covering all scenarios Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… height - Fix incorrect i18n namespace in edit-key-form.tsx (add dashboard. prefix) - Add missing enableStatus translations for ja/ru/zh-TW locales - Fix ResponsiveContainer height propagation in chart.tsx - Make statistics chart height responsive (320px mobile, 400px desktop) - Add legend scroll container with max-height - Improve legend accessibility with button elements and aria-pressed Closes #426 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add dashboard.rateLimits block to en/ja/ru/zh-TW (was only in zh-CN) - Add dashboard.userManagement.userStatus to ja/ru/zh-TW - Fixes rate limit dashboard i18n fallback issues - Fixes user status toggle i18n fallback issues Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
当覆写响应的 message 与测试输入相同时,测试页面会误报 "覆写响应的 message 为空"。修改判断逻辑为检查 message 本身是否为空,而不是检查最终结果是否等于原始消息。
Add a new error rule to handle the "all messages must have non-empty content except for the optional final assistant message" validation error from Claude API. This is a non-retryable client error that should not trigger provider retries. Closes #432 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
#430) Enable distinct session tracking for multiple concurrent Codex CLI sessions from the same user by extracting session_id from request headers/body. Changes: - Add session-extractor.ts with priority-based session ID extraction - Extend SessionManager.extractClientSessionId() to accept headers/userAgent - Pass headers/userAgent from ProxySessionGuard to session extraction - Preserve original session_id in Codex-to-Claude request transformation Security hardening: - Session ID length validation (21-256 chars) - Character whitelist validation (alphanumeric, dash, dot, colon) Backward compatible: Claude/OpenAI format requests unaffected. Closes #430 Generated with [Claude Code](https://claude.ai/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Issue #428: User/Provider filter dropdown unusable with 100+ items - Replace <Select> with Popover + Command (searchable combobox) - Add search filtering, keyboard navigation, clear selection - Add i18n translations for all 5 locales Issue #429: User list pagination shows duplicate records - Fix timestamp precision loss (microseconds -> milliseconds) - Use PostgreSQL to_char() to preserve full 6-digit precision - Apply same fix to usage-logs pagination Files changed: - src/app/[locale]/dashboard/logs/_components/usage-logs-filters.tsx - src/repository/user.ts - src/repository/usage-logs.ts - messages/*/dashboard.json (5 locales) Closes #428, Closes #429 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…r-rule Fix #432: Add error rule for empty message content validation
- Merge 4 token columns into 2: Tokens (input/output) and Cache (write/read) - Enhance duration column to Performance: duration + TTFB + output rate (tok/s) - Extract shared functions to performance-formatter.ts utility - Fix formatDuration handling of 0 value (use == null instead of !value) - Unify cost multiplier badge character to multiplication sign - Add i18n keys for new columns in all 5 locales Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
fix: 修复错误规则测试页面的误报警告
主要改动: 1. 认证错误优化 (auth-guard.ts, session.ts) - 替换通用错误为5个详细场景的中文错误消息 - 添加 errorResponse 字段用于传递详细错误 - 错误场景:未提供凭据、冲突密钥、密钥无效、用户禁用、用户过期 2. 用户列表 UI 优化 (user-key-table-row.tsx) - 添加用户状态徽章(正常/已过期/即将过期/禁用) - Provider Group 拆分显示为彩色徽章(最多2个 + "+N") - 用户标签以 [tag1, tag2] 格式显示 - 改进过期时间验证逻辑(使用 Number.isFinite) 3. 密钥状态优化 (key-row-item.tsx) - 添加密钥状态徽章 - 修复 formatExpiry 函数重复定义问题 - 正确处理"永不过期"等无法解析的日期文本 - Provider Group 拆分显示(最多1个 + "+N") 4. 国际化支持 (dashboard.json) - 为 zh-CN, en, ja, ru, zh-TW 添加 keyStatus 和 userStatus 翻译 - 添加 active, expired, expiringSoon 状态翻译 技术改进: - 72小时过期预警阈值 - 乐观 UI 更新模式 - 更安全的数字验证(Number.isFinite) - 统一错误消息语言(中文) Closes #425
**Issue #431**: 修复删除禁用 key 时的错误提示 - 问题:删除已禁用的 key 时,系统错误地提示"至少需要保留一个可用密钥" - 原因:未区分要删除的 key 是启用还是禁用状态 - 修复:只有删除启用的 key 时才检查剩余启用 key 数量 - 位置:src/actions/keys.ts:478-488 **Issue #438**: 修复删除 key 后前端未刷新的问题 - 问题:删除 key 后,前端页面没有实时刷新,已删除的 key 仍然显示 - 原因:只调用了 router.refresh(),但没有使 React Query 缓存失效 - 修复:在删除成功后调用 queryClient.invalidateQueries({ queryKey: ["users"] }) - 位置:src/app/[locale]/dashboard/_components/user/user-key-table-row.tsx:107,151 **变更内容**: - src/actions/keys.ts: 添加 key.isEnabled 条件判断,只对启用的 key 进行数量检查 - src/app/[locale]/dashboard/_components/user/user-key-table-row.tsx: - 导入 useQueryClient hook - 在 handleDeleteKey 中添加缓存失效逻辑 **符合原则**: - SOLID: 单一职责,每个检查都有明确的职责 - KISS: 逻辑简单清晰,易于理解 - DRY: 与 toggleKeyEnabled 函数保持一致的验证逻辑
- Export normalizeCodexSessionId for unified validation - Add prefix length check to prevent sessionId > 256 chars - Block Codex request fallback to unvalidated metadata - Add boundary value tests (21 and 256 chars) Fixes: - Critical: session_id validation bypass via metadata fallback - Medium: codex_prev_ prefix could exceed 256 char limit - Medium: generateUserID lacked unified validation Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
**问题1**: Key 侧快捷续期时间计算不准确
- 问题:快捷选择 7 天时,实际只延长约 7 天减去当前小时数
- 原因:使用 addDays() 后没有设置时间到当天结束 (23:59:59.999)
- 修复:添加 newDate.setHours(23, 59, 59, 999) 确保整天有效
- 位置:src/app/[locale]/dashboard/_components/user/forms/quick-renew-key-dialog.tsx:104-105
**问题2**: 用户侧快捷续期后前端未实时刷新
- 问题:续期后页面不刷新,显示旧数据
- 原因:只调用 router.refresh(),未使 React Query 缓存失效
- 修复:添加 queryClient.invalidateQueries({ queryKey: ["users"] })
- 位置:src/app/[locale]/dashboard/_components/user/user-management-table.tsx:122,356
**变更内容**:
- quick-renew-key-dialog.tsx: 添加时间设置到当天结束
- user-management-table.tsx:
- 导入 useQueryClient hook
- 在续期成功后使缓存失效
**验证**:
- ✅ TypeScript 类型检查通过
- ✅ 与用户侧 quick-renew-dialog.tsx 保持一致的时间处理逻辑
- ✅ 与 #438 修复保持一致的缓存失效策略
- Fix to_char timezone issue in cursor pagination (user.ts:189, usage-logs.ts:187) - Add AT TIME ZONE 'UTC' to ensure consistent UTC output - Prevents cursor mismatch in non-UTC deployments - Optimize filter dropdown lookup performance (usage-logs-filters.tsx) - Add userMap/providerMap useMemo for O(1) name lookup - Replace Array.find() with Map.get() for 100+ item scenarios Addresses PR #436 review feedback from Codex AI Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
fix(pagination): resolve PR review issues - timezone and performance
- Add form submission validation to ensure at least one key remains enabled - Disable Switch and show tooltip when trying to disable the last enabled key - Add i18n translations for all locales (zh-CN, en, ja, ru, zh-TW) Related to issue #431 and key deletion protection improvements
Previously, when creating a new key through the edit user dialog with isEnabled set to false, the key would still be created as enabled. This was because: 1. addKey() function signature was missing the isEnabled parameter 2. The implementation hardcoded is_enabled to true 3. The frontend was passing the value but it was silently ignored Changes: - Add isEnabled parameter to addKey() function signature - Use data.isEnabled ?? true in createKey() call (defaults to true) - Pass isEnabled: key.isEnabled from unified-edit-dialog Fixes the issue where disabled keys were always created as enabled.
- Remove accidental key-edit-section.tsx changes from PR scope - Optimize calculateOutputRate to single call per row (avoid redundant calculation) - Remove unused formatPerformanceSecondLine function (dead code cleanup) - Add missing i18n keys (tokens, cache, performance) to all locales Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove the _extraKeyGroupOption rename that was accidentally included in the logs table optimization PR. Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat(logs): optimize usage logs table columns and performance display
Previously, the error message for CANNOT_DISABLE_LAST_KEY had a hardcoded Chinese fallback text "无法禁用最后一个可用密钥". This violated i18n principles because: 1. All 5 languages (en/ja/ru/zh-CN/zh-TW) already have proper translations in errors.json 2. The hardcoded fallback would show Chinese to non-Chinese users if i18n system failed 3. It's inconsistent with other error messages that don't have fallbacks Changes: - Removed hardcoded fallback from batchUpdateKeys (2 occurrences) - Now relies on proper i18n translations from errors.json Related translations: - en: "Cannot disable the last active key..." - zh-CN: "无法禁用最后一个可用密钥..." - zh-TW: "無法禁用最後一個可用金鑰..."
- Convert all columns from fixed/mixed widths to flex layout - Adjust flex weights: time(0.8), user/key(0.6), provider/model(1), tokens(0.7), cache(0.8), cost(0.7), performance(0.8), status(0.7) - Move cost multiplier badge inline with provider name - Split TTFB and tok/s into separate lines in performance column Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…imization feat: 优化认证错误和用户/密钥状态显示 (Issue #425)
- Change provider column from flex-[1] to flex-[1.5] - Increase min-width from 80px to 100px Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🧪 测试结果
总体结果: ✅ 所有测试通过 |
Summary of ChangesHello @ding113, 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 delivers a new release (v0.3.37) packed with significant improvements across the platform. The core focus is on providing richer performance data, including Time To First Byte (TTFB) and output rates, which are now integrated into usage logs and leaderboards. Session debugging capabilities are greatly expanded with the addition of request and response header logging. User and key management features have been refined to prevent accidental service interruptions and offer a clearer view of key statuses. Furthermore, error handling is more granular, and session tracking for specific client types has been optimized. These changes collectively aim to enhance observability, manageability, and user experience. Highlights
Using Gemini Code AssistThe 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
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 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
|
There was a problem hiding this comment.
Code Review
This is a substantial release pull request that introduces a wide range of features and improvements. Key additions include performance metrics like TTFB and tokens/second, significant UI/UX enhancements such as searchable dropdowns and more compact data tables, and more granular error messages for authentication failures. The session tracking for Codex clients has also been improved. The overall code quality is high, with good refactoring and bug fixes, including a fix for cursor-based pagination. I have one minor suggestion regarding some leftover code from a refactoring.
| const _extraKeyGroupOption = useMemo(() => { | ||
| if (!normalizedKeyProviderGroup) return null; | ||
| if (normalizedKeyProviderGroup === normalizedUserProviderGroup) return null; | ||
| if (userGroups.includes(normalizedKeyProviderGroup)) return null; | ||
| return normalizedKeyProviderGroup; | ||
| }, [normalizedKeyProviderGroup, normalizedUserProviderGroup, userGroups]); |
There was a problem hiding this comment.
Code Review Summary
This XL PR merges significant feature additions from the dev branch, including error rule override validation, enhanced session management with request sequence tracking, Codex instructions caching, circuit breaker improvements, MCP passthrough support, and HTTP/2 fallback handling. After thorough multi-perspective review, no issues meeting the confidence threshold (80+) were identified.
PR Size: XL
- Lines changed: 5005 (4482 additions + 523 deletions)
- Files changed: 63
Split Suggestion for Future: Given the XL size, consider splitting future PRs by feature area:
- Error handling and override system
- Session management and rate limiting
- Codex/OpenAI compatibility layer
- Provider routing and circuit breaker
- MCP passthrough support
Issues Found
| Category | Critical | High | Medium | Low |
|---|---|---|---|---|
| Logic/Bugs | 0 | 0 | 0 | 0 |
| Security | 0 | 0 | 0 | 0 |
| Error Handling | 0 | 0 | 0 | 0 |
| Types | 0 | 0 | 0 | 0 |
| Comments/Docs | 0 | 0 | 0 | 0 |
| Tests | 0 | 0 | 0 | 0 |
| Simplification | 0 | 0 | 0 | 0 |
Review Coverage
- Logic and correctness - Clean
- Security (OWASP Top 10) - Clean
- Error handling - Clean (proper logging throughout, no silent failures identified)
- Type safety - Clean (appropriate TypeScript patterns, proper type guards)
- Documentation accuracy - Clean
- Test coverage - Adequate (test files updated alongside implementation)
- Code clarity - Good
Notable Observations
Good Practices Observed (informational only):
- Error handling follows fail-open pattern with proper logging
- Circuit breaker integration properly separates provider vs client errors
- Session management uses deterministic IDs for stability
- Type validation in
sanitizeOverrideResponseat repository layer
Automated review by Claude AI
| name: validatedData.name, | ||
| key: generatedKey, | ||
| is_enabled: true, | ||
| is_enabled: data.isEnabled ?? true, |
There was a problem hiding this comment.
[MEDIUM] [TYPE-MISSING-VALIDATION] isEnabled bypasses schema validation
src/actions/keys.ts:249 persists is_enabled: data.isEnabled ?? true, but data.isEnabled is not validated via KeyFormSchema.parse(...) (only validatedData.* fields are). This allows non-boolean input to reach createKey, risking runtime errors or inconsistent DB state if the action is called with malformed payloads.
Suggested fix:
// src/lib/validation/schemas.ts
export const KeyFormSchema = z.object({
// ...existing fields
isEnabled: z.boolean().optional().default(true),
});
// src/actions/keys.ts
const validatedData = KeyFormSchema.parse({
// ...existing fields
isEnabled: data.isEnabled,
});
await createKey({
// ...existing fields
is_enabled: validatedData.isEnabled,
});There was a problem hiding this comment.
Code Review Summary
This PR bundles a wide set of changes (DB migration, proxy metrics, session header capture, and dashboard UI updates) into a single XL release diff, which increases rollback risk and makes regression isolation harder.
One correctness issue surfaced in the key-creation path: the newly added isEnabled input is persisted without going through the existing Zod validation.
PR Size: XL
- Lines changed: 5005
- Files changed: 63
- Split suggestion: Separate into (1) DB/schema + write-path changes (
ttfb_ms, header capture), (2) dashboard/UI changes, (3) error-rule defaults/detector changes, (4) Codex session extraction changes + tests.
Issues Found
| Category | Critical | High | Medium | Low |
|---|---|---|---|---|
| Logic/Bugs | 0 | 0 | 0 | 0 |
| Security | 0 | 0 | 0 | 0 |
| Error Handling | 0 | 0 | 0 | 0 |
| Types | 0 | 0 | 1 | 0 |
| Comments/Docs | 0 | 0 | 0 | 0 |
| Tests | 0 | 0 | 0 | 0 |
| Simplification | 0 | 0 | 0 | 0 |
Critical Issues (Must Fix)
None.
High Priority Issues (Should Fix)
src/actions/keys.ts:249-isEnabledbypassesKeyFormSchemavalidation before persistence (Confidence: 90)
Review Coverage
- Logic and correctness
- Security (OWASP Top 10)
- Error handling
- Type safety
- Documentation accuracy
- Test coverage
- Code clarity
Automated review by Codex AI
- Add extraction for cache_creation_5m_input_tokens and cache_creation_1h_input_tokens at usage root level - Priority order: nested (cache_creation.ephemeral_*) > flat top-level > old relay format - Add 29 unit tests covering all formats, priority rules, and edge cases - Refactor billing/performance sections to side-by-side layout in request details dialog Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🧪 测试结果
总体结果: ✅ 所有测试通过 |
Summary
Release v0.3.37 consolidates 13+ features and bug fixes across proxy infrastructure, dashboard UI, and error handling. Major changes include Codex session isolation, TTFB tracking, request/response header logging, and numerous UI/UX improvements.
Fixes & Features
Closes:
Changes
Core Infrastructure
Codex Session Isolation (
src/app/v1/_lib/codex/)session-extractor.tsextracts session ID from Codex requests via headers/bodysession_id,x-session-id,previous_response_id, andconversation_idfieldsPerformance Tracking (
src/app/v1/_lib/proxy/,src/drizzle/)ttfb_mscolumn tomessage_requesttable (migration 0040)Auth & Error Handling (
src/app/v1/_lib/proxy/auth-guard.ts,src/lib/error-rule-detector.ts)Session Manager (
src/lib/session-manager.ts)Dashboard UI
Logs & Filtering (
src/app/[locale]/dashboard/logs/)User Management (
src/app/[locale]/dashboard/_components/user/)Session Details (
src/app/[locale]/dashboard/sessions/)Leaderboard (
src/app/[locale]/dashboard/leaderboard/)My Quota Page (
src/app/[locale]/dashboard/my-quota/)Supporting Changes
i18n (
messages/)Tests (
tests/,src/app/v1/_lib/codex/__tests__/)Database Migration
Migration
0040_bored_venus.sqladds:Run
bun run db:migrateafter deployment.Checklist
Description enhanced by Claude AI