whosellm 0.2.1__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. {whosellm-0.2.1 → whosellm-0.2.2}/.bumpversion.toml +1 -1
  2. {whosellm-0.2.1 → whosellm-0.2.2}/PKG-INFO +1 -1
  3. {whosellm-0.2.1 → whosellm-0.2.2}/pyproject.toml +1 -1
  4. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_deepseek.py +76 -20
  5. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_deepseek_tencent.py +23 -1
  6. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_gpt5.py +0 -3
  7. {whosellm-0.2.1 → whosellm-0.2.2}/tests/test_auto_register.py +2 -1
  8. {whosellm-0.2.1 → whosellm-0.2.2}/uv.lock +1 -1
  9. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/__init__.py +1 -1
  10. whosellm-0.2.2/whosellm/models/families/deepseek/deepseek_official.py +117 -0
  11. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/deepseek/tencent.py +22 -2
  12. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/openai_gpt_4_1.py +0 -1
  13. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/openai_gpt_5.py +0 -4
  14. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/openai_gpt_5_1.py +0 -1
  15. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/openai_gpt_5_2.py +0 -2
  16. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/openai_gpt_5_4.py +0 -4
  17. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/zhipu.py +0 -5
  18. whosellm-0.2.1/whosellm/models/families/deepseek/deepseek_official.py +0 -72
  19. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/commands/interview.md +0 -0
  20. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/projects/-Users-jqq-PycharmProjects-llmeta/memory/MEMORY.md +0 -0
  21. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/projects/-Users-jqq-PycharmProjects-llmeta/memory/feedback_use_uv.md +0 -0
  22. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/code-review/SKILL.md +0 -0
  23. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/create-skill/SKILL.md +0 -0
  24. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/e2e-metadata/SKILL.md +0 -0
  25. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/evolve/SKILL.md +0 -0
  26. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/fix-review/SKILL.md +0 -0
  27. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/release/SKILL.md +0 -0
  28. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/review-provider-model/SKILL.md +0 -0
  29. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/review-provider-model/providers/alibaba.md +0 -0
  30. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/review-provider-model/providers/anthropic.md +0 -0
  31. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/review-provider-model/providers/deepseek.md +0 -0
  32. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/review-provider-model/providers/gemini.md +0 -0
  33. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/review-provider-model/providers/openai.md +0 -0
  34. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/review-provider-model/providers/others.md +0 -0
  35. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/review-provider-model/providers/vidu.md +0 -0
  36. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/review-provider-model/providers/zhipu.md +0 -0
  37. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/update-provider-model/SKILL.md +0 -0
  38. {whosellm-0.2.1 → whosellm-0.2.2}/.claude/skills/update-provider-model/testing.md +0 -0
  39. {whosellm-0.2.1 → whosellm-0.2.2}/.coveragerc +0 -0
  40. {whosellm-0.2.1 → whosellm-0.2.2}/.github/workflows/publish.yml +0 -0
  41. {whosellm-0.2.1 → whosellm-0.2.2}/.github/workflows/tests.yml +0 -0
  42. {whosellm-0.2.1 → whosellm-0.2.2}/.gitignore +0 -0
  43. {whosellm-0.2.1 → whosellm-0.2.2}/.windsurf/workflows/addmodel.md +0 -0
  44. {whosellm-0.2.1 → whosellm-0.2.2}/.windsurf/workflows/arch.md +0 -0
  45. {whosellm-0.2.1 → whosellm-0.2.2}/.windsurf/workflows/testllmeta.md +0 -0
  46. {whosellm-0.2.1 → whosellm-0.2.2}/CHANGELOG.md +0 -0
  47. {whosellm-0.2.1 → whosellm-0.2.2}/CLAUDE.md +0 -0
  48. {whosellm-0.2.1 → whosellm-0.2.2}/LICENSE +0 -0
  49. {whosellm-0.2.1 → whosellm-0.2.2}/README.md +0 -0
  50. {whosellm-0.2.1 → whosellm-0.2.2}/docs/add_new_model_family.md +0 -0
  51. {whosellm-0.2.1 → whosellm-0.2.2}/docs/refactor_proposal.md +0 -0
  52. {whosellm-0.2.1 → whosellm-0.2.2}/docs/spec_model_family_redesign.md +0 -0
  53. {whosellm-0.2.1 → whosellm-0.2.2}/examples/advanced_usage.py +0 -0
  54. {whosellm-0.2.1 → whosellm-0.2.2}/examples/basic_usage.py +0 -0
  55. {whosellm-0.2.1 → whosellm-0.2.2}/mypy.ini +0 -0
  56. {whosellm-0.2.1 → whosellm-0.2.2}/pytest.ini +0 -0
  57. {whosellm-0.2.1 → whosellm-0.2.2}/ruff.toml +0 -0
  58. {whosellm-0.2.1 → whosellm-0.2.2}/tests/__init__.py +0 -0
  59. {whosellm-0.2.1 → whosellm-0.2.2}/tests/e2e/__init__.py +0 -0
  60. {whosellm-0.2.1 → whosellm-0.2.2}/tests/e2e/conftest.py +0 -0
  61. {whosellm-0.2.1 → whosellm-0.2.2}/tests/e2e/test_anthropic.py +0 -0
  62. {whosellm-0.2.1 → whosellm-0.2.2}/tests/e2e/test_google.py +0 -0
  63. {whosellm-0.2.1 → whosellm-0.2.2}/tests/e2e/test_openai.py +0 -0
  64. {whosellm-0.2.1 → whosellm-0.2.2}/tests/e2e/test_zhipu.py +0 -0
  65. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/__init__.py +0 -0
  66. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/__init__.py +0 -0
  67. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_anthropic.py +0 -0
  68. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_gemini.py +0 -0
  69. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_glm45.py +0 -0
  70. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_glm45v.py +0 -0
  71. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_glm46.py +0 -0
  72. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_glm46v.py +0 -0
  73. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_glm5.py +0 -0
  74. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_gpt3_5.py +0 -0
  75. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_gpt4_1.py +0 -0
  76. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_gpt4o.py +0 -0
  77. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_o1.py +0 -0
  78. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_o3.py +0 -0
  79. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_o4.py +0 -0
  80. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_qwen.py +0 -0
  81. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_qwen3_vl_models.py +0 -0
  82. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_qwen_ollama.py +0 -0
  83. {whosellm-0.2.1 → whosellm-0.2.2}/tests/models/families/test_qwen_plus.py +0 -0
  84. {whosellm-0.2.1 → whosellm-0.2.2}/tests/test_llmeta.py +0 -0
  85. {whosellm-0.2.1 → whosellm-0.2.2}/tests/test_model_version.py +0 -0
  86. {whosellm-0.2.1 → whosellm-0.2.2}/tests/test_provider.py +0 -0
  87. {whosellm-0.2.1 → whosellm-0.2.2}/tests/test_registry_merge.py +0 -0
  88. {whosellm-0.2.1 → whosellm-0.2.2}/tests/test_specific_patterns.py +0 -0
  89. {whosellm-0.2.1 → whosellm-0.2.2}/tests/test_variant_priority_config.py +0 -0
  90. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/capabilities.py +0 -0
  91. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/model_version.py +0 -0
  92. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/__init__.py +0 -0
  93. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/base.py +0 -0
  94. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/config.py +0 -0
  95. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/dynamic_enum.py +0 -0
  96. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/__init__.py +0 -0
  97. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/alibaba.py +0 -0
  98. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/anthropic.py +0 -0
  99. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/deepseek/__init__.py +0 -0
  100. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/gemini.py +0 -0
  101. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/__init__.py +0 -0
  102. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/openai_gpt_3_5.py +0 -0
  103. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/openai_gpt_4.py +0 -0
  104. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/openai_gpt_4o.py +0 -0
  105. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/openai_gpt_5_3.py +0 -0
  106. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/openai_o1.py +0 -0
  107. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/openai_o3.py +0 -0
  108. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/openai/openai_o4.py +0 -0
  109. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/others.py +0 -0
  110. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/families/vidu.py +0 -0
  111. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/patterns.py +0 -0
  112. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/models/registry.py +0 -0
  113. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/provider.py +0 -0
  114. {whosellm-0.2.1 → whosellm-0.2.2}/whosellm/py.typed +0 -0
