Skip to content

Commit 01448fa

Browse files
committed
feat(providers): drop the balance adapter usage query mode
查询方式移除"余额适配器":Rust 删除 balance 模式分支与 DeepSeek/StepFun/SiliconFlow/OpenRouter/Novita 六家适配器及其 提取器与测试;保留自定义脚本、通用模板、NewAPI、Coding Plan 四项。 默认查询方式改为自定义脚本;历史配置中的 "balance" 与未知值在 规范化时统一回退 custom(桌面端存量 JSON 未重写前由 Rust 的 Unsupported mode 错误兜底)。两端下拉选项按 自定义/通用/NewAPI/ Coding Plan 重排,i18n 删除余额适配器文案。
1 parent b235de8 commit 01448fa

10 files changed

Lines changed: 25 additions & 224 deletions

File tree

crates/agent-gateway/web/src/i18n/config.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,7 +1390,6 @@ export const translations: Record<Locale, Record<string, string>> = {
13901390
"settings.providerUsageQuery": "用量查询",
13911391
"settings.providerUsageEnabled": "启用用量查询",
13921392
"settings.providerUsageMode": "查询方式",
1393-
"settings.providerUsageMode.balance": "余额适配器",
13941393
"settings.providerUsageMode.codingPlan": "Coding Plan",
13951394
"settings.providerUsageMode.general": "通用模板",
13961395
"settings.providerUsageMode.newapi": "NewAPI 模板",
@@ -3512,7 +3511,6 @@ export const translations: Record<Locale, Record<string, string>> = {
35123511
"settings.providerUsageQuery": "Usage query",
35133512
"settings.providerUsageEnabled": "Enable usage query",
35143513
"settings.providerUsageMode": "Query mode",
3515-
"settings.providerUsageMode.balance": "Balance adapter",
35163514
"settings.providerUsageMode.codingPlan": "Coding Plan",
35173515
"settings.providerUsageMode.general": "General template",
35183516
"settings.providerUsageMode.newapi": "NewAPI template",

crates/agent-gateway/web/src/lib/settings/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ export type SshSettings = {
273273
projectHostAssociations: Record<string, string[]>;
274274
};
275275

276-
export type UsageQueryMode = "balance" | "coding-plan" | "general" | "newapi" | "custom";
276+
export type UsageQueryMode = "coding-plan" | "general" | "newapi" | "custom";
277277

278278
export type UsageQueryConfig = {
279279
enabled: boolean;
@@ -291,7 +291,7 @@ export type UsageQueryConfig = {
291291
export function getDefaultUsageQueryConfig(): UsageQueryConfig {
292292
return {
293293
enabled: false,
294-
mode: "balance",
294+
mode: "custom",
295295
script: "",
296296
baseUrl: "",
297297
accessToken: "",
@@ -1331,10 +1331,10 @@ function normalizeUsageQueryMode(input: unknown): UsageQueryMode {
13311331
case "coding-plan":
13321332
case "general":
13331333
case "newapi":
1334-
case "custom":
13351334
return input;
13361335
default:
1337-
return "balance";
1336+
// 含历史配置中的 "balance"(余额适配器已移除)——统一回退自定义脚本。
1337+
return "custom";
13381338
}
13391339
}
13401340

crates/agent-gateway/web/src/lib/settings/sync.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ function apiKeyConfiguredForProvider(provider: AppSettings["customProviders"][nu
101101

102102
const DEFAULT_USAGE_QUERY_CONFIG: AppSettings["customProviders"][number]["usageQuery"] = {
103103
enabled: false,
104-
mode: "balance",
104+
mode: "custom",
105105
script: "",
106106
baseUrl: "",
107107
accessToken: "",

crates/agent-gateway/web/src/pages/settings/ProvidersSection.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,20 +1711,17 @@ function ProviderModal({ providerType, initialData, onSave, onTestUsage, onClose
17111711
<SelectValue />
17121712
</SelectTrigger>
17131713
<SelectContent>
1714-
<SelectItem value="balance">
1715-
{t("settings.providerUsageMode.balance")}
1716-
</SelectItem>
1717-
<SelectItem value="coding-plan">
1718-
{t("settings.providerUsageMode.codingPlan")}
1714+
<SelectItem value="custom">
1715+
{t("settings.providerUsageMode.custom")}
17191716
</SelectItem>
17201717
<SelectItem value="general">
17211718
{t("settings.providerUsageMode.general")}
17221719
</SelectItem>
17231720
<SelectItem value="newapi">
17241721
{t("settings.providerUsageMode.newapi")}
17251722
</SelectItem>
1726-
<SelectItem value="custom">
1727-
{t("settings.providerUsageMode.custom")}
1723+
<SelectItem value="coding-plan">
1724+
{t("settings.providerUsageMode.codingPlan")}
17281725
</SelectItem>
17291726
</SelectContent>
17301727
</Select>

crates/agent-gui/src-tauri/src/services/provider_usage.rs

Lines changed: 2 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,6 @@ struct HttpRequest {
256256

257257
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
258258
enum ProviderAdapter {
259-
DeepSeek,
260-
StepFun,
261-
SiliconFlowCn,
262-
SiliconFlowEn,
263-
OpenRouter,
264-
Novita,
265259
Kimi,
266260
Zhipu,
267261
MiniMax,
@@ -336,7 +330,6 @@ fn prepare_query(provider: &StoredProvider) -> Result<PreparedQuery, String> {
336330
}
337331

338332
match provider.usage_query.mode.as_str() {
339-
"balance" => prepare_balance_query(provider),
340333
"coding-plan" => prepare_coding_plan_query(provider),
341334
"general" => prepare_script_query(provider, GENERAL_SCRIPT, true),
342335
"newapi" => prepare_script_query(provider, NEWAPI_SCRIPT, true),
@@ -383,46 +376,6 @@ fn prepare_script_query(
383376
})
384377
}
385378

386-
fn prepare_balance_query(provider: &StoredProvider) -> Result<PreparedQuery, String> {
387-
if provider.api_key.trim().is_empty() {
388-
return Err("Provider API key is not configured".to_string());
389-
}
390-
let base = validate_destination(&provider.base_url)?;
391-
if base.scheme() != "https" {
392-
return Err("Built-in usage adapters require HTTPS".to_string());
393-
}
394-
let host = base.host_str().unwrap_or_default().to_ascii_lowercase();
395-
let (adapter, endpoint) = match host.as_str() {
396-
"api.deepseek.com" => (
397-
ProviderAdapter::DeepSeek,
398-
"https://api.deepseek.com/user/balance",
399-
),
400-
"api.stepfun.ai" | "api.stepfun.com" => (
401-
ProviderAdapter::StepFun,
402-
"https://api.stepfun.com/v1/accounts",
403-
),
404-
"api.siliconflow.cn" => (
405-
ProviderAdapter::SiliconFlowCn,
406-
"https://api.siliconflow.cn/v1/user/info",
407-
),
408-
"api.siliconflow.com" => (
409-
ProviderAdapter::SiliconFlowEn,
410-
"https://api.siliconflow.com/v1/user/info",
411-
),
412-
"openrouter.ai" => (
413-
ProviderAdapter::OpenRouter,
414-
"https://openrouter.ai/api/v1/credits",
415-
),
416-
"api.novita.ai" => (
417-
ProviderAdapter::Novita,
418-
"https://api.novita.ai/v3/user/balance",
419-
),
420-
_ => return Err("No balance adapter matches this provider".to_string()),
421-
};
422-
let request = bearer_request(endpoint, &provider.api_key)?;
423-
Ok(single_request_query(request, adapter))
424-
}
425-
426379
fn prepare_coding_plan_query(provider: &StoredProvider) -> Result<PreparedQuery, String> {
427380
let base = validate_destination(&provider.base_url)?;
428381
if base.scheme() != "https" {
@@ -723,37 +676,6 @@ fn parse_adapter_response(
723676
body: &Value,
724677
) -> Result<Vec<ProviderUsageEntry>, String> {
725678
let entries = match adapter {
726-
ProviderAdapter::DeepSeek => parse_deepseek(body)?,
727-
ProviderAdapter::StepFun => vec![balance_entry(
728-
"StepFun balance",
729-
required_number(body, "balance")?,
730-
"CNY",
731-
)],
732-
ProviderAdapter::SiliconFlowCn | ProviderAdapter::SiliconFlowEn => {
733-
let data = body
734-
.get("data")
735-
.ok_or_else(|| "SiliconFlow response is missing data".to_string())?;
736-
vec![balance_entry(
737-
"SiliconFlow balance",
738-
required_number(data, "totalBalance")?,
739-
if adapter == ProviderAdapter::SiliconFlowCn {
740-
"CNY"
741-
} else {
742-
"USD"
743-
},
744-
)]
745-
}
746-
ProviderAdapter::OpenRouter => {
747-
let data = body.get("data").unwrap_or(body);
748-
let total = required_number(data, "total_credits")?;
749-
let used = required_number(data, "total_usage")?;
750-
vec![balance_entry("OpenRouter balance", total - used, "USD")]
751-
}
752-
ProviderAdapter::Novita => vec![balance_entry(
753-
"Novita balance",
754-
required_number(body, "availableBalance")? / 10_000.0,
755-
"USD",
756-
)],
757679
ProviderAdapter::Kimi => parse_kimi(body),
758680
ProviderAdapter::Zhipu => parse_zhipu(body),
759681
ProviderAdapter::MiniMax => parse_minimax(body),
@@ -768,28 +690,6 @@ fn parse_adapter_response(
768690
Ok(entries)
769691
}
770692

771-
fn parse_deepseek(body: &Value) -> Result<Vec<ProviderUsageEntry>, String> {
772-
let infos = body
773-
.get("balance_infos")
774-
.and_then(Value::as_array)
775-
.ok_or_else(|| "DeepSeek response is missing balance information".to_string())?;
776-
infos
777-
.iter()
778-
.map(|info| {
779-
let unit = info
780-
.get("currency")
781-
.and_then(Value::as_str)
782-
.filter(|unit| !unit.is_empty())
783-
.ok_or_else(|| "DeepSeek response has an invalid currency".to_string())?;
784-
Ok(balance_entry(
785-
"DeepSeek balance",
786-
required_number(info, "total_balance")?,
787-
unit,
788-
))
789-
})
790-
.collect()
791-
}
792-
793693
fn parse_kimi(body: &Value) -> Vec<ProviderUsageEntry> {
794694
let mut entries = Vec::new();
795695
if let Some(limits) = body.get("limits").and_then(Value::as_array) {
@@ -938,10 +838,6 @@ fn parse_volcengine_coding(body: &Value) -> Vec<ProviderUsageEntry> {
938838
.collect()
939839
}
940840

941-
fn balance_entry(label: &str, value: f64, unit: &str) -> ProviderUsageEntry {
942-
quota_entry(label, value, Some(unit))
943-
}
944-
945841
fn quota_entry(label: &str, value: f64, unit: Option<&str>) -> ProviderUsageEntry {
946842
ProviderUsageEntry {
947843
label: label.to_string(),
@@ -950,11 +846,6 @@ fn quota_entry(label: &str, value: f64, unit: Option<&str>) -> ProviderUsageEntr
950846
}
951847
}
952848

953-
fn required_number(value: &Value, field: &str) -> Result<f64, String> {
954-
optional_number(value, field)
955-
.ok_or_else(|| "Usage query response is missing a number".to_string())
956-
}
957-
958849
fn optional_number(value: &Value, field: &str) -> Option<f64> {
959850
let value = value.get(field)?;
960851
let number = value
@@ -1463,7 +1354,7 @@ mod tests {
14631354
#[test]
14641355
fn cache_requires_current_provider_identity_and_supports_invalidation() {
14651356
let mut cache = UsageCache::default();
1466-
let original = test_provider("balance", "https://api.deepseek.com/v1");
1357+
let original = test_provider("coding-plan", "https://api.kimi.com/coding/v1");
14671358
let original_identity = provider_query_identity(&original);
14681359
cache.record_success(
14691360
"provider-a",
@@ -1501,7 +1392,7 @@ mod tests {
15011392
#[test]
15021393
fn failure_only_results_are_not_reusable_cache_entries() {
15031394
let mut cache = UsageCache::default();
1504-
let provider = test_provider("balance", "https://api.deepseek.com/v1");
1395+
let provider = test_provider("coding-plan", "https://api.kimi.com/coding/v1");
15051396
let identity = provider_query_identity(&provider);
15061397

15071398
let result = cache.record_failure("provider-a", identity, "request failed");
@@ -1511,49 +1402,6 @@ mod tests {
15111402
assert!(cache.get("provider-a", &identity).is_none());
15121403
}
15131404

1514-
#[test]
1515-
fn balance_adapters_build_expected_endpoints() {
1516-
let cases = [
1517-
(
1518-
"https://api.deepseek.com/v1",
1519-
ProviderAdapter::DeepSeek,
1520-
"/user/balance",
1521-
),
1522-
(
1523-
"https://api.stepfun.com/v1",
1524-
ProviderAdapter::StepFun,
1525-
"/v1/accounts",
1526-
),
1527-
(
1528-
"https://api.siliconflow.cn/v1",
1529-
ProviderAdapter::SiliconFlowCn,
1530-
"/v1/user/info",
1531-
),
1532-
(
1533-
"https://api.siliconflow.com/v1",
1534-
ProviderAdapter::SiliconFlowEn,
1535-
"/v1/user/info",
1536-
),
1537-
(
1538-
"https://openrouter.ai/api/v1",
1539-
ProviderAdapter::OpenRouter,
1540-
"/api/v1/credits",
1541-
),
1542-
(
1543-
"https://api.novita.ai/v3/openai",
1544-
ProviderAdapter::Novita,
1545-
"/v3/user/balance",
1546-
),
1547-
];
1548-
1549-
for (base_url, expected_adapter, expected_path) in cases {
1550-
let query = test_provider("balance", base_url);
1551-
let prepared = prepare_query(&query).expect("prepare balance query");
1552-
assert_eq!(prepared.primary.adapter, expected_adapter);
1553-
assert_eq!(prepared.primary.request.url.path(), expected_path);
1554-
}
1555-
}
1556-
15571405
#[test]
15581406
fn coding_plan_adapters_build_expected_endpoints() {
15591407
let cases = [
@@ -1613,48 +1461,6 @@ mod tests {
16131461
.is_ok());
16141462
}
16151463

1616-
#[test]
1617-
fn balance_adapter_responses_are_normalized() {
1618-
let cases = [
1619-
(
1620-
ProviderAdapter::DeepSeek,
1621-
json!({"balance_infos": [{"currency": "CNY", "total_balance": "12.50"}]}),
1622-
"12.5",
1623-
"CNY",
1624-
),
1625-
(
1626-
ProviderAdapter::StepFun,
1627-
json!({"balance": 9.25}),
1628-
"9.25",
1629-
"CNY",
1630-
),
1631-
(
1632-
ProviderAdapter::SiliconFlowEn,
1633-
json!({"data": {"totalBalance": "8.75"}}),
1634-
"8.75",
1635-
"USD",
1636-
),
1637-
(
1638-
ProviderAdapter::OpenRouter,
1639-
json!({"data": {"total_credits": 20, "total_usage": 3.5}}),
1640-
"16.5",
1641-
"USD",
1642-
),
1643-
(
1644-
ProviderAdapter::Novita,
1645-
json!({"availableBalance": 42_000}),
1646-
"4.2",
1647-
"USD",
1648-
),
1649-
];
1650-
1651-
for (adapter, body, value, unit) in cases {
1652-
let entries = parse_adapter_response(adapter, &body).expect("parse adapter response");
1653-
assert_eq!(entries[0].value, value);
1654-
assert_eq!(entries[0].unit.as_deref(), Some(unit));
1655-
}
1656-
}
1657-
16581464
#[test]
16591465
fn coding_plan_responses_are_normalized_as_remaining_quota() {
16601466
let cases = [

crates/agent-gui/src/i18n/config.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,7 +1428,6 @@ export const translations: Record<Locale, Record<string, string>> = {
14281428
"settings.providerUsageQuery": "用量查询",
14291429
"settings.providerUsageEnabled": "启用用量查询",
14301430
"settings.providerUsageMode": "查询方式",
1431-
"settings.providerUsageMode.balance": "余额适配器",
14321431
"settings.providerUsageMode.codingPlan": "Coding Plan",
14331432
"settings.providerUsageMode.general": "通用模板",
14341433
"settings.providerUsageMode.newapi": "NewAPI 模板",
@@ -3610,7 +3609,6 @@ export const translations: Record<Locale, Record<string, string>> = {
36103609
"settings.providerUsageQuery": "Usage query",
36113610
"settings.providerUsageEnabled": "Enable usage query",
36123611
"settings.providerUsageMode": "Query mode",
3613-
"settings.providerUsageMode.balance": "Balance adapter",
36143612
"settings.providerUsageMode.codingPlan": "Coding Plan",
36153613
"settings.providerUsageMode.general": "General template",
36163614
"settings.providerUsageMode.newapi": "NewAPI template",

0 commit comments

Comments
 (0)