Commit Graph
3774 Commits
Author SHA1 Message Date
Wesley Liddick 84cedd3d71 Merge pull request #2960 from CheriWen/fix/cwe-79-stored-xss-key-name
[Security] fix: sanitize API key name to prevent stored XSS
2026-06-06 11:09:08 +08:00
Wesley Liddick ff3c976dbd Merge pull request #3009 from liulinhuai/fix/images-upstream-error-passthrough
fix(images): surface real upstream error instead of generic 502
2026-06-06 11:07:53 +08:00
Wesley Liddick 1dda8626d5 Merge pull request #3018 from Zbl1007/openmeta/2989-0
Fix fixed weekly quota usage after switching from rolling reset
2026-06-06 10:59:18 +08:00
Wesley Liddick 1efd3e205d Merge pull request #3056 from CoolCoolTomato/fix/postgres-dsn-dbname
fix(setup): bootstrap postgres connection with maintenance db
2026-06-06 10:42:42 +08:00
shaw bba86f97d8 fix(repo): make userRepo.Delete reuse caller's transaction
userRepository.Delete used the r.client.Tx(ctx)+ErrTxStarted pattern,
which only reuses a transaction when r.client is itself a tx-bound
client. With the singleton base client (how Wire injects repos),
r.client.Tx() always starts a NEW independent transaction and ignores
any tx carried in the context.

As a result, AdminService.DeleteUser's transaction (added in #3047)
only covered the API-key deletions; the user soft-delete escaped into a
separate, immediately-committed transaction. If the outer commit failed
after the user tx had committed, the user was deleted while its API keys
stayed active, reintroducing the unrecoverable state of #3021.

Add a leading dbent.TxFromContext check (mirroring DeleteWithAudit) so
Delete joins an externally-provided transaction and lets the caller
commit/rollback. Extract the deletion body into deleteUser(ctx, exec,
id). All three original paths are preserved; callers passing a plain ctx
are unaffected.

Add user_repo_delete_atomicity_integration_test.go: builds repos with
the base client and a manual outer tx, asserting that delete-keys and
delete-user roll back together on abort and commit together on success.
2026-06-06 10:28:28 +08:00
Wesley Liddick 1a0eecb6ef Merge pull request #3047 from fchange/codex/delete-user-api-keys
fix(admin): delete API keys when deleting a user
2026-06-06 10:14:28 +08:00
Wesley Liddick 1512ba747e Merge pull request #2995 from feitianbubu/opt-proxy-quality-pass
fix: treat allowed proxy quality statuses as pass not warn
2026-06-06 09:58:16 +08:00
Wesley Liddick eb24485fc6 Merge pull request #3036 from whatIsNextToTheMoon/fix/openai-response-failed-passthrough
fix(openai): preserve upstream response.failed errors
2026-06-06 09:53:08 +08:00
Wesley Liddick 75af992819 Merge pull request #3026 from Zbl1007/openmeta/2956-deepseek
Surface DeepSeek reasoning-only responses
2026-06-06 09:35:29 +08:00
Wesley Liddick 427d591212 Merge pull request #2930 from touwaeriol/feat/image-token-billing
fix(billing): channel pricing override for image generation + display image_output_tokens
2026-06-06 09:28:46 +08:00
shaw 7483c43c02 update sponsors 2026-06-06 09:28:18 +08:00
shaw 650981f2e4 fix(lint): 修复 golangci-lint errcheck 与 gofmt 报错
- gateway_service.go buildStableSessionSeed: strings.Builder.WriteString
  返回值用 _, _ = 显式忽略(errcheck)
- openai_codex_transform_additions_test.go: client_metadata 类型断言改为
  双值形式 cm3, _ := ...(errcheck check-type-assertions)
- openai_gateway_service.go: codexCLIUserAgent 常量单独成组,收敛 = 前多余
  空格对齐(gofmt)
2026-06-06 09:21:32 +08:00
Wesley Liddick ddc23c1e83 Merge pull request #3065 from Eyre921/feat/closer-to-codex-and-claude-code
feat(gateway): 提升 Codex / Claude Code 客户端模拟保真度,降低 OAuth 凭证被上游判为第三方的风险
2026-06-06 09:18:27 +08:00
eyre 480f0cba22 merge: 合并 Codex 与 Claude Code 双重模拟改造为统一分支
- feat/closer-to-codex:Codex 指纹/prompt/SSE/include/client_metadata 改造
- feat/closer-to-claude-code:Claude Code 指纹对齐 CLI 2.1.161
两组改动改动文件互不重叠,合并无冲突。
2026-06-06 01:06:20 +08:00
eyre 219da4b9e5 feat(claude-mimicry): align Claude Code fingerprint with CLI 2.1.161
- bump impersonated CLI version 2.1.92 -> 2.1.161; derive User-Agent from
  CLICurrentVersion so the two hardcoded copies can no longer drift apart