@@ -2,7 +2,7 @@
2
2
  # 文档 / Documentation: https://callowayproject.github.io/bump-my-version/
3
3
 
4
4
  [tool.bumpversion]
5
- current_version = "0.2.1"
5
+ current_version = "0.2.2"
6
6
  parse = """(?x)
7
7
  (?P<major>0|[1-9]\\d*)\\.
8
8
  (?P<minor>0|[1-9]\\d*)\\.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: whosellm
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: A unified LLM model version and capability management library
5
5
  Author-email: JQQ <jqq1716@gmail.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "whosellm"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "A unified LLM model version and capability management library"
5
5
  authors = [
6
6
  {name = "JQQ", email = "jqq1716@gmail.com"}
@@ -11,7 +11,7 @@ from whosellm.provider import Provider
11
11
 
12
12
 
13
13
  def test_deepseek_default_capabilities() -> None:
14
- """验证 DeepSeek 官方家族默认能力 / Validate DeepSeek official family default capabilities"""
14
+ """验证 DeepSeek 官方家族默认能力(V4 基线) / Validate DeepSeek official family default capabilities (V4 baseline)"""
15
15
  from whosellm import LLMeta
16
16
 
17
17
  # 使用官方 Provider 前缀确保获取官方配置
@@ -20,8 +20,10 @@ def test_deepseek_default_capabilities() -> None:
20
20
 
21
21
  assert capabilities.supports_streaming is True
22
22
  assert capabilities.supports_function_calling is True
23
- assert capabilities.max_tokens == 8000
24
- assert capabilities.context_window == 128000
23
+ # V4 系列:1M 上下文,384K 最大输出
24
+ assert capabilities.max_tokens == 384_000
25
+ assert capabilities.context_window == 1_000_000
26
+ # deepseek-chat 是 v4-flash 非思考模式的别名
25
27
  assert capabilities.supports_thinking is False
26
28
 
27
29
 
@@ -31,13 +33,13 @@ def test_deepseek_chat_specific_model() -> None:
31
33
 
32
34
  assert config is not None
33
35
  version, variant, capabilities = config
34
- assert version == "1.0"
36
+ assert version == "4.0"
35
37
  assert variant == "chat"
36
38
  assert capabilities is not None
37
39
  assert capabilities.supports_function_calling is True
38
40
  assert capabilities.supports_streaming is True
39
- assert capabilities.max_tokens == 8000
40
- assert capabilities.context_window == 128000
41
+ assert capabilities.max_tokens == 384_000
42
+ assert capabilities.context_window == 1_000_000
41
43
 
42
44
 
43
45
  def test_deepseek_chat_pattern_matching() -> None:
@@ -50,7 +52,7 @@ def test_deepseek_chat_pattern_matching() -> None:
50
52
 
51
53
  assert model.family == ModelFamily.DEEPSEEK
52
54
  assert model.variant == "chat"
53
- assert model.version == "1.0"
55
+ assert model.version == "4.0"
54
56
  assert model.provider == Provider.DEEPSEEK
55
57
 
56
58
 
@@ -60,10 +62,12 @@ def test_deepseek_reasoner_specific_model() -> None:
60
62
 
61
63
  assert config is not None
62
64
  version, variant, capabilities = config
63
- assert version == "1.0"
65
+ assert version == "4.0"
64
66
  assert variant == "reasoner"
65
67
  assert capabilities is not None
66
68
  assert capabilities.supports_thinking is True
69
+ assert capabilities.max_tokens == 384_000
70
+ assert capabilities.context_window == 1_000_000
67
71
 
68
72
 
69
73
  def test_deepseek_base_pattern_without_variant() -> None:
@@ -71,17 +75,16 @@ def test_deepseek_base_pattern_without_variant() -> None:
71
75
  from whosellm import LLMeta
72
76
 
73
77
  # 使用 Provider 前缀确保匹配官方配置
74
- # DeepSeek 官方只支持 chat 和 reasoner,默认使用 chat
75
78
  model = LLMeta("deepseek::deepseek-chat")
76
79
 
77
80
  assert model.family == ModelFamily.DEEPSEEK
78
81
  assert model.variant == "chat"
79
- assert model.version == "1.0"
82
+ assert model.version == "4.0"
80
83
  assert model.capabilities.supports_function_calling is True
81
84
 
82
85
 
83
86
  def test_deepseek_reasoner_does_not_use_chat_capabilities() -> None:
84
- """验证 reasoner 不会意外继承 chat 的函数调用能力 / Ensure reasoner capabilities override family defaults"""
87
+ """验证 reasoner 不会意外继承 chat 的能力 / Ensure reasoner capabilities override family defaults"""
85
88
  from whosellm import LLMeta
86
89
 
87
90
  model = LLMeta("deepseek::deepseek-reasoner")
@@ -95,7 +98,7 @@ def test_deepseek_no_structured_outputs() -> None:
95
98
  """验证 DeepSeek 官方模型不支持 structured_outputs(仅支持 json_object)"""
96
99
  from whosellm import LLMeta
97
100
 
98
- for model_id in ["deepseek-chat", "deepseek-reasoner"]:
101
+ for model_id in ["deepseek-chat", "deepseek-reasoner", "deepseek-v4-flash", "deepseek-v4-pro"]:
99
102
  model = LLMeta(f"deepseek::{model_id}")
100
103
  assert model.capabilities.supports_structured_outputs is False, (
101
104
  f"{model_id}: DeepSeek API 仅支持 response_format={{type:'json_object'}},"
@@ -106,15 +109,68 @@ def test_deepseek_no_structured_outputs() -> None:
106
109
  )
107
110
 
108
111
 
109
- def test_deepseek_official_invalid_model_names() -> None:
110
- """验证 DeepSeek 官方不支持的模型名称会被识别为 UNKNOWN / Validate unsupported official model names are recognized as UNKNOWN"""
112
+ def test_deepseek_v4_flash_specific_model() -> None:
113
+ """验证 deepseek-v4-flash 特定模型配置 / Validate deepseek-v4-flash specific configuration"""
111
114
  from whosellm import LLMeta
112
115
 
113
- # DeepSeek 官方不提供 deepseek-v3.2-exp 这样的命名方式
114
- # 官方只支持 deepseek-chat-{suffix} 和 deepseek-reasoner-{suffix}
115
- model = LLMeta("deepseek::deepseek-v3.2-exp")
116
+ model = LLMeta("deepseek::deepseek-v4-flash")
116
117
 
117
- # 当使用 Provider 前缀时,Provider 会被保留,但 family 会是 UNKNOWN
118
- assert model.family == ModelFamily.UNKNOWN
118
+ assert model.family == ModelFamily.DEEPSEEK
119
+ assert model.provider == Provider.DEEPSEEK
120
+ assert model.version == "4.0"
121
+ assert model.variant == "flash"
122
+
123
+ caps = model.capabilities
124
+ assert caps.supports_thinking is True
125
+ assert caps.supports_function_calling is True
126
+ assert caps.supports_streaming is True
127
+ assert caps.supports_json_outputs is True
128
+ assert caps.supports_structured_outputs is False
129
+ assert caps.max_tokens == 384_000
130
+ assert caps.context_window == 1_000_000
131
+
132
+
133
+ def test_deepseek_v4_pro_specific_model() -> None:
134
+ """验证 deepseek-v4-pro 特定模型配置 / Validate deepseek-v4-pro specific configuration"""
135
+ from whosellm import LLMeta
136
+
137
+ model = LLMeta("deepseek::deepseek-v4-pro")
138
+
139
+ assert model.family == ModelFamily.DEEPSEEK
140
+ assert model.provider == Provider.DEEPSEEK
141
+ assert model.version == "4.0"
142
+ assert model.variant == "pro"
143
+
144
+ caps = model.capabilities
145
+ assert caps.supports_thinking is True
146
+ assert caps.supports_function_calling is True
147
+ assert caps.max_tokens == 384_000
148
+ assert caps.context_window == 1_000_000
149
+
150
+
151
+ def test_deepseek_v4_variant_ordering() -> None:
152
+ """验证 v4-flash < v4-pro 的排序关系 / Validate v4-flash < v4-pro ordering"""
153
+ from whosellm import LLMeta
154
+
155
+ flash = LLMeta("deepseek::deepseek-v4-flash")
156
+ pro = LLMeta("deepseek::deepseek-v4-pro")
157
+
158
+ assert flash < pro
159
+
160
+
161
+ def test_deepseek_versioned_pattern_matches_official_family() -> None:
162
+ """验证带版本号的 DS 模型名能被官方 family 识别 / Validate versioned DS names match the official family"""
163
+ from whosellm import LLMeta
164
+
165
+ # V4 是 DS 官方首次开放版本号命名的系列
166
+ model = LLMeta("deepseek::deepseek-v4-flash")
167
+ assert model.family == ModelFamily.DEEPSEEK
119
168
  assert model.provider == Provider.DEEPSEEK
120
- assert model.variant == "" # 无法匹配到任何 variant
169
+ assert model.version == "4.0"
170
+
171
+ # 带小数版本号也能匹配 family(即使当前没有 specific_model 条目)
172
+ model_v32 = LLMeta("deepseek::deepseek-v3.2-exp")
173
+ assert model_v32.family == ModelFamily.DEEPSEEK
174
+ assert model_v32.provider == Provider.DEEPSEEK
175
+ assert model_v32.version == "3.2"
176
+ assert model_v32.variant == "exp"
@@ -66,6 +66,8 @@ def test_tencent_deepseek_r1_0528() -> None:
66
66
  assert capabilities is not None
67
67
  assert capabilities.supports_thinking is True
68
68
  assert capabilities.context_window == 128000
69
+ # 腾讯云 LKE 官方文档明确列为不支持 Function Calling
70
+ assert capabilities.supports_function_calling is False
69
71
 
70
72
 
71
73
  def test_tencent_deepseek_v3_1() -> None:
@@ -109,6 +111,22 @@ def test_tencent_deepseek_v3_2_exp() -> None:
109
111
  assert capabilities.context_window == 128000
110
112
 
111
113
 
114
+ def test_tencent_deepseek_v3_2() -> None:
115
+ """测试腾讯云 DeepSeek-V3.2(GA) / Test Tencent DeepSeek-V3.2 (GA)"""
116
+ config = get_specific_model_config("deepseek-v3.2")
117
+
118
+ assert config is not None
119
+ version, variant, capabilities = config
120
+ assert version == "v3.2"
121
+ assert variant == "v3.2"
122
+ assert capabilities is not None
123
+ assert capabilities.supports_thinking is True
124
+ assert capabilities.supports_function_calling is True
125
+ assert capabilities.supports_streaming is True
126
+ assert capabilities.max_tokens == 32000
127
+ assert capabilities.context_window == 128000
128
+
129
+
112
130
  def test_tencent_deepseek_pattern_matching() -> None:
113
131
  """测试腾讯云 DeepSeek 模式匹配 / Test Tencent DeepSeek pattern matching"""
114
132
  # 测试 V3 系列
@@ -158,8 +176,12 @@ def test_tencent_deepseek_no_collision_with_official() -> None:
158
176
  assert tencent_v3.variant == "base"
159
177
 
160
178
  # 不同的能力配置
161
- assert official_chat.capabilities.max_tokens == 8000
179
+ # 官方 deepseek-chat 当前指向 V4-flash 非思考模式(1M 上下文,384K 输出)
180
+ assert official_chat.capabilities.max_tokens == 384_000
181
+ assert official_chat.capabilities.context_window == 1_000_000
182
+ # 腾讯云保持其自有的 DeepSeek 部署规格
162
183
  assert tencent_v3.capabilities.max_tokens == 16000
184
+ assert tencent_v3.capabilities.context_window == 64000
163
185
 
164
186
 
165
187
  def test_tencent_deepseek_invalid_model_names() -> None:
@@ -193,7 +193,6 @@ def test_gpt5_4_model():
193
193
  assert m.capabilities.supports_computer_use is True
194
194
 
195
195
 
196
-
197
196
  def test_gpt5_4_with_date_suffix():
198
197
  """测试带日期的GPT-5.4模型 / Test GPT-5.4 with date suffix"""
199
198
  m = LLMeta("gpt-5.4-2026-03-05")
@@ -239,7 +238,6 @@ def test_gpt5_4_mini_model():
239
238
  assert m.capabilities.supports_computer_use is True
240
239
 
241
240
 
242
-
243
241
  def test_gpt5_4_mini_with_date_suffix():
244
242
  """测试带日期的GPT-5.4-mini模型 / Test GPT-5.4-mini with date suffix"""
245
243
  m = LLMeta("gpt-5.4-mini-2026-03-17")
@@ -267,7 +265,6 @@ def test_gpt5_4_nano_model():
267
265
  assert m.capabilities.supports_computer_use is False
268
266
 
269
267
 
270
-
271
268
  def test_gpt5_4_nano_with_date_suffix():
272
269
  """测试带日期的GPT-5.4-nano模型 / Test GPT-5.4-nano with date suffix"""
273
270
  m = LLMeta("gpt-5.4-nano-2026-03-17")
@@ -102,7 +102,8 @@ class TestAutoRegister(unittest.TestCase):
102
102
  assert model.family == ModelFamily.DEEPSEEK
103
103
  assert model.provider == Provider.DEEPSEEK
104
104
  assert model.capabilities.supports_function_calling is True
105
- assert model.capabilities.context_window == 128000
105
+ # V4 deepseek-chat 别名为 v4-flash 非思考模式,上下文扩展为 1M
106
+ assert model.capabilities.context_window == 1_000_000
106
107
 
107
108
  def test_auto_register_qwen_variant(self) -> None:
108
109
  """测试自动注册 Qwen 新型号 / Test auto-register Qwen new variant"""
@@ -968,7 +968,7 @@ wheels = [
968
968
 
969
969
  [[package]]
970
970
  name = "whosellm"
971
- version = "0.2.1"
971
+ version = "0.2.2"
972
972
  source = { editable = "." }
973
973
  dependencies = [
974
974
  { name = "parse" },
@@ -7,7 +7,7 @@
7
7
  LLMeta - 统一的大语言模型版本和能力管理库 / A unified LLM model version and capability management library
8
8
  """
