whosellm 0.3.0__tar.gz → 0.3.1__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.
- {whosellm-0.3.0 → whosellm-0.3.1}/.bumpversion.toml +1 -1
- {whosellm-0.3.0 → whosellm-0.3.1}/PKG-INFO +1 -1
- {whosellm-0.3.0 → whosellm-0.3.1}/pyproject.toml +1 -1
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/e2e/test_anthropic.py +35 -1
- whosellm-0.3.1/tests/e2e/test_deepseek.py +151 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/e2e/test_openai.py +41 -1
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_anthropic.py +68 -2
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_deepseek.py +99 -0
- whosellm-0.3.1/tests/models/families/test_gpt6.py +166 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_media_count_limit_config.py +12 -2
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/test_variant_priority_config.py +9 -6
- {whosellm-0.3.0 → whosellm-0.3.1}/uv.lock +1 -1
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/__init__.py +1 -1
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/anthropic.py +30 -0
- whosellm-0.3.1/whosellm/models/families/deepseek/deepseek_official.py +191 -0
- whosellm-0.3.1/whosellm/models/families/openai/openai_gpt_6.py +94 -0
- whosellm-0.3.0/tests/models/families/test_gpt6.py +0 -70
- whosellm-0.3.0/whosellm/models/families/deepseek/deepseek_official.py +0 -145
- whosellm-0.3.0/whosellm/models/families/openai/openai_gpt_6.py +0 -56
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/commands/interview.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/projects/-Users-jqq-PycharmProjects-llmeta/memory/MEMORY.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/projects/-Users-jqq-PycharmProjects-llmeta/memory/feedback_use_uv.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/settings.json +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/code-review/SKILL.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/create-skill/SKILL.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/e2e-metadata/SKILL.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/evolve/SKILL.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/fix-review/SKILL.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/release/SKILL.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/review-provider-model/SKILL.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/review-provider-model/providers/alibaba.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/review-provider-model/providers/anthropic.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/review-provider-model/providers/deepseek.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/review-provider-model/providers/gemini.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/review-provider-model/providers/openai.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/review-provider-model/providers/others.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/review-provider-model/providers/vidu.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/review-provider-model/providers/zhipu.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/update-provider-model/SKILL.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.claude/skills/update-provider-model/testing.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.coveragerc +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.github/workflows/publish.yml +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.github/workflows/tests.yml +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.gitignore +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.windsurf/workflows/addmodel.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.windsurf/workflows/arch.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/.windsurf/workflows/testllmeta.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/CHANGELOG.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/CLAUDE.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/LICENSE +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/README.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/docs/add_new_model_family.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/docs/refactor_proposal.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/docs/spec_model_family_redesign.md +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/examples/advanced_usage.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/examples/basic_usage.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/mypy.ini +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/pytest.ini +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/ruff.toml +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/__init__.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/e2e/__init__.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/e2e/conftest.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/e2e/test_google.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/e2e/test_zhipu.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/__init__.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/__init__.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_deepseek_tencent.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_gemini.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_glm41v_thinking.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_glm45.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_glm45v.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_glm46.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_glm46v.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_glm5.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_glm53.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_glm5v_turbo.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_gpt3_5.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_gpt4_1.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_gpt4o.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_gpt5.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_o1.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_o3.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_o4.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_qwen.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_qwen3_vl_models.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_qwen_ollama.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/models/families/test_qwen_plus.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/test_auto_register.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/test_claude_4x_versions.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/test_llmeta.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/test_media_count_limit.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/test_model_version.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/test_provider.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/test_registry_merge.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/tests/test_specific_patterns.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/capabilities.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/model_version.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/__init__.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/base.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/config.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/dynamic_enum.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/__init__.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/alibaba.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/deepseek/__init__.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/deepseek/tencent.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/gemini.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/__init__.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_gpt_3_5.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_gpt_4.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_gpt_4_1.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_gpt_4o.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_gpt_5.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_gpt_5_1.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_gpt_5_2.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_gpt_5_3.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_gpt_5_4.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_gpt_5_5.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_gpt_5_6.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_o1.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_o3.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/openai/openai_o4.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/others.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/vidu.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/families/zhipu.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/patterns.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/models/registry.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/provider.py +0 -0
- {whosellm-0.3.0 → whosellm-0.3.1}/whosellm/py.typed +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
来源: https://platform.claude.com/docs/en/docs/about-claude/models
|
|
4
4
|
采集日期: 2026-04-12(2026-09-04 增补 Fable 5.1 / Mythos 5.1)
|
|
5
|
+
2026-09-23 增补 Opus 5.5
|
|
5
6
|
"""
|
|
6
7
|
|
|
7
8
|
import pytest
|
|
@@ -10,6 +11,33 @@ from whosellm import ModelFamily, Provider
|
|
|
10
11
|
|
|
11
12
|
from .conftest import assert_model_metadata
|
|
12
13
|
|
|
14
|
+
# ============================================================================
|
|
15
|
+
# Claude Family — Version 5.5 (2026-09-22 发布 / Released 2026-09-22)
|
|
16
|
+
# 来源: https://platform.claude.com/docs/en/release-notes/overview
|
|
17
|
+
# ============================================================================
|
|
18
|
+
|
|
19
|
+
CLAUDE_55_MODELS = [
|
|
20
|
+
(
|
|
21
|
+
"claude-opus-5-5",
|
|
22
|
+
{
|
|
23
|
+
# 1M ctx (默认且最大) / 128K out;adaptive thinking 常开且不可关闭
|
|
24
|
+
# 1M ctx (default & max) / 128K out; adaptive thinking always on, cannot be disabled
|
|
25
|
+
"provider": Provider.ANTHROPIC,
|
|
26
|
+
"family": ModelFamily.CLAUDE,
|
|
27
|
+
"version": "5.5",
|
|
28
|
+
"variant": "opus",
|
|
29
|
+
"supports_thinking": True,
|
|
30
|
+
"supports_vision": True,
|
|
31
|
+
"supports_streaming": True,
|
|
32
|
+
"supports_function_calling": True,
|
|
33
|
+
"supports_structured_outputs": True,
|
|
34
|
+
"supports_computer_use": True,
|
|
35
|
+
"context_window": 1_000_000,
|
|
36
|
+
"max_tokens": 128_000,
|
|
37
|
+
},
|
|
38
|
+
),
|
|
39
|
+
]
|
|
40
|
+
|
|
13
41
|
# ============================================================================
|
|
14
42
|
# Claude Family — Version 5.1 (2026-09-01 发布 / Released 2026-09-01)
|
|
15
43
|
# 来源: https://platform.claude.com/docs/en/models/fable-5-1/overview
|
|
@@ -234,7 +262,13 @@ CLAUDE_30_MODELS = [
|
|
|
234
262
|
# ============================================================================
|
|
235
263
|
|
|
236
264
|
ALL_MODELS = (
|
|
237
|
-
|
|
265
|
+
CLAUDE_55_MODELS
|
|
266
|
+
+ CLAUDE_51_MODELS
|
|
267
|
+
+ CLAUDE_LATEST_MODELS
|
|
268
|
+
+ CLAUDE_45_MODELS
|
|
269
|
+
+ CLAUDE_41_MODELS
|
|
270
|
+
+ CLAUDE_40_MODELS
|
|
271
|
+
+ CLAUDE_30_MODELS
|
|
238
272
|
)
|
|
239
273
|
|
|
240
274
|
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# filename: test_deepseek.py
|
|
2
|
+
"""
|
|
3
|
+
DeepSeek 官方模型元数据 E2E 测试 / DeepSeek official model metadata E2E tests.
|
|
4
|
+
|
|
5
|
+
来源 / Sources:
|
|
6
|
+
https://api-docs.deepseek.com/zh-cn/updates/(2026-09-10 DeepSeek-V4.1-Flash 发布)
|
|
7
|
+
https://api-docs.deepseek.com/zh-cn/quick_start/pricing
|
|
8
|
+
https://api-docs.deepseek.com/zh-cn/guides/vision
|
|
9
|
+
采集日期 / Collected: 2026-09-28(含 api.deepseek.com 实探复核 / verified against the live API)
|
|
10
|
+
|
|
11
|
+
约定 / Conventions:
|
|
12
|
+
* 旧名(deepseek-v4-flash / -vision-exp / deepseek-chat / deepseek-reasoner)版本仍按名字解析为
|
|
13
|
+
4.0,能力按当前实际服务模型(转发到 DeepSeek-V4.1-Flash)标注。
|
|
14
|
+
Legacy names keep their name-derived version (4.0) while capabilities follow the
|
|
15
|
+
currently serving model (routed to DeepSeek-V4.1-Flash).
|
|
16
|
+
* deepseek-v4-pro 未被路由,保持纯文本(无图像输入)。
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import pytest
|
|
20
|
+
|
|
21
|
+
from whosellm import ModelFamily, Provider
|
|
22
|
+
|
|
23
|
+
from .conftest import assert_model_metadata
|
|
24
|
+
|
|
25
|
+
# ============================================================================
|
|
26
|
+
# DeepSeek V4.1-Flash 正式名(2026-09-10 发布)/ Canonical name of DeepSeek-V4.1-Flash
|
|
27
|
+
# 官方:"将模型名称更改为 deepseek-flash 即可调用最新的 V4.1 Flash 模型"
|
|
28
|
+
# ============================================================================
|
|
29
|
+
|
|
30
|
+
V41_FLASH_MODELS = [
|
|
31
|
+
(
|
|
32
|
+
"deepseek-flash",
|
|
33
|
+
{
|
|
34
|
+
"provider": Provider.DEEPSEEK,
|
|
35
|
+
"family": ModelFamily.DEEPSEEK,
|
|
36
|
+
# 名字无版本号 → 按官方模型版本 DeepSeek-V4.1-Flash 标注
|
|
37
|
+
"version": "4.1",
|
|
38
|
+
"variant": "flash",
|
|
39
|
+
"supports_thinking": True, # 默认开启,effort 默认 high
|
|
40
|
+
"supports_vision": True, # 原生多模态视觉理解
|
|
41
|
+
"supports_function_calling": True,
|
|
42
|
+
"supports_streaming": True,
|
|
43
|
+
"supports_json_outputs": True,
|
|
44
|
+
"supports_structured_outputs": False, # 仅 json_object,无 json_schema
|
|
45
|
+
"context_window": 1_000_000,
|
|
46
|
+
"max_tokens": 384_000,
|
|
47
|
+
},
|
|
48
|
+
),
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
# ============================================================================
|
|
52
|
+
# 兼容路由旧名(官方措辞"暂时路由")/ Routed legacy names ("temporarily routed" per vendor)
|
|
53
|
+
# ============================================================================
|
|
54
|
+
|
|
55
|
+
ROUTED_LEGACY_MODELS = [
|
|
56
|
+
(
|
|
57
|
+
"deepseek-v4-flash",
|
|
58
|
+
{
|
|
59
|
+
"provider": Provider.DEEPSEEK,
|
|
60
|
+
"family": ModelFamily.DEEPSEEK,
|
|
61
|
+
"version": "4.0", # 版本轴按名字 / version parses from the name
|
|
62
|
+
"variant": "flash",
|
|
63
|
+
"supports_thinking": True,
|
|
64
|
+
"supports_vision": True, # 能力轴跟实际服务模型 / capabilities follow the serving model
|
|
65
|
+
"supports_function_calling": True,
|
|
66
|
+
"supports_streaming": True,
|
|
67
|
+
"context_window": 1_000_000,
|
|
68
|
+
"max_tokens": 384_000,
|
|
69
|
+
},
|
|
70
|
+
),
|
|
71
|
+
(
|
|
72
|
+
"deepseek-v4-flash-vision-exp",
|
|
73
|
+
{
|
|
74
|
+
"provider": Provider.DEEPSEEK,
|
|
75
|
+
"family": ModelFamily.DEEPSEEK,
|
|
76
|
+
"version": "4.0",
|
|
77
|
+
"variant": "flash-vision-exp",
|
|
78
|
+
"supports_thinking": True,
|
|
79
|
+
"supports_vision": True,
|
|
80
|
+
"context_window": 1_000_000,
|
|
81
|
+
"max_tokens": 384_000,
|
|
82
|
+
},
|
|
83
|
+
),
|
|
84
|
+
(
|
|
85
|
+
"deepseek-chat",
|
|
86
|
+
{
|
|
87
|
+
"provider": Provider.DEEPSEEK,
|
|
88
|
+
"family": ModelFamily.DEEPSEEK,
|
|
89
|
+
"version": "4.0",
|
|
90
|
+
"variant": "chat",
|
|
91
|
+
"supports_thinking": False, # 别名默认非思考模式 / alias defaults to non-thinking
|
|
92
|
+
"supports_vision": True,
|
|
93
|
+
"context_window": 1_000_000,
|
|
94
|
+
"max_tokens": 384_000,
|
|
95
|
+
},
|
|
96
|
+
),
|
|
97
|
+
(
|
|
98
|
+
"deepseek-reasoner",
|
|
99
|
+
{
|
|
100
|
+
"provider": Provider.DEEPSEEK,
|
|
101
|
+
"family": ModelFamily.DEEPSEEK,
|
|
102
|
+
"version": "4.0",
|
|
103
|
+
"variant": "reasoner",
|
|
104
|
+
"supports_thinking": True, # 别名默认思考模式 / alias defaults to thinking
|
|
105
|
+
"supports_vision": True,
|
|
106
|
+
"context_window": 1_000_000,
|
|
107
|
+
"max_tokens": 384_000,
|
|
108
|
+
},
|
|
109
|
+
),
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
# ============================================================================
|
|
113
|
+
# 未被路由:deepseek-v4-pro 仍是 DeepSeek-V4-Pro-0813,纯文本
|
|
114
|
+
# Not routed: deepseek-v4-pro is still DeepSeek-V4-Pro-0813, text-only
|
|
115
|
+
# 实探 2026-09-28:带图不报错但静默忽略并编造答案 → supports_vision 必须为 False
|
|
116
|
+
# ============================================================================
|
|
117
|
+
|
|
118
|
+
TEXT_ONLY_MODELS = [
|
|
119
|
+
(
|
|
120
|
+
"deepseek-v4-pro",
|
|
121
|
+
{
|
|
122
|
+
"provider": Provider.DEEPSEEK,
|
|
123
|
+
"family": ModelFamily.DEEPSEEK,
|
|
124
|
+
"version": "4.0",
|
|
125
|
+
"variant": "pro",
|
|
126
|
+
"supports_thinking": True,
|
|
127
|
+
"supports_vision": False,
|
|
128
|
+
"supports_function_calling": True,
|
|
129
|
+
"supports_streaming": True,
|
|
130
|
+
"context_window": 1_000_000,
|
|
131
|
+
"max_tokens": 384_000,
|
|
132
|
+
},
|
|
133
|
+
),
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
# ============================================================================
|
|
137
|
+
# 聚合 + 参数化 / Aggregation & parametrization
|
|
138
|
+
# ============================================================================
|
|
139
|
+
|
|
140
|
+
ALL_MODELS = V41_FLASH_MODELS + ROUTED_LEGACY_MODELS + TEXT_ONLY_MODELS
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@pytest.mark.e2e
|
|
144
|
+
@pytest.mark.parametrize(
|
|
145
|
+
"model_name,expected",
|
|
146
|
+
ALL_MODELS,
|
|
147
|
+
ids=[m[0] for m in ALL_MODELS],
|
|
148
|
+
)
|
|
149
|
+
def test_model_metadata(model_name: str, expected: dict) -> None: # type: ignore[type-arg]
|
|
150
|
+
"""验证 DeepSeek 模型元数据与官方文档一致。"""
|
|
151
|
+
assert_model_metadata(model_name, expected)
|
|
@@ -15,6 +15,7 @@ from .conftest import assert_model_metadata
|
|
|
15
15
|
# 来源: https://developers.openai.com/api/docs/models/gpt-5.4(2026-04-12 采集)
|
|
16
16
|
# https://developers.openai.com/api/docs/models/gpt-5.6-sol(2026-08-20 采集 5.5/5.6)
|
|
17
17
|
# https://developers.openai.com/api/docs/models/gpt-6-astra(2026-09-04 采集 6-astra/5.6-cyber)
|
|
18
|
+
# https://developers.openai.com/api/docs/models/gpt-6-sol(2026-09-23 采集 6-sol/6-luna)
|
|
18
19
|
# ============================================================================
|
|
19
20
|
|
|
20
21
|
GPT_MODELS = [
|
|
@@ -219,7 +220,7 @@ GPT_MODELS = [
|
|
|
219
220
|
},
|
|
220
221
|
),
|
|
221
222
|
# ------------------------------------------------------------------
|
|
222
|
-
# GPT-6
|
|
223
|
+
# GPT-6 天体档位系列(2026-09-04 采集 astra)
|
|
223
224
|
# 来源: https://developers.openai.com/api/docs/models/gpt-6-astra
|
|
224
225
|
# ------------------------------------------------------------------
|
|
225
226
|
(
|
|
@@ -239,6 +240,45 @@ GPT_MODELS = [
|
|
|
239
240
|
"max_tokens": 128_000,
|
|
240
241
|
},
|
|
241
242
|
),
|
|
243
|
+
# ------------------------------------------------------------------
|
|
244
|
+
# GPT-6 Sol / Luna(2026-09-22 发布,2026-09-23 采集)
|
|
245
|
+
# 与 astra 同窗口同工具面;sol 中档主力、luna 低成本档,GPT-6 无 terra 档
|
|
246
|
+
# 来源: https://developers.openai.com/api/docs/models/gpt-6-sol
|
|
247
|
+
# ------------------------------------------------------------------
|
|
248
|
+
(
|
|
249
|
+
"gpt-6-sol",
|
|
250
|
+
{
|
|
251
|
+
"provider": Provider.OPENAI,
|
|
252
|
+
"family": ModelFamily.GPT,
|
|
253
|
+
"version": "6.0",
|
|
254
|
+
"variant": "sol",
|
|
255
|
+
"supports_thinking": True,
|
|
256
|
+
"supports_vision": True,
|
|
257
|
+
"supports_streaming": True,
|
|
258
|
+
"supports_function_calling": True,
|
|
259
|
+
"supports_structured_outputs": True,
|
|
260
|
+
"supports_computer_use": True,
|
|
261
|
+
"context_window": 1_050_000,
|
|
262
|
+
"max_tokens": 128_000,
|
|
263
|
+
},
|
|
264
|
+
),
|
|
265
|
+
(
|
|
266
|
+
"gpt-6-luna",
|
|
267
|
+
{
|
|
268
|
+
"provider": Provider.OPENAI,
|
|
269
|
+
"family": ModelFamily.GPT,
|
|
270
|
+
"version": "6.0",
|
|
271
|
+
"variant": "luna",
|
|
272
|
+
"supports_thinking": True,
|
|
273
|
+
"supports_vision": True,
|
|
274
|
+
"supports_streaming": True,
|
|
275
|
+
"supports_function_calling": True,
|
|
276
|
+
"supports_structured_outputs": True,
|
|
277
|
+
"supports_computer_use": True,
|
|
278
|
+
"context_window": 1_050_000,
|
|
279
|
+
"max_tokens": 128_000,
|
|
280
|
+
},
|
|
281
|
+
),
|
|
242
282
|
]
|
|
243
283
|
|
|
244
284
|
# ============================================================================
|
|
@@ -253,7 +253,7 @@ class TestClaudeMythosClassOrdering:
|
|
|
253
253
|
assert LLMeta("claude-mythos-5") > LLMeta("claude-fable-5")
|
|
254
254
|
|
|
255
255
|
def test_mythos5_is_top(self):
|
|
256
|
-
"""mythos-5
|
|
256
|
+
"""mythos-5 在所列模型中最高 / mythos-5 is the highest among the models listed"""
|
|
257
257
|
models = [
|
|
258
258
|
LLMeta("claude-mythos-5"),
|
|
259
259
|
LLMeta("claude-fable-5"),
|
|
@@ -264,6 +264,57 @@ class TestClaudeMythosClassOrdering:
|
|
|
264
264
|
assert max(models).variant == "mythos"
|
|
265
265
|
|
|
266
266
|
|
|
267
|
+
class TestClaudeOpus55:
|
|
268
|
+
"""Claude Opus 5.5 测试(2026-09-22 发布,当前最新) / Claude Opus 5.5 tests (released 2026-09-22)"""
|
|
269
|
+
|
|
270
|
+
def test_specific_model_config(self):
|
|
271
|
+
"""验证 claude-opus-5-5 配置 / Validate claude-opus-5-5 config"""
|
|
272
|
+
config = get_specific_model_config("claude-opus-5-5")
|
|
273
|
+
assert config is not None
|
|
274
|
+
version, variant, capabilities = config
|
|
275
|
+
assert version == "5.5"
|
|
276
|
+
assert variant == "opus"
|
|
277
|
+
assert capabilities is not None
|
|
278
|
+
assert capabilities.supports_vision is True
|
|
279
|
+
assert capabilities.supports_thinking is True # 自适应思考常开且不可关闭 / always on, cannot be disabled
|
|
280
|
+
assert capabilities.supports_function_calling is True
|
|
281
|
+
assert capabilities.supports_streaming is True
|
|
282
|
+
assert capabilities.supports_structured_outputs is True
|
|
283
|
+
assert capabilities.supports_computer_use is True
|
|
284
|
+
assert capabilities.max_tokens == 128000
|
|
285
|
+
assert capabilities.context_window == 1000000
|
|
286
|
+
|
|
287
|
+
def test_pattern_match(self):
|
|
288
|
+
"""验证 claude-opus-5-5 模式匹配 / Validate claude-opus-5-5 pattern match"""
|
|
289
|
+
matched = match_model_pattern("claude-opus-5-5")
|
|
290
|
+
assert matched is not None
|
|
291
|
+
assert matched["family"] == ModelFamily.CLAUDE
|
|
292
|
+
assert matched["variant"] == "opus"
|
|
293
|
+
assert matched["provider"] == Provider.ANTHROPIC
|
|
294
|
+
assert matched["_from_specific_model"] == "claude-opus-5-5"
|
|
295
|
+
|
|
296
|
+
@pytest.mark.parametrize("model_name", ["claude-opus-5-5-20260921", "claude-opus-5-5@20260921"])
|
|
297
|
+
def test_pattern_with_snapshot(self, model_name: str):
|
|
298
|
+
"""验证带 snapshot 的解析(- 与 @ 两种格式,版本号不被吞) / Validate snapshot forms keep version 5.5"""
|
|
299
|
+
meta = LLMeta(model_name)
|
|
300
|
+
assert meta.family == ModelFamily.CLAUDE
|
|
301
|
+
assert meta.version == "5.5"
|
|
302
|
+
assert meta.variant == "opus"
|
|
303
|
+
|
|
304
|
+
def test_not_swallowed_by_opus5(self):
|
|
305
|
+
"""claude-opus-5-5 不得被 claude-opus-5 的配置吞掉 / opus-5-5 must not be captured by opus-5
|
|
306
|
+
|
|
307
|
+
回归保护:opus-5 的子模式在 opus-5-5 之前注册,若 snapshot 宽度匹配不当会退化为 5.0
|
|
308
|
+
Regression guard: opus-5's sub-patterns register before opus-5-5's; a loose snapshot
|
|
309
|
+
width would silently degrade opus-5-5 to version 5.0
|
|
310
|
+
"""
|
|
311
|
+
meta = LLMeta("claude-opus-5-5")
|
|
312
|
+
assert meta.version == "5.5"
|
|
313
|
+
assert meta.variant == "opus"
|
|
314
|
+
assert meta.capabilities.context_window == 1000000
|
|
315
|
+
assert meta.capabilities.max_tokens == 128000
|
|
316
|
+
|
|
317
|
+
|
|
267
318
|
class TestClaudeOpus5:
|
|
268
319
|
"""Claude Opus 5 测试(2026-07-24 GA) / Claude Opus 5 tests"""
|
|
269
320
|
|
|
@@ -345,6 +396,19 @@ class TestClaude5Ordering:
|
|
|
345
396
|
"""opus-5 (v5.0) 高于 opus-4-8 (v4.8) / opus-5 outranks opus-4-8 by version"""
|
|
346
397
|
assert LLMeta("claude-opus-5") > LLMeta("claude-opus-4-8")
|
|
347
398
|
|
|
399
|
+
def test_opus55_outranks_opus5(self):
|
|
400
|
+
"""opus-5-5 (v5.5) 高于 opus-5 (v5.0) / opus-5-5 outranks opus-5 by version"""
|
|
401
|
+
assert LLMeta("claude-opus-5-5") > LLMeta("claude-opus-5")
|
|
402
|
+
assert LLMeta("claude-opus-5-5") > LLMeta("claude-fable-5-1")
|
|
403
|
+
|
|
404
|
+
def test_opus55_outranks_mythos5_by_version(self):
|
|
405
|
+
"""版本优先于档位:opus-5-5 (v5.5) 高于 mythos-5 (v5.0),尽管 mythos 变体档更高
|
|
406
|
+
Version precedes tier: opus-5-5 outranks mythos-5 despite mythos's higher variant tier
|
|
407
|
+
"""
|
|
408
|
+
assert LLMeta("claude-opus-5-5") > LLMeta("claude-mythos-5")
|
|
409
|
+
# 同版本 5.0 内档位排序不受影响 / tier ordering within v5.0 is unaffected
|
|
410
|
+
assert LLMeta("claude-mythos-5") > LLMeta("claude-fable-5")
|
|
411
|
+
|
|
348
412
|
def test_sonnet5_outranks_sonnet46(self):
|
|
349
413
|
"""sonnet-5 (v5.0) 高于 sonnet-4-6 (v4.6) / sonnet-5 outranks sonnet-4-6 by version"""
|
|
350
414
|
assert LLMeta("claude-sonnet-5") > LLMeta("claude-sonnet-4-6")
|
|
@@ -358,7 +422,9 @@ class TestClaude5Ordering:
|
|
|
358
422
|
assert LLMeta("claude-fable-5") > LLMeta("claude-opus-5")
|
|
359
423
|
|
|
360
424
|
def test_mythos5_is_top(self):
|
|
361
|
-
"""
|
|
425
|
+
"""同代 v5.0 内 mythos 档最高(v5.1/v5.5 按版本另行比较)
|
|
426
|
+
mythos is the top tier within the v5.0 generation (v5.1/v5.5 compare by version)
|
|
427
|
+
"""
|
|
362
428
|
models = [
|
|
363
429
|
LLMeta("claude-mythos-5"),
|
|
364
430
|
LLMeta("claude-fable-5"),
|
|
@@ -209,3 +209,102 @@ def test_deepseek_v4_flash_vision_exp_llmeta() -> None:
|
|
|
209
209
|
assert model.variant == "flash-vision-exp"
|
|
210
210
|
assert model.capabilities.context_window == 1_000_000
|
|
211
211
|
assert model.capabilities.supports_vision is True
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class TestDeepSeekRouting:
|
|
215
|
+
"""DeepSeek 旧模型名的路由实况 / Routing reality of DeepSeek legacy names.
|
|
216
|
+
|
|
217
|
+
官方原文(2026-09-10 changelog):"旧版本模型 V4 Flash 与 V4 Flash Vision Exp 现已下线,
|
|
218
|
+
出于兼容考虑,模型名 deepseek-v4-flash、deepseek-v4-flash-vision-exp 将被暂时路由到 V4.1 Flash。"
|
|
219
|
+
Official: legacy V4 Flash / V4 Flash Vision Exp are offline; their model names are
|
|
220
|
+
*temporarily* routed to V4.1 Flash.
|
|
221
|
+
|
|
222
|
+
实探证据(2026-09-28,api.deepseek.com,见 /tmp/probe_deepseek.py):
|
|
223
|
+
- GET /models 仅返回 deepseek-flash 与 deepseek-v4-pro
|
|
224
|
+
- deepseek-v4-flash / deepseek-v4-flash-vision-exp / deepseek-chat / deepseek-reasoner
|
|
225
|
+
的响应 model 字段均回显 deepseek-flash,且能正确读出白底红方块
|
|
226
|
+
- deepseek-v4-pro 回显自身,带图不报错但静默忽略并编造答案
|
|
227
|
+
|
|
228
|
+
⚠️ 路由是"暂时"的:官方撤销后本类测试会失败,届时需重新探针并回改配置
|
|
229
|
+
(能力轴跟端点现状,版本轴跟名字血统)。/ The routing is temporary: when the vendor
|
|
230
|
+
removes it these tests fail on purpose, prompting a re-probe and a config rollback.
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
def test_deepseek_flash_canonical_name(self) -> None:
|
|
234
|
+
"""deepseek-flash 为官方正式名(无版本号),对应 DeepSeek-V4.1-Flash"""
|
|
235
|
+
from whosellm import LLMeta
|
|
236
|
+
|
|
237
|
+
model = LLMeta("deepseek-flash")
|
|
238
|
+
assert model.provider == Provider.DEEPSEEK
|
|
239
|
+
assert model.family == ModelFamily.DEEPSEEK
|
|
240
|
+
# 名字无版本号 → 按官方模型版本标注 4.1
|
|
241
|
+
assert model.version == "4.1"
|
|
242
|
+
assert model.variant == "flash"
|
|
243
|
+
|
|
244
|
+
caps = model.capabilities
|
|
245
|
+
assert caps.supports_vision is True
|
|
246
|
+
assert caps.supports_thinking is True # 默认开启 / on by default
|
|
247
|
+
assert caps.media_count_limit.get("image") == 600
|
|
248
|
+
assert caps.context_window == 1_000_000
|
|
249
|
+
assert caps.max_tokens == 384_000
|
|
250
|
+
|
|
251
|
+
def test_v4_flash_routed_to_v41_flash(self) -> None:
|
|
252
|
+
"""deepseek-v4-flash 已被路由到 V4.1 Flash,视觉能力随之可用"""
|
|
253
|
+
from whosellm import LLMeta
|
|
254
|
+
|
|
255
|
+
model = LLMeta("deepseek-v4-flash")
|
|
256
|
+
# 版本轴仍按名字解析为 4.0 / version still parses from the name (4.0)
|
|
257
|
+
assert model.version == "4.0"
|
|
258
|
+
assert model.variant == "flash"
|
|
259
|
+
# 能力轴跟随实际服务模型 / capabilities follow the serving model
|
|
260
|
+
assert model.capabilities.supports_vision is True
|
|
261
|
+
assert model.capabilities.media_count_limit.get("image") == 600
|
|
262
|
+
|
|
263
|
+
def test_vision_exp_routed_to_v41_flash(self) -> None:
|
|
264
|
+
"""deepseek-v4-flash-vision-exp 同样被路由到 V4.1 Flash"""
|
|
265
|
+
from whosellm import LLMeta
|
|
266
|
+
|
|
267
|
+
model = LLMeta("deepseek-v4-flash-vision-exp")
|
|
268
|
+
assert model.version == "4.0"
|
|
269
|
+
assert model.capabilities.supports_vision is True
|
|
270
|
+
assert model.capabilities.media_count_limit.get("image") == 600
|
|
271
|
+
|
|
272
|
+
def test_chat_and_reasoner_routed_have_vision(self) -> None:
|
|
273
|
+
"""deepseek-chat / deepseek-reasoner 路由到 flash,同样可读图
|
|
274
|
+
|
|
275
|
+
两者保留各自的默认思考模式语义(chat 非思考、reasoner 思考),
|
|
276
|
+
但视觉能力跟随实际服务模型。
|
|
277
|
+
"""
|
|
278
|
+
from whosellm import LLMeta
|
|
279
|
+
|
|
280
|
+
chat = LLMeta("deepseek-chat")
|
|
281
|
+
assert chat.capabilities.supports_thinking is False # 默认非思考 / non-thinking by default
|
|
282
|
+
assert chat.capabilities.supports_vision is True
|
|
283
|
+
assert chat.capabilities.media_count_limit.get("image") == 600
|
|
284
|
+
|
|
285
|
+
reasoner = LLMeta("deepseek-reasoner")
|
|
286
|
+
assert reasoner.capabilities.supports_thinking is True
|
|
287
|
+
assert reasoner.capabilities.supports_vision is True
|
|
288
|
+
assert reasoner.capabilities.media_count_limit.get("image") == 600
|
|
289
|
+
|
|
290
|
+
def test_v4_pro_not_routed_stays_text_only(self) -> None:
|
|
291
|
+
"""deepseek-v4-pro 未被路由,保持纯文本(带图会静默幻觉,绝不能标 True)
|
|
292
|
+
|
|
293
|
+
实探:带图请求返回 200,图片被静默忽略,答案系编造;无图对照亦编造;
|
|
294
|
+
直接追问时模型承认"看不到图片 / [Unsupported Image]"。
|
|
295
|
+
来源:https://api-docs.deepseek.com/zh-cn/quick_start/pricing(图像理解 不支持)
|
|
296
|
+
"""
|
|
297
|
+
from whosellm import LLMeta
|
|
298
|
+
|
|
299
|
+
model = LLMeta("deepseek-v4-pro")
|
|
300
|
+
assert model.version == "4.0"
|
|
301
|
+
assert model.variant == "pro"
|
|
302
|
+
assert model.capabilities.supports_vision is False
|
|
303
|
+
assert model.capabilities.media_count_limit.get("image") == 0 # 键缺失视同不支持
|
|
304
|
+
|
|
305
|
+
def test_version_axis_orders_flash_above_pro(self) -> None:
|
|
306
|
+
"""版本优先于档位:V4.1 Flash > V4 Pro(与官方"全面超越 V4 Pro"表述一致)"""
|
|
307
|
+
from whosellm import LLMeta
|
|
308
|
+
|
|
309
|
+
assert LLMeta("deepseek-flash") > LLMeta("deepseek-v4-pro")
|
|
310
|
+
assert LLMeta("deepseek-v4-pro") > LLMeta("deepseek-v4-flash")
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# filename: test_gpt6.py
|
|
2
|
+
# @Time : 2026/09/04
|
|
3
|
+
# @Author : JQQ
|
|
4
|
+
# @Email : jiaqia@qknode.com
|
|
5
|
+
# @Software: PyCharm
|
|
6
|
+
"""
|
|
7
|
+
GPT-6 模型家族测试 / GPT-6 model family tests
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from datetime import date
|
|
11
|
+
|
|
12
|
+
from whosellm import LLMeta
|
|
13
|
+
from whosellm.models.base import ModelFamily
|
|
14
|
+
|
|
15
|
+
# ============================================================================
|
|
16
|
+
# GPT-6 Astra 测试 / GPT-6 Astra Tests
|
|
17
|
+
# ============================================================================
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_gpt6_astra_model():
|
|
21
|
+
"""测试GPT-6 Astra模型(2026-09-04 发布,旗舰) / Test GPT-6 Astra model"""
|
|
22
|
+
m = LLMeta("gpt-6-astra")
|
|
23
|
+
assert m.family == ModelFamily.GPT
|
|
24
|
+
assert m.version == "6.0"
|
|
25
|
+
assert m.variant == "astra"
|
|
26
|
+
assert m.capabilities.context_window == 1_050_000
|
|
27
|
+
assert m.capabilities.max_tokens == 128_000
|
|
28
|
+
assert m.capabilities.supports_thinking is True
|
|
29
|
+
assert m.capabilities.supports_vision is True
|
|
30
|
+
assert m.capabilities.supports_function_calling is True
|
|
31
|
+
assert m.capabilities.supports_streaming is True
|
|
32
|
+
assert m.capabilities.supports_structured_outputs is True
|
|
33
|
+
assert m.capabilities.supports_web_search is True
|
|
34
|
+
assert m.capabilities.supports_file_search is True
|
|
35
|
+
assert m.capabilities.supports_image_generation is True
|
|
36
|
+
assert m.capabilities.supports_code_interpreter is True
|
|
37
|
+
assert m.capabilities.supports_computer_use is True
|
|
38
|
+
assert m.capabilities.supports_fine_tuning is False
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_gpt6_astra_snapshot():
|
|
42
|
+
"""测试带日期后缀的GPT-6 Astra / Test GPT-6 Astra with date suffix"""
|
|
43
|
+
m = LLMeta("gpt-6-astra-2026-09-04")
|
|
44
|
+
assert m.family == ModelFamily.GPT
|
|
45
|
+
assert m.version == "6.0"
|
|
46
|
+
assert m.variant == "astra"
|
|
47
|
+
assert m.release_date == date(2026, 9, 4)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_gpt6_sol_model():
|
|
51
|
+
"""测试GPT-6 Sol模型(2026-09-22 发布,中档主力) / Test GPT-6 Sol model"""
|
|
52
|
+
m = LLMeta("gpt-6-sol")
|
|
53
|
+
assert m.family == ModelFamily.GPT
|
|
54
|
+
assert m.version == "6.0"
|
|
55
|
+
assert m.variant == "sol"
|
|
56
|
+
assert m.capabilities.context_window == 1_050_000
|
|
57
|
+
assert m.capabilities.max_tokens == 128_000
|
|
58
|
+
assert m.capabilities.supports_thinking is True
|
|
59
|
+
assert m.capabilities.supports_vision is True
|
|
60
|
+
assert m.capabilities.supports_function_calling is True
|
|
61
|
+
assert m.capabilities.supports_streaming is True
|
|
62
|
+
assert m.capabilities.supports_structured_outputs is True
|
|
63
|
+
assert m.capabilities.supports_web_search is True
|
|
64
|
+
assert m.capabilities.supports_file_search is True
|
|
65
|
+
assert m.capabilities.supports_image_generation is True
|
|
66
|
+
assert m.capabilities.supports_code_interpreter is True
|
|
67
|
+
assert m.capabilities.supports_computer_use is True
|
|
68
|
+
assert m.capabilities.supports_fine_tuning is False
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_gpt6_luna_model():
|
|
72
|
+
"""测试GPT-6 Luna模型(2026-09-22 发布,低成本档) / Test GPT-6 Luna model"""
|
|
73
|
+
m = LLMeta("gpt-6-luna")
|
|
74
|
+
assert m.family == ModelFamily.GPT
|
|
75
|
+
assert m.version == "6.0"
|
|
76
|
+
assert m.variant == "luna"
|
|
77
|
+
# 与 sol/astra 同窗口同工具面 / Same window and tool surface as sol/astra
|
|
78
|
+
assert m.capabilities.context_window == 1_050_000
|
|
79
|
+
assert m.capabilities.max_tokens == 128_000
|
|
80
|
+
assert m.capabilities.supports_thinking is True
|
|
81
|
+
assert m.capabilities.supports_vision is True
|
|
82
|
+
assert m.capabilities.supports_function_calling is True
|
|
83
|
+
assert m.capabilities.supports_streaming is True
|
|
84
|
+
assert m.capabilities.supports_structured_outputs is True
|
|
85
|
+
assert m.capabilities.supports_web_search is True
|
|
86
|
+
assert m.capabilities.supports_file_search is True
|
|
87
|
+
assert m.capabilities.supports_image_generation is True
|
|
88
|
+
assert m.capabilities.supports_code_interpreter is True
|
|
89
|
+
assert m.capabilities.supports_computer_use is True
|
|
90
|
+
assert m.capabilities.supports_fine_tuning is False
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_gpt6_sol_snapshot():
|
|
94
|
+
"""测试带日期后缀的GPT-6 Sol / Test GPT-6 Sol with date suffix"""
|
|
95
|
+
m = LLMeta("gpt-6-sol-2026-09-22")
|
|
96
|
+
assert m.family == ModelFamily.GPT
|
|
97
|
+
assert m.version == "6.0"
|
|
98
|
+
assert m.variant == "sol"
|
|
99
|
+
assert m.release_date == date(2026, 9, 22)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_gpt6_luna_snapshot():
|
|
103
|
+
"""测试带日期后缀的GPT-6 Luna / Test GPT-6 Luna with date suffix"""
|
|
104
|
+
m = LLMeta("gpt-6-luna-2026-09-22")
|
|
105
|
+
assert m.family == ModelFamily.GPT
|
|
106
|
+
assert m.version == "6.0"
|
|
107
|
+
assert m.variant == "luna"
|
|
108
|
+
assert m.release_date == date(2026, 9, 22)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_gpt6_media_count_limit():
|
|
112
|
+
"""测试GPT-6三档图片数量上限(版本级继承) / Test GPT-6 image count cap (version-level inherited)
|
|
113
|
+
|
|
114
|
+
官方文档:单请求最多 1500 张图片
|
|
115
|
+
Per docs: up to 1,500 images per request
|
|
116
|
+
"""
|
|
117
|
+
for model_name in ("gpt-6-astra", "gpt-6-sol", "gpt-6-luna"):
|
|
118
|
+
mcl = LLMeta(model_name).capabilities.media_count_limit
|
|
119
|
+
assert mcl.get("image") == 1500, f"{model_name}: {mcl.get('image')}"
|
|
120
|
+
assert mcl.count_mode == "per_type"
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def test_gpt6_parent_pattern_inheritance():
|
|
124
|
+
"""测试 parent pattern 匹配的 GPT-6 变体继承版本级 capabilities
|
|
125
|
+
Test parent pattern matched GPT-6 variant inherits version-level capabilities
|
|
126
|
+
"""
|
|
127
|
+
m = LLMeta("gpt-6-turbo")
|
|
128
|
+
|
|
129
|
+
assert m.family == ModelFamily.GPT
|
|
130
|
+
assert m.version == "6.0"
|
|
131
|
+
assert m.variant == "turbo"
|
|
132
|
+
# 应继承 GPT-6.0 版本级 caps,而非 family default
|
|
133
|
+
assert m.capabilities.context_window == 1_050_000
|
|
134
|
+
assert m.capabilities.supports_thinking is True
|
|
135
|
+
assert m.capabilities.supports_computer_use is True
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_gpt6_version_ordering():
|
|
139
|
+
"""测试GPT-6版本排序 / Test GPT-6 version ordering"""
|
|
140
|
+
v56 = LLMeta("gpt-5.6")
|
|
141
|
+
v60 = LLMeta("gpt-6-astra")
|
|
142
|
+
|
|
143
|
+
assert v56 < v60
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def test_gpt6_tier_ordering():
|
|
147
|
+
"""测试GPT-6天体档位优先级 / Test GPT-6 celestial tier priority
|
|
148
|
+
|
|
149
|
+
官方档位:luna(0) 低成本 < sol(1) 中档主力 < astra(5) 旗舰
|
|
150
|
+
Official tiers: luna(0) < sol(1) < astra(5)
|
|
151
|
+
"""
|
|
152
|
+
luna = LLMeta("gpt-6-luna")
|
|
153
|
+
sol = LLMeta("gpt-6-sol")
|
|
154
|
+
astra = LLMeta("gpt-6-astra")
|
|
155
|
+
|
|
156
|
+
assert luna < sol < astra
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_gpt6_cross_version_ordering():
|
|
160
|
+
"""测试GPT-6与上一代跨版本排序 / Test GPT-6 cross-version ordering vs previous gen
|
|
161
|
+
|
|
162
|
+
版本优先于档位:GPT-6 最低档的 luna 仍高于 GPT-5.6 最高档的 sol
|
|
163
|
+
Version precedes tier: GPT-6 luna (lowest tier) still outranks GPT-5.6 sol
|
|
164
|
+
"""
|
|
165
|
+
assert LLMeta("gpt-5.6-sol") < LLMeta("gpt-6-luna")
|
|
166
|
+
assert LLMeta("gpt-5.5-pro") < LLMeta("gpt-6-luna")
|