- fix x-stainless headers to real 2.1.161 values: package-version
  0.70.0 -> 0.94.0, runtime-version v24.13.0 -> v24.3.0 (verified against
  the installed Bun-compiled binary)
- expand the disguise-path system prompt from a 2-block identity skeleton
  to a 3-block layout (billing + identity + tool-agnostic prose), matching
  real CC's multi-block shape; cache breakpoint moved to the last static
  block. Deliberately excludes # Doing tasks / # Using your tools /
  # Executing actions to avoid polluting proxied-client behavior
- stabilize the synthesized metadata.user_id session_id across conversation
  turns: derive it from (account + client discriminator + first user
  message) instead of a per-turn content/body hash. Sticky-routing
  GenerateSessionHash is intentionally left untouched; remove now-dead
  hashBodyForSessionSeed

Tests: update the 3-block system assertions in gateway_prompt_test and
gateway_anthropic_apikey_passthrough_test; add a session_id cross-turn
stability test in gateway_oauth_metadata_test.
2026-06-06 01:01:58 +08:00
eyre 5e6effd79c feat: 模型感知 Codex prompt / client_metadata / anthropic SSE 补全
- 模型感知 instructions:刷新 instructions.txt 至最新 GPT-5-Codex prompt,新增
  GPT-5.1 / GPT-5.2 真实 Codex 编码 agent prompt;新增 openai.CodexBaseInstructionsForModel
  按模型选用(codex 系→GPT-5-Codex,gpt-5.2→GPT-5.2,gpt-5.1/gpt-5→GPT-5.1),
  defaultCodexSynthInstructions 改为按 model 选择
- client_metadata:OAuth /responses 请求用账号真实 openai_device_id 注入
  client_metadata["x-codex-installation-id"];加法式、幂等、不覆盖既有项,
  无 device_id(非 OAuth 账号)则不写入、不伪造
- anthropic 转换补全 SSE 事件 reasoning_text.delta 与 custom_tool_call_input.delta
  (含 custom_tool_call item 注册为 tool_use),与 chat completions 路径对齐
- 新增单元测试覆盖以上行为(apicompat / openai / service)

承接上一提交,仍为加法式改进,不改动既有可工作的请求头。
2026-06-06 00:59:27 +08:00
eyre baf078fdb7 feat: 提升 Codex 行为模拟保真度(仅加法式改进)
- ForceCodexCLI 兜底 User-Agent 补全为完整结构 {originator}/{ver} ({OS} {ver}; {arch}) {terminal},
  与真实 codex_cli_rs UA 对齐,避免被上游指纹识别为非官方客户端
- 合成路径默认 instructions 改用内嵌的真实 Codex base prompt(openai.DefaultInstructions,
  "You are Codex, based on GPT-5..."),替换通用占位符;transform 与 hotpath 两处统一走
  defaultCodexSynthInstructions()
- /responses→chat 转换补全 SSE 事件 reasoning_text.delta 与 custom_tool_call_input.delta
  (流式 ResponsesEventToChatChunks 与缓冲 BufferedResponseAccumulator 两条路径),
  并将 custom_tool_call item 一并注册以正确映射工具索引
- OAuth /responses 请求带 reasoning 时补齐 include:["reasoning.encrypted_content"],
  幂等且加法式,不改动已有 include

