Skip to content

v1.0.4-preview.4

Choose a tag to compare

@CSCITech CSCITech released this 13 Jul 02:35
ec8d02a

[!WARNING] 发布阻断:Claude/Anthropic 流式输出 token 计费回归。 截至 2026-07-16,v1.0.4-preview.4 当前代码在 Claude/Anthropic 流结束时会正确解析顶层 CompletionTokens,但生成最终 BillingUsage 快照时遗漏 OutputTokens,导致用量日志中的 completion_tokens 可能为 0,输出 token 也可能未进入实际结算。

该问题按响应处理器而不是模型名称划分:Anthropic 原生、AWS Bedrock Claude、Vertex Claude 模式、Advanced Custom Anthropic Messages,以及通过 /v1/messages 复用 Claude 流式处理器的兼容渠道都可能受影响。Claude 非流式请求以及原生 OpenAI Chat、OpenAI Responses、Gemini 路径未发现同类问题。

在修复和完整回归通过前,不应将当前 v1.0.4-preview.4 用于需要准确计费的 Claude/Anthropic 流式生产请求;临时可强制 stream: false,历史受影响请求应结合上游 usage 记录进行对账。

重要升级说明

v1.0.4-preview.4 覆盖计费结算、GPT-5.6 cache_write_tokens 缓存写入计费、Responses/Chat 跨协议转换、异步任务计费、渠道请求改写、日志审计、access token 生成与二次验证、前端富文本渲染、登录注册合规和多数据库兼容等关键路径。升级前建议先在测试环境验证主要模型调用、缓存创建价格、分阶段计费表达式、任务类渠道、用户额度变更、用量日志筛选、Playground、OAuth/注册登录、access token 重新生成、订阅重置和管理端渠道配置。

如果部署使用 GPT-5.6、Responses API、缓存创建倍率或自定义计费表达式,请重点检查 cache_write_tokens 是否按预期进入缓存创建费用;同时复核 Param Override、自动分组/自动路由、Redis 配额缓存、旧 MySQL/PostgreSQL 数据库和反向代理真实 IP 配置。

Note

v1.0.4-preview.4 是预览版草稿,整理自当前分支中已合入的 v1.0.4 系列变更,并补充最近确认的 GPT-5.6 缓存写入计费、分阶段计费、日志审计、额度安全、密码重置和 access token 安全验证更新。发布前请以最终 tag、上游官方价格和实际验证结果为准。

Release Notes

GitHub 地址

https://github.com/MAX-API-Next/MAX-API/releases/tag/v1.0.4-preview.4

Highlights

  • 补强 OpenAI Responses 与 Chat Completions 的双向兼容转换,覆盖普通响应、流式事件、工具调用、reasoning 文本、usage 聚合和跨协议 billing usage 恢复。
  • 完善 OpenAI / Claude / Gemini 语义化 BillingUsage,结算时优先使用原始协议 usage,并保留 cache、cache write、image、audio、reasoning 等细分 token。
  • 补齐 GPT-5.6 Responses usage 中 input_tokens_details.cache_write_tokens 的计费链路,非流式、流式、compact 和 Responses/Chat 转换均会保留缓存写入 token,不再在跨协议后退化为普通输入 token 或被遗漏。
  • cache_write_tokens 会归一为缓存创建 token:ratio 模式使用 CacheCreationRatiotiered_expr 模式进入 cc 变量,并从基础输入 token 中扣除后单独计价,避免漏计或重复计费。
  • 引入统一 quota 饱和转换策略,避免超大计费结果发生 int32 wraparound;严格预扣费路径只拒绝真正越界值,允许精确 MaxInt32 / MinInt32 边界。
  • 异步任务渠道新增更通用的 rate-card / generic billing 框架,支持按输入、输出、图片数量、时长、任务结果和渠道元数据计算费用。
  • 任务类渠道 Param Override 在计费前生效,header override 会在 adaptor 默认值之后写入上游请求,局部配置错误保持本地失败而不触发无意义重试。
  • Doubao、Ali/Kling/Wan、Gemini、Vidu、Vertex、Hailuo、Jimeng、Sora 等任务渠道补齐请求体构造、参数透传、计费和回调结果处理细节。
  • 管理端渠道抽屉、模型/分组倍率编辑器、自动路由展示、OAuth 回调提示、订阅重置和用量日志筛选得到集中优化。
  • Playground 增强选项持久化、清理历史、长输入和选区处理,减少常见交互中的状态丢失与布局问题。
  • 富文本与 HTML 渲染路径继续收紧安全边界,统一用户可见内容展示并降低异常 Markdown/HTML 输入导致的前端崩溃风险。
  • 日志审计字段写入更稳健,quota saturation 和 billing path 只在有效 admin_info 容器中追加,不再覆盖异常字段或在 nil 目标上记录误导性 warning。
  • 用户额度管理和密码重置流程补强安全边界:管理端额度保持在 JavaScript 可精确表示的整数范围内,密码写入失败时重置令牌仍可重试。
  • access token 生成改为 POST 敏感操作并强制执行二次验证、禁缓存和关键操作限流;验证状态绑定当前用户,避免同一浏览器切换账号后继承旧验证结果。
  • 无 2FA 或 Passkey 的普通用户可在 access_token 专用作用域内使用账户密码完成重验证,同时继续优先使用已启用的 Passkey 或 2FA。