9
9
 
10
- __version__ = "0.2.1"
10
+ __version__ = "0.2.2"
11
11
 
12
12
  from whosellm.capabilities import ModelCapabilities
13
13
  from whosellm.model_version import LLMeta
@@ -0,0 +1,117 @@
1
+ # filename: deepseek_official.py
2
+ # @Time : 2025/11/9 15:57
3
+ # @Author : Cascade AI
4
+ """
5
+ DeepSeek 官方模型家族配置 / DeepSeek official model family configuration
6
+
7
+ 当前主力:deepseek-v4-flash / deepseek-v4-pro(1M 上下文,384K 最大输出,
8
+ 支持思考与非思考双模式)。
9
+ Current primary models: deepseek-v4-flash / deepseek-v4-pro (1M context, 384K max output,
10
+ both thinking and non-thinking modes supported).
11
+
12
+ 兼容别名:deepseek-chat / deepseek-reasoner(官方宣布未来将废弃,当前分别对应
13
+ deepseek-v4-flash 的非思考与思考模式)。
14
+ Legacy aliases: deepseek-chat / deepseek-reasoner (announced to be deprecated;
15
+ currently map to deepseek-v4-flash non-thinking and thinking modes respectively).
16
+ """
17
+
18
+ from whosellm.capabilities import ModelCapabilities
19
+ from whosellm.models.base import ModelFamily
20
+ from whosellm.models.config import ModelFamilyConfig, SpecificModelConfig
21
+ from whosellm.provider import Provider
22
+
23
+ # V4 系列共用能力基线 / Shared capability baseline for V4 series
24
+ _V4_CAPABILITIES = ModelCapabilities(
25
+ supports_thinking=True,
26
+ supports_function_calling=True,
27
+ supports_streaming=True,
28
+ supports_json_outputs=True,
29
+ # DeepSeek 仅提供 response_format={type:"json_object"},不支持 json_schema
30
+ # DeepSeek only supports response_format={type:"json_object"}, not json_schema
31
+ supports_structured_outputs=False,
32
+ max_tokens=384_000,
33
+ context_window=1_000_000,
34
+ )
35
+
36
+ DEEPSEEK = ModelFamilyConfig(
37
+ family=ModelFamily.DEEPSEEK,
38
+ provider=Provider.DEEPSEEK,
39
+ version_default="4.0",
40
+ variant_default="flash",
41
+ variant_priority_default=(0,),
42
+ patterns=[
43
+ # 版本号命名(V4 起开放给 API 调用) / Version-numbered naming (open to API since V4)
44
+ "deepseek-v{major:d}.{minor:d}-{variant:variant}",
45
+ "deepseek-v{major:d}.{minor:d}",
46
+ "deepseek-v{major:d}-{variant:variant}",
47
+ "deepseek-v{major:d}",
48
+ # 兼容别名 / Legacy aliases
49
+ "deepseek-chat-{suffix}",
50
+ "deepseek-chat",
51
+ "deepseek-reasoner-{suffix}",
52
+ "deepseek-reasoner",
53
+ ],
54
+ capabilities=_V4_CAPABILITIES,
55
+ specific_models={
56
+ # 当前旗舰:deepseek-v4-flash / Current flagship: deepseek-v4-flash
57
+ "deepseek-v4-flash": SpecificModelConfig(
58
+ version_default="4.0",
59
+ variant_default="flash",
60
+ variant_priority=(0,),
61
+ capabilities=_V4_CAPABILITIES,
62
+ patterns=[
63
+ "deepseek-v4-flash",
64
+ ],
65
+ ),
66
+ # 高阶版:deepseek-v4-pro / Professional tier: deepseek-v4-pro
67
+ "deepseek-v4-pro": SpecificModelConfig(
68
+ version_default="4.0",
69
+ variant_default="pro",
70
+ variant_priority=(4,),
71
+ capabilities=_V4_CAPABILITIES,
72
+ patterns=[
73
+ "deepseek-v4-pro",
74
+ ],
75
+ ),
76
+ # 兼容别名:deepseek-chat → v4-flash 非思考模式
77
+ # Legacy alias: deepseek-chat → v4-flash non-thinking mode
78
+ "deepseek-chat": SpecificModelConfig(
79
+ version_default="4.0",
80
+ variant_default="chat",
81
+ variant_priority=(1,),
82
+ capabilities=ModelCapabilities(
83
+ supports_thinking=False,
84
+ supports_function_calling=True,
85
+ supports_streaming=True,
86
+ supports_json_outputs=True,
87
+ supports_structured_outputs=False,
88
+ max_tokens=384_000,
89
+ context_window=1_000_000,
90
+ ),
91
+ patterns=[
92
+ "deepseek-chat-{suffix}",
93
+ "deepseek-chat",
94
+ ],
95
+ ),
96
+ # 兼容别名:deepseek-reasoner → v4-flash 思考模式
97
+ # Legacy alias: deepseek-reasoner → v4-flash thinking mode
98
+ "deepseek-reasoner": SpecificModelConfig(
99
+ version_default="4.0",
100
+ variant_default="reasoner",
101
+ variant_priority=(2,),
102
+ capabilities=ModelCapabilities(
103
+ supports_thinking=True,
104
+ supports_function_calling=True,
105
+ supports_streaming=True,
106
+ supports_json_outputs=True,
107
+ supports_structured_outputs=False,
108
+ max_tokens=384_000,
109
+ context_window=1_000_000,
110
+ ),
111
+ patterns=[
112
+ "deepseek-reasoner-{suffix}",
113
+ "deepseek-reasoner",
114
+ ],
115
+ ),
116
+ },
117
+ )
@@ -78,12 +78,14 @@ DEEPSEEK_TENCENT = ModelFamilyConfig(
78
78
  ],
