Remove deprecated Flash preview and legacy MTP
This commit is contained in:
@@ -126,13 +126,10 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *model_path;
|
const char *model_path;
|
||||||
const char *mtp_path;
|
|
||||||
ds4_backend backend;
|
ds4_backend backend;
|
||||||
int n_threads;
|
int n_threads;
|
||||||
int context_size;
|
int context_size;
|
||||||
uint32_t prefill_chunk;
|
uint32_t prefill_chunk;
|
||||||
int mtp_draft_tokens;
|
|
||||||
float mtp_margin;
|
|
||||||
float dspark_confidence_threshold;
|
float dspark_confidence_threshold;
|
||||||
const char *directional_steering_file;
|
const char *directional_steering_file;
|
||||||
const char *expert_profile_path;
|
const char *expert_profile_path;
|
||||||
@@ -451,8 +448,6 @@ int ds4_session_ctx(ds4_session *s);
|
|||||||
int ds4_session_prefill_cap(ds4_session *s);
|
int ds4_session_prefill_cap(ds4_session *s);
|
||||||
int ds4_engine_routed_quant_bits(ds4_engine *e);
|
int ds4_engine_routed_quant_bits(ds4_engine *e);
|
||||||
bool ds4_engine_has_output_head(ds4_engine *e);
|
bool ds4_engine_has_output_head(ds4_engine *e);
|
||||||
bool ds4_engine_has_mtp(ds4_engine *e);
|
|
||||||
int ds4_engine_mtp_draft_tokens(ds4_engine *e);
|
|
||||||
const ds4_tokens *ds4_session_tokens(ds4_session *s);
|
const ds4_tokens *ds4_session_tokens(ds4_session *s);
|
||||||
|
|
||||||
/* Low-level graph slice entry points used by distributed inference. The
|
/* Low-level graph slice entry points used by distributed inference. The
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ def post(path, payload):
|
|||||||
first = post(
|
first = post(
|
||||||
"/v1/chat/completions",
|
"/v1/chat/completions",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"messages": [{"role": "user", "content": prompt}],
|
"messages": [{"role": "user", "content": prompt}],
|
||||||
"tools": [chat_tool],
|
"tools": [chat_tool],
|
||||||
"reasoning_effort": "none",
|
"reasoning_effort": "none",
|
||||||
@@ -58,7 +58,7 @@ print("chat-first", json.dumps(first["usage"], separators=(",", ":")))
|
|||||||
second = post(
|
second = post(
|
||||||
"/v1/chat/completions",
|
"/v1/chat/completions",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"messages": [
|
"messages": [
|
||||||
{"role": "user", "content": prompt},
|
{"role": "user", "content": prompt},
|
||||||
{"role": "assistant", "content": "", "tool_calls": [call]},
|
{"role": "assistant", "content": "", "tool_calls": [call]},
|
||||||
@@ -79,7 +79,7 @@ print("chat", json.dumps(second, separators=(",", ":")))
|
|||||||
first = post(
|
first = post(
|
||||||
"/v1/messages",
|
"/v1/messages",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"messages": [{"role": "user", "content": prompt}],
|
"messages": [{"role": "user", "content": prompt}],
|
||||||
"tools": [anthropic_tool],
|
"tools": [anthropic_tool],
|
||||||
"thinking": {"type": "disabled"},
|
"thinking": {"type": "disabled"},
|
||||||
@@ -92,7 +92,7 @@ print("anthropic-first", json.dumps(first["usage"], separators=(",", ":")))
|
|||||||
second = post(
|
second = post(
|
||||||
"/v1/messages",
|
"/v1/messages",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"messages": [
|
"messages": [
|
||||||
{"role": "user", "content": prompt},
|
{"role": "user", "content": prompt},
|
||||||
{"role": "assistant", "content": [call]},
|
{"role": "assistant", "content": [call]},
|
||||||
@@ -118,7 +118,7 @@ print("anthropic", json.dumps(second, separators=(",", ":")))
|
|||||||
first = post(
|
first = post(
|
||||||
"/v1/responses",
|
"/v1/responses",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"input": prompt,
|
"input": prompt,
|
||||||
"tools": [responses_tool],
|
"tools": [responses_tool],
|
||||||
"reasoning": {"effort": "none"},
|
"reasoning": {"effort": "none"},
|
||||||
@@ -131,7 +131,7 @@ print("responses-first", json.dumps(first["usage"], separators=(",", ":")))
|
|||||||
second = post(
|
second = post(
|
||||||
"/v1/responses",
|
"/v1/responses",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"input": [
|
"input": [
|
||||||
{
|
{
|
||||||
"type": "message",
|
"type": "message",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ cases = [
|
|||||||
"chat",
|
"chat",
|
||||||
"/v1/chat/completions",
|
"/v1/chat/completions",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"messages": [
|
"messages": [
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
@@ -42,7 +42,7 @@ cases = [
|
|||||||
"anthropic",
|
"anthropic",
|
||||||
"/v1/messages",
|
"/v1/messages",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"messages": [
|
"messages": [
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
@@ -65,7 +65,7 @@ cases = [
|
|||||||
"responses",
|
"responses",
|
||||||
"/v1/responses",
|
"/v1/responses",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"input": "Call echo with text hi. Do not answer normally.",
|
"input": "Call echo with text hi. Do not answer normally.",
|
||||||
"tools": [
|
"tools": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ cases = [
|
|||||||
"chat",
|
"chat",
|
||||||
"/v1/chat/completions",
|
"/v1/chat/completions",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"messages": [{"role": "user", "content": prompt}],
|
"messages": [{"role": "user", "content": prompt}],
|
||||||
"reasoning_effort": "low",
|
"reasoning_effort": "low",
|
||||||
"temperature": 0,
|
"temperature": 0,
|
||||||
@@ -22,7 +22,7 @@ cases = [
|
|||||||
"anthropic",
|
"anthropic",
|
||||||
"/v1/messages",
|
"/v1/messages",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"messages": [{"role": "user", "content": prompt}],
|
"messages": [{"role": "user", "content": prompt}],
|
||||||
"thinking": {"type": "enabled", "budget_tokens": 64},
|
"thinking": {"type": "enabled", "budget_tokens": 64},
|
||||||
"output_config": {"effort": "low"},
|
"output_config": {"effort": "low"},
|
||||||
@@ -34,7 +34,7 @@ cases = [
|
|||||||
"responses",
|
"responses",
|
||||||
"/v1/responses",
|
"/v1/responses",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"input": prompt,
|
"input": prompt,
|
||||||
"reasoning": {"effort": "low", "summary": "auto"},
|
"reasoning": {"effort": "low", "summary": "auto"},
|
||||||
"temperature": 0,
|
"temperature": 0,
|
||||||
|
|||||||
@@ -12,9 +12,8 @@ HARDWARE_TESTS = (
|
|||||||
"flash_resident_and_ssd_streaming_choose_the_same_tokens",
|
"flash_resident_and_ssd_streaming_choose_the_same_tokens",
|
||||||
"flash_ssd_streaming_maps_batched_prefill_layers",
|
"flash_ssd_streaming_maps_batched_prefill_layers",
|
||||||
"resident_multi_session_switching_preserves_each_kv_frontier",
|
"resident_multi_session_switching_preserves_each_kv_frontier",
|
||||||
"legacy_mtp_runs_a_target_owned_greedy_cycle",
|
|
||||||
"dspark_runs_a_target_owned_greedy_cycle",
|
"dspark_runs_a_target_owned_greedy_cycle",
|
||||||
"ssd_streaming_supports_legacy_mtp_and_dspark",
|
"ssd_streaming_supports_dspark",
|
||||||
"directional_steering_matches_the_ds4_token_oracle",
|
"directional_steering_matches_the_ds4_token_oracle",
|
||||||
"resident_and_streamed_glm_match_ds4_decode_oracles",
|
"resident_and_streamed_glm_match_ds4_decode_oracles",
|
||||||
"streamed_glm_uses_ds4_indexed_prefill_for_long_prompts",
|
"streamed_glm_uses_ds4_indexed_prefill_for_long_prompts",
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ def chat(base_url, prompt):
|
|||||||
base_url,
|
base_url,
|
||||||
"/v1/chat/completions",
|
"/v1/chat/completions",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"messages": [{"role": "user", "content": prompt}],
|
"messages": [{"role": "user", "content": prompt}],
|
||||||
"reasoning_effort": "none",
|
"reasoning_effort": "none",
|
||||||
"temperature": 0,
|
"temperature": 0,
|
||||||
@@ -50,7 +50,7 @@ def anthropic(base_url, prompt):
|
|||||||
base_url,
|
base_url,
|
||||||
"/v1/messages",
|
"/v1/messages",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"messages": [{"role": "user", "content": prompt}],
|
"messages": [{"role": "user", "content": prompt}],
|
||||||
"thinking": {"type": "disabled"},
|
"thinking": {"type": "disabled"},
|
||||||
"temperature": 0,
|
"temperature": 0,
|
||||||
@@ -69,7 +69,7 @@ def responses(base_url, prompt):
|
|||||||
base_url,
|
base_url,
|
||||||
"/v1/responses",
|
"/v1/responses",
|
||||||
{
|
{
|
||||||
"model": "deepseek-v4-flash",
|
"model": "deepseek-v4-flash-0731",
|
||||||
"input": prompt,
|
"input": prompt,
|
||||||
"reasoning": {"effort": "none"},
|
"reasoning": {"effort": "none"},
|
||||||
"temperature": 0,
|
"temperature": 0,
|
||||||
|
|||||||
20
src/agent.rs
20
src/agent.rs
@@ -3812,7 +3812,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn prompts_and_parsers_expose_the_reference_tool_set() {
|
fn prompts_and_parsers_expose_the_reference_tool_set() {
|
||||||
let prompt = system_prompt(ModelChoice::DeepSeekV4Flash, "extra", false);
|
let prompt = system_prompt(ModelChoice::DeepSeekV4Flash0731, "extra", false);
|
||||||
for name in [
|
for name in [
|
||||||
"google_search",
|
"google_search",
|
||||||
"visit_page",
|
"visit_page",
|
||||||
@@ -3830,11 +3830,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
assert!(prompt.ends_with("extra"));
|
assert!(prompt.ends_with("extra"));
|
||||||
assert!(
|
assert!(
|
||||||
system_prompt_reminder(ModelChoice::DeepSeekV4Flash, false)
|
system_prompt_reminder(ModelChoice::DeepSeekV4Flash0731, false)
|
||||||
.contains("[System prompt reminder follows.]")
|
.contains("[System prompt reminder follows.]")
|
||||||
);
|
);
|
||||||
assert!(!prompt.contains("dev_brain_search"));
|
assert!(!prompt.contains("dev_brain_search"));
|
||||||
let dev_brain_prompt = system_prompt(ModelChoice::DeepSeekV4Flash, "", true);
|
let dev_brain_prompt = system_prompt(ModelChoice::DeepSeekV4Flash0731, "", true);
|
||||||
for name in ["dev_brain_info", "dev_brain_search", "dev_brain_validate"] {
|
for name in ["dev_brain_info", "dev_brain_search", "dev_brain_validate"] {
|
||||||
assert!(dev_brain_prompt.contains(name));
|
assert!(dev_brain_prompt.contains(name));
|
||||||
}
|
}
|
||||||
@@ -3851,12 +3851,12 @@ mod tests {
|
|||||||
assert_eq!(calls[0].arguments["path"], "src/main.rs");
|
assert_eq!(calls[0].arguments["path"], "src/main.rs");
|
||||||
|
|
||||||
let dsml = "done<|DSML|tool_calls><|DSML|invoke name=\"read\"><|DSML|parameter name=\"path\" string=\"true\">src/main.rs</|DSML|parameter></|DSML|invoke></|DSML|tool_calls>";
|
let dsml = "done<|DSML|tool_calls><|DSML|invoke name=\"read\"><|DSML|parameter name=\"path\" string=\"true\">src/main.rs</|DSML|parameter></|DSML|invoke></|DSML|tool_calls>";
|
||||||
let (visible, calls) = parse_tool_calls(ModelChoice::DeepSeekV4Flash, dsml).unwrap();
|
let (visible, calls) = parse_tool_calls(ModelChoice::DeepSeekV4Flash0731, dsml).unwrap();
|
||||||
assert_eq!(visible, "done");
|
assert_eq!(visible, "done");
|
||||||
assert_eq!(calls[0].arguments["path"], "src/main.rs");
|
assert_eq!(calls[0].arguments["path"], "src/main.rs");
|
||||||
assert!(
|
assert!(
|
||||||
parse_tool_calls(
|
parse_tool_calls(
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
"<|DSML|tool_calls><|DSML|invoke name=\"read\">"
|
"<|DSML|tool_calls><|DSML|invoke name=\"read\">"
|
||||||
)
|
)
|
||||||
.is_err()
|
.is_err()
|
||||||
@@ -4073,12 +4073,12 @@ mod tests {
|
|||||||
assert!(validate_tool_call(&calls[0]).is_ok());
|
assert!(validate_tool_call(&calls[0]).is_ok());
|
||||||
|
|
||||||
let dsml = "<|DSML|tool_calls><|DSML|invoke name=\"read\"><|DSML|parameter name=\"path\" string=\"true\">README.md</|DSML|parameter><|DSML|parameter name=\"whole\" string=\"false\">true</|DSML|parameter></|DSML|invoke></|DSML|tool_calls>";
|
let dsml = "<|DSML|tool_calls><|DSML|invoke name=\"read\"><|DSML|parameter name=\"path\" string=\"true\">README.md</|DSML|parameter><|DSML|parameter name=\"whole\" string=\"false\">true</|DSML|parameter></|DSML|invoke></|DSML|tool_calls>";
|
||||||
let (_, calls) = parse_tool_calls(ModelChoice::DeepSeekV4Flash, dsml).unwrap();
|
let (_, calls) = parse_tool_calls(ModelChoice::DeepSeekV4Flash0731, dsml).unwrap();
|
||||||
assert_eq!(calls[0].arguments["whole"], true);
|
assert_eq!(calls[0].arguments["whole"], true);
|
||||||
assert!(validate_tool_call(&calls[0]).is_ok());
|
assert!(validate_tool_call(&calls[0]).is_ok());
|
||||||
|
|
||||||
let quoted = "<|DSML|tool_calls><|DSML|invoke name=\"read\"><|DSML|parameter name=\"path\" string=\"true\">README.md</|DSML|parameter><|DSML|parameter name=\"max_lines\" string=\"true\">20</|DSML|parameter></|DSML|invoke></|DSML|tool_calls>";
|
let quoted = "<|DSML|tool_calls><|DSML|invoke name=\"read\"><|DSML|parameter name=\"path\" string=\"true\">README.md</|DSML|parameter><|DSML|parameter name=\"max_lines\" string=\"true\">20</|DSML|parameter></|DSML|invoke></|DSML|tool_calls>";
|
||||||
let (_, calls) = parse_tool_calls(ModelChoice::DeepSeekV4Flash, quoted).unwrap();
|
let (_, calls) = parse_tool_calls(ModelChoice::DeepSeekV4Flash0731, quoted).unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
validation_error(&calls[0])
|
validation_error(&calls[0])
|
||||||
.render()
|
.render()
|
||||||
@@ -4101,7 +4101,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ralph_report_schemas_are_child_only_and_parse_for_both_models() {
|
fn ralph_report_schemas_are_child_only_and_parse_for_both_models() {
|
||||||
for model in [ModelChoice::DeepSeekV4Flash, ModelChoice::Glm52] {
|
for model in [ModelChoice::DeepSeekV4Flash0731, ModelChoice::Glm52] {
|
||||||
let parent = system_prompt(model, "", false);
|
let parent = system_prompt(model, "", false);
|
||||||
let child = ralph_system_prompt(model, "", false);
|
let child = ralph_system_prompt(model, "", false);
|
||||||
assert!(parent.contains("\"name\":\"ralph\""));
|
assert!(parent.contains("\"name\":\"ralph\""));
|
||||||
@@ -4118,7 +4118,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let dsml = "<|DSML|tool_calls><|DSML|invoke name=\"ralph_report\"><|DSML|parameter name=\"status\" string=\"true\">continue</|DSML|parameter><|DSML|parameter name=\"summary\" string=\"true\">Inspected the failing test.</|DSML|parameter><|DSML|parameter name=\"evidence\" string=\"true\">failure reproduced</|DSML|parameter><|DSML|parameter name=\"next_steps\" string=\"true\">Fix the shared parser.</|DSML|parameter><|DSML|parameter name=\"blocker\" string=\"true\"></|DSML|parameter></|DSML|invoke></|DSML|tool_calls>";
|
let dsml = "<|DSML|tool_calls><|DSML|invoke name=\"ralph_report\"><|DSML|parameter name=\"status\" string=\"true\">continue</|DSML|parameter><|DSML|parameter name=\"summary\" string=\"true\">Inspected the failing test.</|DSML|parameter><|DSML|parameter name=\"evidence\" string=\"true\">failure reproduced</|DSML|parameter><|DSML|parameter name=\"next_steps\" string=\"true\">Fix the shared parser.</|DSML|parameter><|DSML|parameter name=\"blocker\" string=\"true\"></|DSML|parameter></|DSML|invoke></|DSML|tool_calls>";
|
||||||
let (_, calls) = parse_tool_calls(ModelChoice::DeepSeekV4Flash, dsml).unwrap();
|
let (_, calls) = parse_tool_calls(ModelChoice::DeepSeekV4Flash0731, dsml).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ralph_report(&calls[0]).unwrap().status,
|
ralph_report(&calls[0]).unwrap().status,
|
||||||
RalphStatus::Continue
|
RalphStatus::Continue
|
||||||
@@ -4700,7 +4700,7 @@ mod tests {
|
|||||||
<|DSML|invoke name="read"><|DSML|parameter name="path" string="true">README.md</|DSML|parameter></|DSML|invoke>
|
<|DSML|invoke name="read"><|DSML|parameter name="path" string="true">README.md</|DSML|parameter></|DSML|invoke>
|
||||||
</|DSML|tool_calls>"#;
|
</|DSML|tool_calls>"#;
|
||||||
let cards = stored_tool_cards(
|
let cards = stored_tool_cards(
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
assistant,
|
assistant,
|
||||||
None,
|
None,
|
||||||
&[Some("Only reads the working directory.".into()), None],
|
&[Some("Only reads the working directory.".into()), None],
|
||||||
|
|||||||
@@ -374,7 +374,6 @@ pub(crate) enum Message {
|
|||||||
PreferenceGenerationReasoningChanged(ReasoningMode),
|
PreferenceGenerationReasoningChanged(ReasoningMode),
|
||||||
PreferenceAccelerationModelChanged(ModelChoice),
|
PreferenceAccelerationModelChanged(ModelChoice),
|
||||||
PreferencePermissionModeChanged(PermissionMode),
|
PreferencePermissionModeChanged(PermissionMode),
|
||||||
PreferenceLegacyMtpChanged(bool),
|
|
||||||
PreferenceDsparkChanged(bool),
|
PreferenceDsparkChanged(bool),
|
||||||
PreferenceTimeoutChanged(String),
|
PreferenceTimeoutChanged(String),
|
||||||
PreferenceA2uiChanged(bool),
|
PreferenceA2uiChanged(bool),
|
||||||
@@ -418,8 +417,6 @@ pub(crate) enum Message {
|
|||||||
PreferencePrefillChunkChanged(String),
|
PreferencePrefillChunkChanged(String),
|
||||||
PreferenceQualityChanged(bool),
|
PreferenceQualityChanged(bool),
|
||||||
PreferenceWarmWeightsChanged(bool),
|
PreferenceWarmWeightsChanged(bool),
|
||||||
PreferenceMtpDraftChanged(String),
|
|
||||||
PreferenceMtpMarginChanged(String),
|
|
||||||
PreferenceGlmMtpChanged(bool),
|
PreferenceGlmMtpChanged(bool),
|
||||||
PreferenceGlmMtpTimingChanged(bool),
|
PreferenceGlmMtpTimingChanged(bool),
|
||||||
PreferenceDsparkConfidenceChanged(String),
|
PreferenceDsparkConfidenceChanged(String),
|
||||||
@@ -2807,7 +2804,6 @@ mod tests {
|
|||||||
shortcut(tab, keyboard::Modifiers::SHIFT),
|
shortcut(tab, keyboard::Modifiers::SHIFT),
|
||||||
Some(Message::FocusPrevious)
|
Some(Message::FocusPrevious)
|
||||||
));
|
));
|
||||||
assert!(ModelChoice::DeepSeekV4Flash.supports_dspark());
|
|
||||||
assert!(ModelChoice::DeepSeekV4Flash0731.supports_dspark());
|
assert!(ModelChoice::DeepSeekV4Flash0731.supports_dspark());
|
||||||
assert!(!ModelChoice::DeepSeekV4Pro.supports_dspark());
|
assert!(!ModelChoice::DeepSeekV4Pro.supports_dspark());
|
||||||
assert!(!ModelChoice::Glm52.supports_dspark());
|
assert!(!ModelChoice::Glm52.supports_dspark());
|
||||||
@@ -2960,7 +2956,7 @@ EOF</|DSML|parameter></|DSML|invoke>
|
|||||||
assistant.tool_approval_reasons = vec![Some("This only prints text.".into())];
|
assistant.tool_approval_reasons = vec![Some("This only prints text.".into())];
|
||||||
let exported = export_markdown(
|
let exported = export_markdown(
|
||||||
"A chat",
|
"A chat",
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
&[
|
&[
|
||||||
message(false, false, true, "private"),
|
message(false, false, true, "private"),
|
||||||
message(true, false, false, "hello"),
|
message(true, false, false, "hello"),
|
||||||
|
|||||||
@@ -2612,11 +2612,11 @@ mod tests {
|
|||||||
</|DSML|tool_calls>"#;
|
</|DSML|tool_calls>"#;
|
||||||
let malformed = assistant(Some(call), "");
|
let malformed = assistant(Some(call), "");
|
||||||
assert!(has_misplaced_tool_call(
|
assert!(has_misplaced_tool_call(
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
&malformed
|
&malformed
|
||||||
));
|
));
|
||||||
assert!(!has_misplaced_tool_call(
|
assert!(!has_misplaced_tool_call(
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
&assistant(Some(call), "I was only discussing this call.")
|
&assistant(Some(call), "I was only discussing this call.")
|
||||||
));
|
));
|
||||||
assert!(is_empty_response(&assistant(Some(""), "")));
|
assert!(is_empty_response(&assistant(Some(""), "")));
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ pub(super) struct PreferenceDraft {
|
|||||||
generation_profiles: BTreeMap<ModelChoice, BTreeMap<ReasoningMode, GenerationPreferences>>,
|
generation_profiles: BTreeMap<ModelChoice, BTreeMap<ReasoningMode, GenerationPreferences>>,
|
||||||
model_profiles: BTreeMap<ModelChoice, ModelPreferences>,
|
model_profiles: BTreeMap<ModelChoice, ModelPreferences>,
|
||||||
pub(super) default_permission_mode: PermissionMode,
|
pub(super) default_permission_mode: PermissionMode,
|
||||||
pub(super) legacy_mtp_enabled: bool,
|
|
||||||
pub(super) dspark_enabled: bool,
|
pub(super) dspark_enabled: bool,
|
||||||
pub(super) idle_timeout_minutes: String,
|
pub(super) idle_timeout_minutes: String,
|
||||||
pub(super) a2ui_enabled: bool,
|
pub(super) a2ui_enabled: bool,
|
||||||
@@ -39,8 +38,6 @@ pub(super) struct PreferenceDraft {
|
|||||||
pub(super) prefill_chunk: String,
|
pub(super) prefill_chunk: String,
|
||||||
pub(super) quality: bool,
|
pub(super) quality: bool,
|
||||||
pub(super) warm_weights: bool,
|
pub(super) warm_weights: bool,
|
||||||
pub(super) mtp_draft_tokens: String,
|
|
||||||
pub(super) mtp_margin: String,
|
|
||||||
pub(super) glm_mtp: bool,
|
pub(super) glm_mtp: bool,
|
||||||
pub(super) glm_mtp_timing: bool,
|
pub(super) glm_mtp_timing: bool,
|
||||||
pub(super) dspark_confidence_threshold: String,
|
pub(super) dspark_confidence_threshold: String,
|
||||||
@@ -78,7 +75,6 @@ impl PreferenceDraft {
|
|||||||
generation_profiles: config.generation_profiles.clone(),
|
generation_profiles: config.generation_profiles.clone(),
|
||||||
model_profiles: config.model_profiles.clone(),
|
model_profiles: config.model_profiles.clone(),
|
||||||
default_permission_mode: config.default_permission_mode,
|
default_permission_mode: config.default_permission_mode,
|
||||||
legacy_mtp_enabled: speculative.legacy_mtp_enabled,
|
|
||||||
dspark_enabled: speculative.dspark_enabled,
|
dspark_enabled: speculative.dspark_enabled,
|
||||||
idle_timeout_minutes: config.idle_timeout_minutes.to_string(),
|
idle_timeout_minutes: config.idle_timeout_minutes.to_string(),
|
||||||
a2ui_enabled: config.a2ui_enabled,
|
a2ui_enabled: config.a2ui_enabled,
|
||||||
@@ -106,8 +102,6 @@ impl PreferenceDraft {
|
|||||||
prefill_chunk: optional_string(execution.prefill_chunk),
|
prefill_chunk: optional_string(execution.prefill_chunk),
|
||||||
quality: execution.quality,
|
quality: execution.quality,
|
||||||
warm_weights: execution.warm_weights,
|
warm_weights: execution.warm_weights,
|
||||||
mtp_draft_tokens: speculative.mtp_draft_tokens.to_string(),
|
|
||||||
mtp_margin: speculative.mtp_margin.to_string(),
|
|
||||||
glm_mtp: speculative.glm_mtp,
|
glm_mtp: speculative.glm_mtp,
|
||||||
glm_mtp_timing: speculative.glm_mtp_timing,
|
glm_mtp_timing: speculative.glm_mtp_timing,
|
||||||
dspark_confidence_threshold: optional_string(speculative.dspark_confidence_threshold),
|
dspark_confidence_threshold: optional_string(speculative.dspark_confidence_threshold),
|
||||||
@@ -217,9 +211,6 @@ impl PreferenceDraft {
|
|||||||
|
|
||||||
pub(super) fn speculative(&self) -> Result<SpeculativePreferences, String> {
|
pub(super) fn speculative(&self) -> Result<SpeculativePreferences, String> {
|
||||||
Ok(SpeculativePreferences {
|
Ok(SpeculativePreferences {
|
||||||
mtp_draft_tokens: parse_positive_i32("MTP draft tokens", &self.mtp_draft_tokens)?,
|
|
||||||
mtp_margin: parse_f32("MTP margin", &self.mtp_margin)?,
|
|
||||||
legacy_mtp_enabled: self.legacy_mtp_enabled,
|
|
||||||
glm_mtp: self.glm_mtp,
|
glm_mtp: self.glm_mtp,
|
||||||
glm_mtp_timing: self.glm_mtp_timing,
|
glm_mtp_timing: self.glm_mtp_timing,
|
||||||
dspark_enabled: self.dspark_enabled,
|
dspark_enabled: self.dspark_enabled,
|
||||||
@@ -262,10 +253,7 @@ impl PreferenceDraft {
|
|||||||
let speculative = profile.speculative;
|
let speculative = profile.speculative;
|
||||||
let ssd = profile.ssd;
|
let ssd = profile.ssd;
|
||||||
self.acceleration_model = model;
|
self.acceleration_model = model;
|
||||||
self.legacy_mtp_enabled = speculative.legacy_mtp_enabled;
|
|
||||||
self.dspark_enabled = speculative.dspark_enabled;
|
self.dspark_enabled = speculative.dspark_enabled;
|
||||||
self.mtp_draft_tokens = speculative.mtp_draft_tokens.to_string();
|
|
||||||
self.mtp_margin = speculative.mtp_margin.to_string();
|
|
||||||
self.glm_mtp = speculative.glm_mtp;
|
self.glm_mtp = speculative.glm_mtp;
|
||||||
self.glm_mtp_timing = speculative.glm_mtp_timing;
|
self.glm_mtp_timing = speculative.glm_mtp_timing;
|
||||||
self.dspark_confidence_threshold = optional_string(speculative.dspark_confidence_threshold);
|
self.dspark_confidence_threshold = optional_string(speculative.dspark_confidence_threshold);
|
||||||
@@ -374,13 +362,6 @@ fn parse_optional_f32(name: &str, value: &str) -> Result<Option<f32>, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_f32(name: &str, value: &str) -> Result<f32, String> {
|
|
||||||
value
|
|
||||||
.trim()
|
|
||||||
.parse()
|
|
||||||
.map_err(|_| format!("{name} must be a number."))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_optional_u64(name: &str, value: &str) -> Result<Option<u64>, String> {
|
fn parse_optional_u64(name: &str, value: &str) -> Result<Option<u64>, String> {
|
||||||
let value = value.trim();
|
let value = value.trim();
|
||||||
if value.is_empty() {
|
if value.is_empty() {
|
||||||
@@ -715,20 +696,6 @@ impl App {
|
|||||||
self.preference_draft.default_permission_mode = mode;
|
self.preference_draft.default_permission_mode = mode;
|
||||||
self.preference_error = None;
|
self.preference_error = None;
|
||||||
}
|
}
|
||||||
Message::PreferenceLegacyMtpChanged(enabled) => {
|
|
||||||
self.preference_draft.legacy_mtp_enabled = self
|
|
||||||
.preference_draft
|
|
||||||
.acceleration_model
|
|
||||||
.supports_legacy_mtp()
|
|
||||||
&& enabled;
|
|
||||||
if self.preference_draft.legacy_mtp_enabled {
|
|
||||||
self.preference_draft.dspark_enabled = false;
|
|
||||||
self.preference_draft.dspark_confidence_threshold.clear();
|
|
||||||
self.preference_draft.dspark_strict = false;
|
|
||||||
self.preference_draft.dspark_exact_sampling = false;
|
|
||||||
}
|
|
||||||
self.preference_error = None;
|
|
||||||
}
|
|
||||||
Message::PreferenceDsparkChanged(enabled) => {
|
Message::PreferenceDsparkChanged(enabled) => {
|
||||||
self.preference_draft.dspark_enabled =
|
self.preference_draft.dspark_enabled =
|
||||||
self.preference_draft.acceleration_model.supports_dspark() && enabled;
|
self.preference_draft.acceleration_model.supports_dspark() && enabled;
|
||||||
@@ -736,8 +703,6 @@ impl App {
|
|||||||
self.preference_draft.dspark_confidence_threshold.clear();
|
self.preference_draft.dspark_confidence_threshold.clear();
|
||||||
self.preference_draft.dspark_strict = false;
|
self.preference_draft.dspark_strict = false;
|
||||||
self.preference_draft.dspark_exact_sampling = false;
|
self.preference_draft.dspark_exact_sampling = false;
|
||||||
} else {
|
|
||||||
self.preference_draft.legacy_mtp_enabled = false;
|
|
||||||
}
|
}
|
||||||
self.preference_error = None;
|
self.preference_error = None;
|
||||||
}
|
}
|
||||||
@@ -884,14 +849,6 @@ impl App {
|
|||||||
self.preference_draft.warm_weights = value;
|
self.preference_draft.warm_weights = value;
|
||||||
self.preference_error = None;
|
self.preference_error = None;
|
||||||
}
|
}
|
||||||
Message::PreferenceMtpDraftChanged(value) => {
|
|
||||||
self.preference_draft.mtp_draft_tokens = value;
|
|
||||||
self.preference_error = None;
|
|
||||||
}
|
|
||||||
Message::PreferenceMtpMarginChanged(value) => {
|
|
||||||
self.preference_draft.mtp_margin = value;
|
|
||||||
self.preference_error = None;
|
|
||||||
}
|
|
||||||
Message::PreferenceGlmMtpChanged(value) => {
|
Message::PreferenceGlmMtpChanged(value) => {
|
||||||
self.preference_draft.glm_mtp =
|
self.preference_draft.glm_mtp =
|
||||||
self.preference_draft.acceleration_model == ModelChoice::Glm52 && value;
|
self.preference_draft.acceleration_model == ModelChoice::Glm52 && value;
|
||||||
@@ -918,7 +875,6 @@ impl App {
|
|||||||
.is_empty()
|
.is_empty()
|
||||||
{
|
{
|
||||||
self.preference_draft.dspark_enabled = true;
|
self.preference_draft.dspark_enabled = true;
|
||||||
self.preference_draft.legacy_mtp_enabled = false;
|
|
||||||
}
|
}
|
||||||
self.preference_error = None;
|
self.preference_error = None;
|
||||||
}
|
}
|
||||||
@@ -927,7 +883,6 @@ impl App {
|
|||||||
self.preference_draft.acceleration_model.supports_dspark() && value;
|
self.preference_draft.acceleration_model.supports_dspark() && value;
|
||||||
if self.preference_draft.dspark_strict {
|
if self.preference_draft.dspark_strict {
|
||||||
self.preference_draft.dspark_enabled = true;
|
self.preference_draft.dspark_enabled = true;
|
||||||
self.preference_draft.legacy_mtp_enabled = false;
|
|
||||||
}
|
}
|
||||||
self.preference_error = None;
|
self.preference_error = None;
|
||||||
}
|
}
|
||||||
@@ -936,7 +891,6 @@ impl App {
|
|||||||
self.preference_draft.acceleration_model.supports_dspark() && value;
|
self.preference_draft.acceleration_model.supports_dspark() && value;
|
||||||
if self.preference_draft.dspark_exact_sampling {
|
if self.preference_draft.dspark_exact_sampling {
|
||||||
self.preference_draft.dspark_enabled = true;
|
self.preference_draft.dspark_enabled = true;
|
||||||
self.preference_draft.legacy_mtp_enabled = false;
|
|
||||||
}
|
}
|
||||||
self.preference_error = None;
|
self.preference_error = None;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,6 @@ use iced::widget::column;
|
|||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub(super) fn preferences_panel(&self) -> Element<'_, Message> {
|
pub(super) fn preferences_panel(&self) -> Element<'_, Message> {
|
||||||
let legacy_mtp_toggle: Option<fn(bool) -> Message> = self
|
|
||||||
.preference_draft
|
|
||||||
.acceleration_model
|
|
||||||
.supports_legacy_mtp()
|
|
||||||
.then_some(Message::PreferenceLegacyMtpChanged);
|
|
||||||
let legacy_mtp = hint(
|
|
||||||
toggle(self.preference_draft.legacy_mtp_enabled)
|
|
||||||
.label("Enable legacy MTP for this model")
|
|
||||||
.on_toggle_maybe(legacy_mtp_toggle),
|
|
||||||
"Uses the managed one-stage MTP support GGUF. The target model verifies every drafted token; it is mutually exclusive with DSpark.",
|
|
||||||
);
|
|
||||||
let dspark_toggle: Option<fn(bool) -> Message> = self
|
let dspark_toggle: Option<fn(bool) -> Message> = self
|
||||||
.preference_draft
|
.preference_draft
|
||||||
.acceleration_model
|
.acceleration_model
|
||||||
@@ -131,7 +120,7 @@ impl App {
|
|||||||
|engine| engine.artifacts.model.display().to_string(),
|
|engine| engine.artifacts.model.display().to_string(),
|
||||||
),
|
),
|
||||||
engine
|
engine
|
||||||
.and_then(|engine| engine.artifacts.mtp.as_ref())
|
.and_then(|engine| engine.artifacts.support.as_ref())
|
||||||
.map_or_else(String::new, |path| format!(
|
.map_or_else(String::new, |path| format!(
|
||||||
" • support: {}",
|
" • support: {}",
|
||||||
path.display()
|
path.display()
|
||||||
@@ -602,18 +591,6 @@ impl App {
|
|||||||
.spacing(12)
|
.spacing(12)
|
||||||
.align_y(Alignment::Center),
|
.align_y(Alignment::Center),
|
||||||
text("SPECULATIVE DECODING").size(11).color(muted_text()),
|
text("SPECULATIVE DECODING").size(11).color(muted_text()),
|
||||||
preference_input_row(
|
|
||||||
"MTP draft tokens",
|
|
||||||
"How many tokens the multi-token-prediction head guesses ahead for the main model to check in a single pass. More drafting pays off on predictable text and is wasted work on surprising text; the engine caps it at 16.",
|
|
||||||
text_input("1", &self.preference_draft.mtp_draft_tokens)
|
|
||||||
.on_input(Message::PreferenceMtpDraftChanged),
|
|
||||||
),
|
|
||||||
preference_input_row(
|
|
||||||
"MTP verifier margin",
|
|
||||||
"How much more likely the main model must find a drafted token before accepting it. A high margin accepts few drafts and stays close to plain decoding; a low one accepts more and rolls back more often.",
|
|
||||||
text_input("3", &self.preference_draft.mtp_margin)
|
|
||||||
.on_input(Message::PreferenceMtpMarginChanged),
|
|
||||||
),
|
|
||||||
hint(
|
hint(
|
||||||
toggle(self.preference_draft.glm_mtp)
|
toggle(self.preference_draft.glm_mtp)
|
||||||
.label("Enable integrated GLM MTP")
|
.label("Enable integrated GLM MTP")
|
||||||
@@ -626,7 +603,6 @@ impl App {
|
|||||||
.on_toggle_maybe(glm_mtp_timing_toggle),
|
.on_toggle_maybe(glm_mtp_timing_toggle),
|
||||||
"Records per-stage timings of the speculative path to the log, to show where the acceleration actually goes. A diagnostic aid that costs a little throughput.",
|
"Records per-stage timings of the speculative path to the log, to show where the acceleration actually goes. A diagnostic aid that costs a little throughput.",
|
||||||
),
|
),
|
||||||
legacy_mtp,
|
|
||||||
dspark,
|
dspark,
|
||||||
preference_input_row(
|
preference_input_row(
|
||||||
"DSpark confidence threshold",
|
"DSpark confidence threshold",
|
||||||
@@ -646,11 +622,11 @@ impl App {
|
|||||||
"For non-zero temperatures, applies DS4's exact acceptance and corrected rejection sampling. Off uses the faster opportunistic mode: sample a boundary token, then accept DSpark tokens only while they match the target's greedy path.",
|
"For non-zero temperatures, applies DS4's exact acceptance and corrected rejection sampling. Off uses the faster opportunistic mode: sample a boundary token, then accept DSpark tokens only while they match the target's greedy path.",
|
||||||
),
|
),
|
||||||
text(if self.preference_draft.acceleration_model.supports_dspark() {
|
text(if self.preference_draft.acceleration_model.supports_dspark() {
|
||||||
"Legacy MTP and DSpark use separate managed support artifacts; entering a DSpark threshold or enabling strict mode selects DSpark."
|
"DeepSeek V4 Flash 0731 uses its managed DSpark support artifact."
|
||||||
} else if self.preference_draft.acceleration_model == ModelChoice::Glm52 {
|
} else if self.preference_draft.acceleration_model == ModelChoice::Glm52 {
|
||||||
"GLM MTP is integrated; DSpark is unavailable for this model."
|
"GLM MTP is integrated; DSpark is unavailable for this model."
|
||||||
} else {
|
} else {
|
||||||
"No managed MTP support artifact is available for this model."
|
"No speculative-decoding support is available for this model."
|
||||||
})
|
})
|
||||||
.size(12),
|
.size(12),
|
||||||
text(acceleration_engine.map_or_else(
|
text(acceleration_engine.map_or_else(
|
||||||
@@ -659,10 +635,7 @@ impl App {
|
|||||||
|engine| {
|
|engine| {
|
||||||
let settings = engine.speculative;
|
let settings = engine.speculative;
|
||||||
format!(
|
format!(
|
||||||
"Engine: MTP draft {} • margin {} • legacy MTP {} • GLM MTP {} • timing {} • DSpark {} • confidence {}{} • target-only {} • exact sampling {}",
|
"Engine: GLM MTP {} • timing {} • DSpark {} • confidence {}{} • target-only {} • exact sampling {}",
|
||||||
settings.mtp_draft_tokens,
|
|
||||||
settings.mtp_margin,
|
|
||||||
if self.preference_draft.legacy_mtp_enabled { "on" } else { "off" },
|
|
||||||
if settings.glm_mtp { "on" } else { "off" },
|
if settings.glm_mtp { "on" } else { "off" },
|
||||||
if settings.glm_mtp_timing { "on" } else { "off" },
|
if settings.glm_mtp_timing { "on" } else { "off" },
|
||||||
if settings.dspark { "on" } else { "off" },
|
if settings.dspark { "on" } else { "off" },
|
||||||
@@ -705,7 +678,7 @@ impl App {
|
|||||||
text_input("Automatic", &self.preference_draft.ssd_preload_experts)
|
text_input("Automatic", &self.preference_draft.ssd_preload_experts)
|
||||||
.on_input(Message::PreferenceSsdPreloadChanged),
|
.on_input(Message::PreferenceSsdPreloadChanged),
|
||||||
),
|
),
|
||||||
text("A blank full-layer value is automatic; an explicit 0 disables fully resident GLM layers. Flash legacy MTP and DSpark support weights remain resident when target experts stream.")
|
text("A blank full-layer value is automatic; an explicit 0 disables fully resident GLM layers. DSpark support weights remain resident when target experts stream.")
|
||||||
.size(12),
|
.size(12),
|
||||||
text(acceleration_engine.map_or_else(
|
text(acceleration_engine.map_or_else(
|
||||||
|| "Effective SSD settings will appear after valid values are entered."
|
|| "Effective SSD settings will appear after valid values are entered."
|
||||||
|
|||||||
@@ -367,7 +367,6 @@ impl App {
|
|||||||
metric_row(
|
metric_row(
|
||||||
"Mode",
|
"Mode",
|
||||||
match stats.speculative_mode {
|
match stats.speculative_mode {
|
||||||
1 => "Legacy MTP",
|
|
||||||
2 => "DSpark",
|
2 => "DSpark",
|
||||||
3 => "GLM MTP",
|
3 => "GLM MTP",
|
||||||
_ => "Off",
|
_ => "Off",
|
||||||
@@ -857,7 +856,7 @@ mod tests {
|
|||||||
|
|
||||||
let summary = SessionStats::from_messages(
|
let summary = SessionStats::from_messages(
|
||||||
&[user, assistant, tool, compaction, system],
|
&[user, assistant, tool, compaction, system],
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -300,6 +300,7 @@ impl Config {
|
|||||||
let mut value: Value = serde_norway::from_str(&text)
|
let mut value: Value = serde_norway::from_str(&text)
|
||||||
.map_err(|error| format!("Could not read {}: {error}", path.display()))?;
|
.map_err(|error| format!("Could not read {}: {error}", path.display()))?;
|
||||||
drop_legacy_model_settings(&mut value);
|
drop_legacy_model_settings(&mut value);
|
||||||
|
let migrated = migrate_deprecated_flash(&mut value);
|
||||||
let dspark_explicit = deepseek_0731_dspark_is_explicit(&value);
|
let dspark_explicit = deepseek_0731_dspark_is_explicit(&value);
|
||||||
let mut config: Self = serde_norway::from_value(value)
|
let mut config: Self = serde_norway::from_value(value)
|
||||||
.map_err(|error| format!("Could not read {}: {error}", path.display()))?;
|
.map_err(|error| format!("Could not read {}: {error}", path.display()))?;
|
||||||
@@ -313,6 +314,9 @@ impl Config {
|
|||||||
.dspark_enabled = true;
|
.dspark_enabled = true;
|
||||||
}
|
}
|
||||||
config.validate()?;
|
config.validate()?;
|
||||||
|
if migrated {
|
||||||
|
config.save(path)?;
|
||||||
|
}
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,6 +455,45 @@ fn drop_legacy_model_settings(value: &mut Value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn migrate_deprecated_flash(value: &mut Value) -> bool {
|
||||||
|
let Value::Mapping(root) = value else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let old = Value::String("deepseek-v4-flash".into());
|
||||||
|
let current = Value::String(ModelChoice::DeepSeekV4Flash0731.id().into());
|
||||||
|
let mut migrated = false;
|
||||||
|
if root.get(Value::String("model".into())) == Some(&old) {
|
||||||
|
root.insert(Value::String("model".into()), current.clone());
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
for section in ["generation_profiles", "model_profiles"] {
|
||||||
|
let Some(Value::Mapping(profiles)) = root.get_mut(Value::String(section.into())) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if let Some(profile) = profiles.remove(&old) {
|
||||||
|
if !profiles.contains_key(¤t) {
|
||||||
|
profiles.insert(current.clone(), profile);
|
||||||
|
}
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(Value::Mapping(profiles)) = root.get_mut(Value::String("model_profiles".into())) {
|
||||||
|
for profile in profiles.values_mut() {
|
||||||
|
let Some(speculative) = profile
|
||||||
|
.as_mapping_mut()
|
||||||
|
.and_then(|profile| profile.get_mut(Value::String("speculative".into())))
|
||||||
|
.and_then(Value::as_mapping_mut)
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
for field in ["legacy_mtp_enabled", "mtp_draft_tokens", "mtp_margin"] {
|
||||||
|
migrated |= speculative.remove(Value::String(field.into())).is_some();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
migrated
|
||||||
|
}
|
||||||
|
|
||||||
/// Drops every value that still matches the default, so the file lists only what
|
/// Drops every value that still matches the default, so the file lists only what
|
||||||
/// the user actually set. Mappings that end up empty disappear with their key.
|
/// the user actually set. Mappings that end up empty disappear with their key.
|
||||||
fn without_defaults(value: Value, defaults: &Value) -> Option<Value> {
|
fn without_defaults(value: Value, defaults: &Value) -> Option<Value> {
|
||||||
@@ -601,4 +644,37 @@ mod tests {
|
|||||||
// A missing file is simply the defaults.
|
// A missing file is simply the defaults.
|
||||||
assert_eq!(Config::load(&path).unwrap(), Config::default());
|
assert_eq!(Config::load(&path).unwrap(), Config::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deprecated_flash_config_migrates_and_persists_only_0731() {
|
||||||
|
let directory =
|
||||||
|
std::env::temp_dir().join(format!("ds4-config-preview-{}", std::process::id()));
|
||||||
|
let path = directory.join("config.yaml");
|
||||||
|
fs::create_dir_all(&directory).unwrap();
|
||||||
|
fs::write(
|
||||||
|
&path,
|
||||||
|
"model: deepseek-v4-flash\ngeneration_profiles:\n deepseek-v4-flash:\n none:\n max_generated_tokens: 123\nmodel_profiles:\n deepseek-v4-flash:\n speculative:\n legacy_mtp_enabled: true\n mtp_draft_tokens: 4\n mtp_margin: 2\n dspark_enabled: false\n",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let config = Config::load(&path).unwrap();
|
||||||
|
assert_eq!(config.model, ModelChoice::DeepSeekV4Flash0731);
|
||||||
|
assert_eq!(
|
||||||
|
config
|
||||||
|
.generation_profiles
|
||||||
|
.get(&ModelChoice::DeepSeekV4Flash0731)
|
||||||
|
.unwrap()
|
||||||
|
.get(&ReasoningMode::Direct)
|
||||||
|
.unwrap()
|
||||||
|
.max_generated_tokens,
|
||||||
|
123
|
||||||
|
);
|
||||||
|
assert!(!config.runtime_for(config.model).speculative.dspark_enabled);
|
||||||
|
let persisted = fs::read_to_string(&path).unwrap();
|
||||||
|
assert!(!persisted.contains("deepseek-v4-flash:"));
|
||||||
|
assert!(!persisted.contains("legacy_mtp"));
|
||||||
|
assert!(!persisted.contains("mtp_draft_tokens"));
|
||||||
|
assert!(persisted.contains("deepseek-v4-flash-0731"));
|
||||||
|
fs::remove_dir_all(&directory).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,8 +109,8 @@ struct Shape {
|
|||||||
original_context: u64,
|
original_context: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
const FLASH: Shape = Shape {
|
const DEEPSEEK_BASE: Shape = Shape {
|
||||||
model: ModelChoice::DeepSeekV4Flash,
|
model: ModelChoice::DeepSeekV4Flash0731,
|
||||||
family: ModelFamily::DeepSeek,
|
family: ModelFamily::DeepSeek,
|
||||||
layers: 43,
|
layers: 43,
|
||||||
embd: 4096,
|
embd: 4096,
|
||||||
@@ -152,10 +152,7 @@ const FLASH: Shape = Shape {
|
|||||||
original_context: 65_536,
|
original_context: 65_536,
|
||||||
};
|
};
|
||||||
|
|
||||||
const FLASH_0731: Shape = Shape {
|
const FLASH_0731: Shape = Shape { ..DEEPSEEK_BASE };
|
||||||
model: ModelChoice::DeepSeekV4Flash0731,
|
|
||||||
..FLASH
|
|
||||||
};
|
|
||||||
|
|
||||||
const PRO: Shape = Shape {
|
const PRO: Shape = Shape {
|
||||||
model: ModelChoice::DeepSeekV4Pro,
|
model: ModelChoice::DeepSeekV4Pro,
|
||||||
@@ -168,7 +165,7 @@ const PRO: Shape = Shape {
|
|||||||
ff_expert: 3072,
|
ff_expert: 3072,
|
||||||
indexer_top_k: 1024,
|
indexer_top_k: 1024,
|
||||||
expert_weight_scale: 2.5,
|
expert_weight_scale: 2.5,
|
||||||
..FLASH
|
..DEEPSEEK_BASE
|
||||||
};
|
};
|
||||||
|
|
||||||
const GLM: Shape = Shape {
|
const GLM: Shape = Shape {
|
||||||
@@ -236,7 +233,6 @@ impl Model {
|
|||||||
pub(crate) fn open(settings: &EngineSettings) -> Result<Self, String> {
|
pub(crate) fn open(settings: &EngineSettings) -> Result<Self, String> {
|
||||||
validate_engine_artifacts(
|
validate_engine_artifacts(
|
||||||
settings.model,
|
settings.model,
|
||||||
settings.artifacts.mtp.is_some() && !settings.speculative.dspark,
|
|
||||||
settings.speculative.dspark,
|
settings.speculative.dspark,
|
||||||
&settings.artifacts,
|
&settings.artifacts,
|
||||||
)?;
|
)?;
|
||||||
@@ -244,7 +240,7 @@ impl Model {
|
|||||||
if settings.execution.warm_weights {
|
if settings.execution.warm_weights {
|
||||||
model.main.warm()?;
|
model.main.warm()?;
|
||||||
}
|
}
|
||||||
if let Some(path) = &settings.artifacts.mtp {
|
if let Some(path) = &settings.artifacts.support {
|
||||||
let support = Gguf::open(path)?;
|
let support = Gguf::open(path)?;
|
||||||
let kind = validate_support(&support, &model.shape)?;
|
let kind = validate_support(&support, &model.shape)?;
|
||||||
if settings.execution.warm_weights {
|
if settings.execution.warm_weights {
|
||||||
@@ -1958,13 +1954,12 @@ mod sampling_tests {
|
|||||||
fn metal_executes_real_flash_token() {
|
fn metal_executes_real_flash_token() {
|
||||||
configure_metal_sources().unwrap();
|
configure_metal_sources().unwrap();
|
||||||
let path = crate::model::engine_artifacts(
|
let path = crate::model::engine_artifacts(
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
false,
|
|
||||||
false,
|
false,
|
||||||
&crate::app::models_path(),
|
&crate::app::models_path(),
|
||||||
)
|
)
|
||||||
.model;
|
.model;
|
||||||
let model = Model::open_main(&path, ModelChoice::DeepSeekV4Flash).unwrap();
|
let model = Model::open_main(&path, ModelChoice::DeepSeekV4Flash0731).unwrap();
|
||||||
let tokens = model.render_prompt(
|
let tokens = model.render_prompt(
|
||||||
"You are a helpful assistant",
|
"You are a helpful assistant",
|
||||||
"Hello",
|
"Hello",
|
||||||
@@ -2008,7 +2003,7 @@ mod sampling_tests {
|
|||||||
.0;
|
.0;
|
||||||
drop(executor);
|
drop(executor);
|
||||||
|
|
||||||
let model = Model::open_main(&path, ModelChoice::DeepSeekV4Flash).unwrap();
|
let model = Model::open_main(&path, ModelChoice::DeepSeekV4Flash0731).unwrap();
|
||||||
let mut restored = metal::Executor::open(model, 32_768, false, 0).unwrap();
|
let mut restored = metal::Executor::open(model, 32_768, false, 0).unwrap();
|
||||||
assert!(restored.load_checkpoint(&checkpoint, &mut |_| {}).unwrap());
|
assert!(restored.load_checkpoint(&checkpoint, &mut |_| {}).unwrap());
|
||||||
assert_eq!(restored.position(), tokens.len() as u32);
|
assert_eq!(restored.position(), tokens.len() as u32);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -301,10 +301,6 @@ impl DeepSeekExecutor {
|
|||||||
self.tokens = tokens;
|
self.tokens = tokens;
|
||||||
self.logits = logits;
|
self.logits = logits;
|
||||||
self.checkpoint_tag = checkpoint_tag;
|
self.checkpoint_tag = checkpoint_tag;
|
||||||
if let Some(mtp) = &mut self.legacy_mtp {
|
|
||||||
mtp.draft_token = None;
|
|
||||||
mtp.raw_rows = 0;
|
|
||||||
}
|
|
||||||
if let Some(dspark) = &mut self.dspark {
|
if let Some(dspark) = &mut self.dspark {
|
||||||
dspark.capture_mask = 0;
|
dspark.capture_mask = 0;
|
||||||
dspark.cache_start = 0;
|
dspark.cache_start = 0;
|
||||||
|
|||||||
@@ -398,8 +398,6 @@ impl GlmExecutor {
|
|||||||
quality,
|
quality,
|
||||||
ssd,
|
ssd,
|
||||||
EngineSpeculativeSettings {
|
EngineSpeculativeSettings {
|
||||||
mtp_draft_tokens: 1,
|
|
||||||
mtp_margin: 3.0,
|
|
||||||
glm_mtp: false,
|
glm_mtp: false,
|
||||||
glm_mtp_timing: false,
|
glm_mtp_timing: false,
|
||||||
dspark: false,
|
dspark: false,
|
||||||
@@ -3243,8 +3241,7 @@ mod tests {
|
|||||||
use crate::settings::EngineSsdSettings;
|
use crate::settings::EngineSsdSettings;
|
||||||
|
|
||||||
fn installed_glm_path() -> std::path::PathBuf {
|
fn installed_glm_path() -> std::path::PathBuf {
|
||||||
crate::model::engine_artifacts(ModelChoice::Glm52, false, false, &crate::app::models_path())
|
crate::model::engine_artifacts(ModelChoice::Glm52, false, &crate::app::models_path()).model
|
||||||
.model
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -3433,8 +3430,6 @@ mod tests {
|
|||||||
preload_experts: 0,
|
preload_experts: 0,
|
||||||
},
|
},
|
||||||
EngineSpeculativeSettings {
|
EngineSpeculativeSettings {
|
||||||
mtp_draft_tokens: 2,
|
|
||||||
mtp_margin: 3.0,
|
|
||||||
glm_mtp: enabled,
|
glm_mtp: enabled,
|
||||||
glm_mtp_timing: false,
|
glm_mtp_timing: false,
|
||||||
dspark: false,
|
dspark: false,
|
||||||
|
|||||||
@@ -288,7 +288,8 @@ mod tests {
|
|||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::thread::current().name().unwrap_or("test")
|
std::thread::current().name().unwrap_or("test")
|
||||||
));
|
));
|
||||||
let mut profile = ExpertProfile::new(path.to_str(), ModelChoice::DeepSeekV4Flash, 1, 8, 2)
|
let mut profile =
|
||||||
|
ExpertProfile::new(path.to_str(), ModelChoice::DeepSeekV4Flash0731, 1, 8, 2)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
profile
|
profile
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ pub(crate) fn validate_model_artifact(
|
|||||||
if support {
|
if support {
|
||||||
let model = Gguf::open(path)?;
|
let model = Gguf::open(path)?;
|
||||||
let shape = match expected {
|
let shape = match expected {
|
||||||
ModelChoice::DeepSeekV4Flash => FLASH,
|
|
||||||
ModelChoice::DeepSeekV4Flash0731 => FLASH_0731,
|
ModelChoice::DeepSeekV4Flash0731 => FLASH_0731,
|
||||||
ModelChoice::DeepSeekV4Pro | ModelChoice::Glm52 => {
|
ModelChoice::DeepSeekV4Pro | ModelChoice::Glm52 => {
|
||||||
return Err(format!("{expected} does not use an external support GGUF"));
|
return Err(format!("{expected} does not use an external support GGUF"));
|
||||||
@@ -38,7 +37,6 @@ pub(crate) fn validate_model_artifact(
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub(super) enum SupportKind {
|
pub(super) enum SupportKind {
|
||||||
LegacyMtp,
|
|
||||||
DSpark,
|
DSpark,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,122 +104,17 @@ pub(super) fn dspark_config(model: &Gguf) -> Result<DsparkConfig, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn validate_support(model: &Gguf, shape: &Shape) -> Result<SupportKind, String> {
|
pub(super) fn validate_support(model: &Gguf, shape: &Shape) -> Result<SupportKind, String> {
|
||||||
if model.tensors.contains_key("mtp.0.e_proj.weight")
|
if model.metadata.contains_key("deepseek4.dspark.block_size")
|
||||||
&& model.tensors.contains_key("mtp.0.h_proj.weight")
|
|
||||||
&& model.tensors.contains_key("mtp.0.hc_head_base.weight")
|
|
||||||
{
|
|
||||||
validate_legacy_mtp(model, shape)?;
|
|
||||||
Ok(SupportKind::LegacyMtp)
|
|
||||||
} else if model.metadata.contains_key("deepseek4.dspark.block_size")
|
|
||||||
|| model.metadata.contains_key("deepseek4.dspark_block_size")
|
|| model.metadata.contains_key("deepseek4.dspark_block_size")
|
||||||
|| model.metadata.contains_key("dspark.block_size")
|
|| model.metadata.contains_key("dspark.block_size")
|
||||||
{
|
{
|
||||||
validate_dspark(model, shape)?;
|
validate_dspark(model, shape)?;
|
||||||
Ok(SupportKind::DSpark)
|
Ok(SupportKind::DSpark)
|
||||||
} else {
|
} else {
|
||||||
Err("support GGUF is neither legacy MTP nor DSpark".into())
|
Err("support GGUF is not a DSpark artifact".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_legacy_mtp(model: &Gguf, shape: &Shape) -> Result<(), String> {
|
|
||||||
if shape.model != ModelChoice::DeepSeekV4Flash {
|
|
||||||
return Err("legacy MTP support is available only for DeepSeek V4 Flash".into());
|
|
||||||
}
|
|
||||||
let prefix = "mtp.0";
|
|
||||||
let hc_dim = shape.embd * shape.hc;
|
|
||||||
let hc_mix = 2 * shape.hc + shape.hc * shape.hc;
|
|
||||||
let q_dim = shape.heads * shape.head_dim;
|
|
||||||
let output_low = shape.out_groups * shape.lora_o;
|
|
||||||
for (suffix, types, dims) in [
|
|
||||||
("hc_head_base.weight", &[F32][..], vec![shape.hc]),
|
|
||||||
("hc_head_fn.weight", PLAIN, vec![hc_dim, shape.hc]),
|
|
||||||
("hc_head_scale.weight", &[F32][..], vec![1]),
|
|
||||||
("e_proj.weight", &[Q8_0][..], vec![shape.embd, shape.embd]),
|
|
||||||
("h_proj.weight", &[Q8_0][..], vec![shape.embd, shape.embd]),
|
|
||||||
("enorm.weight", &[F32][..], vec![shape.embd]),
|
|
||||||
("hnorm.weight", &[F32][..], vec![shape.embd]),
|
|
||||||
("norm.weight", &[F32][..], vec![shape.embd]),
|
|
||||||
("hc_attn_fn.weight", PLAIN, vec![hc_dim, hc_mix]),
|
|
||||||
("hc_attn_scale.weight", &[F32][..], vec![3]),
|
|
||||||
("hc_attn_base.weight", &[F32][..], vec![hc_mix]),
|
|
||||||
("attn_norm.weight", &[F32][..], vec![shape.embd]),
|
|
||||||
(
|
|
||||||
"attn_q_a.weight",
|
|
||||||
&[Q8_0][..],
|
|
||||||
vec![shape.embd, shape.lora_q],
|
|
||||||
),
|
|
||||||
("attn_q_a_norm.weight", &[F32][..], vec![shape.lora_q]),
|
|
||||||
("attn_q_b.weight", &[Q8_0][..], vec![shape.lora_q, q_dim]),
|
|
||||||
(
|
|
||||||
"attn_kv.weight",
|
|
||||||
&[Q8_0][..],
|
|
||||||
vec![shape.embd, shape.head_dim],
|
|
||||||
),
|
|
||||||
("attn_kv_a_norm.weight", &[F32][..], vec![shape.head_dim]),
|
|
||||||
("attn_sinks.weight", &[F32][..], vec![shape.heads]),
|
|
||||||
(
|
|
||||||
"attn_output_a.weight",
|
|
||||||
&[Q8_0][..],
|
|
||||||
vec![
|
|
||||||
shape.head_dim * (shape.heads / shape.out_groups),
|
|
||||||
output_low,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"attn_output_b.weight",
|
|
||||||
&[Q8_0][..],
|
|
||||||
vec![output_low, shape.embd],
|
|
||||||
),
|
|
||||||
("hc_ffn_fn.weight", PLAIN, vec![hc_dim, hc_mix]),
|
|
||||||
("hc_ffn_scale.weight", &[F32][..], vec![3]),
|
|
||||||
("hc_ffn_base.weight", &[F32][..], vec![hc_mix]),
|
|
||||||
("ffn_norm.weight", &[F32][..], vec![shape.embd]),
|
|
||||||
(
|
|
||||||
"ffn_gate_inp.weight",
|
|
||||||
PLAIN,
|
|
||||||
vec![shape.embd, shape.experts],
|
|
||||||
),
|
|
||||||
("exp_probs_b.bias", &[F32][..], vec![shape.experts]),
|
|
||||||
(
|
|
||||||
"ffn_gate_exps.weight",
|
|
||||||
ROUTED,
|
|
||||||
vec![shape.embd, shape.ff_expert, shape.experts],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ffn_up_exps.weight",
|
|
||||||
ROUTED,
|
|
||||||
vec![shape.embd, shape.ff_expert, shape.experts],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ffn_down_exps.weight",
|
|
||||||
ROUTED,
|
|
||||||
vec![shape.ff_expert, shape.embd, shape.experts],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ffn_gate_shexp.weight",
|
|
||||||
&[Q8_0][..],
|
|
||||||
vec![shape.embd, shape.ff_expert],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ffn_up_shexp.weight",
|
|
||||||
&[Q8_0][..],
|
|
||||||
vec![shape.embd, shape.ff_expert],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ffn_down_shexp.weight",
|
|
||||||
&[Q8_0][..],
|
|
||||||
vec![shape.ff_expert, shape.embd],
|
|
||||||
),
|
|
||||||
] {
|
|
||||||
expect(model, &format!("{prefix}.{suffix}"), types, &dims)?;
|
|
||||||
}
|
|
||||||
same_type(
|
|
||||||
model,
|
|
||||||
"mtp.0.ffn_gate_exps.weight",
|
|
||||||
"mtp.0.ffn_up_exps.weight",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn validate_main(model: &Gguf, expected: ModelChoice) -> Result<Shape, String> {
|
pub(super) fn validate_main(model: &Gguf, expected: ModelChoice) -> Result<Shape, String> {
|
||||||
let family = if model.bytes("general.architecture").ok() == Some(b"glm-dsa") {
|
let family = if model.bytes("general.architecture").ok() == Some(b"glm-dsa") {
|
||||||
ModelFamily::Glm
|
ModelFamily::Glm
|
||||||
@@ -232,7 +125,7 @@ pub(super) fn validate_main(model: &Gguf, expected: ModelChoice) -> Result<Shape
|
|||||||
ModelFamily::Glm => GLM,
|
ModelFamily::Glm => GLM,
|
||||||
ModelFamily::DeepSeek => match (model.u32("deepseek4.block_count")?, expected) {
|
ModelFamily::DeepSeek => match (model.u32("deepseek4.block_count")?, expected) {
|
||||||
(43, ModelChoice::DeepSeekV4Flash0731) => FLASH_0731,
|
(43, ModelChoice::DeepSeekV4Flash0731) => FLASH_0731,
|
||||||
(43, _) => FLASH,
|
(43, _) => FLASH_0731,
|
||||||
(61, _) => PRO,
|
(61, _) => PRO,
|
||||||
(layers, _) => return Err(format!("unsupported DeepSeek layer count: {layers}")),
|
(layers, _) => return Err(format!("unsupported DeepSeek layer count: {layers}")),
|
||||||
},
|
},
|
||||||
@@ -766,10 +659,7 @@ fn validate_glm_tensors(model: &Gguf, shape: &Shape) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn validate_dspark(model: &Gguf, shape: &Shape) -> Result<(), String> {
|
pub(super) fn validate_dspark(model: &Gguf, shape: &Shape) -> Result<(), String> {
|
||||||
if !matches!(
|
if !matches!(shape.model, ModelChoice::DeepSeekV4Flash0731) {
|
||||||
shape.model,
|
|
||||||
ModelChoice::DeepSeekV4Flash | ModelChoice::DeepSeekV4Flash0731
|
|
||||||
) {
|
|
||||||
return Err("DSpark support is available only for DeepSeek V4 Flash".into());
|
return Err("DSpark support is available only for DeepSeek V4 Flash".into());
|
||||||
}
|
}
|
||||||
let DsparkConfig {
|
let DsparkConfig {
|
||||||
@@ -1004,18 +894,14 @@ fn float_eq(actual: f32, expected: f32) -> bool {
|
|||||||
|
|
||||||
fn compression_ratio(shape: &Shape, layer: u32) -> u32 {
|
fn compression_ratio(shape: &Shape, layer: u32) -> u32 {
|
||||||
match shape.model {
|
match shape.model {
|
||||||
ModelChoice::DeepSeekV4Flash | ModelChoice::DeepSeekV4Flash0731 if layer < 2 => 0,
|
ModelChoice::DeepSeekV4Flash0731 if layer < 2 => 0,
|
||||||
ModelChoice::DeepSeekV4Pro if layer < 2 => 128,
|
ModelChoice::DeepSeekV4Pro if layer < 2 => 128,
|
||||||
ModelChoice::DeepSeekV4Flash
|
ModelChoice::DeepSeekV4Flash0731 | ModelChoice::DeepSeekV4Pro
|
||||||
| ModelChoice::DeepSeekV4Flash0731
|
|
||||||
| ModelChoice::DeepSeekV4Pro
|
|
||||||
if layer.is_multiple_of(2) =>
|
if layer.is_multiple_of(2) =>
|
||||||
{
|
{
|
||||||
4
|
4
|
||||||
}
|
}
|
||||||
ModelChoice::DeepSeekV4Flash
|
ModelChoice::DeepSeekV4Flash0731 | ModelChoice::DeepSeekV4Pro => 128,
|
||||||
| ModelChoice::DeepSeekV4Flash0731
|
|
||||||
| ModelChoice::DeepSeekV4Pro => 128,
|
|
||||||
ModelChoice::Glm52 => 0,
|
ModelChoice::Glm52 => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1054,8 +940,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn installed_ds4_fixture_opens_and_renders_a_prompt() {
|
fn installed_ds4_fixture_opens_and_renders_a_prompt() {
|
||||||
let path = crate::model::engine_artifacts(
|
let path = crate::model::engine_artifacts(
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
false,
|
|
||||||
false,
|
false,
|
||||||
&crate::app::models_path(),
|
&crate::app::models_path(),
|
||||||
)
|
)
|
||||||
@@ -1063,9 +948,9 @@ mod tests {
|
|||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let model = Model::open_main(&path, ModelChoice::DeepSeekV4Flash).unwrap();
|
let model = Model::open_main(&path, ModelChoice::DeepSeekV4Flash0731).unwrap();
|
||||||
let summary = model.summary();
|
let summary = model.summary();
|
||||||
assert_eq!(summary.model, ModelChoice::DeepSeekV4Flash);
|
assert_eq!(summary.model, ModelChoice::DeepSeekV4Flash0731);
|
||||||
assert_eq!(summary.vocabulary_size, 129_280);
|
assert_eq!(summary.vocabulary_size, 129_280);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
model.tokenize("Hello, world! 1234\nint café = 7;\n中文テスト"),
|
model.tokenize("Hello, world! 1234\nint café = 7;\n中文テスト"),
|
||||||
@@ -1262,33 +1147,14 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn installed_dspark_fixture_passes_the_target_layout() {
|
fn installed_dspark_fixture_passes_the_target_layout() {
|
||||||
let path = crate::model::engine_artifacts(
|
let path = crate::model::engine_artifacts(
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
false,
|
|
||||||
true,
|
true,
|
||||||
&crate::app::models_path(),
|
&crate::app::models_path(),
|
||||||
)
|
)
|
||||||
.mtp
|
.support
|
||||||
.unwrap();
|
.unwrap();
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
validate_model_artifact(&path, ModelChoice::DeepSeekV4Flash, true).unwrap();
|
validate_model_artifact(&path, ModelChoice::DeepSeekV4Flash0731, true).unwrap();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn installed_legacy_mtp_fixture_passes_the_target_layout() {
|
|
||||||
let path = crate::model::engine_artifacts(
|
|
||||||
ModelChoice::DeepSeekV4Flash,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
&crate::app::models_path(),
|
|
||||||
)
|
|
||||||
.mtp
|
|
||||||
.unwrap();
|
|
||||||
if path.exists() {
|
|
||||||
assert_eq!(
|
|
||||||
validate_support(&Gguf::open(&path).unwrap(), &FLASH).unwrap(),
|
|
||||||
SupportKind::LegacyMtp
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -844,7 +844,6 @@ fn source(value: u8) -> WorkSource {
|
|||||||
|
|
||||||
fn model_code(model: ModelChoice) -> u8 {
|
fn model_code(model: ModelChoice) -> u8 {
|
||||||
match model {
|
match model {
|
||||||
ModelChoice::DeepSeekV4Flash => 1,
|
|
||||||
ModelChoice::DeepSeekV4Pro => 2,
|
ModelChoice::DeepSeekV4Pro => 2,
|
||||||
ModelChoice::Glm52 => 3,
|
ModelChoice::Glm52 => 3,
|
||||||
ModelChoice::DeepSeekV4Flash0731 => 4,
|
ModelChoice::DeepSeekV4Flash0731 => 4,
|
||||||
@@ -1027,6 +1026,12 @@ fn cache_usage(root: &Path) -> CacheUsage {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn removed_preview_metric_code_stays_decodable() {
|
||||||
|
assert_eq!(model_name(1), "DeepSeek V4 Flash");
|
||||||
|
assert_eq!(model_code(ModelChoice::DeepSeekV4Flash0731), 4);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn snapshots_track_runtime_and_server_counters() {
|
fn snapshots_track_runtime_and_server_counters() {
|
||||||
let metrics = Metrics::new(Path::new("/path/that/does/not/exist"));
|
let metrics = Metrics::new(Path::new("/path/that/does/not/exist"));
|
||||||
|
|||||||
80
src/model.rs
80
src/model.rs
@@ -9,18 +9,14 @@ use std::fmt;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
pub(crate) const MODEL_CHOICES: [ModelChoice; 4] = [
|
pub(crate) const MODEL_CHOICES: [ModelChoice; 3] = [
|
||||||
ModelChoice::DeepSeekV4Flash0731,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
ModelChoice::DeepSeekV4Flash,
|
|
||||||
ModelChoice::DeepSeekV4Pro,
|
ModelChoice::DeepSeekV4Pro,
|
||||||
ModelChoice::Glm52,
|
ModelChoice::Glm52,
|
||||||
];
|
];
|
||||||
pub(crate) const MANAGED_ARTIFACTS: [ManagedArtifactId; 7] = [
|
pub(crate) const MANAGED_ARTIFACTS: [ManagedArtifactId; 4] = [
|
||||||
ManagedArtifactId::DeepSeekV4Flash0731,
|
ManagedArtifactId::DeepSeekV4Flash0731,
|
||||||
ManagedArtifactId::DeepSeekV4Flash0731Dspark,
|
ManagedArtifactId::DeepSeekV4Flash0731Dspark,
|
||||||
ManagedArtifactId::DeepSeekV4Flash,
|
|
||||||
ManagedArtifactId::DeepSeekV4FlashMtp,
|
|
||||||
ManagedArtifactId::DeepSeekV4FlashDspark,
|
|
||||||
ManagedArtifactId::DeepSeekV4Pro,
|
ManagedArtifactId::DeepSeekV4Pro,
|
||||||
ManagedArtifactId::Glm52,
|
ManagedArtifactId::Glm52,
|
||||||
];
|
];
|
||||||
@@ -28,30 +24,6 @@ pub(crate) const MANAGED_ARTIFACTS: [ManagedArtifactId; 7] = [
|
|||||||
const DEEPSEEK_REPOSITORY: &str = "antirez/deepseek-v4-gguf";
|
const DEEPSEEK_REPOSITORY: &str = "antirez/deepseek-v4-gguf";
|
||||||
const GLM_REPOSITORY: &str = "antirez/glm-5.2-gguf";
|
const GLM_REPOSITORY: &str = "antirez/glm-5.2-gguf";
|
||||||
|
|
||||||
const FLASH: Artifact = Artifact {
|
|
||||||
label: "DeepSeek V4 Flash model",
|
|
||||||
file_name: "DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf",
|
|
||||||
repository: DEEPSEEK_REPOSITORY,
|
|
||||||
size: 86_720_111_488,
|
|
||||||
sha256: "efc7ed607ff27076e3e501fc3fefefa33c0ed8cf1eff483a2b7fdc0c2e616668",
|
|
||||||
support: Some(false),
|
|
||||||
};
|
|
||||||
const FLASH_DSPARK: Artifact = Artifact {
|
|
||||||
label: "DSpark support",
|
|
||||||
file_name: "DeepSeek-V4-Flash-DSpark-support.gguf",
|
|
||||||
repository: DEEPSEEK_REPOSITORY,
|
|
||||||
size: 5_989_114_272,
|
|
||||||
sha256: "8b3adf5942bec22ae2ea867cd7079cf13530ba83ffcffaf00f5de48664a1a34e",
|
|
||||||
support: Some(true),
|
|
||||||
};
|
|
||||||
const FLASH_MTP: Artifact = Artifact {
|
|
||||||
label: "Legacy MTP support",
|
|
||||||
file_name: "DeepSeek-V4-Flash-MTP-Q4K-Q8_0-F32.gguf",
|
|
||||||
repository: DEEPSEEK_REPOSITORY,
|
|
||||||
size: 3_807_602_400,
|
|
||||||
sha256: "afd481ee689dce9037f70f39085fcdae5a5b096d521cdad43b19fa52bf8f4083",
|
|
||||||
support: Some(true),
|
|
||||||
};
|
|
||||||
const FLASH_0731: Artifact = Artifact {
|
const FLASH_0731: Artifact = Artifact {
|
||||||
label: "DeepSeek V4 Flash 0731 model",
|
label: "DeepSeek V4 Flash 0731 model",
|
||||||
file_name: "DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix-0731.gguf",
|
file_name: "DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix-0731.gguf",
|
||||||
@@ -87,8 +59,6 @@ const GLM: Artifact = Artifact {
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
|
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
|
||||||
pub(crate) enum ModelChoice {
|
pub(crate) enum ModelChoice {
|
||||||
#[serde(rename = "deepseek-v4-flash")]
|
|
||||||
DeepSeekV4Flash,
|
|
||||||
#[default]
|
#[default]
|
||||||
#[serde(rename = "deepseek-v4-flash-0731")]
|
#[serde(rename = "deepseek-v4-flash-0731")]
|
||||||
DeepSeekV4Flash0731,
|
DeepSeekV4Flash0731,
|
||||||
@@ -101,7 +71,6 @@ pub(crate) enum ModelChoice {
|
|||||||
impl ModelChoice {
|
impl ModelChoice {
|
||||||
pub(crate) fn id(self) -> &'static str {
|
pub(crate) fn id(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::DeepSeekV4Flash => "deepseek-v4-flash",
|
|
||||||
Self::DeepSeekV4Flash0731 => "deepseek-v4-flash-0731",
|
Self::DeepSeekV4Flash0731 => "deepseek-v4-flash-0731",
|
||||||
Self::DeepSeekV4Pro => "deepseek-v4-pro",
|
Self::DeepSeekV4Pro => "deepseek-v4-pro",
|
||||||
Self::Glm52 => "glm-5.2",
|
Self::Glm52 => "glm-5.2",
|
||||||
@@ -112,17 +81,12 @@ impl ModelChoice {
|
|||||||
MODEL_CHOICES.into_iter().find(|model| model.id() == id)
|
MODEL_CHOICES.into_iter().find(|model| model.id() == id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn supports_legacy_mtp(self) -> bool {
|
|
||||||
self == Self::DeepSeekV4Flash
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn supports_dspark(self) -> bool {
|
pub(crate) fn supports_dspark(self) -> bool {
|
||||||
matches!(self, Self::DeepSeekV4Flash | Self::DeepSeekV4Flash0731)
|
self == Self::DeepSeekV4Flash0731
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main_artifact(self) -> &'static Artifact {
|
fn main_artifact(self) -> &'static Artifact {
|
||||||
match self {
|
match self {
|
||||||
Self::DeepSeekV4Flash => &FLASH,
|
|
||||||
Self::DeepSeekV4Flash0731 => &FLASH_0731,
|
Self::DeepSeekV4Flash0731 => &FLASH_0731,
|
||||||
Self::DeepSeekV4Pro => &PRO,
|
Self::DeepSeekV4Pro => &PRO,
|
||||||
Self::Glm52 => &GLM,
|
Self::Glm52 => &GLM,
|
||||||
@@ -131,21 +95,15 @@ impl ModelChoice {
|
|||||||
|
|
||||||
fn dspark_artifact(self) -> Option<&'static Artifact> {
|
fn dspark_artifact(self) -> Option<&'static Artifact> {
|
||||||
match self {
|
match self {
|
||||||
Self::DeepSeekV4Flash => Some(&FLASH_DSPARK),
|
|
||||||
Self::DeepSeekV4Flash0731 => Some(&FLASH_0731_DSPARK),
|
Self::DeepSeekV4Flash0731 => Some(&FLASH_0731_DSPARK),
|
||||||
Self::DeepSeekV4Pro | Self::Glm52 => None,
|
Self::DeepSeekV4Pro | Self::Glm52 => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn artifacts(
|
fn artifacts(self, dspark_enabled: bool) -> impl Iterator<Item = &'static Artifact> {
|
||||||
self,
|
|
||||||
legacy_mtp_enabled: bool,
|
|
||||||
dspark_enabled: bool,
|
|
||||||
) -> impl Iterator<Item = &'static Artifact> {
|
|
||||||
[
|
[
|
||||||
Some(self.main_artifact()),
|
Some(self.main_artifact()),
|
||||||
(self.supports_legacy_mtp() && legacy_mtp_enabled).then_some(&FLASH_MTP),
|
|
||||||
dspark_enabled.then(|| self.dspark_artifact()).flatten(),
|
dspark_enabled.then(|| self.dspark_artifact()).flatten(),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -156,20 +114,17 @@ impl ModelChoice {
|
|||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub(crate) struct EngineArtifacts {
|
pub(crate) struct EngineArtifacts {
|
||||||
pub(crate) model: PathBuf,
|
pub(crate) model: PathBuf,
|
||||||
pub(crate) mtp: Option<PathBuf>,
|
pub(crate) support: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn engine_artifacts(
|
pub(crate) fn engine_artifacts(
|
||||||
model: ModelChoice,
|
model: ModelChoice,
|
||||||
legacy_mtp_enabled: bool,
|
|
||||||
dspark_enabled: bool,
|
dspark_enabled: bool,
|
||||||
models_path: &Path,
|
models_path: &Path,
|
||||||
) -> EngineArtifacts {
|
) -> EngineArtifacts {
|
||||||
EngineArtifacts {
|
EngineArtifacts {
|
||||||
model: model.main_artifact().path(model, models_path),
|
model: model.main_artifact().path(model, models_path),
|
||||||
mtp: if model.supports_legacy_mtp() && legacy_mtp_enabled {
|
support: if dspark_enabled {
|
||||||
Some(FLASH_MTP.path(model, models_path))
|
|
||||||
} else if dspark_enabled {
|
|
||||||
model
|
model
|
||||||
.dspark_artifact()
|
.dspark_artifact()
|
||||||
.map(|artifact| artifact.path(model, models_path))
|
.map(|artifact| artifact.path(model, models_path))
|
||||||
@@ -181,30 +136,21 @@ pub(crate) fn engine_artifacts(
|
|||||||
|
|
||||||
pub(crate) fn validate_engine_artifacts(
|
pub(crate) fn validate_engine_artifacts(
|
||||||
model: ModelChoice,
|
model: ModelChoice,
|
||||||
legacy_mtp_enabled: bool,
|
|
||||||
dspark_enabled: bool,
|
dspark_enabled: bool,
|
||||||
artifacts: &EngineArtifacts,
|
artifacts: &EngineArtifacts,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if legacy_mtp_enabled && dspark_enabled {
|
|
||||||
return Err("Legacy MTP and DSpark cannot be enabled together".into());
|
|
||||||
}
|
|
||||||
if legacy_mtp_enabled && !model.supports_legacy_mtp() {
|
|
||||||
return Err(format!("Legacy MTP is not compatible with {model}"));
|
|
||||||
}
|
|
||||||
if dspark_enabled && !model.supports_dspark() {
|
if dspark_enabled && !model.supports_dspark() {
|
||||||
return Err(format!("DSpark is not compatible with {model}"));
|
return Err(format!("DSpark is not compatible with {model}"));
|
||||||
}
|
}
|
||||||
model
|
model
|
||||||
.main_artifact()
|
.main_artifact()
|
||||||
.validate_installed_path(&artifacts.model)?;
|
.validate_installed_path(&artifacts.model)?;
|
||||||
let expected_support = if legacy_mtp_enabled {
|
let expected_support = if dspark_enabled {
|
||||||
model.supports_legacy_mtp().then_some(&FLASH_MTP)
|
|
||||||
} else if dspark_enabled {
|
|
||||||
model.dspark_artifact()
|
model.dspark_artifact()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
match (expected_support, artifacts.mtp.as_deref()) {
|
match (expected_support, artifacts.support.as_deref()) {
|
||||||
(Some(expected), Some(path)) => expected.validate_installed_path(path),
|
(Some(expected), Some(path)) => expected.validate_installed_path(path),
|
||||||
(None, None) => Ok(()),
|
(None, None) => Ok(()),
|
||||||
(Some(_), None) => Err(format!("{model} is missing its required support GGUF")),
|
(Some(_), None) => Err(format!("{model} is missing its required support GGUF")),
|
||||||
@@ -217,9 +163,6 @@ pub(crate) fn validate_engine_artifacts(
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub(crate) enum ManagedArtifactId {
|
pub(crate) enum ManagedArtifactId {
|
||||||
DeepSeekV4Flash,
|
|
||||||
DeepSeekV4FlashMtp,
|
|
||||||
DeepSeekV4FlashDspark,
|
|
||||||
DeepSeekV4Flash0731,
|
DeepSeekV4Flash0731,
|
||||||
DeepSeekV4Flash0731Dspark,
|
DeepSeekV4Flash0731Dspark,
|
||||||
DeepSeekV4Pro,
|
DeepSeekV4Pro,
|
||||||
@@ -229,9 +172,6 @@ pub(crate) enum ManagedArtifactId {
|
|||||||
impl ManagedArtifactId {
|
impl ManagedArtifactId {
|
||||||
pub(crate) fn model(self) -> ModelChoice {
|
pub(crate) fn model(self) -> ModelChoice {
|
||||||
match self {
|
match self {
|
||||||
Self::DeepSeekV4Flash | Self::DeepSeekV4FlashMtp | Self::DeepSeekV4FlashDspark => {
|
|
||||||
ModelChoice::DeepSeekV4Flash
|
|
||||||
}
|
|
||||||
Self::DeepSeekV4Flash0731 | Self::DeepSeekV4Flash0731Dspark => {
|
Self::DeepSeekV4Flash0731 | Self::DeepSeekV4Flash0731Dspark => {
|
||||||
ModelChoice::DeepSeekV4Flash0731
|
ModelChoice::DeepSeekV4Flash0731
|
||||||
}
|
}
|
||||||
@@ -242,9 +182,6 @@ impl ManagedArtifactId {
|
|||||||
|
|
||||||
fn artifact(self) -> &'static Artifact {
|
fn artifact(self) -> &'static Artifact {
|
||||||
match self {
|
match self {
|
||||||
Self::DeepSeekV4Flash => &FLASH,
|
|
||||||
Self::DeepSeekV4FlashMtp => &FLASH_MTP,
|
|
||||||
Self::DeepSeekV4FlashDspark => &FLASH_DSPARK,
|
|
||||||
Self::DeepSeekV4Flash0731 => &FLASH_0731,
|
Self::DeepSeekV4Flash0731 => &FLASH_0731,
|
||||||
Self::DeepSeekV4Flash0731Dspark => &FLASH_0731_DSPARK,
|
Self::DeepSeekV4Flash0731Dspark => &FLASH_0731_DSPARK,
|
||||||
Self::DeepSeekV4Pro => &PRO,
|
Self::DeepSeekV4Pro => &PRO,
|
||||||
@@ -340,7 +277,6 @@ pub(crate) enum DownloadOutcome {
|
|||||||
impl fmt::Display for ModelChoice {
|
impl fmt::Display for ModelChoice {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
formatter.write_str(match self {
|
formatter.write_str(match self {
|
||||||
Self::DeepSeekV4Flash => "DeepSeek V4 Flash (deprecated preview)",
|
|
||||||
Self::DeepSeekV4Flash0731 => "DeepSeek V4 Flash 0731",
|
Self::DeepSeekV4Flash0731 => "DeepSeek V4 Flash 0731",
|
||||||
Self::DeepSeekV4Pro => "DeepSeek V4 Pro 0813",
|
Self::DeepSeekV4Pro => "DeepSeek V4 Pro 0813",
|
||||||
Self::Glm52 => "GLM 5.2",
|
Self::Glm52 => "GLM 5.2",
|
||||||
|
|||||||
@@ -330,50 +330,33 @@ mod tests {
|
|||||||
Some(ModelChoice::DeepSeekV4Flash0731)
|
Some(ModelChoice::DeepSeekV4Flash0731)
|
||||||
);
|
);
|
||||||
assert!(ModelChoice::from_id("unknown").is_none());
|
assert!(ModelChoice::from_id("unknown").is_none());
|
||||||
assert_eq!(
|
assert_eq!(MODEL_CHOICES.len(), 3);
|
||||||
ModelChoice::DeepSeekV4Flash.main_artifact().size,
|
assert_eq!(MANAGED_ARTIFACTS.len(), 4);
|
||||||
86_720_111_488
|
|
||||||
);
|
|
||||||
assert_eq!(ModelChoice::Glm52.main_artifact().size, 211_075_856_448);
|
assert_eq!(ModelChoice::Glm52.main_artifact().size, 211_075_856_448);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ModelChoice::DeepSeekV4Flash0731.main_artifact().size,
|
ModelChoice::DeepSeekV4Flash0731.main_artifact().size,
|
||||||
86_720_111_488
|
86_720_111_488
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(ModelChoice::DeepSeekV4Flash0731.artifacts(true).count(), 2);
|
||||||
ModelChoice::DeepSeekV4Flash.artifacts(true, true).count(),
|
assert_eq!(ModelChoice::Glm52.artifacts(true).count(), 1);
|
||||||
3
|
|
||||||
);
|
|
||||||
assert_eq!(ModelChoice::Glm52.artifacts(true, true).count(), 1);
|
|
||||||
assert_eq!(
|
|
||||||
ModelChoice::DeepSeekV4Flash0731
|
|
||||||
.artifacts(true, true)
|
|
||||||
.count(),
|
|
||||||
2
|
|
||||||
);
|
|
||||||
|
|
||||||
let id = SystemTime::now()
|
let id = SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_nanos();
|
.as_nanos();
|
||||||
let models_path = std::env::temp_dir().join(format!("ds4-server-models-{id}"));
|
let models_path = std::env::temp_dir().join(format!("ds4-server-models-{id}"));
|
||||||
let engine = engine_artifacts(ModelChoice::DeepSeekV4Flash, false, true, &models_path);
|
let engine = engine_artifacts(ModelChoice::DeepSeekV4Flash0731, true, &models_path);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.model.file_name(),
|
engine.model.file_name(),
|
||||||
Some(std::ffi::OsStr::new(FLASH.file_name))
|
Some(std::ffi::OsStr::new(FLASH_0731.file_name))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.mtp.as_deref().and_then(Path::file_name),
|
engine.support.as_deref().and_then(Path::file_name),
|
||||||
Some(std::ffi::OsStr::new(FLASH_DSPARK.file_name))
|
|
||||||
);
|
|
||||||
let flash_0731 =
|
|
||||||
engine_artifacts(ModelChoice::DeepSeekV4Flash0731, false, true, &models_path);
|
|
||||||
assert_eq!(
|
|
||||||
flash_0731.mtp.as_deref().and_then(Path::file_name),
|
|
||||||
Some(std::ffi::OsStr::new(FLASH_0731_DSPARK.file_name))
|
Some(std::ffi::OsStr::new(FLASH_0731_DSPARK.file_name))
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
engine_artifacts(ModelChoice::DeepSeekV4Flash0731, true, false, &models_path)
|
engine_artifacts(ModelChoice::DeepSeekV4Flash0731, false, &models_path)
|
||||||
.mtp
|
.support
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
let empty = Artifact {
|
let empty = Artifact {
|
||||||
@@ -384,18 +367,20 @@ mod tests {
|
|||||||
sha256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
sha256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||||
support: None,
|
support: None,
|
||||||
};
|
};
|
||||||
let partial = empty.partial_path(ModelChoice::DeepSeekV4Flash, &models_path);
|
let partial = empty.partial_path(ModelChoice::DeepSeekV4Flash0731, &models_path);
|
||||||
fs::create_dir_all(partial.parent().unwrap()).unwrap();
|
fs::create_dir_all(partial.parent().unwrap()).unwrap();
|
||||||
fs::write(&partial, []).unwrap();
|
fs::write(&partial, []).unwrap();
|
||||||
download_artifact(ModelChoice::DeepSeekV4Flash, &empty, &models_path).unwrap();
|
download_artifact(ModelChoice::DeepSeekV4Flash0731, &empty, &models_path).unwrap();
|
||||||
assert!(empty.is_installed(ModelChoice::DeepSeekV4Flash, &models_path));
|
assert!(empty.is_installed(ModelChoice::DeepSeekV4Flash0731, &models_path));
|
||||||
assert!(!partial.exists());
|
assert!(!partial.exists());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
fs::read_to_string(empty.verification_path(ModelChoice::DeepSeekV4Flash, &models_path))
|
fs::read_to_string(
|
||||||
|
empty.verification_path(ModelChoice::DeepSeekV4Flash0731, &models_path)
|
||||||
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
empty.sha256
|
empty.sha256
|
||||||
);
|
);
|
||||||
let installed = empty.path(ModelChoice::DeepSeekV4Flash, &models_path);
|
let installed = empty.path(ModelChoice::DeepSeekV4Flash0731, &models_path);
|
||||||
assert!(empty.validate_installed_path(&installed).is_ok());
|
assert!(empty.validate_installed_path(&installed).is_ok());
|
||||||
let wrong_name = installed.with_file_name("wrong-checkpoint.gguf");
|
let wrong_name = installed.with_file_name("wrong-checkpoint.gguf");
|
||||||
fs::write(&wrong_name, []).unwrap();
|
fs::write(&wrong_name, []).unwrap();
|
||||||
@@ -405,10 +390,9 @@ mod tests {
|
|||||||
validate_engine_artifacts(
|
validate_engine_artifacts(
|
||||||
ModelChoice::DeepSeekV4Flash0731,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
&EngineArtifacts {
|
&EngineArtifacts {
|
||||||
model: installed.clone(),
|
model: installed.clone(),
|
||||||
mtp: None,
|
support: None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.is_err()
|
.is_err()
|
||||||
@@ -416,11 +400,10 @@ mod tests {
|
|||||||
assert!(
|
assert!(
|
||||||
validate_engine_artifacts(
|
validate_engine_artifacts(
|
||||||
ModelChoice::DeepSeekV4Pro,
|
ModelChoice::DeepSeekV4Pro,
|
||||||
false,
|
|
||||||
true,
|
true,
|
||||||
&EngineArtifacts {
|
&EngineArtifacts {
|
||||||
model: installed,
|
model: installed,
|
||||||
mtp: None,
|
support: None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.is_err()
|
.is_err()
|
||||||
@@ -452,7 +435,7 @@ mod tests {
|
|||||||
verify(
|
verify(
|
||||||
&path,
|
&path,
|
||||||
&artifact,
|
&artifact,
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
&AtomicBool::new(false),
|
&AtomicBool::new(false),
|
||||||
&verified_bytes,
|
&verified_bytes,
|
||||||
)
|
)
|
||||||
@@ -472,7 +455,7 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.as_nanos()
|
.as_nanos()
|
||||||
));
|
));
|
||||||
let id = ManagedArtifactId::DeepSeekV4Flash;
|
let id = ManagedArtifactId::DeepSeekV4Flash0731;
|
||||||
let partial = id.artifact().partial_path(id.model(), &models_path);
|
let partial = id.artifact().partial_path(id.model(), &models_path);
|
||||||
fs::create_dir_all(partial.parent().unwrap()).unwrap();
|
fs::create_dir_all(partial.parent().unwrap()).unwrap();
|
||||||
fs::write(&partial, b"part").unwrap();
|
fs::write(&partial, b"part").unwrap();
|
||||||
@@ -611,14 +594,14 @@ mod tests {
|
|||||||
sha256: "unused",
|
sha256: "unused",
|
||||||
support: None,
|
support: None,
|
||||||
};
|
};
|
||||||
let partial = artifact.partial_path(ModelChoice::DeepSeekV4Flash, &directory);
|
let partial = artifact.partial_path(ModelChoice::DeepSeekV4Flash0731, &directory);
|
||||||
fs::create_dir_all(partial.parent().unwrap()).unwrap();
|
fs::create_dir_all(partial.parent().unwrap()).unwrap();
|
||||||
fs::write(&partial, b"part").unwrap();
|
fs::write(&partial, b"part").unwrap();
|
||||||
let cancel = AtomicBool::new(true);
|
let cancel = AtomicBool::new(true);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
download_artifact_with_cancel(
|
download_artifact_with_cancel(
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
&artifact,
|
&artifact,
|
||||||
&directory,
|
&directory,
|
||||||
&cancel,
|
&cancel,
|
||||||
|
|||||||
@@ -546,7 +546,7 @@ fn model_json(id: &str, model: ModelChoice, context: i32, default_tokens: i32) -
|
|||||||
|
|
||||||
fn model_alias(id: &str) -> Option<ModelChoice> {
|
fn model_alias(id: &str) -> Option<ModelChoice> {
|
||||||
match id {
|
match id {
|
||||||
"deepseek-chat" | "deepseek-reasoner" => Some(ModelChoice::DeepSeekV4Flash),
|
"deepseek-chat" | "deepseek-reasoner" => Some(ModelChoice::DeepSeekV4Flash0731),
|
||||||
"glm-5.2-chat"
|
"glm-5.2-chat"
|
||||||
| "glm-5.2-no-think"
|
| "glm-5.2-no-think"
|
||||||
| "glm-5.2-nothink"
|
| "glm-5.2-nothink"
|
||||||
@@ -929,7 +929,7 @@ mod tests {
|
|||||||
let request = ResponseOptions {
|
let request = ResponseOptions {
|
||||||
protocol: Protocol::Chat,
|
protocol: Protocol::Chat,
|
||||||
reasoning_summary: false,
|
reasoning_summary: false,
|
||||||
model_id: "deepseek-v4-flash".into(),
|
model_id: "deepseek-v4-flash-0731".into(),
|
||||||
stream: true,
|
stream: true,
|
||||||
include_usage: false,
|
include_usage: false,
|
||||||
has_tools: true,
|
has_tools: true,
|
||||||
@@ -1002,9 +1002,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn model_metadata_uses_the_requested_alias_and_default_token_limit() {
|
fn model_metadata_uses_the_requested_alias_and_default_token_limit() {
|
||||||
|
assert_eq!(
|
||||||
|
model_alias("deepseek-chat"),
|
||||||
|
Some(ModelChoice::DeepSeekV4Flash0731)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
model_alias("deepseek-reasoner"),
|
||||||
|
Some(ModelChoice::DeepSeekV4Flash0731)
|
||||||
|
);
|
||||||
let model = model_json(
|
let model = model_json(
|
||||||
"deepseek-reasoner",
|
"deepseek-reasoner",
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
32_768,
|
32_768,
|
||||||
50_000,
|
50_000,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ pub(crate) const REASONING_MODES: [ReasoningMode; 3] = [
|
|||||||
const STANDARD_REASONING_MODES: [ReasoningMode; 2] = [ReasoningMode::High, ReasoningMode::Direct];
|
const STANDARD_REASONING_MODES: [ReasoningMode; 2] = [ReasoningMode::High, ReasoningMode::Direct];
|
||||||
const THINK_MAX_MIN_CONTEXT: i32 = 393_216;
|
const THINK_MAX_MIN_CONTEXT: i32 = 393_216;
|
||||||
const MAX_CPU_THREADS: u32 = 32;
|
const MAX_CPU_THREADS: u32 = 32;
|
||||||
const MAX_MTP_DRAFT_TOKENS: i32 = 16;
|
|
||||||
pub(crate) const GIB: u64 = 1024 * 1024 * 1024;
|
pub(crate) const GIB: u64 = 1024 * 1024 * 1024;
|
||||||
/// DS4 disk KV cache defaults, from `ds4_kvstore.h` and `--kv-disk-space-mb`.
|
/// DS4 disk KV cache defaults, from `ds4_kvstore.h` and `--kv-disk-space-mb`.
|
||||||
pub(crate) const DEFAULT_KV_BUDGET_GIB: u64 = 4;
|
pub(crate) const DEFAULT_KV_BUDGET_GIB: u64 = 4;
|
||||||
@@ -19,12 +18,9 @@ const DEFAULT_KV_MIN_TOKENS: u32 = 512;
|
|||||||
const DEFAULT_KV_COLD_MAX_TOKENS: u32 = 30_000;
|
const DEFAULT_KV_COLD_MAX_TOKENS: u32 = 30_000;
|
||||||
const DEFAULT_KV_CONTINUED_INTERVAL_TOKENS: u32 = 10_000;
|
const DEFAULT_KV_CONTINUED_INTERVAL_TOKENS: u32 = 10_000;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||||
#[serde(default, deny_unknown_fields)]
|
#[serde(default, deny_unknown_fields)]
|
||||||
pub(crate) struct SpeculativePreferences {
|
pub(crate) struct SpeculativePreferences {
|
||||||
pub(crate) mtp_draft_tokens: i32,
|
|
||||||
pub(crate) mtp_margin: f32,
|
|
||||||
pub(crate) legacy_mtp_enabled: bool,
|
|
||||||
pub(crate) glm_mtp: bool,
|
pub(crate) glm_mtp: bool,
|
||||||
pub(crate) glm_mtp_timing: bool,
|
pub(crate) glm_mtp_timing: bool,
|
||||||
pub(crate) dspark_enabled: bool,
|
pub(crate) dspark_enabled: bool,
|
||||||
@@ -33,28 +29,8 @@ pub(crate) struct SpeculativePreferences {
|
|||||||
pub(crate) dspark_exact_sampling: bool,
|
pub(crate) dspark_exact_sampling: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SpeculativePreferences {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
mtp_draft_tokens: 1,
|
|
||||||
mtp_margin: 3.0,
|
|
||||||
legacy_mtp_enabled: false,
|
|
||||||
glm_mtp: false,
|
|
||||||
glm_mtp_timing: false,
|
|
||||||
dspark_enabled: false,
|
|
||||||
dspark_confidence_threshold: None,
|
|
||||||
dspark_strict: false,
|
|
||||||
dspark_exact_sampling: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SpeculativePreferences {
|
impl SpeculativePreferences {
|
||||||
pub(crate) fn validate(&self, model: ModelChoice) -> Result<(), String> {
|
pub(crate) fn validate(&self, model: ModelChoice) -> Result<(), String> {
|
||||||
if self.mtp_draft_tokens <= 0 {
|
|
||||||
return Err("MTP draft tokens must be a positive whole number.".into());
|
|
||||||
}
|
|
||||||
validate_float("MTP margin", self.mtp_margin, 0.0, 1000.0)?;
|
|
||||||
if self.glm_mtp_timing && !self.glm_mtp {
|
if self.glm_mtp_timing && !self.glm_mtp {
|
||||||
return Err("GLM MTP timing requires GLM MTP.".into());
|
return Err("GLM MTP timing requires GLM MTP.".into());
|
||||||
}
|
}
|
||||||
@@ -64,12 +40,6 @@ impl SpeculativePreferences {
|
|||||||
if self.dspark_enabled && !model.supports_dspark() {
|
if self.dspark_enabled && !model.supports_dspark() {
|
||||||
return Err("DSpark is not available for the selected model.".into());
|
return Err("DSpark is not available for the selected model.".into());
|
||||||
}
|
}
|
||||||
if self.legacy_mtp_enabled && !model.supports_legacy_mtp() {
|
|
||||||
return Err("Legacy MTP is not available for the selected model.".into());
|
|
||||||
}
|
|
||||||
if self.legacy_mtp_enabled && self.dspark_enabled {
|
|
||||||
return Err("Legacy MTP and DSpark use different support artifacts.".into());
|
|
||||||
}
|
|
||||||
if (self.dspark_confidence_threshold.is_some()
|
if (self.dspark_confidence_threshold.is_some()
|
||||||
|| self.dspark_strict
|
|| self.dspark_strict
|
||||||
|| self.dspark_exact_sampling)
|
|| self.dspark_exact_sampling)
|
||||||
@@ -85,8 +55,6 @@ impl SpeculativePreferences {
|
|||||||
|
|
||||||
pub(crate) fn engine_settings(&self) -> EngineSpeculativeSettings {
|
pub(crate) fn engine_settings(&self) -> EngineSpeculativeSettings {
|
||||||
EngineSpeculativeSettings {
|
EngineSpeculativeSettings {
|
||||||
mtp_draft_tokens: self.mtp_draft_tokens.min(MAX_MTP_DRAFT_TOKENS),
|
|
||||||
mtp_margin: self.mtp_margin,
|
|
||||||
glm_mtp: self.glm_mtp,
|
glm_mtp: self.glm_mtp,
|
||||||
glm_mtp_timing: self.glm_mtp_timing,
|
glm_mtp_timing: self.glm_mtp_timing,
|
||||||
dspark: self.dspark_enabled,
|
dspark: self.dspark_enabled,
|
||||||
@@ -100,8 +68,6 @@ impl SpeculativePreferences {
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub(crate) struct EngineSpeculativeSettings {
|
pub(crate) struct EngineSpeculativeSettings {
|
||||||
pub(crate) mtp_draft_tokens: i32,
|
|
||||||
pub(crate) mtp_margin: f32,
|
|
||||||
pub(crate) glm_mtp: bool,
|
pub(crate) glm_mtp: bool,
|
||||||
pub(crate) glm_mtp_timing: bool,
|
pub(crate) glm_mtp_timing: bool,
|
||||||
pub(crate) dspark: bool,
|
pub(crate) dspark: bool,
|
||||||
@@ -415,12 +381,7 @@ impl RuntimePreferences {
|
|||||||
self.validate(model)?;
|
self.validate(model)?;
|
||||||
Ok(EngineSettings {
|
Ok(EngineSettings {
|
||||||
model,
|
model,
|
||||||
artifacts: model::engine_artifacts(
|
artifacts: model::engine_artifacts(model, self.speculative.dspark_enabled, models_path),
|
||||||
model,
|
|
||||||
self.speculative.legacy_mtp_enabled,
|
|
||||||
self.speculative.dspark_enabled,
|
|
||||||
models_path,
|
|
||||||
),
|
|
||||||
context_tokens,
|
context_tokens,
|
||||||
execution: self.execution.engine_settings(),
|
execution: self.execution.engine_settings(),
|
||||||
speculative: self.speculative.engine_settings(),
|
speculative: self.speculative.engine_settings(),
|
||||||
@@ -698,7 +659,7 @@ mod tests {
|
|||||||
assert_eq!(defaults.system_prompt, DEFAULT_SYSTEM_PROMPT);
|
assert_eq!(defaults.system_prompt, DEFAULT_SYSTEM_PROMPT);
|
||||||
assert!(defaults.system_prompt.contains("\n\nGuidelines:\n-"));
|
assert!(defaults.system_prompt.contains("\n\nGuidelines:\n-"));
|
||||||
let cache = KvCachePreferences::default().settings();
|
let cache = KvCachePreferences::default().settings();
|
||||||
let deepseek = defaults.turn_settings(ModelChoice::DeepSeekV4Flash, cache);
|
let deepseek = defaults.turn_settings(ModelChoice::DeepSeekV4Flash0731, cache);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
(deepseek.temperature, deepseek.top_p, deepseek.min_p),
|
(deepseek.temperature, deepseek.top_p, deepseek.min_p),
|
||||||
(1.0, 1.0, 0.05)
|
(1.0, 1.0, 0.05)
|
||||||
@@ -773,7 +734,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
assert!(
|
assert!(
|
||||||
unsupported_threads
|
unsupported_threads
|
||||||
.validate(ModelChoice::DeepSeekV4Flash)
|
.validate(ModelChoice::DeepSeekV4Flash0731)
|
||||||
.is_err()
|
.is_err()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -782,7 +743,7 @@ mod tests {
|
|||||||
prefill_chunk: Some(4096),
|
prefill_chunk: Some(4096),
|
||||||
..ExecutionPreferences::default()
|
..ExecutionPreferences::default()
|
||||||
};
|
};
|
||||||
assert!(tuned.validate(ModelChoice::DeepSeekV4Flash).is_ok());
|
assert!(tuned.validate(ModelChoice::DeepSeekV4Flash0731).is_ok());
|
||||||
assert!(tuned.validate(ModelChoice::Glm52).is_err());
|
assert!(tuned.validate(ModelChoice::Glm52).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,21 +751,18 @@ mod tests {
|
|||||||
fn speculative_settings_match_acceleration_defaults_and_dependencies() {
|
fn speculative_settings_match_acceleration_defaults_and_dependencies() {
|
||||||
let defaults = SpeculativePreferences::default();
|
let defaults = SpeculativePreferences::default();
|
||||||
let engine = defaults.engine_settings();
|
let engine = defaults.engine_settings();
|
||||||
assert_eq!((engine.mtp_draft_tokens, engine.mtp_margin), (1, 3.0));
|
|
||||||
assert_eq!(engine.dspark_confidence_threshold, 0.8);
|
assert_eq!(engine.dspark_confidence_threshold, 0.8);
|
||||||
assert!(!engine.dspark_confidence_threshold_set);
|
assert!(!engine.dspark_confidence_threshold_set);
|
||||||
|
|
||||||
let tuned = SpeculativePreferences {
|
let tuned = SpeculativePreferences {
|
||||||
mtp_draft_tokens: 20,
|
|
||||||
dspark_enabled: true,
|
dspark_enabled: true,
|
||||||
dspark_confidence_threshold: Some(0.7),
|
dspark_confidence_threshold: Some(0.7),
|
||||||
dspark_strict: true,
|
dspark_strict: true,
|
||||||
dspark_exact_sampling: true,
|
dspark_exact_sampling: true,
|
||||||
..defaults
|
..defaults
|
||||||
};
|
};
|
||||||
assert!(tuned.validate(ModelChoice::DeepSeekV4Flash).is_ok());
|
assert!(tuned.validate(ModelChoice::DeepSeekV4Flash0731).is_ok());
|
||||||
assert!(tuned.validate(ModelChoice::Glm52).is_err());
|
assert!(tuned.validate(ModelChoice::Glm52).is_err());
|
||||||
assert_eq!(tuned.engine_settings().mtp_draft_tokens, 16);
|
|
||||||
|
|
||||||
let glm = SpeculativePreferences {
|
let glm = SpeculativePreferences {
|
||||||
glm_mtp: true,
|
glm_mtp: true,
|
||||||
@@ -814,21 +772,6 @@ mod tests {
|
|||||||
assert!(glm.validate(ModelChoice::Glm52).is_ok());
|
assert!(glm.validate(ModelChoice::Glm52).is_ok());
|
||||||
assert!(glm.validate(ModelChoice::DeepSeekV4Pro).is_err());
|
assert!(glm.validate(ModelChoice::DeepSeekV4Pro).is_err());
|
||||||
|
|
||||||
let legacy = SpeculativePreferences {
|
|
||||||
legacy_mtp_enabled: true,
|
|
||||||
..SpeculativePreferences::default()
|
|
||||||
};
|
|
||||||
assert!(legacy.validate(ModelChoice::DeepSeekV4Flash).is_ok());
|
|
||||||
assert!(legacy.validate(ModelChoice::DeepSeekV4Flash0731).is_err());
|
|
||||||
assert!(legacy.validate(ModelChoice::DeepSeekV4Pro).is_err());
|
|
||||||
assert!(
|
|
||||||
SpeculativePreferences {
|
|
||||||
dspark_enabled: true,
|
|
||||||
..legacy
|
|
||||||
}
|
|
||||||
.validate(ModelChoice::DeepSeekV4Flash)
|
|
||||||
.is_err()
|
|
||||||
);
|
|
||||||
assert!(
|
assert!(
|
||||||
SpeculativePreferences {
|
SpeculativePreferences {
|
||||||
dspark_exact_sampling: true,
|
dspark_exact_sampling: true,
|
||||||
@@ -892,7 +835,7 @@ mod tests {
|
|||||||
..RuntimePreferences::default()
|
..RuntimePreferences::default()
|
||||||
};
|
};
|
||||||
let effective = effective_settings(
|
let effective = effective_settings(
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
&GenerationPreferences::default(),
|
&GenerationPreferences::default(),
|
||||||
&runtime,
|
&runtime,
|
||||||
Path::new("/models"),
|
Path::new("/models"),
|
||||||
@@ -900,7 +843,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let engine = effective.engine;
|
let engine = effective.engine;
|
||||||
assert_eq!(engine.context_tokens, 32_768);
|
assert_eq!(engine.context_tokens, 32_768);
|
||||||
assert!(engine.artifacts.mtp.is_none());
|
assert!(engine.artifacts.support.is_none());
|
||||||
assert_eq!(engine.ssd.cache_bytes, 64 * GIB);
|
assert_eq!(engine.ssd.cache_bytes, 64 * GIB);
|
||||||
assert!(engine.ssd.full_layers_set);
|
assert!(engine.ssd.full_layers_set);
|
||||||
assert_eq!(engine.ssd.full_layers, 0);
|
assert_eq!(engine.ssd.full_layers, 0);
|
||||||
@@ -914,7 +857,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
..runtime
|
..runtime
|
||||||
};
|
};
|
||||||
assert!(combined.validate(ModelChoice::DeepSeekV4Flash).is_ok());
|
assert!(combined.validate(ModelChoice::DeepSeekV4Flash0731).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -932,7 +875,7 @@ mod tests {
|
|||||||
..RuntimePreferences::default()
|
..RuntimePreferences::default()
|
||||||
};
|
};
|
||||||
let effective = effective_settings(
|
let effective = effective_settings(
|
||||||
ModelChoice::DeepSeekV4Flash,
|
ModelChoice::DeepSeekV4Flash0731,
|
||||||
&generation,
|
&generation,
|
||||||
&runtime,
|
&runtime,
|
||||||
Path::new("/models"),
|
Path::new("/models"),
|
||||||
@@ -942,9 +885,9 @@ mod tests {
|
|||||||
assert_eq!(effective.engine.context_tokens, 65_536);
|
assert_eq!(effective.engine.context_tokens, 65_536);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
effective.engine.artifacts.model.parent(),
|
effective.engine.artifacts.model.parent(),
|
||||||
Some(Path::new("/models/deepseek-v4-flash"))
|
Some(Path::new("/models/deepseek-v4-flash-0731"))
|
||||||
);
|
);
|
||||||
assert!(effective.engine.artifacts.mtp.is_some());
|
assert!(effective.engine.artifacts.support.is_some());
|
||||||
assert_eq!(effective.turn.temperature, 0.25);
|
assert_eq!(effective.turn.temperature, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -967,9 +910,6 @@ mod tests {
|
|||||||
"--kv-disk-space-mb",
|
"--kv-disk-space-mb",
|
||||||
"--min-p",
|
"--min-p",
|
||||||
"--model",
|
"--model",
|
||||||
"--mtp",
|
|
||||||
"--mtp-draft",
|
|
||||||
"--mtp-margin",
|
|
||||||
"--nothink",
|
"--nothink",
|
||||||
"--power",
|
"--power",
|
||||||
"--prefill-chunk",
|
"--prefill-chunk",
|
||||||
|
|||||||
Reference in New Issue
Block a user