New Features

  • 新增 service/openaicompat 兼容层,用于 Responses request/response 与 Chat Completions request/response 互转。
  • 新增 Gemini Responses adaptor,支持 Gemini 通道参与 Responses API 兼容路径。
  • 新增 dto.BillingUsage 协议快照结构,支持 OpenAI、Claude、Gemini usage 在跨协议转换后仍按原始语义结算。
  • InputTokenDetails 新增 cache_write_tokens 字段和共享复制逻辑,支持在 input_tokens_detailsprompt_tokens_detailsBillingUsage 之间完整传递 GPT-5.6 缓存写入用量。
  • 新增 tiered_expr 分阶段计费模式,单条表达式即可描述模型的基础价格、长上下文阶梯、缓存价格、媒体 token 价格和请求条件倍率。
  • 新增分阶段计费可视化编辑器与表达式编辑器,支持价格档位、兜底档位、请求体/header/时间规则、实时费用预估、命中档位展示和 JSON 批量配置。
  • 新增 GPT-5.4 Priority/Flex、Claude 长上下文与 Fast Mode、多模态和时段折扣等模板,管理员也可按实际上游价格创建其他模型表达式。
  • 计费表达式支持 pclencrcccc1himgimg_oaiao 等变量,以及 param()header() 和时间函数,可覆盖文本、缓存、多模态和请求级价格规则。
  • 新增 quota math helper 和测试,统一 float、decimal、rounding 到 quota 的饱和处理。
  • 新增 protected fetch client 与管理端模型拉取防护测试,用于统一 SSRF 边界和响应体关闭行为。
  • 新增任务通用请求体构造、路径配置和协议配置工具,减少各任务 adaptor 重复实现。
  • 新增任务通用计费模块和覆盖测试,用于图像、视频、音频等异步任务统一结算。
  • 新增订阅重置入口和管理端对话框,便于管理员批量处理用户订阅状态。
  • 新增用量日志 quota 区间筛选控件,普通日志和任务日志筛选栏都可按额度状态过滤。
  • 新增自动路由/自动分组前端展示工具,模型价格页可解释自动链路的实际分组来源。
  • 新增 OAuth 回调地址提示组件,帮助管理员检查第三方登录回调配置。
  • 新增安全验证方式发现接口和作用域化密码重验证,前端可根据当前账户实际可用的 Passkey、2FA 或密码方式打开对应验证界面。
  • 新增多语言文案,覆盖新增设置项、日志筛选、订阅操作、渠道表单和计费说明。

