Skip to content

feat: add generation debug inspector for usage logs#5621

Closed
MaJingyiFighting wants to merge 2 commits into
QuantumNous:mainfrom
MaJingyiFighting:feat/generation-debug-usage-inspector
Closed

feat: add generation debug inspector for usage logs#5621
MaJingyiFighting wants to merge 2 commits into
QuantumNous:mainfrom
MaJingyiFighting:feat/generation-debug-usage-inspector

Conversation

@MaJingyiFighting

@MaJingyiFighting MaJingyiFighting commented Jun 20, 2026

Copy link
Copy Markdown

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

新增可选的生成调试采集与查看能力。后端在请求转发和计费阶段记录经过脱敏、限长处理的提示字段、供应商 token 用量、缓存读取/写入及响应摘要;Default 与 Classic 日志界面使用同一份调试数据,展示字段 token 分布、缓存命中区间和断裂点。

供应商返回的 prompt/cached token 作为精确总量,字段级 token 和缓存边界按累计比例推断并明确标注置信度。零 token 字段按其所在缓存前缀继承状态,不再产生中途未命中、随后又命中的假断层。缓存写入与缓存命中分开统计,旧日志缺少边界数据时可由供应商总量重建视图。原始请求和响应仅管理员可见,且受环境配置控制。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 Issues 与 PRs,确认不是重复提交。
  • Bug fix 说明: 本 PR 未标记为 Bug fix,无需关联 Bug Issue。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

以下检查均在合并最新 upstream/main 后通过:

GOCACHE=/tmp/newapi-go-cache go test ./...
Default: TypeScript typecheck + targeted oxlint + production build
Classic: targeted Prettier check + production build

缓存连续性新增单测覆盖:缓存前缀中的零 token 字段保持命中,真实断裂点仍落在后续部分命中的非空字段内。

Summary by CodeRabbit

  • New Features
    • Added a generation-debug capture system with environment-based enablement, deterministic sampling, and max-byte limits for request/response tracking.
    • Implemented safe redaction and truncation for captured payloads.
    • Instrumented generation flows and extended usage logs with a “Generation Debug” modal (prompt analysis, completion details, cache hit/boundary metrics, latency/throughput, and optional raw views for admins).
    • Added generation-debug UI components and new multi-language (EN/FR/JA/KO/RU/ZH/etc.) labels.
  • Tests
    • Added coverage for sanitization, cache/token accounting, SSE + non-SSE output extraction, and capture/merge lifecycle behavior.

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7d5c480c-9d27-436d-bed2-22d1d117660b

📥 Commits

Reviewing files that changed from the base of the PR and between 6ae6ad6 and 56c5afc.

📒 Files selected for processing (15)
  • pkg/generationdebug/extract.go
  • pkg/generationdebug/generationdebug_test.go
  • web/classic/src/components/table/usage-logs/generation-debug/PromptDebugPanel.jsx
  • web/classic/src/components/table/usage-logs/generation-debug/utils.js
  • web/classic/src/i18n/locales/zh-CN.json
  • web/classic/src/i18n/locales/zh-TW.json
  • web/classic/src/i18n/locales/zh.json
  • web/default/src/features/usage-logs/components/generation-debug/json-viewer.tsx
  • web/default/src/features/usage-logs/components/generation-debug/prompt-debug-panel.tsx
  • web/default/src/features/usage-logs/components/generation-debug/utils.ts
  • web/default/src/i18n/locales/en.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/i18n/locales/ru.json
  • web/default/src/i18n/locales/vi.json
✅ Files skipped from review due to trivial changes (3)
  • web/classic/src/i18n/locales/zh-TW.json
  • web/classic/src/i18n/locales/zh.json
  • web/default/src/i18n/locales/en.json
🚧 Files skipped from review as they are similar to previous changes (12)
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/vi.json
  • web/default/src/features/usage-logs/components/generation-debug/json-viewer.tsx
  • web/default/src/i18n/locales/ru.json
  • web/classic/src/i18n/locales/zh-CN.json
  • web/default/src/i18n/locales/ja.json
  • web/classic/src/components/table/usage-logs/generation-debug/PromptDebugPanel.jsx
  • web/classic/src/components/table/usage-logs/generation-debug/utils.js
  • web/default/src/features/usage-logs/components/generation-debug/prompt-debug-panel.tsx
  • web/default/src/features/usage-logs/components/generation-debug/utils.ts
  • pkg/generationdebug/extract.go
  • pkg/generationdebug/generationdebug_test.go