79
79
  ),
80
80
  # DeepSeek-R1-0528
81
+ # 腾讯云 LKE 文档明确列为 Function Calling 不支持(位于"不支持设置的功能")
82
+ # Tencent LKE docs explicitly list Function Calling as unsupported for this model
81
83
  "deepseek-r1-0528": SpecificModelConfig(
82
84
  version_default="r1-0528",
83
85
  variant_default="r1-0528",
84
86
  capabilities=ModelCapabilities(
85
87
  supports_thinking=True,
86
- supports_function_calling=True,
88
+ supports_function_calling=False,
87
89
  supports_streaming=True,
88
90
  max_tokens=16000,
89
91
  context_window=128000,
@@ -125,7 +127,8 @@ DEEPSEEK_TENCENT = ModelFamilyConfig(
125
127
  "deepseek-v3.1-terminus",
126
128
  ],
127
129
  ),
128
- # DeepSeek-V3.2-Exp
130
+ # DeepSeek-V3.2-Exp(已被 deepseek-v3.2 GA 版替代,保留以兼容历史调用)
131
+ # DeepSeek-V3.2-Exp (superseded by deepseek-v3.2 GA; kept for backward compatibility)
129
132
  "deepseek-v3.2-exp": SpecificModelConfig(
130
133
  version_default="v3.2-exp",
131
134
  variant_default="v3.2-exp",
@@ -141,5 +144,22 @@ DEEPSEEK_TENCENT = ModelFamilyConfig(
141
144
  "deepseek-v3.2-exp",
142
145
  ],
143
146
  ),
147
+ # DeepSeek-V3.2(GA 版,685B MoE,稀疏注意力,可选思考模式)
148
+ # DeepSeek-V3.2 (GA, 685B MoE, sparse attention, optional thinking mode)
149
+ "deepseek-v3.2": SpecificModelConfig(
150
+ version_default="v3.2",
151
+ variant_default="v3.2",
152
+ capabilities=ModelCapabilities(
153
+ supports_thinking=True,
154
+ supports_function_calling=True,
155
+ supports_streaming=True,
156
+ max_tokens=32000,
157
+ context_window=128000,
158
+ ),
159
+ variant_priority=(1,),
160
+ patterns=[
161
+ "deepseek-v3.2",
162
+ ],
163
+ ),
144
164
  },
145
165
  )
@@ -31,7 +31,6 @@ GPT_4_1 = ModelFamilyConfig(
31
31
  supports_file_search=True,
32
32
  supports_image_generation=True,
33
33
  supports_code_interpreter=True,
34
-
35
34
  max_tokens=32768,
36
35
  context_window=1_047_576,
37
36
  ),
@@ -33,7 +33,6 @@ GPT_5 = ModelFamilyConfig(
33
33
  supports_file_search=True,
34
34
  supports_image_generation=True,
35
35
  supports_code_interpreter=True,
36
-
37
36
  max_tokens=128_000,
38
37
  context_window=400_000,
39
38
  ),
@@ -66,7 +65,6 @@ GPT_5 = ModelFamilyConfig(
66
65
  supports_file_search=True,
67
66
  supports_image_generation=False,
68
67
  supports_code_interpreter=True,
69
-
70
68
  max_tokens=128_000,
71
69
  context_window=400_000,
72
70
  ),
@@ -93,7 +91,6 @@ GPT_5 = ModelFamilyConfig(
93
91
  supports_file_search=True,
94
92
  supports_image_generation=False,
95
93
  supports_code_interpreter=False,
96
-
97
94
  max_tokens=16_384,
98
95
  context_window=128_000,
99
96
  ),