Improvements

  • Responses 转 Chat 后会把 input_tokens_details 映射回 prompt_tokens_details,并在 BillingUsage 恢复时保留细分 input token,避免 cache write、cached、image、audio input 在结算中丢失;六类 input token 字段改由 DTO 共享映射统一维护,降低后续新增字段时跨路径漏同步的风险。
  • Chat 转 Responses 会保留 usage 细节和 billing usage 快照,跨协议返回后仍能走统一计费入口。
  • Claude / Gemini usage 恢复逻辑补齐 cache creation、cache read、thoughts/reasoning 和 modality token 映射。
  • OpenAI BillingUsage 恢复会从 input_tokens_details 补齐 prompt_tokens_details.cache_write_tokens,保证 GPT-5.6 Responses 转 Chat 后仍使用原始缓存写入数据结算。
  • cached_creation_tokenscache_write_tokens 作为同类缓存创建统计进行兼容归一化;两者同时存在时取较大值,不直接相加,避免同一批缓存写入被重复收费。
  • 分阶段计费使用 len 判断上下文档位;len 始终表示包含缓存 token 在内的完整输入长度,避免大量缓存命中后误进入较低的长上下文价格档位。
  • 表达式会根据实际引用的变量自动从 p / c 中排除已单独计价的缓存、图片和音频 token,减少基础 token 与细分类 token 重复计费。
  • 预扣费会冻结模型名、表达式、请求条件、分组倍率和预计命中档位;结算时使用同一快照与实际 usage 重新计算,避免请求处理中途修改配置导致前后价格不一致。
  • 用量日志会写入归一化后的 cache_write_tokens,分阶段计费结果还会记录 billing mode、表达式和命中档位,便于管理员核对缓存创建费用。
  • 计费表达式 rounding 增加 quota 专用转换,降低浮点乘法和极端金额输入带来的边界风险。
  • quota saturation 会写入日志 admin_info.quota_saturation,便于管理员追踪被截断的原始值和 clamp 类型。
  • 预扣费和结算路径统一使用 quota helper,超大价格、倍率或 token 数不会因为整数溢出变成反向扣费。
  • BillingSession 预扣费和 legacy 预扣费入口共用同一套 QuotaClamp / 负数 quota 校验,保持模型价格错误的状态码、错误码和 skip-retry 语义一致。
  • 上游错误处理限制本地日志体积,保留排障信息同时减少异常响应占用内存。
  • 流式扫描器和 ping 处理逻辑得到重构,减少空 chunk、ping frame 和异常 EOF 对流式 relay 的影响。
  • API request 构造逻辑补充上下文、参数和 header 合并测试,降低高级自定义渠道回归风险。
  • 渠道表单抽屉拆分更多字段状态和转换逻辑,复杂通道配置更容易维护。
  • 分组倍率和模型倍率编辑器优化输入、验证和视觉反馈,减少配置错误。
  • 模型价格可视化编辑器的空状态文案改为显式条件计算,搜索、未设置价格和默认空列表状态更容易维护。
  • 自动路由显示会过滤不可见分组和重复分组,并保留旧配置 fallback。
  • 用量日志 retry / empty-retry / quota 筛选逻辑更清晰,前端过滤和后端聚合语义保持一致。
  • 用户、token、订阅和兑换码相关模型更新路径增加零值安全处理,避免局部更新意外覆盖会计字段。
  • 管理端用户额度对话框增加安全整数校验、行内错误提示和多语言文案,增加、扣减或覆盖操作在提交前会检查输入值与计算结果。
  • 密码重置验证码增加并发占用和提交语义:密码更新成功后才消费验证码,数据库写入失败或异常退出时释放占用并允许在有效期内重试。
  • access token 对话框接入统一安全验证流程,并按实际可用性选择默认方式;仅启用 2FA 的用户不会再进入不可用的 Passkey 状态。
  • /api/verify 同时按客户端 IP 和已认证用户 ID 限制关键验证请求,降低通过代理轮换扩大密码或验证码尝试次数的风险。
  • OpenAPI 补齐 POST /api/user/tokenPOST /api/verify 请求体以及 GET /api/verify/methods?scope=access_token 的参数与验证方式枚举。
  • 订阅、任务和日志模型增加 CAS / row-lock / 异步落库测试,降低并发状态回退风险。
  • README 和多语言 README 调整为新的产品定位和能力描述,保持各语言文档同步。

