mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-11 01:51:34 -10:00
Keep uncatalogued DeepSeek models on Chat
Remove version-prefix Responses inference while preserving exact catalog protocols. Unknown preview IDs retain their wire model and Chat pass-through; this adds no capability, pricing, context or output-limit claims. Config library: 684 passed, 0 failed, 1 ignored. Restoring the old resolver makes the exact-preview regression fail 0 passed / 1 failed; restoring the fix passes 1 / 0. Config production and TUI test metadata compilation pass; TUI executable acceptance remains for the root integration gate. Formatting and diff checks pass. No provider inference or OS action performed.
This commit is contained in:
1 parent
647922b224
commit
a4578184d8
3 files changed
+82
-23
No files matched your search
@@ -250,18 +250,8 @@ impl RouteResolver {
|
||||
require_catalog_match,
|
||||
)?
|
||||
};
|
||||
if provider_kind == ProviderKind::Deepseek {
|
||||
if custom_endpoint {
|
||||
selected.endpoint_key = "chat".to_string();
|
||||
} else if selected.canonical_model.is_none()
|
||||
&& deepseek_versioned_model_prefers_responses(selected.wire_model_id.as_str())
|
||||
{
|
||||
// DeepSeek introduced its native agent wire on V4 Flash. Keep
|
||||
// exact catalog rows authoritative (notably V4 Pro => Chat),
|
||||
// while allowing future versioned direct models to adopt the
|
||||
// new Responses surface without a Codewhale release.
|
||||
selected.endpoint_key = "responses".to_string();
|
||||
}
|
||||
if provider_kind == ProviderKind::Deepseek && custom_endpoint {
|
||||
selected.endpoint_key = "chat".to_string();
|
||||
}
|
||||
if custom_endpoint && !endpoint_catalog_authoritative {
|
||||
// Capabilities and pricing belong to the exact provider endpoint
|
||||
@@ -644,15 +634,6 @@ fn request_uses_custom_endpoint(
|
||||
.is_some_and(|base_url| provider_preserves_custom_base_url_model(descriptor.kind, base_url))
|
||||
}
|
||||
|
||||
fn deepseek_versioned_model_prefers_responses(model: &str) -> bool {
|
||||
model
|
||||
.trim()
|
||||
.to_ascii_lowercase()
|
||||
.strip_prefix("deepseek-v")
|
||||
.and_then(|suffix| suffix.chars().next())
|
||||
.is_some_and(|first| first.is_ascii_digit())
|
||||
}
|
||||
|
||||
/// True when `base_url` is an `http://` endpoint whose host is NOT loopback
|
||||
/// (#1519). Such an endpoint sends credentials in plaintext over the network;
|
||||
/// loopback (`localhost` / `127.0.0.1` / `::1`) is exempt because local
|
||||
|
||||
@@ -415,8 +415,8 @@ fn resolver_routes_only_official_deepseek_flash_over_responses() {
|
||||
Some("deepseek-v5-future"),
|
||||
))
|
||||
.expect("unknown future model preserves direct-provider pass-through");
|
||||
assert_eq!(future.protocol(), RequestProtocol::Responses);
|
||||
assert_eq!(future.endpoint().endpoint_key, "responses");
|
||||
assert_eq!(future.protocol(), RequestProtocol::ChatCompletions);
|
||||
assert_eq!(future.endpoint().endpoint_key, "chat");
|
||||
|
||||
let legacy_unknown = resolver
|
||||
.resolve(&req(
|
||||
@@ -444,6 +444,34 @@ fn resolver_routes_only_official_deepseek_flash_over_responses() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolver_uncatalogued_deepseek_preview_keeps_chat_and_verbatim_model() {
|
||||
let model = "deepseek-v4.1-flash-expires-on-0910";
|
||||
for base_url in [
|
||||
"https://api.deepseek.com",
|
||||
"https://api.deepseek.com/v1",
|
||||
"https://api.deepseek.com/beta",
|
||||
] {
|
||||
let route = RouteResolver::new()
|
||||
.resolve(&RouteRequest {
|
||||
base_url_override: Some(base_url.to_string()),
|
||||
..req(Some(ProviderKind::Deepseek), Some(model))
|
||||
})
|
||||
.expect("uncatalogued preview keeps direct-provider pass-through");
|
||||
assert_eq!(route.provider_kind(), ProviderKind::Deepseek);
|
||||
assert_eq!(route.wire_model_id().as_str(), model);
|
||||
assert!(
|
||||
route.canonical_model().is_none(),
|
||||
"no fallback to a known model"
|
||||
);
|
||||
assert_eq!(route.protocol(), RequestProtocol::ChatCompletions);
|
||||
assert_eq!(route.endpoint().endpoint_key, "chat");
|
||||
assert_eq!(route.endpoint().base_url, base_url);
|
||||
assert_eq!(route.capabilities().image_input, CapabilityState::Unknown);
|
||||
assert_eq!(route.limits().output_tokens, None);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolver_routes_deepseek_vision_exp_over_chat_with_image_input() {
|
||||
for base_url_override in [
|
||||
|
||||
@@ -13178,6 +13178,56 @@ mod tests {
|
||||
assert_eq!(prepared.body["reasoning"]["effort"], "max");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uncatalogued_deepseek_preview_binds_chat_request_without_model_fallback() {
|
||||
let model = "deepseek-v4.1-flash-expires-on-0910";
|
||||
let (_config, route) = deepseek_route_for_test("https://api.deepseek.com", model);
|
||||
assert_eq!(route.candidate.protocol(), WireFormat::ChatCompletions);
|
||||
assert_eq!(route.candidate.wire_model_id().as_str(), model);
|
||||
assert!(route.candidate.canonical_model().is_none());
|
||||
|
||||
for client in [
|
||||
DeepSeekClient::new(&route.config).expect("preview client resolves"),
|
||||
DeepSeekClient::from_candidate(&route.config, &route.candidate)
|
||||
.expect("preview client binds the admitted candidate"),
|
||||
] {
|
||||
assert_eq!(client.wire_format, WireFormat::ChatCompletions);
|
||||
assert_eq!(client.default_model, model);
|
||||
let prepared = client
|
||||
.prepare_outbound_request(
|
||||
MessageRequest {
|
||||
model: model.to_string(),
|
||||
messages: vec![Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::Text {
|
||||
text: "hello".to_string(),
|
||||
cache_control: None,
|
||||
}],
|
||||
}],
|
||||
max_tokens: 64,
|
||||
system: None,
|
||||
tools: None,
|
||||
tool_choice: None,
|
||||
metadata: None,
|
||||
thinking: None,
|
||||
reasoning_effort: None,
|
||||
stream: Some(true),
|
||||
temperature: None,
|
||||
top_p: None,
|
||||
},
|
||||
true,
|
||||
)
|
||||
.expect("preview Chat request prepares");
|
||||
assert_eq!(prepared.dialect, WireDialect::ChatCompletions);
|
||||
assert_eq!(
|
||||
prepared.endpoint.url,
|
||||
"https://api.deepseek.com/chat/completions"
|
||||
);
|
||||
assert_eq!(prepared.body["model"], model);
|
||||
assert_eq!(prepared.body["messages"][0]["content"], "hello");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rebinding_a_chat_bound_client_for_flash_switches_to_responses() {
|
||||
// #5042: fleet dispatch binds the child client before the profile
|
||||
|
||||
Reference in new issue
Block a user