保持旧稳定版兼容:不改动现有可工作的请求头(session_id/conversation_id/originator/
OpenAI-Beta 维持原样)。client_metadata(installation-id) 属最新版特征,会与旧稳定版
头指纹混搭冲突,本次未加。
2026-06-06 00:44:49 +08:00
Wesley Liddick 1cecd2716c Merge pull request #2972 from northya/fix/chat-completions-response-failed
fix: 修复 Chat Completions 兼容层误将 response.failed 返回为成功响应
2026-06-05 21:51:23 +08:00
Wesley Liddick 8775047f84 Merge pull request #3051 from wucm667/fix/openai-messages-missing-terminal-event-failover
fix(openai): /v1/messages 流式缺终止事件时纳入 failover 与 ops 错误归因
2026-06-05 21:34:14 +08:00
Wesley Liddick 872e56aed7 Merge pull request #3052 from wucm667/feat/openai-image-ratelimit-cooldown-failover
feat(openai): gpt-image 图片限流按能力维度冷却并 failover,不再误伤文字请求
2026-06-05 21:25:40 +08:00
CoolCoolTomato 8a56c9fa0c fix(setup): bootstrap postgres connection with maintenance db 2026-06-05 20:48:04 +08:00
Wesley Liddick b5b68f86bd Merge pull request #3037 from feitianbubu/pr/fix-auto-mode-invalid-by-security-monitor
fix: cc开启auto mode后无法通过cc客户端验证的问题
2026-06-05 20:43:37 +08:00
wucm667 36721d35a8 feat(openai): cool down image rate limits by capability 2026-06-05 18:12:33 +08:00
wucm667 8e27ff20af fix(openai): handle missing messages stream terminal 2026-06-05 18:11:23 +08:00
erio b8c89c34d8 fix(ci): add missing fields to pass frontend typecheck and contract test
- Add `service_quota_enabled` to PublicSettings default in app.ts
- Add `image_output_tokens` and `image_output_cost` to usage contract test
2026-06-05 17:55:22 +08:00
方程 705fe7d880 fix(admin): delete user api keys with user 2026-06-05 16:23:56 +08:00
Wesley Liddick d895d765b6 Merge pull request #3042 from DaydreamCoding/feat/usage-error-requests
feat(usage/ops): 失败请求记录与展示(用户端 + 管理端)+ 错误日志 Key 归因
2026-06-05 15:42:25 +08:00
feitianbubuandClaude Opus 4.8 d626ccce1d fix: recognize claude code clients via billing block, not just prompt
Genuine Claude Code CLI sub-requests (e.g. the security monitor) carry
no identity system prompt, so claude_code_only groups wrongly rejected
them with "this group only allows Claude Code clients". Detect the
x-anthropic-billing-header block with cc_entrypoint=cli as a stable
client signal, while keeping the existing header/metadata checks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 14:09:03 +08:00
DaydreamCodingandClaude Opus 4.8 fe8952733a fix(usage): 管理端错误请求页过滤与分列完善
- 错误请求标签补传 model/account_id/group_id 过滤(此前 loadAdminErrors 丢弃),admin handler
  读取 model 查询参数走精确匹配
- 错误表格拆成 用户/API Key/账号 三独立列(上游行也显示用户),补 api_key_name/api_key_deleted,
  已删除 key 显示红色「已删除」标记;i18n keyDeletedBadge 补入 errorLog 命名空间

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 14:00:57 +08:00
DaydreamCodingandClaude Opus 4.8 cf12bc521b fix(usage): 用量明细虚拟表对可空字段渲染崩溃致整表空白
- formatDuration 兜底 null(duration_ms 后端为 *int,count_tokens/失败等请求无耗时)
- tokens/cost 单元格与 CSV 导出加 (x ?? 0) 防御
- duration_ms 前端类型改 number|null,对齐后端指针,编译器从此拦未保护用法
- DataTable 虚拟化加固:initialRect 一屏兜底 + 过滤 0 高度读数

根因:渲染对 null 调 .toFixed() 抛错→Vue 弃整个 tbody→空白;虚拟化只渲可视行故呈概率性。
非 b3847fa 引入(formatDuration 自首个 commit 即存在)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 14:00:57 +08:00
DaydreamCodingandClaude Opus 4.8 cfb195c7b2 feat(usage): 记录并展示失败请求(用户端+管理端)
- 记录失败请求并在用户端/管理端展示;分类下拉改用统一 Select 组件
- 模型过滤改后端 ILIKE 模糊匹配;新增「Key 名称」列(含已删除标记)与按 Key 过滤;时间列移至末列
- 用户可见「已删除 key 失败请求」:OpsErrorLogFilter 加 MatchDeletedKeyOwner,用户侧归属
  放宽为 (user_id OR deleted_key_owner_user_id),让 key 原所有者能看到删除 key 后继续请求
  导致的认证失败记录(他人仍 NotFound,不泄露存在性)
- 迁移 148:ops_error_logs 用户+时间索引

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 14:00:57 +08:00
DaydreamCodingandClaude Opus 4.8 ddf063352a feat(ops): 错误日志 key 归因与早退字段补全
让 /admin/ops 错误详情正确归因 API key 并补全早退场景字段,合并三项改动:

