Skip to content

修复:管理员复制他人 API Key 失败(新增 admin key 读取端点并接入前端 adminMode) - #11

Merged
LoSealL merged 3 commits into
developfrom
fix-admin-copy-user-key
Sep 2, 2026
Merged

LoSealL merged 3 commits into
developfrom
fix-admin-copy-user-key

Conversation

@LoSealL

@LoSealL LoSealL commented Sep 2, 2026

Copy link
Copy Markdown

从 fix-admin-copy-user-key 分支合入 develop。

- 后端:移除 256KiB 采集上限,请求/响应体全量入库(MySQL 列已为 LONGTEXT)
- 前端:新增 format-body,Claude SSE 流重组为等价非流式消息(text/thinking/signature/tool_use),
  其他 SSE 解析为数组,截断 JSON 重新缩进分行展示
- 测试:vitest 9 例覆盖格式化各分支;capture writer 增加大 body 不截断回归测试

Signed-off-by: AGENTS (opencode)
- 会话识别:请求消息原始字节构建 SHA256 前缀哈希链,token 作用域内链值匹配即同一会话,
  只存增量消息(new_messages),响应仍全量存储;compact/编辑重发自然开新会话
- 数据模型:chat_sessions(链头/轮次/消息数/system) + chat_turns(增量+响应);
  master 迁移 AutoMigrate 两表并 DROP 旧 chat_logs;MySQL system 保留字列反引号处理
- 提取:OpenAI chat/Claude/Gemini 规范化候选链,其余格式单轮会话;同会话并行写竞争按 v1 接受
- 管理 API:GET /api/chat_logs/sessions[/:id];列表不含消息体
- 前端:会话列表 + 转录时间线,跳过每轮回显的 assistant/model 消息,响应经 formatChatLogBody
  重组展示(并入此前 OpenAI SSE 分块合并为 chat.completion)
- 测试:Go service/model/controller 四包 + 前端 vitest 17 例;i18n 7 语言

Signed-off-by: AGENTS (opencode)
Copilot AI lite review requested due to automatic review settings September 2, 2026 01:35
@LoSealL
LoSealL merged commit 1918ac7 into develop Sep 2, 2026
6 checks passed
@LoSealL
LoSealL deleted the fix-admin-copy-user-key branch September 2, 2026 01:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The new chat-log session/turn persistence introduces concurrency and memory-risk issues (no transactional locking and unbounded capture) and includes a potentially destructive DB migration (DROP TABLE) that needs an explicit migration/rollout decision.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR adds admin-capable API key plaintext retrieval endpoints and wires the frontend to use them in adminMode, while also refactoring chat-log storage and the admin chat-log UI from “per request log rows” into “sessions + turns” with a transcript viewer and improved request/response body formatting.

Changes:

  • Add admin endpoints to fetch single/batch token keys and integrate frontend key resolution with adminMode.
  • Replace chat log persistence/schema and admin APIs/UI with chat_sessions + chat_turns, including transcript display and SSE/JSON body formatting utilities + tests.
  • Update i18n locale keys used by the new chat-log UI.
File summaries
File Description
web/src/routes/_authenticated/chat-logs/index.tsx Adds user_id to URL search schema for chat sessions filtering.
web/src/i18n/locales/en.json Adds new chat-log UI keys; removes unused keys.
web/src/i18n/locales/zh.json Adds new chat-log UI keys; removes unused keys.
web/src/i18n/locales/zh-TW.json Adds new chat-log UI keys; removes unused keys.
web/src/i18n/locales/fr.json Adds new chat-log UI keys; removes unused keys.
web/src/i18n/locales/ja.json Adds new chat-log UI keys; removes unused keys.
web/src/i18n/locales/ru.json Adds new chat-log UI keys; removes unused keys.
web/src/i18n/locales/vi.json Adds new chat-log UI keys; removes unused keys.
web/src/features/keys/components/api-keys-provider.tsx Switches key-resolution calls to admin endpoints when adminMode is enabled.
web/src/features/keys/api.ts Adds admin key-fetch APIs and batch APIs.
web/src/features/chat-logs/types.ts Replaces legacy chat-log types with session/turn/transcript-oriented types.
web/src/features/chat-logs/lib/transcript.ts Adds transcript builder for session turns.
web/src/features/chat-logs/lib/format-body.ts Adds robust body formatter (JSON pretty print, SSE parsing/reassembly, truncated JSON reindent).
web/src/features/chat-logs/lib/tests/transcript.test.ts Tests transcript building behavior.
web/src/features/chat-logs/lib/tests/format-body.test.ts Tests body formatting, including Claude/OpenAI SSE reconstruction.
web/src/features/chat-logs/index.tsx Switches page from logs table to sessions table.
web/src/features/chat-logs/components/session-detail-sheet.tsx New transcript side-sheet rendering session meta and turn-by-turn content.
web/src/features/chat-logs/components/chat-sessions-table.tsx Replaces logs table with sessions table + filters (token/user/model) and transcript opening.
web/src/features/chat-logs/components/chat-log-detail-sheet.tsx Removes legacy per-log detail sheet.
web/src/features/chat-logs/api.ts Updates frontend admin API calls to session-based endpoints + new query keys.
service/task_billing_test.go Updates migrations/cleanup to new chat session/turn tables.
service/chat_log_session.go Adds message-chain extraction + prefix-hash computation for session identification.
service/chat_log_session_test.go Adds unit tests for chain extraction and hashing properties.
service/chat_log_persist.go Replaces per-request ChatLog inserts with session resolution + turn inserts and session advancement.
service/chat_log_persist_test.go Updates persistence tests to validate session chaining + deltas.
service/chat_log_capture.go Simplifies response capture writer (now fully buffers response).
service/chat_log_capture_test.go Updates capture writer tests to match new behavior.
service/channel_affinity_usage_cache_test.go Makes test keys more collision-resistant across OS clock resolution.
router/chat-log-router.go Switches admin chat-log routes to /sessions and /sessions/:id.
router/api-router.go Adds admin token key retrieval endpoints (single + batch).
model/token.go Allows GetTokenKeysByIds to bypass user filter when userId == 0 (admin batch use).
model/task_cas_test.go Updates migrations/cleanup to new chat session/turn tables.
model/main.go Migrates chatlog DB schema to sessions/turns and drops legacy chat_logs table.
model/chat_log.go Replaces ChatLog model with ChatSession and ChatTurn models + queries.
model/chat_log_test.go Updates model tests for sessions/turns behavior.
controller/token.go Adds AdminGetTokenKey and AdminGetTokenKeysBatch handlers + audit event.
controller/token_test.go Adds test coverage for admin cross-user token key retrieval.
controller/relay.go Passes relayFormat into chat-log capture installer.
controller/chat_log.go Replaces admin chat-log list/detail handlers with session/turn endpoints.
controller/chat_log_test.go Updates controller tests to validate new session list/detail shapes.
controller/audit.go Adds audit template for token.key_view.
.gitignore Adds .superpowers/ ignore entry.
Review details

