1. 30 Apr, 2026 9 commits
  2. 29 Apr, 2026 23 commits
    • github-actions[bot]'s avatar
      8ad099ba
    • shaw's avatar
      fix(scheduler): resolve SetSnapshot race conditions and remove usage throttle · 8bf2a7b8
      shaw authored
      Backend: Fix three race conditions in SetSnapshot that caused account
      scheduling anomalies and broken sticky sessions:
      - Use Lua CAS script for atomic version activation, preventing version
        rollback when concurrent goroutines write snapshots simultaneously
      - Add UnlockBucket to release rebuild lock immediately after completion
        instead of waiting 30s TTL expiry
      - Replace immediate DEL of old snapshots with 60s EXPIRE grace period,
        preventing readers from hitting empty ZRANGE during version switches
      
      Frontend: Remove serial queue throttle (1-2s delay per request) from
      usage loading since backend now uses passive sampling. All usage
      requests execute immediately in parallel.
      8bf2a7b8
    • shaw's avatar
      40feb86b
    • Wesley Liddick's avatar
      Merge pull request #1990 from haha1903/feat/zstd-request-decompression · f972a2fa
      Wesley Liddick authored
      feat(httputil): decode zstd/gzip/deflate request bodies
      f972a2fa
    • Wesley Liddick's avatar
      Merge pull request #2005 from gaoren002/pr/openai-strip-passthrough-fields · 55a7fa1e
      Wesley Liddick authored
      fix(openai): strip unsupported passthrough fields
      55a7fa1e
    • shaw's avatar
      fix(lint): check type assertion error in codex transform test · 5e54d492
      shaw authored
      The errcheck linter flagged an unchecked type assertion on
      item["type"].(string). Use the two-value form with require.True
      to satisfy the linter and fail clearly on unexpected types.
      5e54d492
    • Wesley Liddick's avatar
      Merge pull request #2068 from Ogannesson/fix/openai-drop-reasoning-items-from-input · 8d6d3154
      Wesley Liddick authored
      fix(openai): drop reasoning items from /v1/responses input on OAuth path
      8d6d3154
    • Wesley Liddick's avatar
      Merge pull request #2027 from hansnow/codex/fix-api-key-rate-limit-reset · 17ced6b7
      Wesley Liddick authored
      fix(api-key): reset rate limit usage cache
      17ced6b7
    • Wesley Liddick's avatar
      Merge pull request #2100 from KnowSky404/fix/codex-cli-edit-resend-tool-continuation · 7f8f3fe0
      Wesley Liddick authored
      [codex] fix WS continuation inference for explicit tool replay
      7f8f3fe0
    • Wesley Liddick's avatar
      Merge pull request #2050 from zvensmoluya/fix/openai-compact-payload-fields · 46f06b24
      Wesley Liddick authored
      fix(openai): preserve current Codex compact payload fields
      46f06b24
    • shaw's avatar
      chore: remove superpowers docs · 7ce5b832
      shaw authored
      7ce5b832
    • Wesley Liddick's avatar
      Merge pull request #2030 from KnowSky404/feature/account-bulk-edit-scope-and-compact · 27cad10d
      Wesley Liddick authored
      feat: support filtered account bulk edit and align compact OpenAI bulk fields
      27cad10d
    • Wesley Liddick's avatar
      Merge pull request #2058 from ivanvolt-labs/fix-responses-function-tool-choice · ff6fa020
      Wesley Liddick authored
      fix: use Responses-compatible function tool_choice format
      ff6fa020
    • KnowSky404's avatar
      fix: format ingress continuation test · f7c13af1
      KnowSky404 authored
      f7c13af1
    • KnowSky404's avatar
    • Wesley Liddick's avatar
      Merge pull request #2066 from alfadb/fix/anthropic-stream-eof-failover · 4d676ddd
      Wesley Liddick authored
      fix(gateway): Anthropic 流式 EOF 失败移交 + SSE error 帧标准化
      4d676ddd
    • shaw's avatar
      fix(vertex): audit fixes for Vertex Service Account feature (#1977) · 93d91e20
      shaw authored
      - Security: force token_uri to Google default, preventing SSRF via crafted service account JSON
      - Dedup: extract shared getVertexServiceAccountAccessToken() to eliminate ~35 lines of duplication between ClaudeTokenProvider and GeminiTokenProvider
      - Fix: apply model mapping + Vertex model ID normalization in forward_as_responses and forward_as_chat_completions paths
      - Fix: exclude service_account from AI Studio endpoint selection (Vertex cannot serve generativelanguage.googleapis.com)
      - Feature: add model restriction/mapping UI for service_account in EditAccountModal
      - Dedup: extract VERTEX_LOCATION_OPTIONS to shared constants
      - i18n: replace all hardcoded Chinese strings in Vertex UI with translation keys
      93d91e20
    • Wesley Liddick's avatar
      Merge pull request #1977 from sholiverlee/vertex · 63ef2310
      Wesley Liddick authored
      feat: 支持 Vertex Service Account(Anthropic / Gemini)
      63ef2310
    • alfadb's avatar
      fix(gateway): sanitize stream errors to avoid leaking infrastructure topology · d78478e8
      alfadb authored
      (*net.OpError).Error() concatenates Source/Addr fields, so the previous
      disconnectMsg surfaced internal source IP/port and upstream server address
      to clients via SSE error frames and UpstreamFailoverError.ResponseBody
      (reported by @Wei-Shaw on PR #2066).
      
      - Add sanitizeStreamError that maps known errors (io.ErrUnexpectedEOF,
        context.Canceled, syscall.ECONNRESET/EPIPE/ETIMEDOUT/...) to fixed
        descriptions and falls back to a generic placeholder, with an explicit
        *net.OpError branch that drops Source/Addr fields entirely.
      - Use sanitized message in client-facing disconnectMsg; full ev.err is
        still preserved in the existing operator log line for diagnosis.
      - Tests cover net.OpError redaction, the failover ResponseBody path, and
        every known sanitized error mapping.
      d78478e8
    • Wesley Liddick's avatar
      Merge pull request #2044 from VitalyAnkh/fix/openai-image-apikey-versioned-base-url · bf43fb4e
      Wesley Liddick authored
      fix(openai): honor versioned image base URLs
      bf43fb4e
    • Wesley Liddick's avatar
      Merge pull request #2090 from touwaeriol/feat/ops-retention-zero · a16c6650
      Wesley Liddick authored
      feat(ops): allow retention days = 0 to wipe table on each scheduled cleanup
      a16c6650
    • erio's avatar
      feat(ops): allow retention days = 0 to wipe table on each scheduled cleanup · 4b6954f9
      erio authored
      Background / 背景
      
      The ops cleanup task currently rejects retention days < 1 in both validate
      and normalize, so operators who want minimal-history setups (e.g. high
      churn deployments that prefer near-realtime cleanup) cannot express that
      intent through the UI. The only options are 1+ days, which keeps at least
      24h of history regardless of cron frequency.
      
      ops 清理任务目前在 validate 和 normalize 两处都拒绝小于 1 的保留天数,
      让希望尽量不留历史的运维场景(高吞吐部署 + 想用近实时清理)无法通过 UI
      表达。最低只能配 1,等于不管 cron 多频繁,至少都会保留 24 小时的历史。
      
      Purpose / 目的
      
      Let admins set retention days to 0, meaning "every scheduled cleanup
      run wipes the corresponding table(s) entirely". Combined with a more
      frequent cron (e.g. `0 * * * *`) this yields effectively rolling cleanup.
      
      允许管理员把保留天数设为 0,语义为"每次定时清理时把对应表全部清空"。
      搭配更频繁的 cron(比如每小时整点)即可获得近似滚动清理的效果。
      
      Changes / 改动内容
      
      Backend
      
      - service/ops_settings.go: validate accepts [0, 365]; normalize only
        refills default 30 when value is < 0 (negative is treated as legacy
        bad data, 0 is honoured)
      - service/ops_cleanup_service.go: introduce `opsCleanupPlan(now, days)`
        returning `(cutoff, truncate, ok)`. days==0 returns truncate=true and
        short-circuits to a new `truncateOpsTable` helper that uses
        `TRUNCATE TABLE` (O(1), no WAL, no VACUUM pressure). days>0 keeps
        the existing batched DELETE path unchanged. Empty tables skip
        TRUNCATE to avoid the ACCESS EXCLUSIVE lock entirely
      - Extract `isMissingRelationError` helper to dedupe the "table not
        yet created" tolerance shared by both delete and truncate paths
      - Add unit tests for `opsCleanupPlan` (three branches) and
        `isMissingRelationError`
      
      后端
      
      - service/ops_settings.go: validate 接受 [0, 365];normalize 仅在 < 0
        时回填默认 30(负数视为脏数据,0 被尊重)
      - service/ops_cleanup_service.go: 抽 `opsCleanupPlan(now, days)` 返回
        `(cutoff, truncate, ok)`。days==0 → truncate=true,走新增
        `truncateOpsTable`(TRUNCATE TABLE,O(1),无 WAL、无 VACUUM 压力);
        days>0 仍走原批量 DELETE 路径,行为完全不变。空表跳过 TRUNCATE,
        避免无意义的 ACCESS EXCLUSIVE 锁
      - 抽 `isMissingRelationError` helper 复用 delete / truncate 两处的
        "表不存在"宽容判断
      - 补 `opsCleanupPlan` 三分支 + `isMissingRelationError` 单元测试
      
      Frontend
      
      - OpsSettingsDialog.vue: validation accepts [0, 365]; input min=0
      - i18n (zh/en): hint mentions "0 = wipe all on every cleanup",
        validation message updated to 0-365 range
      
      前端
      
      - OpsSettingsDialog.vue: 校验放宽到 [0, 365],input min 改 0
      - i18n(zh/en):hint 补"0 = 每次清理时清空所有",错误提示改 0-365
      
      Trade-offs / 取舍
      
      - TRUNCATE requires ACCESS EXCLUSIVE lock briefly, but ops tables only
        have the cleanup task as a writer, so the lock is invisible to other
        workloads
      - Empty-table guard avoids the lock when there is nothing to clean
      - Negative values are still treated as legacy bad data and replaced
        with default 30 to preserve compatibility
      4b6954f9
    • shaw's avatar
      chore: update sponsors · da4b078d
      shaw authored
      da4b078d
  3. 28 Apr, 2026 8 commits
    • Oganneson's avatar
      fix(openai): drop reasoning items from /v1/responses input on OAuth path · 7452fad8
      Oganneson authored
      Closes #1957
      
      The OAuth path forwards client requests to chatgpt.com/backend-api/codex/responses,
      where applyCodexOAuthTransform forces store=false (chatgpt.com's codex backend
      rejects store=true). Reasoning items emitted under store=false are NEVER
      persisted upstream, so any rs_* reference that a client carries forward in a
      subsequent input[] array triggers a guaranteed upstream 404:
      
          Item with id 'rs_...' not found. Items are not persisted when `store` is
          set to false. Try again with `store` set to true, or remove this item
          from your input.
      
      sub2api wraps this as 502 "Upstream request failed" and the conversation
      breaks on every multi-turn /v1/responses request that uses reasoning + tools
      (reproducible with gpt-5.5; gpt-5.4 happens to dodge it because the upstream
      does not emit reasoning items for that model).
      
      Affected clients include any that follow the OpenAI Responses API spec and
      replay prior assistant items verbatim — in practice this hit OpenClaw and
      similar agent harnesses on every turn ≥2 with tool use.
      
      The fix: in filterCodexInput, drop input items with type == "reasoning"
      entirely. The model never reads reasoning summary text from input (only
      encrypted_content can carry reasoning context across turns, and chatgpt.com
      under store=false does not emit it), so this is a no-op for the model itself
      and a clean removal of unreachable upstream lookups.
      
      Scope is intentionally narrow:
        * Only OAuth account requests (account.Type == AccountTypeOAuth) reach
          applyCodexOAuthTransform / filterCodexInput.
        * API-key accounts going to api.openai.com/v1/responses are unaffected
          (store=true works there, rs_* persists, multi-turn already works).
        * Anthropic / Gemini platform groups go through different transforms and
          are unaffected.
        * /v1/chat/completions is unaffected (no reasoning items).
        * item_reference items (different type) are unaffected — only type ==
          "reasoning" is dropped.
      
      Verification:
        * Existing tests pass: go test ./internal/service/ -run Codex|Tool|OAuth
        * New regression test asserts reasoning items are dropped under both
          preserveReferences=true and preserveReferences=false.
        * End-to-end repro on gpt-5.5 multi-turn + tools: pre-patch 502, post-patch
          200. Repro on gpt-5.4 unchanged. Three-turn deep loop on gpt-5.5 passes.
      7452fad8
    • alfadb's avatar
      fix(gateway): emit Anthropic-standard SSE error events and failover body · 4c474616
      alfadb authored
      
      
      Two follow-ups to PR #2066's failover-wrap fix:
      
      1. Failover ResponseBody (`UpstreamFailoverError.ResponseBody`) was encoded
         as `{"error": "<msg>"}` (string field). `ExtractUpstreamErrorMessage`
         probes for `error.message`, `detail`, or top-level `message` only — so
         `handleFailoverExhausted` and downstream passthrough rules saw an empty
         message, losing the EOF root cause in ops logs. Re-encode as the
         Anthropic standard shape `{"type":"error","error":{"type":"upstream_disconnected","message":"..."}}`.
         (Addresses the inline review comment from copilot-pull-request-reviewer
         on Wei-Shaw/sub2api#2066.)
      
      2. The streaming `event: error` SSE frame for `response_too_large`,
         `stream_read_error`, and `stream_timeout` was non-standard
         (`{"error":"<reason>"}`). Anthropic SDKs (and Claude Code) expect
         `{"type":"error","error":{"type":"...","message":"..."}}` and parse
         `error.type`/`error.message` accordingly. Refactor `sendErrorEvent` to
         take both reason and message, and emit the standard frame so client
         SDKs surface a real diagnostic message instead of a generic stream error.
      
      This does not by itself prevent task interruption on long-stream EOF
      (SSE has no resume; client-side retry remains the only complete fix), but
      it gives both server-side ops logs and client-side error UIs a meaningful
      upstream message so users know the next step is to retry.
      
      Tests updated to assert the new body shape on both branches plus a new
      assertion that `ExtractUpstreamErrorMessage` returns a non-empty string.
      Co-Authored-By: default avatarClaude Opus 4.7 (1M context) <noreply@anthropic.com>
      4c474616
    • alfadb's avatar
      fix(gateway): wrap Anthropic stream EOF as failover error before client output · 63275735
      alfadb authored
      
      
      Anthropic streaming path (gateway_service.go) returned a plain error on
      upstream SSE read failure, so the handler-level UpstreamFailoverError check
      never fired and the client received a bare `stream_read_error` event,
      breaking long-running tasks even when no bytes had been written yet.
      
      The most common trigger is HTTP/2 GOAWAY from api.anthropic.com edge
      backends doing graceful rotation: Go's http.Transport surfaces this as
      `unexpected EOF` and never auto-retries.
      
      Mirror what the OpenAI and antigravity gateways already do: when the read
      error happens before any byte has reached the client (`!c.Writer.Written()`),
      return `*UpstreamFailoverError{StatusCode: 502, RetryableOnSameAccount: true}`
      so the handler can retry on the same or another account. After client
      output has begun, SSE has no resume protocol — keep the existing passthrough
      behavior.
      
      Tests cover both branches via streamReadCloser-based fixtures.
      Co-Authored-By: default avatarClaude Opus 4.7 (1M context) <noreply@anthropic.com>
      63275735
    • ivanvolt's avatar
      04b2866f
    • 陈曦's avatar
      trafficapi商用migration upgrade · 0d997a20
      陈曦 authored
      0d997a20
    • 陈曦's avatar
      merge capture requests branch to upstream follow · a7386882
      陈曦 authored
      a7386882
    • 陈曦's avatar
    • Wesley Liddick's avatar
      Merge pull request #2051 from DaydreamCoding/openai-fast-flex-policy · b0a2252e
      Wesley Liddick authored
      feat(openai): OpenAI Fast/Flex Policy 完整实现(HTTP + WebSocket + Admin)
      b0a2252e