• keh4l's avatar
    fix(gateway): apply full Claude Code mimicry on /chat/completions and /responses · b5467d61
    keh4l authored
    Before: the OpenAI-compat forwarders only called injectClaudeCodePrompt,
    which prepends the Claude Code banner but leaves the rest of the body
    in its original non-Claude-Code shape. The codebase already admits this
    is insufficient (see the comment on rewriteSystemForNonClaudeCode in
    gateway_service.go: "仅前置追加 Claude Code 提示词无法通过检测").
    
    Effect: OAuth accounts served through /v1/chat/completions or /v1/responses
    were detected as third-party apps and bled plan quota with:
    
        Third-party apps now draw from your extra usage, not your plan limits.
    
    Fix:
      - apicompat.AnthropicRequest: add Metadata json.RawMessage so metadata
        survives the OpenAI->Anthropic->Marshal round trip; without it the
        downstream rewrite has no user_id to work with.
      - service: extract applyClaudeCodeOAuthMimicryToBody, a ParsedRequest-free
        variant of the /v1/messages mimicry pipeline
        (rewriteSystemForNonClaudeCode + normalizeClaudeOAuthRequestBody +
        metadata.user_id injection) so the OpenAI-compat forwarders can reuse it.
      - service: add buildOAuthMetadataUserIDFromBody + hashBodyForSessionSeed
        for the same reason (no ParsedRequest at the call site).
      - ForwardAsChatCompletions / ForwardAsResponses: replace the 3-line
        prompt-prepend with the full mimicry pipeline.
      - applyClaudeCodeMimicHeaders: set x-client-request-id per-request
        (real Claude CLI always does); missing/duplicated values are one more
        third-party fingerprint signal.
    
    No change to the native /v1/messages path: it already called the full
    pipeline, we only lift those helpers into a reusable function.
    
    Tests:
      - go build ./... passes
      - go test ./internal/service/... ./internal/pkg/apicompat/... passes
      - lsp_diagnostics clean on all touched files
      - pre-existing failures in internal/config are unrelated (env-sensitive
        tests that also fail on upstream main)
    b5467d61
gateway_forward_as_responses.go 16 KB