From 6dc89765fd66a30fcdd0a0d76278179b7d307ff9 Mon Sep 17 00:00:00 2001 From: keh4l <2461454684@qq.com> Date: Sat, 25 Apr 2026 00:26:37 +0800 Subject: [PATCH] fix(gateway): always apply full mimicry for OAuth accounts regardless of client identity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before: isClaudeCodeRequest() checked whether the client looks like a real Claude Code CLI (UA, system prompt, X-App header, metadata format). If it looked like Claude Code, all mimicry was skipped — the assumption being that a real CLI needs no help. Problem: third-party tools like opencode partially impersonate Claude Code (sending claude-cli UA + claude-code beta + CC system prompt) but miss critical details (billing attribution block, tool-name obfuscation, cache breakpoints, full beta set). Some users' opencode instances pass the isClaudeCodeRequest check, causing sub2api to skip mimicry entirely, while Anthropic still detects the request as third-party. This explains why 'same opencode version, some users work, some don't' — it depends on which opencode features/config trigger the validator. Fix: OAuth accounts now unconditionally run the full mimicry pipeline, matching Parrot's behavior (Parrot never checks client identity). This is safe because our mimicry is strictly more complete than any third-party client's partial impersonation. Changed: - /v1/messages path: remove isClaudeCode gate - /v1/messages/count_tokens path: same --- backend/internal/service/gateway_service.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/backend/internal/service/gateway_service.go b/backend/internal/service/gateway_service.go index de4b7d34..011cc5bc 100644 --- a/backend/internal/service/gateway_service.go +++ b/backend/internal/service/gateway_service.go @@ -4155,12 +4155,14 @@ func (s *GatewayService) Forward(ctx context.Context, c *gin.Context, account *A }) } - isClaudeCode := isClaudeCodeRequest(ctx, c, parsed) - shouldMimicClaudeCode := account.IsOAuth() && !isClaudeCode + // OAuth 账号无条件走完整 mimicry,与 Parrot 对齐。 + // 不再检查 isClaudeCodeRequest —— 即使客户端自称 Claude Code(opencode 等 + // 第三方工具会伪装 UA / X-App / system prompt),它的伪装往往不完整(缺 billing + // block / 工具名混淆 / cache 策略等),被 Anthropic 判为 third-party。 + // 无条件覆盖不会对真正的 Claude Code 造成问题,因为我们的伪装更完整。 + shouldMimicClaudeCode := account.IsOAuth() if shouldMimicClaudeCode { - // 非 Claude Code 客户端:将 system 替换为 Claude Code 标识,原始 system 迁移至 messages - // 条件:1) OAuth/SetupToken 账号 2) 不是 Claude Code 客户端 3) 不是 Haiku 模型 4) system 中还没有 Claude Code 提示词 systemRewritten := false if !strings.Contains(strings.ToLower(reqModel), "haiku") && !systemIncludesClaudeCodePrompt(parsed.System) { @@ -8386,8 +8388,7 @@ func (s *GatewayService) ForwardCountTokens(ctx context.Context, c *gin.Context, // Pre-filter: strip empty text blocks to prevent upstream 400. body = StripEmptyTextBlocks(body) - isClaudeCode := isClaudeCodeRequest(ctx, c, parsed) - shouldMimicClaudeCode := account.IsOAuth() && !isClaudeCode + shouldMimicClaudeCode := account.IsOAuth() if shouldMimicClaudeCode { normalizeOpts := claudeOAuthNormalizeOptions{stripSystemCacheControl: true}