1. 30 Apr, 2026 1 commit
  2. 28 Apr, 2026 1 commit
    • DaydreamCoding's avatar
      feat(openai): OpenAI Fast/Flex Policy 完整实现(HTTP + WebSocket + Admin) · 30f55a1f
      DaydreamCoding authored
      
      
      对称参照 Claude BetaPolicy 的 fast-mode 过滤实现,新增针对 OpenAI 上游
      service_tier 字段(priority / flex,含客户端 "fast" → "priority" 归一化)的
      pass / filter / block 三态策略,覆盖全部 OpenAI 入口 + admin 配置入口。
      
      后端核心
      - 新增 SettingKeyOpenAIFastPolicySettings、OpenAIFastPolicyRule、
        OpenAIFastPolicySettings 配置模型,含规则的 service_tier × action × scope
        × 模型白名单 × fallback action 维度。
      - SettingService.Get/SetOpenAIFastPolicySettings;缺失时返回内置默认策略
        (所有模型的 priority 走 filter,whitelist 为空,fallback=pass)。设计
        依据:service_tier=fast 是用户级开关,与 model 字段正交,默认锁定特定
        model slug 会留下"用 gpt-4 + fast 透传 priority 上游"的绕过路径。JSON
        解析失败不再静默 fallback,slog.Warn 记录脏数据,便于运维定位。
      - service_tier 归一化(trim + ToLower + fast→priority + 白名单 priority/flex)
        与策略评估(evaluateOpenAIFastPolicy)作为唯一真实来源,HTTP / WS 共用。
        抽出纯函数 evaluateOpenAIFastPolicyWithSettings,配合 ctx-bound settings
        快照(withOpenAIFastPolicyContext / openAIFastPolicySettingsFromContext),
        WS 长会话入口预取一次后所有帧复用,避免每帧打到 settingService。
      
      HTTP 入口(4 个)
      - Chat Completions、Anthropic 兼容(Messages,含 BetaFastMode→priority 二次
        命中)、原生 Responses、Passthrough Responses 全部接入
        applyOpenAIFastPolicyToBody,filter 走 sjson 顶层删除 service_tier,block
        返回 403 forbidden_error JSON。
      - 4 入口统一使用 upstream 视角的 model(GetMappedModel +
        normalizeOpenAIModelForUpstream + Codex OAuth normalize 后的 slug),
        避免 chat/messages/native /responses/passthrough 因为 model 维度不同
        造成 whitelist 命中差异。
      - 在 pass 路径也把客户端 "fast" 别名归一化为 "priority" 写回 body,
        否则 native /responses 与 passthrough 入口会把 "fast" 原样透传给上游
        导致 400/拒绝(chat-completions 入口的 normalizeResponsesBodyServiceTier
        此前已具备同等行为)。
      
      WebSocket 入口
      - 新增 applyOpenAIFastPolicyToWSResponseCreate:严格匹配
        type="response.create",仅处理顶层 service_tier;filter 用 sjson 删字段,
        block 返回 typed *OpenAIFastBlockedError。
      - ingress 路径在 parseClientPayload 内调用,block 命中先 Write Realtime
        风格 error event 再返回 OpenAIWSClientCloseError(StatusPolicyViolation
        =1008),依赖底层 WebSocket Conn.Write 的同步 flush 保证 error 先于
        close。
      - passthrough 路径在 RunEntry 前对 firstClientMessage 应用策略,并通过
        openAIWSPolicyEnforcingFrameConn 包装 ReadFrame 对每个 client→upstream
        帧执行策略;后续帧无 model 字段时回退到 capturedSessionModel。
        filter 闭包内同时侦测 session.update / session.created 帧的 session.model
        字段刷新 capturedSessionModel,封堵"首帧 model=gpt-4o(pass)→
        session.update 改为 gpt-5.5 → 不带 model 的 response.create fallback
        到 gpt-4o"的 mid-session 绕过路径。
      - passthrough billing:requestServiceTier 在策略 filter 之后再从
        firstClientMessage 提取,filter 命中时 OpenAIForwardResult.ServiceTier
        上报 nil(default tier),与 HTTP 入口(reqBody 来自 post-filter map)
        / WS ingress(payload 来自 post-filter bytes)的语义一致。
      - 错误事件 schema:{event_id: "evt_<32hex>", type: "error",
        error: {type: "forbidden_error", code: "policy_violation", message}},
        与 OpenAI codex 客户端 error event 解析兼容。
      
      Admin / Frontend
      - dto.SystemSettings / UpdateSettingsRequest 新增
        openai_fast_policy_settings 字段(omitempty),bulk GET/PUT 接入。
      - Settings 页 Gateway 页签新增 Fast/Flex Policy 表单卡片:
        service_tier × action × scope × 模型白名单 × fallback action 全字段配置。
      - 前端守门:openaiFastPolicyLoaded 标志仅在 GET 真带回字段时才允许回写,
        避免 rollout/错误把默认规则覆盖成空;saveSettings 回写循环 skip 该字段,
        由专用刷新逻辑处理;仅 action=block 时发送 error_message,匹配后端
        omitempty 行为。
      
      测试
      - HTTP 路径:openai_fast_policy_test.go 覆盖默认配置(whitelist=[],所有
        模型 priority filter)/ block 自定义错误 / scope 区分 / filter 删字段 /
        block 不改 body / block 短路上游 / Anthropic BetaFastMode 触发 OpenAI
        fast policy 等场景。
      - WebSocket 路径:openai_fast_policy_ws_test.go 覆盖
          helper 单元(filter / fast→priority 归一化 / flex 透传 / block typed
          error / 无 service_tier 字节不变 / 非 response.create 帧不动 / 空 type
          帧不动 / event_id+code 字段断言 / 非字符串 service_tier 容错)+
          pass 路径 fast 别名归一化回归 +
          ingress 端到端(filter 后上游不含 service_tier / block 后客户端先收
          error event 再收 close 1008 且上游 0 写)+
          passthrough capturedSessionModel fallback 用例(whitelist 策略下首帧
          建立、缺 model 命中 fallback、缺少 fallback 时的 leak 文档化)+
          passthrough session.update / session.created 旋转 capturedSessionModel
          的 mid-session 绕过回归 +
          passthrough billing post-filter ServiceTier 与 idempotent filter 回归。
      Co-Authored-By: default avatarClaude Opus 4.7 (1M context) <noreply@anthropic.com>
      30f55a1f
  3. 27 Apr, 2026 4 commits
    • 陈曦's avatar
    • shaw's avatar
      feat(affiliate): 完善邀请返利系统 · 11c06803
      shaw authored and 陈曦's avatar 陈曦 committed
        - 修复返利不到账的根因:tryClaimAffiliateRebateAudit 中 PostgreSQL 参数类型推断冲突
        - 补全 OAuth 注册路径(LinuxDo/OIDC/WeChat/Pending Flow)的邀请码绑定
        - 前端 OAuth 注册页面传递 aff_code 参数
        - 新增返利冻结期机制:可配置冻结时间,到期后自动解冻(懒解冻)
        - 新增返利有效期:绑定后 N 天内有效,过期不再产生返利
        - 新增单人返利上限:超出上限部分精确截断
        - 增强返利流程 slog 结构化日志,便于排查问题
        - 已邀请用户列表增加返利明细列
      11c06803
    • shaw's avatar
      feat(affiliate): add feature toggle and per-user custom invite settings · ae317432
      shaw authored and 陈曦's avatar 陈曦 committed
      - 在系统设置「功能开关」中新增邀请返利总开关,默认关闭;
        关闭态:菜单隐藏、注册忽略 aff、新充值不返利,但已有 quota 仍可转余额
      - 支持管理员为指定用户设置专属邀请码(覆盖随机码,全局唯一)
      - 支持管理员为指定用户设置专属返利比例(覆盖全局比例,可单条/批量调整)
      - 在系统设置邀请返利卡片内嵌入专属用户管理表格(搜索/编辑/批量/删除),
        删除采用项目通用 ConfirmDialog,会同时清除专属比例并把邀请码重置为系统随机码
      - /affiliate 用户页新增「我的返利比例」卡片与动态使用说明,让用户直观看到
        分享后能拿到多少(同源 resolveRebateRatePercent 计算,与实际充值一致)
      - 新增数据库迁移 132 添加 aff_rebate_rate_percent 与 aff_code_custom 列
      - 新增 admin 路由组 /api/v1/admin/affiliates/users/* 共 5 个端点
      - AffiliateService 改为只依赖 *SettingService,去除冗余的 SettingRepository
      - 邀请码格式校验放宽到 [A-Z0-9_-]{4,32},兼容旧 12 位系统码与新自定义码
      - 补充单元测试与集成测试覆盖新方法、冲突路径与边界值
      ae317432
    • VpSanta33's avatar
      feat: add affiliate invite rebate flow and admin rebate-rate setting · 2b67e632
      VpSanta33 authored and 陈曦's avatar 陈曦 committed
      2b67e632
  4. 26 Apr, 2026 1 commit
    • shaw's avatar
      feat(affiliate): 完善邀请返利系统 · 9b6dcc57
      shaw authored
        - 修复返利不到账的根因:tryClaimAffiliateRebateAudit 中 PostgreSQL 参数类型推断冲突
        - 补全 OAuth 注册路径(LinuxDo/OIDC/WeChat/Pending Flow)的邀请码绑定
        - 前端 OAuth 注册页面传递 aff_code 参数
        - 新增返利冻结期机制:可配置冻结时间,到期后自动解冻(懒解冻)
        - 新增返利有效期:绑定后 N 天内有效,过期不再产生返利
        - 新增单人返利上限:超出上限部分精确截断
        - 增强返利流程 slog 结构化日志,便于排查问题
        - 已邀请用户列表增加返利明细列
      9b6dcc57
  5. 25 Apr, 2026 1 commit
    • shaw's avatar
      feat(affiliate): add feature toggle and per-user custom invite settings · 4e1bb2b4
      shaw authored
      - 在系统设置「功能开关」中新增邀请返利总开关,默认关闭;
        关闭态:菜单隐藏、注册忽略 aff、新充值不返利,但已有 quota 仍可转余额
      - 支持管理员为指定用户设置专属邀请码(覆盖随机码,全局唯一)
      - 支持管理员为指定用户设置专属返利比例(覆盖全局比例,可单条/批量调整)
      - 在系统设置邀请返利卡片内嵌入专属用户管理表格(搜索/编辑/批量/删除),
        删除采用项目通用 ConfirmDialog,会同时清除专属比例并把邀请码重置为系统随机码
      - /affiliate 用户页新增「我的返利比例」卡片与动态使用说明,让用户直观看到
        分享后能拿到多少(同源 resolveRebateRatePercent 计算,与实际充值一致)
      - 新增数据库迁移 132 添加 aff_rebate_rate_percent 与 aff_code_custom 列
      - 新增 admin 路由组 /api/v1/admin/affiliates/users/* 共 5 个端点
      - AffiliateService 改为只依赖 *SettingService,去除冗余的 SettingRepository
      - 邀请码格式校验放宽到 [A-Z0-9_-]{4,32},兼容旧 12 位系统码与新自定义码
      - 补充单元测试与集成测试覆盖新方法、冲突路径与边界值
      4e1bb2b4
  6. 24 Apr, 2026 1 commit
  7. 23 Apr, 2026 2 commits
    • erio's avatar
      sync: bring over remaining release/custom-0.1.115 changes · 748a84d8
      erio authored
      - Extract PublicSettingsInjectionPayload named struct with drift test
      - Add channel_monitor_default_interval_seconds to SSR injection
      - Add image_output_price to SupportedModelChip
      - Simplify AppSidebar buildSelfNavItems (admins see available channels)
      - Add gateway WARN logs for 503 no-available-accounts branches
      - Wire ChannelMonitorRunner into provideCleanup for graceful shutdown
      - Add migrations 130/131 (CC template userid fix + mimicry field cleanup)
      - Clean up fork-only features (sora, claude max simulation, client affinity)
      - Remove ~320 obsolete i18n keys
      - Add codexUsage utility, WechatServiceButton, BulkEditAccountModal
      - Tidy go.sum
      748a84d8
    • james-6-23's avatar
      feat(rpm): RPM 限流模块优化 · dc5d42ad
      james-6-23 authored
      P0:
      - rpm_override 嵌入 Auth Cache Snapshot,消除每请求 DB 查询 (snapshot v6→v7)
      - 429 RPM 响应返回 Retry-After 头(当前分钟剩余秒数)
      
      P1:
      - ClearAll 按钮直连 DELETE API,带 loading 防重复
      - 新增 GET /admin/users/:id/rpm-status 管理员 RPM 用量查询端点
      
      优化:
      - checkRPM 从级联互斥改为并行取最严,user.rpm_limit 作为全局硬上限始终生效
      - Override/Group 变更后自动失效 auth cache
      - fail-open 语义不变,Redis 故障不阻塞业务
      dc5d42ad
  8. 21 Apr, 2026 4 commits
  9. 20 Apr, 2026 5 commits
    • IanShaw027's avatar
      067eb23d
    • erio's avatar
      feat(channel-monitor): add feature switch settings + fix extra_models save · 7da51240
      erio authored
      Settings:
      - New "功能开关" tab between 通用设置 and 安全与认证
      - ChannelMonitorEnabled toggle: runner skips scheduling when false,
        user-facing list returns empty
      - ChannelMonitorDefaultIntervalSeconds (15-3600): pre-fills interval
        when creating a new monitor; each monitor can still override
      
      Bug fix:
      - ModelTagInput now commits pending input on blur, not just Enter/Tab.
        Previously clicking "save" with an un-Enter'd extra model would drop
        the value (DB stored extra_models=[] even when user typed entries).
      
      Backend:
      - domain_constants: SettingKeyChannelMonitor{Enabled,DefaultIntervalSeconds}
      - SettingService.GetChannelMonitorRuntime: lightweight getter used by
        runner tick + user handler per-request (fail-open on DB error)
      - Runner tickDueChecks: bails early when feature disabled
      - ChannelMonitorUserHandler: checks feature flag before serving
      - Comment on runner doc: scheduler state is implicit (every tick re-reads
        ListEnabled from DB), so CRUD ops on monitors self-maintain the schedule
      
      Bump VERSION to 0.1.114.25
      7da51240
    • IanShaw027's avatar
    • IanShaw027's avatar
      feat: add pending oauth email onboarding flow · 6a75bd77
      IanShaw027 authored
      6a75bd77
    • IanShaw027's avatar
      feat: rebuild auth identity foundation flow · e9de839d
      IanShaw027 authored
      e9de839d
  10. 14 Apr, 2026 10 commits
    • erio's avatar
      fix: resolve cherry-pick conflicts and restore compilation · d6965b06
      erio authored
      - Restore gateway_cache.go to upstream (no lua embeds)
      - Restore payment_order.go to upstream (use out_trade_no lookup)
      - Restore payment_fulfillment.go to upstream (same reason)
      - Add FeaturesConfig field and IsWebSearchEmulationEnabled to Channel
      - Add applyAccountStatsCost wrapper function
      - Add SettingKeyWebSearchEmulationConfig constant
      - Add WebSearchEmulationEnabled to SystemSettings
      - Add notify code rate limiting methods to EmailCache interface
      - Remove AllowUserRefund references (ent schema not present)
      - Fix duplicate import in payment_handler.go
      - Fix wire_gen.go argument mismatches
      d6965b06
    • erio's avatar
      fix: gofmt formatting across all Go source files · 1e6912ea
      erio authored
      1e6912ea
    • erio's avatar
      feat(notify): add platform/ID to quota alert email, add recharge URL to balance alert · c1eb79e4
      erio authored
      - Quota alert email now shows account ID and platform
      - Balance low email includes a "Top Up Now" button when recharge URL is configured
      - New setting: balance_low_notify_recharge_url in admin settings
      c1eb79e4
    • erio's avatar
      feat(notify): convert email lists to NotifyEmailEntry struct with toggle support · 915b7a4a
      erio authored
      - Change balance_notify_extra_emails and account_quota_notify_emails
        from []string to []NotifyEmailEntry{email, disabled, verified}
      - Add per-email enable/disable toggle for both user and admin notifications
      - Add PUT /user/notify-email/toggle API endpoint
      - Fix critical bug: API key auth cache snapshot missing balance notify
        fields (Email, Username, BalanceNotifyEnabled, etc.), causing
        notifications to never fire on cached request paths
      - Bump cache snapshot version 3→4 to invalidate stale entries
      - Add SQL migration 104 to convert old format data
      - Backward compatible: parseNotifyEmails auto-detects old/new format
      - User balance notify: max 3 emails (primary + 2 extra)
      - Admin quota notify: unlimited emails, each with toggle
      915b7a4a
    • erio's avatar
      feat(notify): improve balance notify card UX · 81287e96
      erio authored
      - Show system default threshold as placeholder in custom threshold input
      - Display user's primary email with "Primary" badge
      - Support adding multiple pending emails before verification
      - Each pending email has independent send/verify/resend flow
      - Expose balance_low_notify_threshold in PublicSettings API
      - Clean up timers on unmount to prevent leaks
      81287e96
    • erio's avatar
      feat(notify): add global toggles, percentage threshold, and visibility control · eba289a7
      erio authored
      - Add global toggle for account quota notification in admin settings
      - Add percentage-based threshold type for per-account quota alerts
      - Hide balance notify card on user profile when global toggle is off
      - Expose balance_low_notify_enabled and account_quota_notify_enabled in PublicSettings
      - Add threshold type (fixed/percentage) to QuotaNotifyToggle with $ / % switcher
      eba289a7
    • erio's avatar
      fix(notify): remove percentage threshold from balance notification · cef22c70
      erio authored
      Balance low notification only supports fixed USD amount threshold.
      Percentage threshold is a quota concept, not applicable to balance.
      Reverted threshold_type from admin settings, user profile, and all
      backend/frontend layers. DB fields (balance_notify_threshold_type,
      total_recharged) retained for potential future quota use.
      cef22c70
    • erio's avatar
      feat(notify): add percentage threshold type for balance low notification · f694afbb
      erio authored
      - Add threshold_type field (fixed/percentage) to system and user settings
      - Add total_recharged field to users table, auto-incremented on balance credit
      - Percentage mode: effective threshold = total_recharged × percentage / 100
      - User-level threshold_type inherits from system default when not set
      - Update admin settings UI with radio selector (fixed amount / percentage)
      - Migration: 102_add_balance_notify_threshold_type.sql
      f694afbb
    • erio's avatar
      feat(notify): add balance low & account quota notification system · b32d1a2c
      erio authored
      - User balance low notification: email alert when balance drops below
        configurable threshold (user email + verified extra emails)
      - Account quota notification: broadcast email to admin-configured
        recipients when daily/weekly/total quota usage exceeds alert threshold
      - Admin settings: global enable/disable, default threshold, quota
        notification email list (Email Settings tab)
      - User profile: enable/disable, custom threshold, add/remove extra
        notification emails with verification code flow
      - Account quota: per-dimension alert toggle and threshold in quota
        control card
      - Trigger logic: first-crossing only (old >= threshold && new < threshold
        for balance; old < threshold && new >= threshold for quota), naturally
        prevents duplicate notifications without Redis dedup
      b32d1a2c
    • erio's avatar
      feat(gateway): add web search emulation for Anthropic API Key accounts · 1b53ffca
      erio authored
      Inject web search capability for Claude Console (API Key) accounts that
      don't natively support Anthropic's web_search tool. When a pure
      web_search request is detected, the gateway calls Brave Search or Tavily
      API directly and constructs an Anthropic-protocol-compliant SSE/JSON
      response without forwarding to upstream.
      
      Backend:
      - New `pkg/websearch/` SDK: Brave and Tavily provider implementations
        with io.LimitReader, proxy support, and Redis-based quota tracking
        (Lua atomic INCR + TTL, DECR rollback on failure)
      - Global config via `settings.web_search_emulation_config` (JSON) with
        in-process cache + singleflight, input validation, API key merge on
        save, and sanitized API responses
      - Channel-level toggle via `channels.features_config` JSONB column
        (DB migration 101)
      - Account-level toggle via `accounts.extra.web_search_emulation`
      - Request interception in `Forward()` with SSE streaming response
        construction using json.Marshal (no manual string concatenation)
      - Manager hot-reload: `RebuildWebSearchManager()` called on config save
        and startup via `SetWebSearchRedisClient()`
      - 70 unit tests covering providers, manager, config validation,
        sanitization, tool detection, query extraction, and response building
      
      Frontend:
      - Settings → Gateway tab: Web Search Emulation config card with global
        toggle, provider list (add/remove, API key, priority, quota, proxy)
      - Channels → Anthropic tab: web search emulation toggle with global
        state linkage (disabled when global off)
      - Account Create/Edit modals: web search emulation toggle for API Key
        type with Toggle component
      - Full i18n coverage (zh + en)
      1b53ffca
  11. 11 Apr, 2026 1 commit
  12. 09 Apr, 2026 2 commits
  13. 08 Apr, 2026 3 commits
  14. 07 Apr, 2026 1 commit
  15. 05 Apr, 2026 1 commit
  16. 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