Suppressed comments (3)

web/src/features/keys/api.ts:136

  • Same indentation issue here: tabs and extra indentation diverge from the file’s formatting. Reformat to match the surrounding style.
    web/src/features/keys/api.ts:150
  • Same indentation issue here: tabs and extra indentation diverge from the file’s formatting. Reformat to match the surrounding style.
    web/src/features/chat-logs/components/chat-sessions-table.tsx:11
  • License header typo: missing “the” in “without even the implied warranty of”. Please keep the AGPL boilerplate consistent.
  • Files reviewed: 41/42 changed files
  • Comments generated: 10
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread model/main.go
Comment on lines +444 to 459
if err := CHATLOG_DB.AutoMigrate(&ChatSession{}, &ChatTurn{}); err != nil {
return err
}
if dbType == common.DatabaseTypeMySQL {
if err := CHATLOG_DB.Exec("ALTER TABLE chat_logs MODIFY COLUMN request_body LONGTEXT").Error; err != nil {
if err := CHATLOG_DB.Exec("ALTER TABLE chat_turns MODIFY COLUMN new_messages LONGTEXT").Error; err != nil {
return err
}
if err := CHATLOG_DB.Exec("ALTER TABLE chat_logs MODIFY COLUMN response_body LONGTEXT").Error; err != nil {
if err := CHATLOG_DB.Exec("ALTER TABLE chat_turns MODIFY COLUMN response_body LONGTEXT").Error; err != nil {
return err
}
if err := CHATLOG_DB.Exec("ALTER TABLE chat_sessions MODIFY COLUMN `system` LONGTEXT").Error; err != nil {
return err
}
}
return nil
return CHATLOG_DB.Exec("DROP TABLE IF EXISTS chat_logs").Error
}
Comment on lines +24 to 34
// ponytail: response is buffered fully in memory per request; chat-log is
// opt-in per token, add a cap again if this ever becomes a memory problem.
func (w *chatLogCaptureWriter) Write(data []byte) (int, error) {
n, err := w.ResponseWriter.Write(data)
if err != nil {
return n, err
}
w.mu.Lock()
defer w.mu.Unlock()
if w.truncated {
return n, nil
}
remaining := w.maxBytes - w.buffer.Len()
if remaining <= 0 {
w.truncated = true
return n, nil
}
if len(data) <= remaining {
w.buffer.Write(data)
} else {
w.buffer.Write(data[:remaining])
w.truncated = true
}
w.buffer.Write(data)
return n, nil
Comment on lines +81 to +85
turn := &model.ChatTurn{
SessionId: session.Id, TurnIndex: session.TurnCount,
RequestId: requestId, ModelName: modelName, ChannelId: channelId,
StatusCode: statusCode, UseTime: useTime, IsStream: isStream,
NewMessages: newMessages, ResponseBody: respBody,
Comment on lines 38 to 43
func (r *ChatLogRecorder) SetRequestBody(body []byte) {
if r == nil || len(body) == 0 {
return
}
if len(body) > defaultChatLogMaxBodyBytes {
r.requestBody = string(body[:defaultChatLogMaxBodyBytes])
return
}
r.requestBody = string(body)
}
Comment on lines 9 to 11
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Comment on lines +14 to +15
You should have received a copy of the GNU Affero General License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Comment on lines +9 to +11
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Comment on lines +14 to +15
You should have received a copy of the GNU Affero General License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Comment on lines 9 to 11
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Comment on lines 120 to +124
// Batch fetch real (unmasked) keys for multiple tokens
export async function fetchTokenKeysBatch(ids: number[]): Promise<{
success: boolean
message?: string
data?: { keys: Record<number, string> }
}> {
const res = await api.post('/api/token/batch/keys', { ids })
return res.data
}

export async function fetchTokenKeysBatch(ids: number[]): Promise<{
success: boolean
message?: string
data?: {
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.

2 participants