- 鉴权早退补全用户/分组/平台字段:引入 ops fallback key(ContextKeyOpsFallbackAPIKey),
  apiKey 一加载成功即写入,覆盖分组停用/删除、Key 停用/过期/额度、用户停用、IP 限制等早退
  路径;ops 错误日志改用 getOpsAPIKey(正式 key 优先、回退键兜底),不改「已鉴权」语义。
- 已删除 key 归因(迁移 145):删除 key 时同一事务写 deleted_api_key_audits 映射,认证失败
  时用明文反查命中原所有者,错误详情展示「已删除 Key 所有者」「尝试的 Key 前缀」。
- 有效 key 报错快照前缀(迁移 147):对绑定有效 key 的错误,落库时快照明文前 8 位到
  api_key_prefix(与 attempted_key_prefix 互斥),key 之后被删仍保留报错当时真实前缀。

均仅对上线后新产生的错误/删除生效。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 14:00:57 +08:00
Wesley Liddick 57bae985a7 Merge pull request #2711 from wucm667/fix/db-pool-enforce-conn-lifetime-floor
fix(db-pool): 强制连接生命期下限,缓解 lib/pq watchCancel 协程泄漏
2026-06-05 13:55:07 +08:00
Wesley Liddick e080d3f966 Merge pull request #2975 from wucm667/fix/easypay-queryorder-trade-status
fix(payment): EasyPay 查单以 trade_status 判定支付成功,避免未付订单误判到账
2026-06-05 13:54:54 +08:00
Wesley Liddick f332e0a83c Merge pull request #2872 from wucm667/fix/scheduler-sticky-health-escape
fix(scheduler): session_hash sticky 引入健康度逃逸,慢账号不再独占用户会话
2026-06-05 13:54:37 +08:00
Wesley Liddick 83cce858a5 Merge pull request #3039 from StarryKira/fix/issue-2994-codex-5h-used-percent-selfheal
fix(openai): self-heal stale Codex used% snapshots + lock semantics (#2994)
2026-06-05 13:54:18 +08:00
Wesley Liddick bebeaf57c5 Merge pull request #2854 from ttt132/fix/responses-stream-completed-output
fix: normalize responses streaming terminal output
2026-06-05 13:54:05 +08:00
Wesley Liddick a879f254c8 Merge pull request #3012 from visa2/fix/responses-anthropic-tool-pairing
fix(apicompat): repair tool_use/tool_result pairing on the Responses→Anthropic path
2026-06-05 13:53:31 +08:00
Wesley Liddick fbd25acae0 Merge pull request #3035 from ghostg00/fix/admin-group-clear-description
fix(group): 管理员清空分组描述时正确持久化
2026-06-05 13:53:20 +08:00
Wesley Liddick 05f0326e99 Merge pull request #2988 from wucm667: content audit auto-ban exempts admin accounts
fix(risk-control): 内容审计 auto-ban 豁免管理员账号,避免封禁管理员/超管
2026-06-05 13:47:10 +08:00
Wesley Liddick b34480df68 Merge pull request #3001 from Pluviobyte: bump Go patch version to 1.26.4
chore: bump Go patch version to 1.26.4
2026-06-05 13:46:37 +08:00
harukaandClaude Opus 4.8 86d9b6bff9 fix(openai): self-heal stale Codex used% snapshots + lock semantics (#2994)
The OpenAI/Codex 5h "used %" inversion that caused fresh accounts to show
~96-99% used (PR #2918, commit b65dde63) was already reverted in #2993, so the
stored value is now the correct "used %" again. This commit hardens that fix:

1. Regression test locking in direct "used %" semantics. The semantics have
   flip-flopped twice (#2918 -> #2993) with no value-level guard — a fresh
   account (secondary_used_percent=1, 5h window) must store
   codex_5h_used_percent=1, not 99.

2. Stale-bounded self-heal in resolveOpenAIQuotaUtilization (the single
   auto-pause chokepoint). An account poisoned with an inflated used% gets
   excluded from scheduling, and a paused account never receives traffic to
   refresh its snapshot — so it stayed stuck until the window's reset_at passed
   (up to 5h/7d). When codex_usage_updated_at is older than 2h, the account is
   no longer auto-paused on that snapshot; it gets one request whose response
   headers refresh the snapshot and self-heal it. A missing timestamp is treated
   as fresh (stays paused), and an actively-served exhausted account refreshes
   the timestamp every response so it never crosses the bound — it cannot escape
   auto-pause.

No change to Normalize(); no 100-x reintroduced; no new dependency wiring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 22:07:36 +08:00
ghostg00 bc7ce18574 fix(group): 管理员清空分组描述时正确持久化
UpdateGroup 之前用 `if input.Description != ""` 判空,
把"未提供"和"显式置空"混为一谈,导致管理员在分组编辑表单
里清空备注后保存无效。

将 UpdateGroupRequest / UpdateGroupInput 的 Description 改为
*string:nil 表示未提供(保持原值),"" 表示显式清空。
2026-06-04 19:48:03 +08:00
whatIsNextToTheMoon 5bd3d90434 fix(openai): preserve upstream response.failed errors 2026-06-04 11:17:22 +00:00
Wesley Liddick f1aa589646 Merge pull request #2993 from ghostg00/fix/openai-5h-used-percent-direct
fix(usage): revert OpenAI 5h used_percent inversion (#2918 regression)
2026-06-04 16:02:52 +08:00
Zbl1007 9b99f6c1f3 fix(apicompat): surface DeepSeek reasoning-only replies 2026-06-04 11:34:54 +08:00
Zbl1007 fb0195f3dc fix(account): normalize fixed quota windows on edit 2026-06-04 01:06:41 +08:00
visa2andClaude Opus 4.8 60867022b6 fix(apicompat): repair tool_use/tool_result pairing on the Responses→Anthropic path
When an OpenAI Chat Completions client targets an Anthropic-platform group,
ForwardAsChatCompletions converts the request CC → Responses → Anthropic
(ChatCompletionsToResponses → ResponsesToAnthropicRequest) before forwarding it
upstream. The Responses→Anthropic converter emits each function_call as its own
assistant message and each function_call_output as its own user message and
relies solely on mergeConsecutiveMessages to alternate roles. That is not enough
to satisfy Anthropic's tool-pairing invariants, so a trimmed or partial tool
history produces an upstream 400, e.g.:

    tool_use_id found in tool_result blocks: call_00_...
    Each tool_result block must have a corresponding tool_use block in the
    previous message.

The failures this leaves unrepaired:

  - orphan tool_result — a client that does sliding-window context management
    keeps a recent tool result but drops the assistant tool_calls message that
    announced it, so the tool_result has no matching tool_use;
  - unanswered/dangling tool_use — a parallel call whose sibling result never
    came back, or a call left dangling, which Anthropic also rejects.

Add normalizeAnthropicToolPairing, run between two merge passes: the first merge
groups parallel calls and their results; the pairing pass indexes every
tool_result by its tool_use id, keeps only answered tool_use blocks (dropping
unanswered/dangling calls, and the assistant message entirely when nothing else
remains) and re-emits the matching tool_result blocks as the immediately
following user message; standalone/orphan tool_results are dropped from their
original position; the second merge restores alternation. This mirrors
normalizeChatMessages on the Responses→Chat path.

Tested two ways: responses_to_anthropic_tool_pairing_test.go covers the repair
on direct Responses input (developer message between call and output, parallel
both-answered kept grouped, parallel one-unanswered dropped, orphan tool_result,
dangling call, single-call baseline); responses_to_anthropic_cc_chain_test.go
drives the real ChatCompletionsToResponses → ResponsesToAnthropicRequest chain
and reproduces the production 400 (orphan and unanswered-parallel) — both fail
without the repair and pass with it. The full apicompat suite stays green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 17:26:05 +08:00
Liu LinhuaiandClaude Opus 4.8 381d1d6d6c fix(images): surface real upstream error instead of generic 502
The /v1/images/generations and /v1/images/edits paths routed every
non-failover upstream error through the generic handleErrorResponse,
whose final switch collapses anything that isn't 401/402/403/429 into a
hardcoded 502 "Upstream request failed" — discarding the actual upstream
status code, type, code, message, and param. So a gpt-image-2 400
(invalid_request_error, moderation, unsupported parameter, ...) reached
the client as an opaque 502.

The sibling Chat Completions and Messages compat paths already avoid this
via handleCompatErrorResponse, which preserves the real status and
message. Add the equivalent for images: handleOpenAIImagesErrorResponse
keeps all existing side-effects (ops logging, error-passthrough rules,
ShouldHandleErrorCode, account-disable/secondary-failover) but surfaces
the real upstream status + type/code/message/param by reusing the
existing OpenAIImagesUpstreamError machinery. Both forward paths now call
it instead of handleErrorResponse for non-failover errors.

Failover behavior (5xx / 401 / 403 / 429 / 529) is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 17:23:13 +08:00
Pluviobyte 5634cc83eb chore: bump Go patch version 2026-06-03 14:24:50 +08:00