"backend/internal/vscode:/vscode.git/clone" did not exist on "9bf8ab7048e1a98deff92619132818afb344588b"
  1. 14 Apr, 2026 2 commits
    • erio's avatar
      refactor: move channel model restriction from handler to scheduling phase · 2dce4306
      erio authored
      Move the model pricing restriction check from 8 handler entry points
      to the account scheduling phase (SelectAccountForModelWithExclusions /
      SelectAccountWithLoadAwareness), aligning restriction with billing:
      
      - requested: check original request model against pricing list
      - channel_mapped: check channel-mapped model against pricing list
      - upstream: per-account check using account-mapped model
      
      Handler layer now only resolves channel mapping (no restriction).
      Scheduling layer performs pre-check for requested/channel_mapped,
      and per-account filtering for upstream billing source.
      2dce4306
    • erio's avatar
      style: apply gofmt formatting · 1cd033e5
      erio authored
      
      Co-Authored-By: default avatarClaude Opus 4.6 <noreply@anthropic.com>
      1cd033e5
  2. 13 Apr, 2026 2 commits
    • sakurawztlt's avatar
      fix: Anthropic 非流式路径在上游终态事件 output 为空时从 delta 事件重建响应内容 · a1e299a3
      sakurawztlt authored
      b2e379cf 引入的 BufferedResponseAccumulator 已修复了 chat_completions
      非流式路径和 responses OAuth 非流式路径,但遗漏了 Anthropic /v1/messages
      非流式路径 (handleAnthropicBufferedStreamingResponse)。
      
      当客户端请求 stream=false 且模型开启思考时,上游 response.completed
      终态事件的 output 字段可能为空,实际 message 内容通过
      response.output_text.delta 增量事件下发。旧代码只读终态事件的 Response,
      导致客户端收到的 content 字段为空 ([{"type":"text"}])。
      
      本 commit 将 b2e379cf 的相同修复模式镜像到 Anthropic 路径:在 SSE 扫描
      过程中用 BufferedResponseAccumulator 累积 delta 内容,终态 output 为空
      时通过 SupplementResponseOutput 补充重建。
      
      同时修复 handleAnthropicBufferedStreamingResponse 遗漏 response.done
      事件类型的问题,与 chat completions 路径保持一致,避免上游发送
      response.done 时 handler 认不出终态事件、最终返回 502 的潜在问题。
      
      BufferedResponseAccumulator 已在 chatcompletions_responses_test.go 有
      完整单元测试覆盖(TextOnly/ToolCalls/Reasoning/Mixed/SupplementEmpty/
      NoSupplementWhenOutputExists/EmptyDeltas/IgnoresNonFunctionCallItems),
      本次复用相同累加器无需新增测试。
      a1e299a3
    • erio's avatar
      fix(payment): fix Alipay/Wxpay direct provider type mapping and enable... · f498eb8f
      erio authored
      fix(payment): fix Alipay/Wxpay direct provider type mapping and enable cross-provider load balancing
      
      Two issues fixed:
      
      1. Alipay.SupportedTypes() returned ["alipay_direct"] and Wxpay returned
         ["wxpay_direct"], but the frontend sends payment_type="alipay"/"wxpay".
         The registry lookup failed with "payment method (alipay) is not
         configured". Fix: return the base types ["alipay"]/["wxpay"].
      
      2. When multiple providers support the same payment type (e.g. EasyPay
         and Alipay direct both handle "alipay"), only the last-registered
         provider's instances were reachable — the registry mapped one type to
         one provider key, and SelectInstance queried by that single key.
      
         Fix: bypass the registry in invokeProvider and let SelectInstance
         query across all providers when providerKey is empty. The selected
         instance's own ProviderKey (now included in InstanceSelection) is
         used to create the correct provider, enabling true cross-provider
         load balancing.
      
      Closes #1592
      f498eb8f
  3. 12 Apr, 2026 1 commit
    • bot's avatar
      fix: handle Anthropic credit balance exhausted (400) as account error · cb016ad8
      bot authored
      When an Anthropic API key's credit balance is depleted, the upstream
      returns HTTP 400 with message containing "credit balance". Previously,
      the 400 handler only checked for "organization has been disabled",
      so credit-exhausted accounts kept being scheduled — every request
      returned the same error.
      
      Treat this case identically to 402 (Payment Required): call
      handleAuthError → SetError to stop scheduling the account until
      an admin manually recovers it after topping up credits.
      
      Closes #1586
      cb016ad8
  4. 11 Apr, 2026 4 commits
    • shuanbao0's avatar
      fix(gateway): 剥离 Cursor raw body 透传路径中 Codex 不支持的 Responses API 参数 · 422e25c9
      shuanbao0 authored
      
      
      在前一个 commit 的 isResponsesShape 短路路径基础上,补充对 Cursor 云端
      带过来的、Codex 上游统一不支持的顶层 Responses API 参数的剥离:
      
        - prompt_cache_retention
        - safety_identifier
        - metadata
        - stream_options
      
      根因补充:这条 raw-body 透传路径为了保留 Cursor 的 input 数组整体结构,
      不再经过 ChatCompletionsRequest 的反序列化过滤,所以这些 Go 结构体里
      没有对应字段的参数会被原样发到上游,上游返回:
          Unsupported parameter: <field>
      常规 Chat Completions 转换路径天然通过 ChatCompletionsRequest 丢弃未知字段,
      不受影响;此处仅在 isResponsesShape 分支内用 sjson.DeleteBytes 显式过滤,
      作用域最小。剥离列表与 openai_gateway_service.go:2034 的
      unsupportedFields 语义对齐。
      
      另外在 applyCodexOAuthTransform 的 OAuth 兜底 strip 列表里同步追加
      prompt_cache_retention,作为对该函数所有其他 OAuth 调用点的 defense
      in depth(当前只有 Cursor 路径的短路已在前面剥过,但保留这一层更稳)。
      
      测试:
      - TestCursorMixedShape_StripsUnsupportedFields — 验证所有 4 个字段都被剥
      - TestApplyCodexOAuthTransform_StripsPromptCacheRetention — OAuth 兜底路径
      Co-Authored-By: default avatarClaude Opus 4.6 (1M context) <noreply@anthropic.com>
      422e25c9
    • shuanbao0's avatar
      fix(gateway): 兼容 Cursor /v1/chat/completions 的 Responses API body · b7edc3ed
      shuanbao0 authored
      
      
      Cursor 云端 (User-Agent: Go-http-client/2.0) 发往 /v1/chat/completions 的
      body 使用 Responses API 格式:
          {"model":"gpt-5.4","input":[{"role":"system","content":"..."}],"stream":true}
      
      原代码用 ChatCompletionsRequest 反序列化,该结构体没有 Input 字段,
      Cursor 的 input 数组被静默丢弃,ChatCompletionsToResponses 转换后产出
      input: null,Codex 上游以 "Invalid type for 'input': expected a string,
      but got an object" 拒绝请求(上游 typeof null === 'object')。
      
      修复:在 ForwardAsChatCompletions 里用 gjson 检测 body shape,当 input
      存在且 messages 缺失时,跳过 Chat→Responses 转换,用 sjson 仅改写 model
      字段后原样透传 body。billing 所需的 ServiceTier 和 Reasoning.Effort 通过
      gjson 从 raw body 提取,下游 codex OAuth transform 路径保持不变。
      
      测试:新增 openai_cursor_warmup_pipeline_test.go,覆盖 5 个 shape 检测
      用例(正向/标准请求不误伤/两字段共存/空 body/JSON 回读)。
      Co-Authored-By: default avatarClaude Opus 4.6 (1M context) <noreply@anthropic.com>
      b7edc3ed
    • erio's avatar
      refactor(payment): code standards fixes and regression repairs · e3a000e0
      erio authored
      Backend:
      - Split payment_order.go (546→314 lines) into payment_order_lifecycle.go
      - Replace magic strings with constants in factory, easypay, webhook handler
      - Add rate limit/validity unit constants in payment_order_lifecycle, payment_service
      - Fix critical regression: add PaymentEnabled to GetPublicSettings response
      - Add missing migration 099_fix_migrated_purchase_menu_label_icon.sql
      
      Frontend:
      - Fix StripePopupView.vue: replace `as any` with typed interface, use extractApiErrorMessage
      - Fix AdminOrderTable.vue: replace hardcoded column labels with i18n t() calls
      - Fix SubscriptionsView.vue: replace hardcoded Today/Tomorrow with i18n
      - Extract duplicate statusBadgeClass/canRefund/formatOrderDateTime to orderUtils.ts
      - Add missing i18n keys: common.today, common.tomorrow, payment.orders.orderType/actions
      - Remove dead PurchaseSubscriptionView.vue (replaced by PaymentView)
      e3a000e0
    • erio's avatar
      feat(payment): add complete payment system with multi-provider support · 63d1860d
      erio authored
      Add a full payment and subscription system supporting EasyPay (Alipay/WeChat),
      Stripe, and direct Alipay/WeChat Pay providers with multi-instance load balancing.
      63d1860d
  5. 10 Apr, 2026 1 commit
  6. 09 Apr, 2026 11 commits
  7. 08 Apr, 2026 4 commits
    • ius's avatar
      265687b5
    • shaw's avatar
      fix: resolve errcheck lint and add missing enable_cch_signing to test · b982076e
      shaw authored
      - Suppress errcheck for xxhash Digest.Write (never returns error)
      - Add enable_cch_signing field to settings API contract test
      b982076e
    • shaw's avatar
      feat: sync billing header cc_version with User-Agent and add opt-in CCH signing · e51c9e50
      shaw authored
      - Sync cc_version in x-anthropic-billing-header with the fingerprint
        User-Agent version, preserving the message-derived suffix
      - Implement xxHash64-based CCH signing to replace the cch=00000
        placeholder with a computed hash
      - Add admin toggle (enable_cch_signing) under gateway forwarding settings,
        disabled by default
      e51c9e50
    • shaw's avatar
      fix: 修复非CC客户端OAuth伪装被Anthropic检测为第三方应用的问题 · 1c9a2128
      shaw authored
      commit f3aa54b7 的 rewriteSystemForNonClaudeCode 未能通过 Anthropic 第三方检测,
      根因是两个关键信号与真实 Claude Code 不一致:
      
      1. anthropic-beta 头缺少 claude-code-20250219:伪装路径主动将该 beta
         加入 drop set 并移除,但 Anthropic 依赖此 beta 识别 Claude Code 请求。
         修复:非 haiku 模型的伪装请求强制包含 claude-code beta。
      
      2. system 字段使用 string 格式而非 array+cache_control:真实 Claude Code
         始终以 [{type,text,cache_control:{type:"ephemeral"}}] 发送 system,
         string 格式成为第三方检测信号。
         修复:rewriteSystemForNonClaudeCode 改为注入 array 格式。
      
      附带调整:stripSystemCacheControl 按 system 是否被重写动态决定,
      重写时保留 CC prompt 的 cache_control,未重写时(haiku/已含CC前缀)
      保持原有剥离行为。
      1c9a2128
  8. 07 Apr, 2026 6 commits
  9. 05 Apr, 2026 9 commits
    • erio's avatar
      refactor(channel): split long functions, extract shared validation, move... · 9151d34d
      erio authored
      refactor(channel): split long functions, extract shared validation, move billing validation to service
      
      - Split Update (98→25 lines), buildCache (54→20 lines), Create (51→25 lines)
        into focused sub-functions: applyUpdateInput, checkGroupConflicts,
        fetchChannelData, populateChannelCache, storeErrorCache, getOldGroupIDs,
        invalidateAuthCacheForGroups
      - Extract validateChannelConfig to eliminate duplicated validation calls
        between Create and Update
      - Move validatePricingBillingMode from handler to service layer for
        proper separation of concerns
      - Add error logging to IsModelRestricted (was silently swallowing errors)
      - Add 12 new tests: ToUsageFields, billing mode validation, antigravity
        wildcard mapping isolation, Create/Update mapping conflict integration
      9151d34d
    • erio's avatar
      fix: remove cross-platform pricing/mapping leakage for antigravity groups · c5688fef
      erio authored
      Antigravity groups were incorrectly matching pricing and model mapping
      entries from anthropic/gemini platform tabs. Each platform should be
      strictly isolated — antigravity groups only use antigravity-tagged pricing.
      c5688fef
    • erio's avatar
      fix: gofmt formatting · 19655a15
      erio authored
      19655a15
    • erio's avatar
      fix: use upstream versions of shared files and remove only Sora code · f345b0f5
      erio authored
      Restore gateway_service.go, setting_handler.go, routes/admin.go,
      dto/settings.go, group_repo.go, api_key_repo.go, wire_gen.go to
      upstream/main versions and surgically remove only Sora references.
      
      This preserves upstream-only features (RequireOauthOnly, RequirePrivacySet,
      GroupResolution, etc.) that were missing when using release branch versions.
      f345b0f5
    • shaw's avatar
      fix(billing): prevent channel_mapped override from reverting BillingModel when channel did not map · f585a15e
      shaw authored
      When a channel has no model mapping for the requested model, ChannelMappedModel
      equals OriginalModel (the user's arbitrary input). Combined with the default
      BillingModelSource="channel_mapped", this incorrectly overrides the BillingModel
      set by the OpenAI format conversion layer (e.g., gpt-5.4 from DefaultMappedModel)
      back to the unmapped original model (e.g., glm) which has no pricing — resulting
      in zero-cost billing.
      
      Add guard condition so the channel_mapped override only fires when the channel
      actually changed the model (ChannelMappedModel != OriginalModel).
      f585a15e
    • erio's avatar
      fix: gofmt formatting · a29f5a48
      erio authored
      a29f5a48
    • erio's avatar
    • erio's avatar
      fix: resolve CI failures — gofmt, unused functions, test parameter mismatches · 5bb8b2ad
      erio authored
      - gofmt: user.go, config_test.go, group_handler.go, smart_retry_test.go
      - Remove unused: mergeGroupIDs, resolveProxyURL, "time" import
      - Fix api_contract_test.go: remove extra Sora args from NewAdminService,
        NewSettingHandler, NewAccountHandler; remove Sora field expectations
      - Fix account_test_service_openai_test.go: restore test helpers
      5bb8b2ad
    • erio's avatar
      fix: resolve CI failures — gofmt, unused functions, missing test helpers · 93b42ccf
      erio authored
      - Run gofmt on user schema, config test, group handler
      - Remove unused mergeGroupIDs function
      - Restore shared test helpers (newJSONResponse, queuedHTTPUpstream)
        that were in deleted Sora test file
      93b42ccf