Bug Fixes

  • 修复 GPT-5.6 Responses 返回 cache_write_tokens 时,部分非流式、流式、compact 或 Responses → Chat 路径没有把该字段带入最终 PromptTokensDetails,导致缓存写入 token 可能按普通输入价格结算或未按缓存创建倍率计费的问题。
  • 修复跨协议 BillingUsage 恢复只保留 input token 总数和部分明细、遗漏 cache_write_tokens,导致转换后的实际结算与上游原始 usage 不一致的问题。
  • 修复 Responses 转 Chat / 跨协议后 BillingUsage 恢复只保留 token 总数,导致 input token 细分项从结算视角消失的问题。
  • 修复 strict quota 把精确 2147483647-2147483648 误判为 clamp 错误的问题。
  • 修复 attachQuotaSaturationToOtheradmin_info 已存在但不是 map 时覆盖原值的问题。
  • 修复 attachQuotaSaturationother == nil 时仍输出“已写入审计信息”语义 warning 的问题。
  • 修复部分 OpenAI Responses / Chat 转换路径中 tool call id、reasoning、finish reason、usage 聚合和流式 done event 不一致的问题。
  • 修复 Gemini 非 function tool、Responses relay 和 usage metadata 在跨协议路径中的兼容问题。
  • 修复 Doubao 任务可选标量字段使用非指针类型时,显式 0 / false 可能在转发时被 omitempty 丢弃的问题。
  • 修复任务 Param Override 在计费后才生效,导致实际上游请求与本地计费参数可能不一致的问题。
  • 修复 task header override 不能稳定覆盖 adaptor 默认 header 的问题。
  • 修复本地 Param Override 配置错误被当作可重试上游错误的问题。
  • 修复异步任务回调和轮询结算中部分任务状态、费用、结果字段缺失或类型不一致的问题。
  • 修复用量日志 retry 筛选、任务日志 quota 筛选和聚合读路径中的类型/边界问题。
  • 修复富文本 HTML 渲染和 sanitizer 在部分异常输入下的展示或安全边界问题。
  • 修复 Playground 清空历史、长文本输入、选项恢复和请求参数同步中的前端状态问题。
  • 修复管理端用户设置、用户资料、余额调整和 token 更新中零值字段无法正确保存或可能被误覆盖的问题。
  • 修复管理员可把用户额度设置到 int64 上限,导致超过 Number.MAX_SAFE_INTEGER 后前端展示和回传值发生精度丢失的问题。
  • 修复密码重置先销毁验证码再更新密码,导致密码哈希或数据库写入失败后重置链接提前失效的问题。
  • 修复 access token 通过 GET 生成且缺少禁缓存与二次验证,可能被缓存、预取或误重放的问题。
  • 修复安全验证 session 只记录时间戳,账号 A 验证后在同一浏览器会话登录账号 B 时,账号 B 可能继承验证状态的问题。
  • 修复未启用 2FA 或 Passkey 的普通用户无法生成 access token,以及仅启用 2FA 时前端仍默认选择 Passkey 的问题。
  • 修复 /api/verify 仅按 IP 限流,攻击者可通过切换代理地址扩大同一账户验证尝试次数的问题。
  • 修复管理用户接口收到非正用户 ID 时可能形成空条件查询并错误命中首条用户记录的问题。
  • 修复订阅重置、订阅弹窗和订阅 delta 返回值在管理端交互中的状态同步问题。
  • 修复模型列表、分组显示和自动链路价格页在自动分组配置缺失或别名分组存在时的展示问题。
  • 修复部分数据库迁移、命名锁、quota bigint 和老库兼容路径在 MySQL/PostgreSQL/SQLite 上的差异问题。
  • 修复日志审计写入在异常 admin_info 结构下可能丢失已有审计元数据的问题。
  • 修复 jsonwrapcheck allowlist 与当前代码不一致,减少业务代码直接调用标准 JSON marshal/unmarshal 的回归空间。