Walkthrough

Adds a new generationdebug Go package that captures per-request prompt/response bytes, extracts cache statistics and token analytics, sanitizes sensitive data, and merges debug summaries into log records. Three relay handlers and two quota services are instrumented. Frontend components for both classic and default UIs render the debug data as panels, charts, and tabbed modals, backed by shared TypeScript/JavaScript utilities and nine locale files.

Changes

Generation Debug Pipeline

Layer / File(s) Summary
Go data contracts, config, and sanitization
pkg/generationdebug/types.go, pkg/generationdebug/config.go, pkg/generationdebug/sanitize.go
Defines all exported structs (CaptureConfig, PromptDebug, Summary, RawDebug, etc.), loads capture settings from GENERATION_DEBUG_* env vars with FNV-1a sampling, and implements recursive JSON redaction plus unstructured bearer-token/base64 sanitization with sha256-digest omission summaries.
Prompt, cache stats, and output extraction
pkg/generationdebug/extract.go
Implements BuildCacheStatsFromUsage, ExtractPromptFromRequest (multi-schema: messages/input/instructions), ApplyPromptAccounting with per-unit cache boundary inference, ExtractOutputFromRawResponse, and ExtractOutputFromSSE with delta-accumulation for both chat and responses API shapes.
Capture lifecycle and log merge
pkg/generationdebug/capture.go, pkg/generationdebug/merge.go
Implements the per-request captureState stored in Gin context (Begin/CaptureInboundRequest/CaptureUpstreamRequest/CapturePassThroughUpstream/MarkUpstreamStart/MarkResponseComplete/WrapResponseBody), bounded limitedCapture writer, snapshot helpers, and MergeContextIntoLogOther/MergeIntoLogOther that assemble the final Summary and RawDebug into other/admin_info log map fields.
Relay handler and quota instrumentation
relay/compatible_handler.go, relay/responses_handler.go, relay/chat_completions_via_responses.go, service/text_quota.go, service/quota.go
Inserts Begin, Capture*, MarkUpstreamStart, WrapResponseBody, and MarkResponseComplete calls into TextHelper, ResponsesHelper, and chatCompletionsViaResponses; calls MergeContextIntoLogOther in both text and audio quota post-processing with request IDs, streaming flag, and cache-write override.
Go tests
pkg/generationdebug/generationdebug_test.go, service/generation_debug_billing_test.go
Covers sanitization redaction, cache-boundary classification (hit/partial/miss), SSE and raw response output extraction, full capture lifecycle under env flags, user-log stripping, RAW stream truncation enforcement, and an OpenRouter billing integration test asserting debug data does not affect quota computation.
Frontend types, utilities, and i18n
web/default/.../generation-debug/types.ts, web/default/.../generation-debug/utils.ts, web/classic/.../generation-debug/utils.js, web/default/.../types.ts, web/*/i18n/locales/*
Defines TypeScript interfaces for GenerationDebugSummary, PromptDebugData, GenerationDebugRaw, etc.; provides formatting helpers (latency, throughput, cost, tokens), normalizedPromptUnits, derivePromptCacheView, and label mappers; extends LogOtherData.admin_info; adds i18n entries in 9 locale files.
Frontend debug panel components
web/default/.../generation-debug/completion-debug-panel.tsx, web/default/.../generation-debug/generation-debug-section.tsx, web/default/.../generation-debug/json-viewer.tsx, web/default/.../generation-debug/prompt-debug-panel.tsx, web/default/.../generation-debug/raw-debug-panel.tsx, web/default/.../generation-debug/token-message-chart.tsx, web/classic/.../generation-debug/*
Adds JsonViewer (copy-to-clipboard JSON display), TokenMessageChart (recharts/Semi UI stacked bar with cache-status coloring and breakpoint reference line), PromptDebugPanel (unit list, cache boundary card, detail pane), CompletionDebugPanel, RawDebugPanel, GenerationDebugSection (metric grid + tabs), and GenerationDebugModal for the classic UI.
Frontend wiring
web/classic/.../usage-logs/index.jsx, web/classic/.../usage-logs/useUsageLogsData.jsx, web/default/.../dialogs/details-dialog.tsx
Registers GenerationDebugModal in the classic usage-log page, adds modal state/handlers and GenerationDebugEntry row rendering to useUsageLogsData, inserts GenerationDebugSection into the default details dialog with adaptive dialogWidthClass/contentHeight, and applies stable React key fixes and reasoningEffortVariant refactor.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant RelayHandler as TextHelper / ResponsesHelper
  participant generationdebug as generationdebug pkg
  participant Upstream as Upstream LLM Provider
  participant QuotaService as text_quota / quota
  participant LogDB as Log Storage

  Client->>RelayHandler: Incoming request
  RelayHandler->>generationdebug: Begin(ctx, requestID, streaming)
  RelayHandler->>generationdebug: CaptureInboundRequest(ctx, req, bodyReader)
  RelayHandler->>generationdebug: CaptureUpstreamRequest(ctx, upstreamJSON)
  RelayHandler->>generationdebug: MarkUpstreamStart(ctx)
  RelayHandler->>Upstream: DoRequest(httpReq)
  Upstream-->>RelayHandler: httpResp
  RelayHandler->>generationdebug: WrapResponseBody(ctx, httpResp.Body, streaming)
  generationdebug-->>RelayHandler: tee ReadCloser (writes to limitedCapture)
  RelayHandler->>generationdebug: MarkResponseComplete(ctx)
  RelayHandler->>QuotaService: PostTextConsumeQuota(usage, ...)
  QuotaService->>generationdebug: MergeContextIntoLogOther(ctx, other, usage, meta)
  generationdebug->>generationdebug: ExtractOutputFromSSE / RawResponse
  generationdebug->>generationdebug: BuildCacheStatsFromUsage
  generationdebug->>generationdebug: ApplyPromptAccounting
  generationdebug-->>QuotaService: other["generation_debug"] = Summary
  generationdebug-->>QuotaService: other["admin_info"]["generation_debug_raw"] = RawDebug
  QuotaService->>LogDB: WriteLog(other)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • QuantumNous/new-api#2629: Both PRs modify relay/chat_completions_via_responses.go — the retrieved PR introduced the chat-completions-via-responses relay path and this PR adds generationdebug capture/marking calls inside that same flow.
  • QuantumNous/new-api#2780: This PR reads request bodies via common.GetBodyStorage/io.ReadSeeker in CaptureInboundRequest and CapturePassThroughUpstream, directly depending on the BodyStorage context plumbing introduced by the retrieved PR.
  • QuantumNous/new-api#5533: Both PRs modify web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx dialog layout props (contentHeight, overflow, width classes), making the two sets of changes structurally coupled.

Suggested reviewers

  • Calcium-Ion
  • seefs001

Poem

🐇 A rabbit hops through logs so vast,
Capturing prompts and caching fast.
Each token counted, each secret hid,
Debug panels bloom — oh what we did!
With SSE streams and FNV hash,
Generation Debug lands with a dash! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.19% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main feature addition: a generation debug inspector for usage logs, which is the primary objective of this changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@MaJingyiFighting

Copy link
Copy Markdown
Author
截屏2026-06-20 14 20 07 截屏2026-06-20 14 20 18

提供两个截图供参考,样式是参照openrouter做的

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@web/classic/src/components/table/usage-logs/generation-debug/PromptDebugPanel.jsx`:
- Around line 303-317: The selectedUnitIndex state is storing logical unit
indices (unit.index) but the code is using it as a direct array offset to access
the units array at line 317 (selectedUnit = units[selectedUnitIndex]). This
causes mismatches when unit indices are sparse or not sequentially aligned with
array positions. Fix this by either storing the array position/offset instead of
the logical unit index when setting selectedUnitIndex, or by finding the unit
from the units array by matching its index property against the stored logical
index value, rather than using it directly as an array offset.

In `@web/classic/src/components/table/usage-logs/generation-debug/utils.js`:
- Around line 113-118: The cacheStatus assignment logic for zero-token units
uses a strict less-than comparison (`<`) on line 115 that incorrectly marks
units as 'miss' when unit.cumulative_start exactly equals estimatedCachedTokens
at the boundary. Change the comparison operator from `<` to `<=` in the
condition checking `unit.cumulative_start < estimatedCachedTokens` to ensure
zero-token units at the exact boundary are marked as 'hit' instead of 'miss',
preserving cache continuity in the visualization.

In `@web/classic/src/i18n/locales/zh-CN.json`:
- Around line 3-79: The zh-CN.json locale file is missing the Copied translation
key that is used by PromptDebugPanel.jsx when displaying copy success feedback.
Add a Copied entry to the zh-CN.json file with an appropriate Chinese
translation to ensure Chinese users see the localized message instead of the
English fallback when a copy action succeeds. Place this new key in a logical
location among the existing translations, ideally near Copy path for
consistency.

In
`@web/default/src/features/usage-logs/components/generation-debug/json-viewer.tsx`:
- Line 51: The Badge component with variant='secondary' contains a hard-coded
string "JSON" that is not localized, preventing it from respecting locale
changes. Replace the hard-coded "JSON" text with a call to the i18n translation
function t() using the appropriate translation key for the JSON label. Ensure
the translation key is imported and used consistently with other localized
strings in the component.

In
`@web/default/src/features/usage-logs/components/generation-debug/prompt-debug-panel.tsx`:
- Around line 62-63: The selectedUnitIndex state is inconsistently used: it is
initialized as an array position at line 62, but at line 152 it is being set to
unit.index (the unit's index property) instead of the unit's position in the
units array. This causes line 87 to select the wrong unit when indices are
sparse or non-sequential. Fix this by ensuring that when storing the selected
unit at line 152, you store the actual array position of that unit in the units
array (using the findIndex method or similar) rather than the unit.index
property, so that selectedUnitIndex consistently represents the array position
throughout the component.
- Around line 199-203: In the promptTokens constant declaration, replace the
logical OR operators (||) with nullish coalescing operators (??). The current
implementation using || treats explicit zero values for providerPromptTokens as
falsy and incorrectly falls back to other estimates, which can misreport
authoritative vendor totals. The nullish coalescing operator ?? only treats null
and undefined as falsy values, which will properly preserve explicit zero values
from the provider while still falling back to estimates when the value is
actually null or undefined.

In `@web/default/src/features/usage-logs/components/generation-debug/utils.ts`:
- Around line 333-350: The boundary object construction in derivePromptCacheView
unconditionally overwrites the source and confidence fields with
'cache_boundary_inference' and 'inferred' values, replacing any authoritative
backend metadata from existingBoundary. To preserve existing cache-boundary
metadata when provided, conditionally set the source and confidence fields only
when existingBoundary does not already have these values, allowing fallback to
inferred values only when no existing boundary data is present. This way,
authoritative backend source and confidence values are retained when available
instead of being downgraded to inferred values.

In `@web/default/src/i18n/locales/ja.json`:
- Around line 651-684: In the ja.json file, normalize all Japanese debug-label
translations by replacing the English word "token" with its Japanese equivalent
"トークン" in the translation values. Specifically, update all entries in the
provided diff where "token" appears in English (such as in "Cache overlap",
"Cache write tokens", "Estimated prompt tokens", "Estimated tokens", "Provider
cached tokens", "Provider prompt tokens", and "Tokens per prompt field") to use
"トークン" instead for consistency in the Japanese UI.

In `@web/default/src/i18n/locales/ru.json`:
- Line 653: The Russian translation file is missing the cache_status subkeys
(hit, partial, miss, write, unknown) that are referenced by cacheStatusLabel.
Add a cache_status object with translations for all five status values (hit,
partial, miss, write, unknown) to the ru.json file, similar to how the "Cache
status" label is currently defined. This will prevent the UI from falling back
to English text for cache status values.

In `@web/default/src/i18n/locales/vi.json`:
- Around line 649-654: The Vietnamese locale file is missing the specific
cache_status.* keys that are referenced by the debug panel utility (specifically
in the generation-debug utils which maps cache statuses through
cache_status.hit, cache_status.partial, cache_status.miss, cache_status.write,
and cache_status.unknown). While the generic "Cache status" key exists, users
will fall back to English if these specific keys are not defined. Add the
following locale keys to the vi.json file: cache_status.hit,
cache_status.partial, cache_status.miss, cache_status.write, and
cache_status.unknown, each with an appropriate Vietnamese translation describing
that specific cache status type.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eea51309-44f6-447d-b245-49868c544711

📥 Commits

Reviewing files that changed from the base of the PR and between cb84185 and 6ae6ad6.

📒 Files selected for processing (41)
  • pkg/generationdebug/capture.go
  • pkg/generationdebug/config.go
  • pkg/generationdebug/extract.go
  • pkg/generationdebug/generationdebug_test.go
  • pkg/generationdebug/merge.go
  • pkg/generationdebug/sanitize.go
  • pkg/generationdebug/types.go
  • relay/chat_completions_via_responses.go
  • relay/compatible_handler.go
  • relay/responses_handler.go
  • service/generation_debug_billing_test.go
  • service/quota.go
  • service/text_quota.go
  • web/classic/src/components/table/usage-logs/generation-debug/GenerationDebugEntry.jsx
  • web/classic/src/components/table/usage-logs/generation-debug/GenerationDebugModal.jsx
  • web/classic/src/components/table/usage-logs/generation-debug/JsonViewer.jsx
  • web/classic/src/components/table/usage-logs/generation-debug/PromptDebugPanel.jsx
  • web/classic/src/components/table/usage-logs/generation-debug/RawDebugPanel.jsx
  • web/classic/src/components/table/usage-logs/generation-debug/TokenMessageChart.jsx
  • web/classic/src/components/table/usage-logs/generation-debug/utils.js
  • web/classic/src/components/table/usage-logs/index.jsx
  • web/classic/src/hooks/usage-logs/useUsageLogsData.jsx
  • web/classic/src/i18n/locales/zh-CN.json
  • web/classic/src/i18n/locales/zh-TW.json
  • web/classic/src/i18n/locales/zh.json
  • web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx
  • web/default/src/features/usage-logs/components/generation-debug/completion-debug-panel.tsx
  • web/default/src/features/usage-logs/components/generation-debug/generation-debug-section.tsx
  • web/default/src/features/usage-logs/components/generation-debug/json-viewer.tsx
  • web/default/src/features/usage-logs/components/generation-debug/prompt-debug-panel.tsx
  • web/default/src/features/usage-logs/components/generation-debug/raw-debug-panel.tsx
  • web/default/src/features/usage-logs/components/generation-debug/token-message-chart.tsx
  • web/default/src/features/usage-logs/components/generation-debug/types.ts
  • web/default/src/features/usage-logs/components/generation-debug/utils.ts
  • web/default/src/features/usage-logs/types.ts
  • web/default/src/i18n/locales/en.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/i18n/locales/ru.json
  • web/default/src/i18n/locales/vi.json
  • web/default/src/i18n/locales/zh.json

Comment thread web/classic/src/i18n/locales/zh-CN.json
Comment thread web/default/src/features/usage-logs/components/generation-debug/json-viewer.tsx Outdated
Comment thread web/default/src/i18n/locales/ja.json Outdated
Comment thread web/default/src/i18n/locales/ru.json
Comment thread web/default/src/i18n/locales/vi.json
@MaJingyiFighting

Copy link
Copy Markdown
Author

Addressed all 10 CodeRabbit findings in 56c5afc8.

Validation rerun after the fixes:

  • GOCACHE=/tmp/newapi-go-cache go test ./...
  • Default: oxfmt, targeted oxlint, TypeScript typecheck, production build
  • Classic: Prettier check, production build

The zero-token boundary regression test now covers a zero-length field exactly at the cache breakpoint.

@MaJingyiFighting MaJingyiFighting deleted the feat/generation-debug-usage-inspector branch June 28, 2026 06:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant