feat(llm): 新增 StepFun 供应商预设;修复 Codex OAuth 默认模型不可用 (#836)
StepFun 预设: - 供应商下拉新增 StepFun(阶跃星辰),预填 https://api.stepfun.com/v1, 默认模型 step-1o-turbo-vision(无思考,流式首字 ~0.3s;step-3.x-flash 系列为推理模型且思考无法关闭,正式内容需等隐藏思考结束,不适合听写润色) - thinking 控制表新增 stepfun → reasoning_effort(开=medium / 关=low), base_url 兜底识别同步支持"自定义"preset 接入 StepFun 的场景 - 补默认 endpoint 映射与两个单元测试 Codex OAuth 默认模型: - gpt-5.3-codex-spark 对 ChatGPT 账号会被后端 400 拒绝 ("model is not supported when using Codex with a ChatGPT account"), 导致每次润色静默失败回退原文;默认与占位改为实测可用的 gpt-5.5 Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
17fe67c59b
commit
ce3fd8d847
8 files changed
+73
-3
No files matched your search
@@ -92,6 +92,7 @@ fn llm_provider_default_endpoint(provider: &str) -> Option<&'static str> {
|
||||
"openrouterFree" => Some("https://openrouter.ai/api/v1"),
|
||||
"alibabaCoding" => Some("https://coding-intl.dashscope.aliyuncs.com/v1"),
|
||||
"codingPlanX" => Some("https://api.codingplanx.ai/v1"),
|
||||
"stepfun" => Some("https://api.stepfun.com/v1"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,10 @@ const DEFAULT_REQUEST_TIMEOUT_SECS: u64 = 30;
|
||||
const BODY_PREVIEW_LIMIT: usize = 200;
|
||||
pub const CODEX_OAUTH_PROVIDER_ID: &str = "codex_oauth";
|
||||
pub const CODEX_DEFAULT_BASE_URL: &str = "https://chatgpt.com/backend-api";
|
||||
pub const CODEX_DEFAULT_MODEL: &str = "gpt-5.3-codex-spark";
|
||||
// 注意:gpt-5.3-codex-spark 不能做默认——ChatGPT 账号走 Codex OAuth 时后端会
|
||||
// 400 拒绝("model is not supported when using Codex with a ChatGPT account"),
|
||||
// 每次润色都失败并回退原文。gpt-5.5 是该通道实测可用的模型。
|
||||
pub const CODEX_DEFAULT_MODEL: &str = "gpt-5.5";
|
||||
const CODEX_MIN_TOKEN_TTL_SECS: u64 = 60;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -1607,7 +1610,9 @@ fn openai_compatible_thinking_control(provider_id: &str) -> Option<ThinkingContr
|
||||
"minimax" => Some(ThinkingControl::MiniMaxThinking),
|
||||
"openrouterFree" => Some(ThinkingControl::OpenRouterReasoning),
|
||||
"alibabaCoding" => Some(ThinkingControl::EnableThinking),
|
||||
"openai" | "codingPlanX" => Some(ThinkingControl::ReasoningEffort),
|
||||
// StepFun step-3.x-flash 系列按官方文档接受 reasoning_effort(low/medium/high,
|
||||
// 无法完全关闭思考);非推理模型(如 step-1o-turbo-vision)会忽略该字段。
|
||||
"openai" | "codingPlanX" | "stepfun" => Some(ThinkingControl::ReasoningEffort),
|
||||
// custom / 其他未声明 provider 走 base_url 兜底识别——用户用自定义
|
||||
// endpoint 接入 MiniMax 时,根据 base_url 命中即下发官方 thinking 参数。
|
||||
_ => None,
|
||||
@@ -1643,6 +1648,9 @@ fn openai_compatible_thinking_control_for_base_url(base_url: &str) -> Option<Thi
|
||||
if host.contains("dashscope") || host.contains("aliyuncs") {
|
||||
return Some(ThinkingControl::EnableThinking);
|
||||
}
|
||||
if host.contains("stepfun") {
|
||||
return Some(ThinkingControl::ReasoningEffort);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -2650,6 +2658,47 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn openai_chat_body_adds_reasoning_effort_for_stepfun_channel() {
|
||||
// StepFun 按渠道声明下发 reasoning_effort:开启思考发 medium,关闭发 low。
|
||||
for (thinking_enabled, expected) in [(true, "medium"), (false, "low")] {
|
||||
let provider = OpenAICompatibleLLMProvider::new(
|
||||
OpenAICompatibleConfig::new(
|
||||
"stepfun",
|
||||
"StepFun",
|
||||
"https://api.stepfun.com/v1",
|
||||
"k",
|
||||
"step-3.7-flash",
|
||||
)
|
||||
.with_thinking_enabled(thinking_enabled),
|
||||
);
|
||||
|
||||
let body = provider.chat_body(false, vec![json!({ "role": "user", "content": "hi" })]);
|
||||
|
||||
assert_eq!(body["reasoning_effort"], expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn openai_chat_body_falls_back_to_base_url_for_custom_stepfun_endpoint() {
|
||||
// 用 "custom" preset + StepFun base_url 接入时,base_url 兜底识别需要
|
||||
// 命中 "stepfun" 关键字,下发 reasoning_effort。
|
||||
let provider = OpenAICompatibleLLMProvider::new(
|
||||
OpenAICompatibleConfig::new(
|
||||
"custom",
|
||||
"Custom",
|
||||
"https://api.stepfun.com/v1",
|
||||
"k",
|
||||
"step-3.7-flash",
|
||||
)
|
||||
.with_thinking_enabled(false),
|
||||
);
|
||||
|
||||
let body = provider.chat_body(false, vec![json!({ "role": "user", "content": "hi" })]);
|
||||
|
||||
assert_eq!(body["reasoning_effort"], "low");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn openai_chat_body_omits_thinking_control_for_unknown_provider() {
|
||||
let provider = OpenAICompatibleLLMProvider::new(
|
||||
|
||||
@@ -782,6 +782,7 @@ export const en: typeof zhCN = {
|
||||
alibabaCoding: 'Alibaba Cloud Coding Plan',
|
||||
codingPlanX: 'CodingPlanX',
|
||||
minimax: 'MiniMax (M3)',
|
||||
stepfun: 'StepFun',
|
||||
custom: 'Custom',
|
||||
asrVolcengine: 'Volcengine bigasr',
|
||||
asrBailian: 'Alibaba Bailian realtime ASR',
|
||||
|
||||
@@ -784,6 +784,7 @@ export const ja: typeof zhCN = {
|
||||
alibabaCoding: 'Alibaba Cloud Coding Plan',
|
||||
codingPlanX: 'CodingPlanX',
|
||||
minimax: 'MiniMax(M3)',
|
||||
stepfun: 'StepFun(階躍星辰)',
|
||||
custom: 'カスタム',
|
||||
asrVolcengine: 'Volcengine bigasr',
|
||||
asrBailian: 'Alibaba Bailian リアルタイム ASR',
|
||||
|
||||
@@ -784,6 +784,7 @@ export const ko: typeof zhCN = {
|
||||
alibabaCoding: 'Alibaba Cloud Coding Plan',
|
||||
codingPlanX: 'CodingPlanX',
|
||||
minimax: 'MiniMax (M3)',
|
||||
stepfun: 'StepFun',
|
||||
custom: '사용자 정의',
|
||||
asrVolcengine: 'Volcengine bigasr',
|
||||
asrBailian: 'Alibaba Bailian 실시간 ASR',
|
||||
|
||||
@@ -780,6 +780,7 @@ export const zhCN = {
|
||||
alibabaCoding: '阿里云 Coding Plan',
|
||||
codingPlanX: 'CodingPlanX',
|
||||
minimax: 'MiniMax(M3)',
|
||||
stepfun: 'StepFun(阶跃星辰)',
|
||||
custom: '自定义',
|
||||
asrVolcengine: '火山引擎 bigasr',
|
||||
asrBailian: '阿里云百炼实时 ASR',
|
||||
|
||||
@@ -782,6 +782,7 @@ export const zhTW: typeof zhCN = {
|
||||
alibabaCoding: '阿里雲 Coding Plan',
|
||||
codingPlanX: 'CodingPlanX',
|
||||
minimax: 'MiniMax(M3)',
|
||||
stepfun: 'StepFun(階躍星辰)',
|
||||
custom: '自定義',
|
||||
asrVolcengine: '火山引擎 bigasr',
|
||||
asrBailian: '阿里雲百煉即時 ASR',
|
||||
|
||||
@@ -88,7 +88,9 @@ const LLM_PRESETS = [
|
||||
id: 'codex_oauth',
|
||||
nameKey: 'codexOAuth',
|
||||
baseUrl: '',
|
||||
modelPlaceholder: 'gpt-5.3-codex-spark',
|
||||
// gpt-5.3-codex-spark 对 ChatGPT 账号的 Codex 通道会被 400 拒绝,
|
||||
// 默认与占位一律用实测可用的 gpt-5.5(见 polish.rs::CODEX_DEFAULT_MODEL)。
|
||||
modelPlaceholder: 'gpt-5.5',
|
||||
},
|
||||
{
|
||||
id: 'mimo',
|
||||
@@ -132,6 +134,19 @@ const LLM_PRESETS = [
|
||||
baseUrl: 'https://api.minimaxi.com/v1',
|
||||
modelPlaceholder: 'MiniMax-M3',
|
||||
},
|
||||
{
|
||||
// StepFun(阶跃星辰)OpenAI 兼容 /v1/chat/completions。
|
||||
// 默认模型选 step-1o-turbo-vision:step-3.x-flash 系列是推理模型且思考无法关闭
|
||||
// (reasoning_effort 只能调档,正式内容要等隐藏思考结束,润色场景 TTFT 2s+),
|
||||
// 而 step-1o-turbo-vision 无思考、TTFT ~0.3s,润色忠实度实测更适合听写链路。
|
||||
// provider_id 在后端 polish.rs::openai_compatible_thinking_control 命中
|
||||
// "stepfun" → ReasoningEffort 分支;走"自定义"preset 接入时由 base_url
|
||||
// 含 "stepfun" 兜底识别,见 polish.rs。
|
||||
id: 'stepfun',
|
||||
nameKey: 'stepfun',
|
||||
baseUrl: 'https://api.stepfun.com/v1',
|
||||
modelPlaceholder: 'step-1o-turbo-vision',
|
||||
},
|
||||
{
|
||||
id: 'custom',
|
||||
nameKey: 'custom',
|
||||
|
||||
Reference in new issue
Block a user