Compatibility Notes

  • 任务类渠道如果依赖 Param Override,请注意本版本会在计费前应用最终请求参数;升级后计费结果会更贴近实际发送给上游的 payload。
  • header override 现在会在 adaptor 默认 header 后生效;如果旧配置依赖默认值覆盖自定义值,需要重新检查渠道配置。
  • 本地 Param Override 配置错误不再进入重试链路;这类错误应作为配置问题修正,而不是依赖自动重试。
  • Responses API 兼容路径会尽量保留原始协议 usage;如果外部系统读取 usage 字段,请同时关注 prompt_tokens_detailsinput_tokens_detailsbilling_usage
  • GPT-5.6 上游可能在 input_tokens_details.cache_write_tokens 返回缓存写入量;该值会按缓存创建 token 处理。ratio 模式需要正确配置 CacheCreationRatio,表达式模式应使用 cc 为缓存写入单独定价。
  • 如果上游同时返回 cached_creation_tokenscache_write_tokens,系统会取两者中的较大值作为归一化缓存创建总量,不会相加;外部账单对账工具应采用相同口径。
  • 计费表达式中的系数是每 100 万 token 的实际美元价格,不再隐含旧倍率表的 /2、completion multiplier 或其他换算;从 ratio 模式迁移时不能直接复制旧倍率数值。
  • 未显式把模型切换为 tiered_expr 时,现有模型继续使用 ModelRatio / ModelPrice 计费;启用后该模型的预扣费与实际结算以表达式和请求条件为准。
  • GPT/OpenAI usage 的 prompt_tokens 通常包含缓存和媒体 token;表达式只有在引用 crimgai 等变量时才会自动拆分对应 token。长上下文条件应使用 len,不要使用拆分后的 p
  • strict quota 只拒绝超出 int32 可表示范围的值;精确边界值不再记录 saturation 或返回错误。
  • 管理端用户额度调整接口只接受不超过 9007199254740991 的正整数变更量,加减结果必须保持在 JavaScript 安全整数区间,覆盖值必须位于 0..9007199254740991。历史超范围额度可通过覆盖操作恢复到安全范围,依赖更大 int64 额度的外部管理脚本需要同步调整。
  • 预扣费入口遇到 quota clamp 或负数预扣费时仍返回 model_price_error、HTTP 400 和 skip-retry;本次只是统一校验来源,不改变外部错误契约。
  • quota saturation 审计只会写入 map 形态的 admin_info;如果调用方传入了异常类型,已有值会被保留但不会追加 saturation 详情。
  • 异步任务通用计费会让部分历史上未精确计费的任务按 rate-card 细则结算;建议先在测试环境核对常用任务模型的价格配置。
  • 自动路由展示更贴近实际配置,但只展示当前可见分组;隐藏分组不会被前端强行暴露。
  • 用量日志筛选项更细,旧的 retry 过滤理解应区分普通 retry 与 empty retry 等子类型。
  • access token 生成接口已从 GET /api/user/token 改为 POST /api/user/token;依赖旧接口的脚本、SDK 或自动化客户端必须同步调整请求方法,旧 GET 路由不再可用。
  • 密码重验证仅作为 access_token 作用域的回退方案,并且只在账户没有启用 2FA 和 Passkey 时提供;密码验证结果不能用于其他敏感操作。
  • PasswordLoginEnabled=false 只禁止新的密码登录,不会使已登录账户现有的密码凭证失效;符合回退条件的用户仍可用当前密码完成 access token 重验证。
  • 多数据库迁移继续要求 SQLite、MySQL 和 PostgreSQL 同时兼容;升级前建议备份数据库,并在老库上先跑启动迁移验证。

Verification

发布前建议按最终 tag 和发布分支重新执行并更新结果:

  • go test ./common ./service ./service/openaicompat -count=1
  • go test ./dto ./service ./service/openaicompat ./relay/channel/openai -run "Test(CopyInputTokenDetails|CalculateTextQuotaSummaryPreservesResponsesInputDetailsThroughBillingUsage|CacheWriteTokensTotal|ResponsesResponseToChatCompletionsResponse)" -count=1
  • go test ./pkg/billingexpr -run "Test(Len|Cache|ComputeTieredQuota|RunExpr)" -count=1
  • go test ./relay/helper -run "Test(ModelPriceHelperTiered|ResolveIncomingBillingExprRequestInput)" -count=1
  • go test ./service -run "Test(TryTieredSettle|BuildTieredTokenParams)" -count=1
  • go test ./... -count=1
  • go test ./common ./controller ./model -count=1
  • go test ./relay/helper -count=1
  • go test ./service -run TestAttachQuotaSaturation -count=1
  • go test ./service -run TestPreConsumeValidationSharedByBillingAndQuota -count=1
  • go test ./common -run TestQuotaFromFloatStrictAcceptsExactInt32Boundaries -count=1
  • go test ./service -run TestCalculateTextQuotaSummaryPreservesResponsesInputDetailsThroughBillingUsage -count=1
  • go test ./controller ./model ./middleware ./relay/helper
  • go test ./controller ./middleware ./router -count=1
  • go test ./router -run 'Test(UniversalVerifyRateLimitFollowsUserAcrossIPs|SecureVerificationOpenAPIIncludesScopeAndRequestBody)' -count=1
  • go test ./router -run TestUniversalVerifyRateLimitFollowsUserAcrossIPs -count=3
  • go test ./relay/channel/openai ./relay/channel/gemini ./relay/channel/claude ./relay/channel/advancedcustom
  • go test ./relay/channel/task/taskcommon ./relay/channel/task/doubao ./relay/channel/task/ali
  • go run ./tools/jsonwrapcheck
  • cd web/default && bun run typecheck
  • cd web/default && bun test src/features/users/lib/quota-safety.test.ts
  • cd web/default && bun test tests/secure-verification-method-selection.test.ts
  • cd web/default && bun run i18n:sync
  • cd web/default && bun test
  • git diff --check -- service/billing.go service/pre_consume_quota.go web/default/src/features/system-settings/models/model-ratio-visual-editor.tsx
  • git diff --check

Full Changelog: v1.0.3...v1.0.4