mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-09 08:06:27 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4105c1ece6 | ||
|
|
4d59687cbc | ||
|
|
8621e24e7c |
@@ -173,22 +173,19 @@ impl AccountQuotaForecast {
|
||||
};
|
||||
self.low_sample = sample.sampled_percent < LOW_SAMPLE_PERCENT
|
||||
|| (method == QuotaForecastMethod::Incremental && sample.block_count < 2);
|
||||
// 漏记和个别缺失只影响精度,仍按已记录数值估算,不按请求数补齐未知消耗。
|
||||
// 预测是近似展示值;不复用为账单金额,也不把月折算当成自然月或额外余额。
|
||||
let capacity_factor = 100.0 / sample.sampled_percent;
|
||||
let factor = capacity_factor * self.target_seconds as f64 / seconds as f64;
|
||||
let tokens = Some(usage.tokens).filter(|tokens| *tokens > 0 && !self.incomplete_tokens);
|
||||
let tokens = Some(usage.tokens).filter(|tokens| *tokens > 0);
|
||||
self.estimated_tokens = tokens.and_then(|value| estimate_tokens(value, factor));
|
||||
self.estimated_usd = usd
|
||||
.filter(|_| !self.incomplete_cost)
|
||||
.and_then(|value| estimate(value, factor));
|
||||
self.estimated_usd = usd.and_then(|value| estimate(value, factor));
|
||||
let remaining_factor = (100.0 - percent) / sample.sampled_percent;
|
||||
self.remaining_tokens = tokens.and_then(|value| estimate_tokens(value, remaining_factor));
|
||||
self.remaining_usd = usd
|
||||
.filter(|_| !self.incomplete_cost)
|
||||
.and_then(|value| estimate(value, remaining_factor));
|
||||
self.remaining_usd = usd.and_then(|value| estimate(value, remaining_factor));
|
||||
self.unavailable_reason = if self.estimated_tokens.is_none() && self.estimated_usd.is_none()
|
||||
{
|
||||
Some("本周期缺少可用的 Token 或完整费用记录,暂时无法预测额度。")
|
||||
Some("本周期暂无可用于估算的 Token 或费用数据,请积累用量后重试。")
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
@@ -246,14 +246,15 @@ fn incremental_sample_supports_mid_cycle_accounts_and_remaining_uses_current_per
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_tokens_suppress_token_estimates_without_discarding_complete_costs() {
|
||||
fn missing_tokens_keep_estimates_from_recorded_usage() {
|
||||
let source = quota(vec![window("week", 7)]);
|
||||
let mut sample = samples(&source).remove(0);
|
||||
sample.usage.missing_token_count = 1;
|
||||
let [week, _] = account_quota_forecasts(&source, now() - Duration::days(60), now(), &[sample]);
|
||||
assert!(week.incomplete_tokens);
|
||||
assert_eq!(week.estimated_tokens, None);
|
||||
assert_eq!(week.remaining_tokens, None);
|
||||
assert!(week.unavailable_reason.is_none());
|
||||
assert_eq!(week.estimated_tokens, Some(5_000));
|
||||
assert_eq!(week.remaining_tokens, Some(4_000));
|
||||
assert_eq!(week.estimated_usd, Some(10.0));
|
||||
assert_eq!(week.source.unwrap().tokens, Some(1_000));
|
||||
}
|
||||
@@ -269,7 +270,7 @@ fn discontinuous_samples_never_fall_back_to_cumulative_predictions() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_or_unknown_costs_suppress_only_money_estimates() {
|
||||
fn partial_costs_keep_estimates_from_known_amounts() {
|
||||
for coverage in [
|
||||
CostCoverage {
|
||||
calculated_count: 9,
|
||||
@@ -281,19 +282,77 @@ fn partial_or_unknown_costs_suppress_only_money_estimates() {
|
||||
unavailable_count: 1,
|
||||
..Default::default()
|
||||
},
|
||||
CostCoverage::default(),
|
||||
] {
|
||||
let mut sample = window("week", 7);
|
||||
sample.local_usage.as_mut().unwrap().cost_coverage = coverage;
|
||||
let [week, _] = forecast("a(vec![sample]));
|
||||
assert!(week.incomplete_cost);
|
||||
assert!(week.unavailable_reason.is_none());
|
||||
assert!(week.estimated_usd.is_none());
|
||||
assert!(week.remaining_usd.is_none());
|
||||
assert_eq!(week.estimated_usd, Some(10.0));
|
||||
assert_eq!(week.remaining_usd, Some(8.0));
|
||||
assert_eq!(week.estimated_tokens, Some(5_000));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_tokens_and_costs_do_not_block_recorded_capacity_or_remaining_estimates() {
|
||||
let source = quota(vec![window("week", 7)]);
|
||||
let mut sample = samples(&source).remove(0);
|
||||
// 完整请求之外混有缺少计量的成功请求,不把已有用量和费用一并作废。
|
||||
sample.usage.request_count += 2;
|
||||
sample.usage.missing_token_count = 2;
|
||||
sample.usage.unavailable_cost_count = 2;
|
||||
sample.usage.excluded_request_count = 1;
|
||||
sample.pending_request_count = 1;
|
||||
let [week, month] =
|
||||
account_quota_forecasts(&source, now() - Duration::days(60), now(), &[sample]);
|
||||
assert!(week.incomplete_tokens);
|
||||
assert!(week.incomplete_cost);
|
||||
assert!(week.unavailable_reason.is_none());
|
||||
assert_eq!(week.estimated_tokens, Some(5_000));
|
||||
assert_eq!(week.estimated_usd, Some(10.0));
|
||||
assert_eq!(week.remaining_tokens, Some(4_000));
|
||||
assert_eq!(week.remaining_usd, Some(8.0));
|
||||
assert_eq!(month.estimated_tokens, Some(21_429));
|
||||
assert_eq!(month.remaining_tokens, week.remaining_tokens);
|
||||
assert_eq!(month.remaining_usd, week.remaining_usd);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn entirely_unknown_costs_leave_only_money_estimates_unavailable() {
|
||||
let mut sample = window("week", 7);
|
||||
let usage = sample.local_usage.as_mut().unwrap();
|
||||
usage.cost_coverage = CostCoverage {
|
||||
unavailable_count: usage.request_count,
|
||||
..Default::default()
|
||||
};
|
||||
usage.costs.clear();
|
||||
let [week, _] = forecast("a(vec![sample]));
|
||||
assert!(week.incomplete_cost);
|
||||
assert!(week.unavailable_reason.is_none());
|
||||
assert_eq!(week.estimated_tokens, Some(5_000));
|
||||
assert_eq!(week.estimated_usd, None);
|
||||
assert_eq!(week.remaining_usd, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn entirely_unknown_tokens_and_costs_do_not_invent_zero_estimates() {
|
||||
let source = quota(vec![window("week", 7)]);
|
||||
let mut sample = samples(&source).remove(0);
|
||||
sample.usage = QuotaForecastUsage {
|
||||
request_count: 2,
|
||||
missing_token_count: 2,
|
||||
unavailable_cost_count: 2,
|
||||
..Default::default()
|
||||
};
|
||||
let [week, _] = account_quota_forecasts(&source, now() - Duration::days(60), now(), &[sample]);
|
||||
assert!(week.unavailable_reason.is_some());
|
||||
assert_eq!(week.estimated_tokens, None);
|
||||
assert_eq!(week.estimated_usd, None);
|
||||
assert_eq!(week.remaining_tokens, None);
|
||||
assert_eq!(week.remaining_usd, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_known_cost_is_valid_but_missing_usd_is_not_invented() {
|
||||
let mut sample = window("week", 7);
|
||||
|
||||
@@ -222,6 +222,8 @@ struct PricingRule {
|
||||
// 价格来源:https://developers.openai.com/api/docs/pricing,核验日期 2026-09-09。
|
||||
// 使用常规价,不采用 Sol 的临时 $4/$20 优惠;缓存、Flex、Fast 和长上下文
|
||||
// 档位也统一按常规价计算。
|
||||
// 已按 https://developers.openai.com/api/docs/deprecations 核验至 2026-09-13,
|
||||
// 移除已关闭的型号;仅宣布弃用但尚未到关闭日期的型号继续保留。
|
||||
const PRICING_RULES: &[PricingRule] = &[
|
||||
// Astra:https://developers.openai.com/api/docs/models/gpt-6-astra
|
||||
// 已于 2026-09-09 对照官方价目表核验。
|
||||
@@ -428,14 +430,6 @@ const PRICING_RULES: &[PricingRule] = &[
|
||||
},
|
||||
// 各变体独立采用已公开的价格与档位,不能继承父型号的所有档位。
|
||||
// Cyber 长上下文的官方来源存在差异,该区间暂不估价。
|
||||
PricingRule {
|
||||
model: "gpt-5.1-codex-mini",
|
||||
pricing: ModelPricing::new(2_500, 20_000, 250),
|
||||
},
|
||||
PricingRule {
|
||||
model: "gpt-5.3-chat-latest",
|
||||
pricing: ModelPricing::new(17_500, 140_000, 1_750),
|
||||
},
|
||||
PricingRule {
|
||||
model: "gpt-5.6-cyber",
|
||||
pricing: ModelPricing::new(125_000, 750_000, 12_500)
|
||||
@@ -450,34 +444,6 @@ const PRICING_RULES: &[PricingRule] = &[
|
||||
model: "chat-latest",
|
||||
pricing: ModelPricing::new(50_000, 300_000, 5_000),
|
||||
},
|
||||
PricingRule {
|
||||
model: "gpt-5-codex",
|
||||
pricing: ModelPricing::new(12_500, 100_000, 1_250),
|
||||
},
|
||||
PricingRule {
|
||||
model: "gpt-5.1-codex",
|
||||
pricing: ModelPricing::new(12_500, 100_000, 1_250),
|
||||
},
|
||||
PricingRule {
|
||||
model: "gpt-5.1-codex-max",
|
||||
pricing: ModelPricing::new(12_500, 100_000, 1_250),
|
||||
},
|
||||
PricingRule {
|
||||
model: "gpt-5-chat-latest",
|
||||
pricing: ModelPricing::new(12_500, 100_000, 1_250),
|
||||
},
|
||||
PricingRule {
|
||||
model: "gpt-5.1-chat-latest",
|
||||
pricing: ModelPricing::new(12_500, 100_000, 1_250),
|
||||
},
|
||||
PricingRule {
|
||||
model: "gpt-5.2-codex",
|
||||
pricing: ModelPricing::new(17_500, 140_000, 1_750),
|
||||
},
|
||||
PricingRule {
|
||||
model: "gpt-5.2-chat-latest",
|
||||
pricing: ModelPricing::new(17_500, 140_000, 1_750),
|
||||
},
|
||||
];
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -784,7 +750,6 @@ fn normalize_model_name(model: &str) -> String {
|
||||
fn pricing_model_name(model: &str) -> &str {
|
||||
match model {
|
||||
"gpt-3.5-turbo-0125" => "gpt-3.5-turbo",
|
||||
"gpt-4-0314" => "gpt-4",
|
||||
"gpt-4-0613" => "gpt-4",
|
||||
"gpt-4-turbo-2024-04-09" => "gpt-4-turbo",
|
||||
"gpt-4.1-2025-04-14" => "gpt-4.1",
|
||||
|
||||
@@ -243,15 +243,11 @@ async fn exact_limit_success_body_should_be_accepted() {
|
||||
fn billing_should_use_explicit_variant_prices_and_verified_snapshots() {
|
||||
// 每个用例包含一个普通输入 token 和一个输出 token,金额单位为 USD ticks。
|
||||
for (model, expected) in [
|
||||
("gpt-5.1-codex-mini", 22_500),
|
||||
("gpt-5.3-chat-latest", 157_500),
|
||||
("gpt-5.6-cyber", 875_000),
|
||||
("gpt-5.5-cyber", 875_000),
|
||||
("gpt-daybreak-red-latest", 875_000),
|
||||
("gpt-daybreak-blue-latest", 350_000),
|
||||
("chat-latest", 350_000),
|
||||
("gpt-5.1-codex-max", 112_500),
|
||||
("gpt-5.2-codex", 157_500),
|
||||
("gpt-5.4-2026-03-05", 175_000),
|
||||
(" OpenAI/GPT-4o-2024-08-06 ", 125_000),
|
||||
("gpt-4o-2024-05-13", 200_000),
|
||||
@@ -268,6 +264,53 @@ fn billing_should_use_explicit_variant_prices_and_verified_snapshots() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn billing_should_not_price_shutdown_models_or_restore_them_through_aliases() {
|
||||
// 官方关闭日期已过;同族仍在服务的基础型号不能为这些旧型号兜底。
|
||||
for model in [
|
||||
"gpt-4-0314",
|
||||
" OpenAI/GPT-4-0314 ",
|
||||
"gpt-5-codex",
|
||||
"gpt-5.1-codex",
|
||||
"gpt-5.1-codex-max",
|
||||
"gpt-5.1-codex-mini",
|
||||
"gpt-5.2-codex",
|
||||
"gpt-5-chat-latest",
|
||||
"gpt-5.1-chat-latest",
|
||||
"gpt-5.2-chat-latest",
|
||||
"gpt-5.3-chat-latest",
|
||||
] {
|
||||
for tier in [None, Some("flex"), Some("fast")] {
|
||||
assert!(
|
||||
openai_billing_breakdown(model, billing_usage(100, 10, 20, 0), tier).is_none(),
|
||||
"{model} {tier:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn billing_should_keep_deprecated_models_before_their_shutdown_dates() {
|
||||
// 截至 2026-09-13,这些型号尚未到官方关闭日期,仍按已公布单价计费。
|
||||
for model in [
|
||||
"gpt-3.5-turbo-instruct",
|
||||
"gpt-3.5-turbo-1106",
|
||||
"gpt-4-0613",
|
||||
"gpt-4-turbo-2024-04-09",
|
||||
"gpt-4o-2024-05-13",
|
||||
"gpt-4.1-nano",
|
||||
"o1",
|
||||
"o1-pro",
|
||||
"o3-mini",
|
||||
"o4-mini",
|
||||
] {
|
||||
assert!(
|
||||
openai_billing_breakdown(model, billing_usage(100, 10, 20, 0), None).is_some(),
|
||||
"{model}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn billing_should_not_inherit_prices_for_unknown_models_or_tiers() {
|
||||
for model in [
|
||||
@@ -291,7 +334,7 @@ fn billing_should_not_inherit_prices_for_unknown_models_or_tiers() {
|
||||
("gpt-5.6-cyber", 272_001, None),
|
||||
("gpt-5.5-cyber", 272_001, None),
|
||||
("gpt-5.6-cyber", 1, Some("fast")),
|
||||
("gpt-5.1-codex-mini", 1, Some("flex")),
|
||||
("gpt-5.3-codex", 1, Some("flex")),
|
||||
("gpt-6-astra", 1, Some("auto")),
|
||||
("gpt-6-astra", 1, Some("ultrafast")),
|
||||
] {
|
||||
|
||||
+12
-3
@@ -490,7 +490,10 @@ OAuth start 使用:
|
||||
`observedAt` 表示额度观测时间,与本次查询的 `generatedAt` 不同。
|
||||
- `unavailableReason`:不能估算时的说明,正常为 `null`。有效进度少于 5 个百分点不预测;
|
||||
`lowSample` 表示有效进度不足 10 个百分点,或增量采样少于 2 个完整段,仅是质量提示,不承诺精度。
|
||||
`incompleteCost` 仅抑制费用预测;`incompleteTokens` 仅抑制 Token 预测。未知值不按确定的零消耗外推。
|
||||
`incompleteCost` / `incompleteTokens` 仅提示费用 / Token 记录存在缺口,不阻断已有数据的预测。
|
||||
Token 使用已记录的正数用量,费用使用已知的有效 USD 金额;对应数据完全缺失时该项为 `null`,
|
||||
两项均不可估算时才返回无可用数据的说明。明确记录的零 USD 仍可估算为零,未知费用不能当成零。
|
||||
不按请求数量补齐未知消耗;漏记、失败或缺少计量可能使估算偏低,不代表完整账单或真实剩余额度。
|
||||
|
||||
内部采样优先采用近期分段,条件不足时才使用窗口累计估算。同一额度段内,以历史额度和截至相应
|
||||
完成时间的累计用量建立基线,每累计至少 5 个百分点形成一段,使用最近 3 个完整段及未满一段的尾部。
|
||||
@@ -847,8 +850,14 @@ Dashboard 的 `accountUsage[]` 由后端提供 `usageWindow`、`metricLabel`、`
|
||||
|
||||
OpenAI 的 `serviceTier` 只接受上游响应生命周期事件确认的实际 `response.service_tier`;请求里的
|
||||
期望档位只保留在 request summary,不能冒充响应事实。计费展示把 `priority`/`fast` 映射为 `Fast`,
|
||||
`flex` 映射为 `Flex`,缺失或 `default` 映射为 `Default`;未知非空值原样展示。Fast 优先使用模型的
|
||||
priority 价格,缺少专用价格时回退到标准价格的 `2.00x`;Flex 为 `0.50x`,Default 为 `1.00x`。
|
||||
`flex` 映射为 `Flex`,缺失或 `default` 映射为 `Default`;未知非空值原样展示。各模型、档位及长上下文
|
||||
区间使用明确登记的价格;缺少对应价格时不估算,不以固定倍数兜底。展示的倍率由所选档位与标准档位
|
||||
费用之比计算,托管工具调用费不随 Token 档位倍增。
|
||||
响应未报告实际档位时,本地费用估算回退到请求档位;该推测不写入响应 `serviceTier`,也不能确认
|
||||
上游最终采用了该档位,因此本地费用不能代替官方账单。
|
||||
|
||||
本地计价规则只保留尚在服务的型号;已过官方关闭日期的型号不再新增本地估价。清理计价规则不删除或
|
||||
重新计算已存储的历史费用;缺少当前计价规则时,历史总额仍保留,但无法再据此补充费用拆分。
|
||||
|
||||
## 11. 版本、更新与重启
|
||||
|
||||
|
||||
@@ -392,8 +392,9 @@ credential 与 quota 是两组独立事实:credential refresh 不等于 quota
|
||||
账号容量预测属于 Admin 的只读派生规则,不参与 quota 权威状态、调度或金额结算。Store 通过专用采样端口
|
||||
在同一 SQL 快照内返回截至观测时间的累计数值及有界历史 Provider 文档;文档仅由具体 Provider 复用协议
|
||||
解析器解释,Admin 按中立的额度事实选择近期进度段。该采样不改变全站完整交付用量口径,不创建第二份
|
||||
持久化额度状态。未知 Token/美元费用分别抑制对应预测;历史请求完成时间只是额度时间的近似,不承诺
|
||||
严格扣额归因或预测准确率。公开字段与采样门槛见 [周/月额度预测](api.md#周月额度预测)。
|
||||
持久化额度状态。部分 Token/美元费用缺失仅提示精度限制,继续按已记录数值估算;对应数值完全不可用时
|
||||
才不返回该项预测,不按请求数量补齐未知消耗。历史请求完成时间只是额度时间的近似,不承诺严格扣额归因
|
||||
或预测准确率。公开字段与采样门槛见 [周/月额度预测](api.md#周月额度预测)。
|
||||
|
||||
请求观测通过有界进程内队列异步投影到 PostgreSQL。队列满、Store 暂不可用或进程退出超时时,允许丢失
|
||||
可恢复观测并累计指标,但不允许改变客户端响应。Usage 详情中的 attempt 因此是 best-effort,并通过
|
||||
|
||||
+4
-13
@@ -1,19 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import type { AccountQuotaForecast } from '@/api'
|
||||
import { ArrowRight, Info, TriangleAlert } from '@lucide/vue'
|
||||
import { ArrowRight, Info } from '@lucide/vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{ forecast: AccountQuotaForecast }>()
|
||||
const source = computed(() => props.forecast.source)
|
||||
const incompleteNotice = computed(() => {
|
||||
if (props.forecast.incompleteTokens && props.forecast.incompleteCost)
|
||||
return '用量和费用数据不完整,暂时无法预测。'
|
||||
if (props.forecast.incompleteTokens)
|
||||
return '用量数据不完整,暂时无法预测 Token 容量。'
|
||||
if (props.forecast.incompleteCost)
|
||||
return '费用数据不完整,暂时无法估算金额。'
|
||||
return null
|
||||
})
|
||||
const metrics = computed(() => [
|
||||
{
|
||||
label: 'Token 容量',
|
||||
@@ -89,9 +80,9 @@ const metrics = computed(() => [
|
||||
{{ forecast.remainingUsdDisplay }}
|
||||
</span>
|
||||
</div>
|
||||
<p v-if="incompleteNotice" class="m-0 flex items-start gap-1.5 text-cp-xs leading-relaxed text-cp-warning-text">
|
||||
<TriangleAlert class="mt-0.5 size-3.5 shrink-0" aria-hidden="true" />
|
||||
{{ incompleteNotice }}
|
||||
<p v-if="forecast.incompleteTokens || forecast.incompleteCost" class="m-0 flex items-start gap-1.5 text-cp-xs leading-relaxed text-cp-text-secondary">
|
||||
<Info class="mt-0.5 size-3.5 shrink-0" aria-hidden="true" />
|
||||
按已记录数据估算,缺失的用量或费用可能使结果偏低。
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -123,7 +123,7 @@ function handleExplanationKeydown(event: KeyboardEvent) {
|
||||
仅供参考
|
||||
</h4>
|
||||
<p class="m-0">
|
||||
根据已记录用量估算,结果会随使用的模型和方式变化,并非官方承诺额度。
|
||||
根据已记录用量估算,漏记或失败请求的消耗可能使结果偏低;结果会随使用的模型和方式变化,并非官方承诺额度。
|
||||
</p>
|
||||
<p v-if="forecast?.lowSample" class="m-0">
|
||||
目前数据还较少,结果可能有较大波动。
|
||||
|
||||
+6
-19
@@ -1,25 +1,12 @@
|
||||
# v3.6.0
|
||||
|
||||
## 新增功能
|
||||
|
||||
- 创建客户端密钥时支持填写自定义 Key,便于沿用旧平台凭据;留空仍自动生成。自定义值支持不同前缀、长度和标点,沿用本平台的分组权限、限额与并发规则。
|
||||
- 密钥列表、请求记录和错误列表支持按密钥名称搜索;创建和修改名称时校验重名,忽略大小写和首尾空白。
|
||||
# v3.6.1
|
||||
|
||||
## 问题修复
|
||||
|
||||
- 修复 Codex 模型目录丢失原生元数据的问题,完整保留上游提示词、工具能力、上下文窗口及 `service_tiers`,使支持的客户端可按上游声明显示 `/fast` 等服务档位。目录遵守密钥的账号范围,模型别名保留目标模型的完整元数据。
|
||||
- 修复同源 HTTP 管理端无法保持登录及复制失败的问题;会话 Cookie 随浏览器来源区分 HTTP 与 HTTPS,HTTPS 反向代理使用 HTTP 回源时仍保留安全属性。
|
||||
- 将 OpenAI 的 `generate: false` 预热请求排除出推理用量和额度预测统计,保留审计记录与额度观测,避免预热记录干扰预测;预测面板使用实际额度观测时间。
|
||||
|
||||
## 体验优化
|
||||
|
||||
- 精简额度预测面板,聚焦容量与剩余估算,减少采样明细和重复提示。
|
||||
- 精简请求诊断面板,缺少时间线时使用空状态展示,保留诊断包导出。
|
||||
- 简化部署初始化命令,合并目录创建、配置复制和权限设置。
|
||||
- 周/月额度预测不再因个别请求缺少 Token 或费用记录而整体不可用,继续使用已记录数据估算容量与剩余量。对应数据完全缺失时仍保留未知状态,不补算为零。
|
||||
- 将“数据不完整,暂时无法预测”提示改为估算精度说明,提示漏记或失败请求的消耗可能使结果偏低。
|
||||
- 清理官方已关闭的 OpenAI 模型计价规则及旧别名;仅宣布弃用、尚未到关闭日期的型号继续保留计价。
|
||||
|
||||
## 升级说明
|
||||
|
||||
- 从 v3.5.0 升级时,服务启动自动执行 `0006_custom_client_keys.sql`,保留已有密钥;无需新增配置项。历史重名密钥仍可使用,再次保存时需调整为未被占用的名称。
|
||||
- 密钥相关搜索不再匹配 Key 值或可见前缀,请改用密钥名称;请求记录仍支持按 Client Key ID 查询。
|
||||
- 额度预测管理接口移除了 `generatedAtDisplay`、`method` / `methodDisplay` 及部分采样诊断字段。自建管理客户端需按 [当前 API 合同](https://github.com/zyycn/codex-proxy-rs/blob/v3.6.0/docs/api.md#周月额度预测) 调整。
|
||||
- Codex 客户端需重新加载模型目录,才能取得更新后的服务档位与能力信息。
|
||||
- 从 v3.6.0 升级无需新增配置或数据库迁移。
|
||||
- 历史费用总额保留,不重新计价;已移除计价规则的型号无法再补充历史费用拆分。现役模型的常规价格及 GPT-6 Astra 计费公式不变。
|
||||
|
||||
@@ -1 +1 @@
|
||||
version: "3.6.0"
|
||||
version: "3.6.1"
|
||||
|
||||
Reference in New Issue
Block a user