修复: 队列发送失败回填不丢消息+池权重revert+lang解析DRY+注释变量名修正
This commit is contained in:
@@ -336,8 +336,10 @@ impl AnthropicCompatProvider {
|
||||
// F-260614-05 Phase 2a: 多模态 user 消息 → content blocks 数组(text/image)。
|
||||
// 含图时把 content + parts 拍平成 blocks:Text 片 → {type:text},
|
||||
// Image 片 → {type:image, source:{type:base64, media_type, data}}。
|
||||
// Anthropic 协议要求 image 必须内嵌 base64(不接受 URL 直传),
|
||||
// url 模式应由 commands 层预拉字节回填 base64(provider 不发额外 HTTP)。
|
||||
// Anthropic 协议要求 image 必须内嵌 base64(不接受 URL 直传)。
|
||||
// 现状:前端(Phase2b)只产 base64 模式图片片,url 模式当前不可达。
|
||||
// 未来若加 url 图片输入,必须在 commands 层补 url→base64 预拉
|
||||
//(provider 不发额外 HTTP),否则下方兜底会发空 data 致 Anthropic 400。
|
||||
// 纯文本消息(无图)保持原字符串简写,与现有端点零回归。
|
||||
if m.has_image() {
|
||||
let blocks: Vec<serde_json::Value> = m
|
||||
@@ -351,12 +353,13 @@ impl AnthropicCompatProvider {
|
||||
crate::provider::ContentPart::Image { url, base64, media_type, alt: _ } => {
|
||||
let mt = media_type.clone().unwrap_or_else(|| "image/png".into());
|
||||
let data = base64.clone().unwrap_or_else(|| {
|
||||
// url 模式无 base64 时 provider 层兜底(commands 层应已预拉):
|
||||
// 发空 data 会让 Anthropic 报错,warn 提示但不阻塞。
|
||||
// 完整性兜底:当前 url 模式不可达(前端 Phase2b 只产 base64 图片片)。
|
||||
// 若未来接入 url 图片输入而 commands 层未补 url→base64 预拉,
|
||||
// 此处会发空 data 致 Anthropic 400,warn 留痕但不阻塞(避免静默吞数据)。
|
||||
if url.is_some() {
|
||||
warn!(
|
||||
url = ?url,
|
||||
"Anthropic user 消息含 Image(url) 但未预拉 base64,将发空 data(commands 层应回填 base64)"
|
||||
"Anthropic user 消息含 Image(url) 但 base64 缺失,将发空 data(commands 层未补 url→base64 预拉)"
|
||||
);
|
||||
}
|
||||
String::new()
|
||||
|
||||
@@ -332,7 +332,12 @@ impl OpenAICompatProvider {
|
||||
format!("data:{};base64,{}", mt, b)
|
||||
}
|
||||
(None, Some(u), _) => u,
|
||||
// 兜底:缺数据时退化为占位,避免发空 url 触发 400
|
||||
// 完整性兜底:当前 image_base64 构造器强制 media_type:Some,
|
||||
// image_url 构造器提供 url:Some,二者分别命中上两个分支;
|
||||
// 此分支仅在 parts 来源被外部直接构造且字段均缺时才可达
|
||||
//(如 url:None+base64:None 或 base64:Some+media_type:None)。
|
||||
// 退化为空串(OpenAI 对空 image_url.url 会 400),
|
||||
// 由调用方保证 parts 合法性,provider 层不做静默伪造。
|
||||
_ => String::new(),
|
||||
};
|
||||
serde_json::json!({
|
||||
|
||||
@@ -101,7 +101,7 @@ pub fn get_provider_secret(id: &str) -> Option<String> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 消费点用:解析 provider 真实密钥 — keyring 优先,fallback DB.api_key(兼容未迁移老库)
|
||||
/// 消费点用:解析 provider 真实密钥 — DB 优先,fallback keyring(兼容未迁移老库)
|
||||
pub fn resolve_provider_secret(record: &AiProviderRecord) -> String {
|
||||
if !record.api_key.is_empty() {
|
||||
return record.api_key.clone();
|
||||
|
||||
Reference in New Issue
Block a user