1. 29 Mar, 2026 1 commit
    • shaw's avatar
      feat(tls-fingerprint): 新增 TLS 指纹 Profile 数据库管理及代码质量优化 · b22ab6ad
      shaw authored and 陈曦's avatar 陈曦 committed
      新增功能:
      - 新增 TLS 指纹 Profile CRUD 管理(Ent schema + 迁移 + Admin API + 前端管理界面)
      - 支持账号绑定数据库中的自定义 TLS Profile,或随机选择(profile_id=-1)
      - HTTPUpstream.DoWithTLS 接口从 bool 改为 *tlsfingerprint.Profile,支持按账号指定 Profile
      - AccountUsageService 注入 TLSFingerprintProfileService,统一 usage 场景与网关的 Profile 解析逻辑
      
      代码优化:
      - 删除已被 TLSFingerprintProfileService 完全取代的 registry.go 死代码(418 行)
      - 提取 3 个 dialer 的重复 TLS 握手逻辑为 performTLSHandshake() 共用函数
      - 修复 GetTLSFingerprintProfileID 缺少 json.Number 处理的 bug
      - gateway_service.Forward 中 ResolveTLSProfile 从重试循环内重复调用改为预解析局部变量
      - 删除冗余的 buildClientHelloSpec() 单行 wrapper 和 int64(e.ID) 无效转换
      - tls_fingerprint_profile_cache.go 日志从 log.Printf 改为 slog 结构化日志
      - dialer_capture_test.go 添加 //go:build integration 标签,防止 CI 失败
      - 去重 TestProfileExpectation 类型至共享 test_types_test.go
      - 修复 9 个测试文件缺少 tlsfingerprint import 的编译错误
      - 修复 error_policy_integration_test.go 中 handleError 回调签名被错误替换的问题
      b22ab6ad
  2. 26 Mar, 2026 2 commits
    • shaw's avatar
      feat(rectifier): 请求整流器增加 API Key 账号签名整流支持 · d571f300
      shaw authored
      新增独立开关控制 API Key 账号的签名整流功能,支持配置自定义
      匹配关键词以捕获不同格式的上游错误响应。
      
      - 新增 apikey_signature_enabled 开关(默认关闭)
      - 新增 apikey_signature_patterns 自定义关键词配置
      - 内置签名检测规则对 API Key 账号同样生效
      - 自定义关键词对完整响应体做不区分大小写匹配
      - 重试二阶段检测仅做模式匹配,不重复校验开关
      - Handler 层校验关键词数量(≤50)和长度(≤500)
      - API 响应 nil patterns 统一序列化为空数组
      - OAuth/SetupToken/Upstream/Bedrock 账号行为不变
      d571f300
    • shaw's avatar
      feat: 网关请求头 wire casing 保持、转发行为开关、调试日志增强及 accept-encoding 恢复 · b20e1422
      shaw authored
      - 新增 header_util.go,通过 setHeaderRaw/getHeaderRaw/addHeaderRaw 绕过
        Go 的 canonical-case 规范化,保持真实 Claude CLI 抓包的请求头大小写
        (如 "x-app" 而非 "X-App","X-Stainless-OS" 而非 "X-Stainless-Os")
      - 新增管理后台开关:指纹统一化(默认开启)和 metadata 透传(默认关闭),
        使用 atomic.Value + singleflight 缓存模式,60s TTL
      - 调试日志从控制台 body 打印升级为文件级完整快照
        (按真实 wire 顺序输出 headers + 格式化 JSON body + 上下文元数据)
      - 恢复 accept-encoding 到白名单,在 http_upstream.go 新增 decompressResponseBody
        处理 gzip/brotli/deflate 解压(Go 显式设置 Accept-Encoding 时不会自动解压)
      - OAuth 服务 axios UA 从 1.8.4 更新至 1.13.6
      - 测试断言改用 getHeaderRaw 适配 raw header 存储方式
      b20e1422
  3. 24 Mar, 2026 1 commit
  4. 22 Mar, 2026 1 commit
    • alfadb's avatar
      fix(gateway): strip empty text blocks from nested tool_result content · 70a9d0d3
      alfadb authored
      Empty text blocks inside tool_result.content were not being filtered,
      causing upstream 400 errors: 'text content blocks must be non-empty'.
      
      Changes:
      - Add stripEmptyTextBlocksFromSlice helper for recursive content filtering
      - FilterThinkingBlocksForRetry now recurses into tool_result nested content
      - Add StripEmptyTextBlocks pre-filter on initial request path to avoid
        unnecessary 400+retry round-trips
      - Add unit tests for nested empty text block scenarios
      70a9d0d3
  5. 21 Mar, 2026 2 commits
  6. 20 Mar, 2026 1 commit
  7. 19 Mar, 2026 1 commit
  8. 18 Mar, 2026 3 commits
    • alfadb's avatar
    • alfadb's avatar
      fix: strip empty text blocks in retry filter and fix error pattern matching · b8ada63a
      alfadb authored
      
      
      Empty text blocks ({"type":"text","text":""}) cause Anthropic upstream to
      return 400: "text content blocks must be non-empty". This was not caught
      by the existing error detection pattern in isThinkingBlockSignatureError,
      nor handled by FilterThinkingBlocksForRetry.
      
      - Add empty text block stripping to FilterThinkingBlocksForRetry
      - Fix isThinkingBlockSignatureError to match new Anthropic error format
      - Add fast-path byte patterns to avoid unnecessary JSON parsing
      Co-Authored-By: default avatarClaude Opus 4.6 (1M context) <noreply@anthropic.com>
      b8ada63a
    • shaw's avatar
      fix: 兼容 Claude Code v2.1.78+ 新 JSON 格式 metadata.user_id · a14babdc
      shaw authored
      Claude Code v2.1.78 起将 metadata.user_id 从拼接字符串改为 JSON:
      旧: user_{hex}_account_{uuid}_session_{uuid}
      新: {"device_id":"...","account_uuid":"...","session_id":"..."}
      
      新增集中解析/格式化模块 metadata_userid.go:
      - ParseMetadataUserID: 自动识别两种格式,提取 DeviceID/AccountUUID/SessionID
      - FormatMetadataUserID: 根据 UA 版本输出对应格式(>= 2.1.78 输出 JSON)
      - ExtractCLIVersion: 从 UA 提取版本号,消除与 ClaudeCodeValidator.ExtractVersion 的重复
      
      修改消费者统一使用新模块:
      - claude_code_validator: 用 ParseMetadataUserID 替代只匹配旧格式的 userIDPattern
      - identity_service: RewriteUserID/WithMasking 增加 fingerprintUA 参数,
        解析用 ParseMetadataUserID,输出用 FormatMetadataUserID(版本感知)
      - gateway_service: GenerateSessionHash 用 ParseMetadataUserID 提取 session_id,
        buildOAuthMetadataUserID 用 FormatMetadataUserID 输出版本匹配格式,
        两处 RewriteUserIDWithMasking 调用传入 fp.UserAgent
      - account_test_service: generateSessionString 改用 FormatMetadataUserID,
        自动跟随 DefaultHeaders UA 版本
      
      删除三个旧正则: userIDPattern, userIDRegex, sessionIDRegex
      统一 hex 匹配为 [a-fA-F0-9],修复旧 userIDRegex 只匹配小写的不一致
      a14babdc
  9. 17 Mar, 2026 1 commit
    • Ethan0x0000's avatar
      feat(service): record upstream model across all gateway paths · 2e4ac88a
      Ethan0x0000 authored
      Propagate UpstreamModel through ForwardResult and OpenAIForwardResult in Anthropic direct, API-key passthrough, Bedrock, and OpenAI gateway flows. Extract optionalNonEqualStringPtr and optionalTrimmedStringPtr into usage_log_helpers.go. Store upstream_model only when it differs from the requested model.
      
      Also introduces anthropicPassthroughForwardInput struct to reduce parameter count.
      2e4ac88a
  10. 15 Mar, 2026 3 commits
    • Ethan0x0000's avatar
      feat: add InboundEndpoint/UpstreamEndpoint fields to non-OpenAI usage records · 1b79b0f3
      Ethan0x0000 authored
      Extend RecordUsageInput and RecordUsageLongContextInput structs with InboundEndpoint and UpstreamEndpoint so that Claude, Gemini, and Sora handlers can record endpoint info alongside OpenAI handlers.
      
      Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode
      
      )
      Co-authored-by: default avatarSisyphus <clio-agent@sisyphuslabs.ai>
      1b79b0f3
    • erio's avatar
      feat(ops): add ignore insufficient balance errors toggle and extract error constants · cfe72159
      erio authored
      - Add 5th error filter switch IgnoreInsufficientBalanceErrors to suppress
        upstream insufficient balance / insufficient_quota errors from ops log
      - Extract hardcoded error strings into package-level constants for
        shouldSkipOpsErrorLog, normalizeOpsErrorType, classifyOpsPhase, and
        classifyOpsIsBusinessLimited
      - Define ErrNoAvailableAccounts sentinel error and replace all
        errors.New("no available accounts") call sites
      - Update tests to use require.ErrorIs with the sentinel error
      cfe72159
    • YanzheL's avatar
      fix: extract and log Claude output_config.effort in usage records · 1bff2292
      YanzheL authored
      Claude's output_config.effort parameter (low/medium/high/max) was not
      being extracted from requests or logged in the reasoning_effort column
      of usage logs. Only the OpenAI path populated this field.
      
      Changes:
      - Extract output_config.effort in ParseGatewayRequest
      - Add ReasoningEffort field to ForwardResult
      - Populate reasoning_effort in both RecordUsage and RecordUsageWithLongContext
      - Guard against overwriting service-set effort values in handler
      - Update stale comments that described reasoning_effort as OpenAI-only
      - Add unit tests for extraction, normalization, and persistence
      1bff2292
  11. 14 Mar, 2026 2 commits
    • SsageParuders's avatar
      refactor: merge bedrock-apikey into bedrock with auth_mode credential · 4644af2c
      SsageParuders authored
      Consolidate two separate channel types (bedrock + bedrock-apikey) into
      a single "AWS Bedrock" channel. Authentication mode is now distinguished
      by credentials.auth_mode ("sigv4" | "apikey") instead of separate types.
      
      Backend:
      - Remove AccountTypeBedrockAPIKey constant
      - IsBedrock() simplified; IsBedrockAPIKey() checks auth_mode
      - Add IsAPIKeyOrBedrock() helper to eliminate repeated type checks
      - Extend pool mode, quota scheduling, and billing to bedrock
      - Add RetryableOnSameAccount to handleBedrockUpstreamErrors
      - Add "bedrock" scope to Beta Policy for independent control
      
      Frontend:
      - Merge two buttons into one "AWS Bedrock" with auth mode radio
      - Badge displays "Anthropic | AWS"
      - Pool mode and quota limit UI available for bedrock
      - Quota display in account list (usage bars, capacity badges, reset)
      - Remove all bedrock-apikey type references
      4644af2c
    • InCerry's avatar
      2666422b
  12. 13 Mar, 2026 2 commits
  13. 12 Mar, 2026 3 commits
  14. 11 Mar, 2026 1 commit
    • amberwarden's avatar
      fix: 为 Anthropic Messages API 流式转发添加下游 keepalive ping · 6e90ec61
      amberwarden authored
      
      
      Anthropic Messages API 的流式转发路径(gateway_service.go)在上游长时间
      无数据时(如 Opus extended thinking 阶段)不会向下游发送任何内容,导致
      Cloudflare Tunnel 等代理因连接空闲而断开。
      
      复用已有的 StreamKeepaliveInterval 配置(默认 10 秒),在 select 循环中
      添加 keepalive 分支,定时发送 Anthropic 原生格式的 ping 事件保活,与
      OpenAI 兼容路径的实现模式保持一致。
      Co-Authored-By: default avatarClaude Opus 4.6 <noreply@anthropic.com>
      6e90ec61
  15. 10 Mar, 2026 1 commit
  16. 09 Mar, 2026 3 commits
  17. 08 Mar, 2026 1 commit
  18. 07 Mar, 2026 2 commits
    • shaw's avatar
      feat: 支持后台设置是否启用整流开关 · a3791104
      shaw authored
      a3791104
    • erio's avatar
      feat(account): add daily/weekly periodic quota limits for API Key accounts · 1ee17383
      erio authored
      
      
      Extend the existing total quota limit with daily and weekly periodic
      dimensions. Each dimension is independently configurable and uses lazy
      reset — when the period expires, usage is automatically reset to zero on
      the next increment. Any dimension exceeding its limit will pause the
      account from scheduling.
      
      Backend:
      - Add GetQuotaDailyLimit/Used, GetQuotaWeeklyLimit/Used, HasAnyQuotaLimit
      - Rewrite IncrementQuotaUsed with atomic CTE SQL for 3-dimension update
      - Rewrite ResetQuotaUsed to clear all dimensions and period timestamps
      - Update postUsageBilling to use HasAnyQuotaLimit()
      - Preserve daily/weekly used values on account edit
      
      Frontend:
      - Refactor QuotaLimitCard from single v-model to 3-dimension props
      - Add QuotaBadge component for compact D/W/$ display
      - Update AccountCapacityCell with per-dimension badges
      - Update Create/Edit modals with daily/weekly quota fields
      - Update AccountActionMenu hasQuotaLimit to check all dimensions
      - Add i18n strings for daily/weekly/total quota labels
      Co-Authored-By: default avatarClaude Opus 4.6 <noreply@anthropic.com>
      1ee17383
  19. 06 Mar, 2026 4 commits
    • yangjianbo's avatar
      fix(openai): 统一专属倍率计费链路并补齐回归测试 · a18bbb5f
      yangjianbo authored
      抽取共享的用户分组专属倍率解析器,统一缓存、singleflight 与回退逻辑。\n\n让 OpenAI 独立计费链路复用专属倍率解析,修复 usage 记录与实际扣费未命中用户专属倍率的问题。\n\n补齐 OpenAI 计费与解析器单元测试,并修复全量回归中暴露的 lint 阻塞项。\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
      a18bbb5f
    • erio's avatar
      fix(openai): remove misplaced passthrough check from isModelSupportedByAccount · c28f691f
      erio authored
      isModelSupportedByAccount 不被 OpenAI 调度路径调用,
      OpenAI /responses 和 /chat/completions 走的是
      openai_account_scheduler.go,透传短路已在 PR #806 的
      第二个 commit 中正确添加到该文件。
      
      此处的检查是多余的死代码,因为 OpenAI 账号不会走到
      isModelSupportedByAccount 的这个分支。
      c28f691f
    • alfadb's avatar
      feat(openai): add /v1/messages endpoint and API compatibility layer · ff1f1149
      alfadb authored
      Add Anthropic Messages API support for OpenAI platform groups, enabling
      clients using Claude-style /v1/messages format to access OpenAI accounts
      through automatic protocol conversion.
      
      - Add apicompat package with type definitions and bidirectional converters
        (Anthropic  Chat, Chat  Responses, Anthropic 
      
       Responses)
      - Implement /v1/messages endpoint for OpenAI gateway with streaming support
      - Add model mapping UI for OpenAI OAuth accounts (whitelist + mapping modes)
      - Support prompt caching fields and codex OAuth transforms
      - Fix tool call ID conversion for Responses API (fc_ prefix)
      - Ensure function_call_output has non-empty output field
      Co-Authored-By: default avatarClaude Opus 4.6 <noreply@anthropic.com>
      ff1f1149
    • erio's avatar
      fix: OpenAI passthrough accounts bypass model mapping check · 79ae15d5
      erio authored
      透传模式账号仅替换认证,应允许所有模型通过。之前调度阶段的
      isModelSupportedByAccount 不感知透传模式,导致 model_mapping
      中未配置的新模型(如 gpt-5.4)被拒绝返回 503。
      79ae15d5
  20. 05 Mar, 2026 5 commits