@@ -121,7 +118,6 @@ GPT_5 = ModelFamilyConfig(
121
118
  supports_image_generation=True,
122
119
  supports_code_interpreter=True,
123
120
  supports_computer_use=True,
124
-
125
121
  max_tokens=128_000,
126
122
  context_window=400_000,
127
123
  ),
@@ -25,7 +25,6 @@ GPT_5_1 = ModelFamilyConfig(
25
25
  supports_file_search=True,
26
26
  supports_image_generation=True,
27
27
  supports_code_interpreter=True,
28
-
29
28
  max_tokens=128_000,
30
29
  context_window=1_050_000,
31
30
  ),
@@ -25,7 +25,6 @@ GPT_5_2 = ModelFamilyConfig(
25
25
  supports_file_search=True,
26
26
  supports_image_generation=True,
27
27
  supports_code_interpreter=True,
28
-
29
28
  max_tokens=128_000,
30
29
  context_window=1_050_000,
31
30
  ),
@@ -57,7 +56,6 @@ GPT_5_2 = ModelFamilyConfig(
57
56
  supports_image_generation=True,
58
57
  supports_code_interpreter=True,
59
58
  supports_computer_use=True,
60
-
61
59
  max_tokens=128_000,
62
60
  context_window=1_050_000,
63
61
  ),
@@ -40,7 +40,6 @@ GPT_5_4 = ModelFamilyConfig(
40
40
  supports_image_generation=True,
41
41
  supports_code_interpreter=True,
42
42
  supports_computer_use=True,
43
-
44
43
  max_tokens=128_000,
45
44
  context_window=1_050_000,
46
45
  ),
@@ -72,7 +71,6 @@ GPT_5_4 = ModelFamilyConfig(
72
71
  supports_image_generation=True,
73
72
  supports_code_interpreter=False,
74
73
  supports_computer_use=True,
75
-
76
74
  max_tokens=128_000,
77
75
  context_window=1_050_000,
78
76
  ),
@@ -98,7 +96,6 @@ GPT_5_4 = ModelFamilyConfig(
98
96
  supports_image_generation=True,
99
97
  supports_code_interpreter=True,
100
98
  supports_computer_use=True,
101
-
102
99
  max_tokens=128_000,
103
100
  context_window=400_000,
104
101
  ),
@@ -124,7 +121,6 @@ GPT_5_4 = ModelFamilyConfig(
124
121
  supports_image_generation=True,
125
122
  supports_code_interpreter=True,
126
123
  supports_computer_use=False,
127
-
128
124
  max_tokens=128_000,
129
125
  context_window=400_000,
130
126
  ),
@@ -260,7 +260,6 @@ GLM_TEXT = ModelFamilyConfig(
260
260
  supports_function_calling=True,
261
261
  supports_structured_outputs=False,
262
262
  supports_streaming=True,
263
-
264
263
  max_tokens=128000,
265
264
  context_window=200000,
266
265
  ),
@@ -275,7 +274,6 @@ GLM_TEXT = ModelFamilyConfig(
275
274
  supports_function_calling=True,
276
275
  supports_structured_outputs=False,
277
276
  supports_streaming=True,
278
-
279
277
  max_tokens=128000,
280
278
  context_window=200000,
281
279
  ),
@@ -289,7 +287,6 @@ GLM_TEXT = ModelFamilyConfig(
289
287
  supports_function_calling=True,
290
288
  supports_structured_outputs=False,
291
289
  supports_streaming=True,
292
-
293
290
  max_tokens=128000,
294
291
  context_window=200000,
295
292
  ),
@@ -308,7 +305,6 @@ GLM_TEXT = ModelFamilyConfig(
308
305
  supports_function_calling=True,
309
306
  supports_structured_outputs=False,
310
307
  supports_streaming=True,
311
-
312
308
  max_tokens=128000,
313
309
  context_window=200000,
314
310
  ),
@@ -329,7 +325,6 @@ GLM_TEXT = ModelFamilyConfig(
329
325
  supports_streaming=True,
330
326
  supports_structured_outputs=False,
331
327
  supports_web_search=True,
332
-
333
328
  max_tokens=128000,
334
329
  context_window=200000,
335
330
  ),
@@ -1,72 +0,0 @@
1
- # filename: deepseek_official.py
2
- # @Time : 2025/11/9 15:57
3
- # @Author : Cascade AI
4
- """
5
- DeepSeek 官方模型家族配置 / DeepSeek official model family configuration
6
-
7
- 包含 deepseek-chat 与 deepseek-reasoner 模型
8
- Includes deepseek-chat and deepseek-reasoner models
9
- """
10
-
11
- from whosellm.capabilities import ModelCapabilities
12
- from whosellm.models.base import ModelFamily
13
- from whosellm.models.config import ModelFamilyConfig, SpecificModelConfig
14
- from whosellm.provider import Provider
15
-
16
- DEEPSEEK = ModelFamilyConfig(
17
- family=ModelFamily.DEEPSEEK,
18
- provider=Provider.DEEPSEEK,
19
- version_default="1.0",
20
- variant_default="base",
21
- variant_priority_default=(1,),
22
- patterns=[
23
- "deepseek-chat-{suffix}",
24
- "deepseek-chat",
25
- "deepseek-reasoner-{suffix}",
26
- "deepseek-reasoner",
27
- ],
28
- capabilities=ModelCapabilities(
29
- supports_function_calling=True,
30
- supports_streaming=True,
31
- supports_structured_outputs=False,
32
- max_tokens=8000,
33
- context_window=128000,
34
- ),
35
- specific_models={
36
- "deepseek-chat": SpecificModelConfig(
37
- version_default="1.0",
38
- variant_default="chat",
39
- capabilities=ModelCapabilities(
40
- supports_function_calling=True,
41
- supports_streaming=True,
42
- supports_structured_outputs=False,
43
- max_tokens=8000,
44
- context_window=128000,
45
- ),
46
- variant_priority=(1,),
47
- patterns=[
48
- "deepseek-chat-{suffix}",
49
- "deepseek-chat",
50
- ],
51
- ),
52
- "deepseek-reasoner": SpecificModelConfig(
53
- version_default="1.0",
54
- variant_default="reasoner",
55
- capabilities=ModelCapabilities(
56
- supports_thinking=True,
57
- supports_streaming=True,
58
- # DS Reasoner模型原生是不支持工具调用的,但是官方做了优化,如果向R1模型发起带有Tools调用的请求,会自动路由至Chat模型。
59
- # 因此在这里标记为支持FunctionCall
60
- supports_function_calling=True,
61
- supports_structured_outputs=False,
62
- max_tokens=64000,
63
- context_window=128000,
64
- ),
65
- variant_priority=(2,),
66
- patterns=[
67
- "deepseek-reasoner-{suffix}",
68
- "deepseek-reasoner",
69
- ],
70
- ),
71
- },
72
- )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes