whosellm 0.2.4__tar.gz → 0.2.5__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.

Potentially problematic release.


This version of whosellm might be problematic. Click here for more details.

Files changed (120) hide show
  1. {whosellm-0.2.4 → whosellm-0.2.5}/.bumpversion.toml +1 -1
  2. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/review-provider-model/providers/gemini.md +9 -0
  3. {whosellm-0.2.4 → whosellm-0.2.5}/CHANGELOG.md +5 -0
  4. {whosellm-0.2.4 → whosellm-0.2.5}/PKG-INFO +2 -2
  5. {whosellm-0.2.4 → whosellm-0.2.5}/pyproject.toml +1 -1
  6. {whosellm-0.2.4 → whosellm-0.2.5}/tests/e2e/test_google.py +193 -4
  7. {whosellm-0.2.4 → whosellm-0.2.5}/tests/e2e/test_openai.py +116 -2
  8. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_anthropic.py +105 -0
  9. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_gemini.py +77 -11
  10. whosellm-0.2.5/tests/models/families/test_glm41v_thinking.py +99 -0
  11. whosellm-0.2.5/tests/models/families/test_glm53.py +169 -0
  12. whosellm-0.2.5/tests/models/families/test_glm5v_turbo.py +81 -0
  13. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_gpt5.py +178 -0
  14. {whosellm-0.2.4 → whosellm-0.2.5}/tests/test_variant_priority_config.py +6 -2
  15. {whosellm-0.2.4 → whosellm-0.2.5}/uv.lock +1 -1
  16. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/__init__.py +1 -1
  17. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/anthropic.py +44 -0
  18. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/gemini.py +302 -4
  19. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/__init__.py +4 -0
  20. whosellm-0.2.5/whosellm/models/families/openai/openai_gpt_5_5.py +76 -0
  21. whosellm-0.2.5/whosellm/models/families/openai/openai_gpt_5_6.py +85 -0
  22. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/zhipu.py +151 -0
  23. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/commands/interview.md +0 -0
  24. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/projects/-Users-jqq-PycharmProjects-llmeta/memory/MEMORY.md +0 -0
  25. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/projects/-Users-jqq-PycharmProjects-llmeta/memory/feedback_use_uv.md +0 -0
  26. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/settings.json +0 -0
  27. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/code-review/SKILL.md +0 -0
  28. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/create-skill/SKILL.md +0 -0
  29. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/e2e-metadata/SKILL.md +0 -0
  30. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/evolve/SKILL.md +0 -0
  31. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/fix-review/SKILL.md +0 -0
  32. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/release/SKILL.md +0 -0
  33. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/review-provider-model/SKILL.md +0 -0
  34. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/review-provider-model/providers/alibaba.md +0 -0
  35. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/review-provider-model/providers/anthropic.md +0 -0
  36. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/review-provider-model/providers/deepseek.md +0 -0
  37. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/review-provider-model/providers/openai.md +0 -0
  38. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/review-provider-model/providers/others.md +0 -0
  39. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/review-provider-model/providers/vidu.md +0 -0
  40. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/review-provider-model/providers/zhipu.md +0 -0
  41. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/update-provider-model/SKILL.md +0 -0
  42. {whosellm-0.2.4 → whosellm-0.2.5}/.claude/skills/update-provider-model/testing.md +0 -0
  43. {whosellm-0.2.4 → whosellm-0.2.5}/.coveragerc +0 -0
  44. {whosellm-0.2.4 → whosellm-0.2.5}/.github/workflows/publish.yml +0 -0
  45. {whosellm-0.2.4 → whosellm-0.2.5}/.github/workflows/tests.yml +0 -0
  46. {whosellm-0.2.4 → whosellm-0.2.5}/.gitignore +0 -0
  47. {whosellm-0.2.4 → whosellm-0.2.5}/.windsurf/workflows/addmodel.md +0 -0
  48. {whosellm-0.2.4 → whosellm-0.2.5}/.windsurf/workflows/arch.md +0 -0
  49. {whosellm-0.2.4 → whosellm-0.2.5}/.windsurf/workflows/testllmeta.md +0 -0
  50. {whosellm-0.2.4 → whosellm-0.2.5}/CLAUDE.md +0 -0
  51. {whosellm-0.2.4 → whosellm-0.2.5}/LICENSE +0 -0
  52. {whosellm-0.2.4 → whosellm-0.2.5}/README.md +0 -0
  53. {whosellm-0.2.4 → whosellm-0.2.5}/docs/add_new_model_family.md +0 -0
  54. {whosellm-0.2.4 → whosellm-0.2.5}/docs/refactor_proposal.md +0 -0
  55. {whosellm-0.2.4 → whosellm-0.2.5}/docs/spec_model_family_redesign.md +0 -0
  56. {whosellm-0.2.4 → whosellm-0.2.5}/examples/advanced_usage.py +0 -0
  57. {whosellm-0.2.4 → whosellm-0.2.5}/examples/basic_usage.py +0 -0
  58. {whosellm-0.2.4 → whosellm-0.2.5}/mypy.ini +0 -0
  59. {whosellm-0.2.4 → whosellm-0.2.5}/pytest.ini +0 -0
  60. {whosellm-0.2.4 → whosellm-0.2.5}/ruff.toml +0 -0
  61. {whosellm-0.2.4 → whosellm-0.2.5}/tests/__init__.py +0 -0
  62. {whosellm-0.2.4 → whosellm-0.2.5}/tests/e2e/__init__.py +0 -0
  63. {whosellm-0.2.4 → whosellm-0.2.5}/tests/e2e/conftest.py +0 -0
  64. {whosellm-0.2.4 → whosellm-0.2.5}/tests/e2e/test_anthropic.py +0 -0
  65. {whosellm-0.2.4 → whosellm-0.2.5}/tests/e2e/test_zhipu.py +0 -0
  66. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/__init__.py +0 -0
  67. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/__init__.py +0 -0
  68. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_deepseek.py +0 -0
  69. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_deepseek_tencent.py +0 -0
  70. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_glm45.py +0 -0
  71. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_glm45v.py +0 -0
  72. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_glm46.py +0 -0
  73. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_glm46v.py +0 -0
  74. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_glm5.py +0 -0
  75. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_gpt3_5.py +0 -0
  76. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_gpt4_1.py +0 -0
  77. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_gpt4o.py +0 -0
  78. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_o1.py +0 -0
  79. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_o3.py +0 -0
  80. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_o4.py +0 -0
  81. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_qwen.py +0 -0
  82. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_qwen3_vl_models.py +0 -0
  83. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_qwen_ollama.py +0 -0
  84. {whosellm-0.2.4 → whosellm-0.2.5}/tests/models/families/test_qwen_plus.py +0 -0
  85. {whosellm-0.2.4 → whosellm-0.2.5}/tests/test_auto_register.py +0 -0
  86. {whosellm-0.2.4 → whosellm-0.2.5}/tests/test_claude_4x_versions.py +0 -0
  87. {whosellm-0.2.4 → whosellm-0.2.5}/tests/test_llmeta.py +0 -0
  88. {whosellm-0.2.4 → whosellm-0.2.5}/tests/test_model_version.py +0 -0
  89. {whosellm-0.2.4 → whosellm-0.2.5}/tests/test_provider.py +0 -0
  90. {whosellm-0.2.4 → whosellm-0.2.5}/tests/test_registry_merge.py +0 -0
  91. {whosellm-0.2.4 → whosellm-0.2.5}/tests/test_specific_patterns.py +0 -0
  92. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/capabilities.py +0 -0
  93. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/model_version.py +0 -0
  94. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/__init__.py +0 -0
  95. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/base.py +0 -0
  96. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/config.py +0 -0
  97. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/dynamic_enum.py +0 -0
  98. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/__init__.py +0 -0
  99. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/alibaba.py +0 -0
  100. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/deepseek/__init__.py +0 -0
  101. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/deepseek/deepseek_official.py +0 -0
  102. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/deepseek/tencent.py +0 -0
  103. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/openai_gpt_3_5.py +0 -0
  104. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/openai_gpt_4.py +0 -0
  105. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/openai_gpt_4_1.py +0 -0
  106. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/openai_gpt_4o.py +0 -0
  107. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/openai_gpt_5.py +0 -0
  108. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/openai_gpt_5_1.py +0 -0
  109. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/openai_gpt_5_2.py +0 -0
  110. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/openai_gpt_5_3.py +0 -0
  111. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/openai_gpt_5_4.py +0 -0
  112. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/openai_o1.py +0 -0
  113. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/openai_o3.py +0 -0
  114. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/openai/openai_o4.py +0 -0
  115. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/others.py +0 -0
  116. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/families/vidu.py +0 -0
  117. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/patterns.py +0 -0
  118. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/models/registry.py +0 -0
  119. {whosellm-0.2.4 → whosellm-0.2.5}/whosellm/provider.py +0 -0
  120. {whosellm-0.2.4 → whosellm-0.2.5}/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.4"
5
+ current_version = "0.2.5"
6
6
  parse = """(?x)
7
7
  (?P<major>0|[1-9]\\d*)\\.
8
8
  (?P<minor>0|[1-9]\\d*)\\.
@@ -63,3 +63,12 @@ description: Google Gemini 模型信息采集指南
63
63
  - `supports_file_search` 和 `supports_code_interpreter` 并非所有变体都支持,flash-lite 和 2.0 系列通常不支持 code_interpreter
64
64
  - 大部分 Gemini 模型的 `context_window` 为 `1048576`(1M tokens),但特殊变体例外
65
65
  - `supports_web_search` 在 2.0 flash 及以上版本可用,2.0 flash-lite 不支持
66
+
67
+ ## 采集经验(2026-08-20 更新)
68
+
69
+ - **3.1 及以后的官方 ID 一律用点号**:`gemini-3.1-pro-preview`、`gemini-3.5-flash` 等。曾误注册短横线 `gemini-3-1-pro-preview`,导致真实 ID 走泛型 pattern、variant 解析错误
70
+ - **弃用时间线看 `deprecations` 页**:`https://ai.google.dev/gemini-api/docs/deprecations` 有每个模型的发布日期、关停日期、推荐替代品,比模型列表页信息更全
71
+ - **部分模型详情页没有规格卡**(如 gemini-3.1-flash-lite、gemini-3.1-flash-live-preview)。Live API 模型的上下文上限在 `live-api/capabilities` 页(原生音频输出模型 128k);其余可参照官方指定的迁移源模型规格,并在配置注释中说明数据来源
72
+ - **模型详情页与总览页的 model code 可能不一致**(如 gemini-omni-flash vs gemini-omni-flash-preview),两个都收录进 patterns
73
+ - `capabilities.py` 的默认值中 `supports_structured_outputs/Json_outputs/streaming` 默认 True,受限模型(image/TTS/live 特化版)必须显式置 False
74
+ - 特化端点别名也应收录:如 `gemini-3.1-pro-preview-customtools`
@@ -2,6 +2,11 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.2.4] - Unreleased
6
+
7
+ ### Added
8
+ - 新增 Claude 5 代模型配置(官方规格核实):`claude-sonnet-5`(2026-06-30 GA,$2/$10)、`claude-opus-5`(2026-07-24 GA,$5/$25)。两者均 1M 上下文(默认且最大)、128K 最大输出、自适应思考默认开启(映射 `supports_thinking=True`),支持结构化输出 + computer use。版本 5.0 高于 4.8/4.6(如 `claude-opus-5 > claude-opus-4-8`),同版本下变体优先级维持 `mythos > fable > opus > sonnet`
9
+
5
10
  ## [0.2.3] - Unreleased
6
11
 
7
12
  ### Added
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: whosellm
3
- Version: 0.2.4
3
+ Version: 0.2.5
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.4"
3
+ version = "0.2.5"
4
4
  description = "A unified LLM model version and capability management library"
5
5
  authors = [
6
6
  {name = "JQQ", email = "jqq1716@gmail.com"}
@@ -1,7 +1,7 @@
1
1
  """Google E2E 元数据测试。
2
2
 
3
3
  来源: https://ai.google.dev/gemini-api/docs/models
4
- 采集日期: 2026-04-12
4
+ 采集日期: 2026-04-12(2026-08-20 增补 3.5/3.6/3.7 Flash、Nano Banana 2 系列、Live/TTS 等新模型)
5
5
  """
6
6
 
7
7
  import pytest
@@ -17,7 +17,7 @@ from .conftest import assert_model_metadata
17
17
 
18
18
  GEMINI_3X_MODELS = [
19
19
  (
20
- "gemini-3-1-pro-preview",
20
+ "gemini-3.1-pro-preview",
21
21
  {
22
22
  "provider": Provider.GOOGLE,
23
23
  "family": ModelFamily.GEMINI,
@@ -53,7 +53,7 @@ GEMINI_3X_MODELS = [
53
53
  },
54
54
  ),
55
55
  (
56
- "gemini-3-1-flash-lite-preview",
56
+ "gemini-3.1-flash-lite-preview",
57
57
  {
58
58
  "provider": Provider.GOOGLE,
59
59
  "family": ModelFamily.GEMINI,
@@ -93,6 +93,195 @@ GEMINI_3X_MODELS = [
93
93
  ),
94
94
  ]
95
95
 
96
+ # ============================================================================
97
+ # Gemini Family — 2026-08 新增(GA Flash 主线 / Nano Banana 2 / Live / TTS)
98
+ # 来源: https://ai.google.dev/gemini-api/docs/models/gemini-3.7-flash 等(2026-08-20 采集)
99
+ # ============================================================================
100
+
101
+ GEMINI_2026_NEW_MODELS = [
102
+ (
103
+ "gemini-3.7-flash",
104
+ {
105
+ "provider": Provider.GOOGLE,
106
+ "family": ModelFamily.GEMINI,
107
+ "version": "3.7",
108
+ "variant": "flash",
109
+ "supports_thinking": True,
110
+ "supports_vision": True,
111
+ "supports_audio": True,
112
+ "supports_video": True,
113
+ "supports_streaming": True,
114
+ "supports_function_calling": True,
115
+ "supports_structured_outputs": True,
116
+ "context_window": 1_048_576,
117
+ "max_tokens": 65_536,
118
+ },
119
+ ),
120
+ (
121
+ "gemini-3.6-flash",
122
+ {
123
+ "provider": Provider.GOOGLE,
124
+ "family": ModelFamily.GEMINI,
125
+ "version": "3.6",
126
+ "variant": "flash",
127
+ "supports_thinking": True,
128
+ "supports_vision": True,
129
+ "supports_audio": True,
130
+ "supports_video": True,
131
+ "supports_streaming": True,
132
+ "supports_function_calling": True,
133
+ "supports_structured_outputs": True,
134
+ "context_window": 1_048_576,
135
+ "max_tokens": 65_536,
136
+ },
137
+ ),
138
+ (
139
+ "gemini-3.5-flash",
140
+ {
141
+ "provider": Provider.GOOGLE,
142
+ "family": ModelFamily.GEMINI,
143
+ "version": "3.5",
144
+ "variant": "flash",
145
+ "supports_thinking": True,
146
+ "supports_vision": True,
147
+ "supports_audio": True,
148
+ "supports_video": True,
149
+ "supports_streaming": True,
150
+ "supports_function_calling": True,
151
+ "supports_structured_outputs": True,
152
+ "context_window": 1_048_576,
153
+ "max_tokens": 65_536,
154
+ },
155
+ ),
156
+ (
157
+ "gemini-3.5-flash-lite",
158
+ {
159
+ "provider": Provider.GOOGLE,
160
+ "family": ModelFamily.GEMINI,
161
+ "version": "3.5",
162
+ "variant": "flash-lite",
163
+ "supports_thinking": True,
164
+ "supports_vision": True,
165
+ "supports_audio": True,
166
+ "supports_video": True,
167
+ "supports_streaming": True,
168
+ "supports_function_calling": True,
169
+ "supports_structured_outputs": True,
170
+ "context_window": 1_048_576,
171
+ "max_tokens": 65_536,
172
+ },
173
+ ),
174
+ (
175
+ "gemini-3.1-flash-lite",
176
+ {
177
+ "provider": Provider.GOOGLE,
178
+ "family": ModelFamily.GEMINI,
179
+ "version": "3.1",
180
+ "variant": "flash-lite",
181
+ "supports_thinking": True,
182
+ "supports_vision": True,
183
+ "supports_audio": True,
184
+ "supports_video": True,
185
+ "supports_streaming": True,
186
+ "supports_function_calling": True,
187
+ "supports_structured_outputs": True,
188
+ "context_window": 1_048_576,
189
+ "max_tokens": 65_536,
190
+ },
191
+ ),
192
+ (
193
+ # Nano Banana 2:官方卡片 thinking=Supported,但接口不支持配置 thinking 行为,按家族惯例置 False
194
+ "gemini-3.1-flash-image",
195
+ {
196
+ "provider": Provider.GOOGLE,
197
+ "family": ModelFamily.GEMINI,
198
+ "version": "3.1",
199
+ "variant": "flash-image",
200
+ "supports_thinking": False,
201
+ "supports_vision": True,
202
+ "supports_audio": False,
203
+ "supports_streaming": True,
204
+ "supports_function_calling": False,
205
+ "supports_structured_outputs": False,
206
+ "supports_image_generation": True,
207
+ "context_window": 131_072,
208
+ "max_tokens": 32_768,
209
+ },
210
+ ),
211
+ (
212
+ "gemini-3.1-flash-lite-image",
213
+ {
214
+ "provider": Provider.GOOGLE,
215
+ "family": ModelFamily.GEMINI,
216
+ "version": "3.1",
217
+ "variant": "flash-lite-image",
218
+ "supports_thinking": False,
219
+ "supports_vision": True,
220
+ "supports_audio": False,
221
+ "supports_streaming": True,
222
+ "supports_function_calling": True,
223
+ "supports_structured_outputs": False,
224
+ "supports_image_generation": True,
225
+ "context_window": 65_536,
226
+ "max_tokens": 4_096,
227
+ },
228
+ ),
229
+ (
230
+ # Nano Banana Pro(GA)
231
+ "gemini-3-pro-image",
232
+ {
233
+ "provider": Provider.GOOGLE,
234
+ "family": ModelFamily.GEMINI,
235
+ "version": "3.0",
236
+ "variant": "pro-image",
237
+ "supports_thinking": False,
238
+ "supports_vision": True,
239
+ "supports_audio": False,
240
+ "supports_streaming": True,
241
+ "supports_function_calling": False,
242
+ "supports_structured_outputs": False,
243
+ "supports_image_generation": True,
244
+ "context_window": 65_536,
245
+ "max_tokens": 32_768,
246
+ },
247
+ ),
248
+ (
249
+ # 官方详情页未附规格卡:ctx 取 Live API 原生音频模型约束 128k,max 参照迁移源 12-2025
250
+ "gemini-3.1-flash-live-preview",
251
+ {
252
+ "provider": Provider.GOOGLE,
253
+ "family": ModelFamily.GEMINI,
254
+ "version": "3.1",
255
+ "variant": "flash-live",
256
+ "supports_thinking": True,
257
+ "supports_audio": True,
258
+ "supports_video": True,
259
+ "supports_streaming": True,
260
+ "supports_function_calling": True,
261
+ "supports_audio_generation": True,
262
+ "context_window": 131_072,
263
+ "max_tokens": 8_192,
264
+ },
265
+ ),
266
+ (
267
+ "gemini-3.1-flash-tts-preview",
268
+ {
269
+ "provider": Provider.GOOGLE,
270
+ "family": ModelFamily.GEMINI,
271
+ "version": "3.1",
272
+ "variant": "flash-tts",
273
+ "supports_thinking": False,
274
+ "supports_vision": False,
275
+ "supports_audio": False,
276
+ "supports_streaming": True,
277
+ "supports_structured_outputs": False,
278
+ "supports_audio_generation": True,
279
+ "context_window": 8_192,
280
+ "max_tokens": 16_384,
281
+ },
282
+ ),
283
+ ]
284
+
96
285
  # ============================================================================
97
286
  # Gemini Family — Version 2.5 (Stable)
98
287
  # 来源: https://ai.google.dev/gemini-api/docs/models/gemini-2.5-flash
@@ -206,7 +395,7 @@ GEMINI_20_MODELS = [
206
395
  # 聚合 + 参数化
207
396
  # ============================================================================
208
397
 
209
- ALL_MODELS = GEMINI_3X_MODELS + GEMINI_25_MODELS + GEMINI_20_MODELS
398
+ ALL_MODELS = GEMINI_3X_MODELS + GEMINI_2026_NEW_MODELS + GEMINI_25_MODELS + GEMINI_20_MODELS
210
399
 
211
400
 
212
401
  @pytest.mark.e2e
@@ -11,8 +11,9 @@ from whosellm import ModelFamily, Provider
11
11
  from .conftest import assert_model_metadata
12
12
 
13
13
  # ============================================================================
14
- # GPT Family (latest: 5.4)
15
- # 来源: https://developers.openai.com/api/docs/models/gpt-5.4
14
+ # GPT Family (latest: 5.6)
15
+ # 来源: https://developers.openai.com/api/docs/models/gpt-5.4(2026-04-12 采集)
16
+ # https://developers.openai.com/api/docs/models/gpt-5.6-sol(2026-08-20 采集 5.5/5.6)
16
17
  # ============================================================================
17
18
 
18
19
  GPT_MODELS = [
@@ -85,6 +86,119 @@ GPT_MODELS = [
85
86
  "max_tokens": 128_000,
86
87
  },
87
88
  ),
89
+ # ------------------------------------------------------------------
90
+ # GPT-5.5 系列(2026-08-20 采集)
91
+ # 来源: https://developers.openai.com/api/docs/models/gpt-5.5
92
+ # ------------------------------------------------------------------
93
+ (
94
+ "gpt-5.5",
95
+ {
96
+ "provider": Provider.OPENAI,
97
+ "family": ModelFamily.GPT,
98
+ "version": "5.5",
99
+ "variant": "base",
100
+ "supports_thinking": True,
101
+ "supports_vision": True,
102
+ "supports_streaming": True,
103
+ "supports_function_calling": True,
104
+ "supports_structured_outputs": True,
105
+ "supports_computer_use": True,
106
+ "context_window": 1_050_000,
107
+ "max_tokens": 128_000,
108
+ },
109
+ ),
110
+ (
111
+ "gpt-5.5-pro",
112
+ {
113
+ # 仅 Responses API(含 Batch),不支持 Chat Completions 与 streaming
114
+ "provider": Provider.OPENAI,
115
+ "family": ModelFamily.GPT,
116
+ "version": "5.5",
117
+ "variant": "pro",
118
+ "supports_thinking": True,
119
+ "supports_vision": True,
120
+ "supports_streaming": False,
121
+ "supports_function_calling": True,
122
+ "supports_structured_outputs": True,
123
+ "supports_code_interpreter": True,
124
+ "supports_computer_use": False,
125
+ "context_window": 1_050_000,
126
+ "max_tokens": 128_000,
127
+ },
128
+ ),
129
+ # ------------------------------------------------------------------
130
+ # GPT-5.6 天体档位系列(2026-08-20 采集)
131
+ # sol≈无后缀档 / terra≈mini / luna≈nano,三档能力一致
132
+ # 来源: https://developers.openai.com/api/docs/models/gpt-5.6-sol
133
+ # ------------------------------------------------------------------
134
+ (
135
+ "gpt-5.6",
136
+ {
137
+ "provider": Provider.OPENAI,
138
+ "family": ModelFamily.GPT,
139
+ "version": "5.6",
140
+ "variant": "base",
141
+ "supports_thinking": True,
142
+ "supports_vision": True,
143
+ "supports_streaming": True,
144
+ "supports_function_calling": True,
145
+ "supports_structured_outputs": True,
146
+ "supports_computer_use": True,
147
+ "context_window": 1_050_000,
148
+ "max_tokens": 128_000,
149
+ },
150
+ ),
151
+ (
152
+ "gpt-5.6-sol",
153
+ {
154
+ "provider": Provider.OPENAI,
155
+ "family": ModelFamily.GPT,
156
+ "version": "5.6",
157
+ "variant": "sol",
158
+ "supports_thinking": True,
159
+ "supports_vision": True,
160
+ "supports_streaming": True,
161
+ "supports_function_calling": True,
162
+ "supports_structured_outputs": True,
163
+ "supports_computer_use": True,
164
+ "context_window": 1_050_000,
165
+ "max_tokens": 128_000,
166
+ },
167
+ ),
168
+ (
169
+ "gpt-5.6-terra",
170
+ {
171
+ "provider": Provider.OPENAI,
172
+ "family": ModelFamily.GPT,
173
+ "version": "5.6",
174
+ "variant": "terra",
175
+ "supports_thinking": True,
176
+ "supports_vision": True,
177
+ "supports_streaming": True,
178
+ "supports_function_calling": True,
179
+ "supports_structured_outputs": True,
180
+ "supports_computer_use": True,
181
+ "context_window": 1_050_000,
182
+ "max_tokens": 128_000,
183
+ },
184
+ ),
185
+ (
186
+ "gpt-5.6-luna",
187
+ {
188
+ "provider": Provider.OPENAI,
189
+ "family": ModelFamily.GPT,
190
+ "version": "5.6",
191
+ "variant": "luna",
192
+ "supports_thinking": True,
193
+ "supports_vision": True,
194
+ "supports_streaming": True,
195
+ "supports_function_calling": True,
196
+ "supports_structured_outputs": True,
197
+ "supports_computer_use": True,
198
+ "context_window": 1_050_000,
199
+ "max_tokens": 128_000,
200
+ },
201
+ ),
88
202
  ]
89
203
 
90
204
  # ============================================================================
@@ -196,6 +196,111 @@ class TestClaudeMythosClassOrdering:
196
196
  assert max(models).variant == "mythos"
197
197
 
198
198
 
199
+ class TestClaudeOpus5:
200
+ """Claude Opus 5 测试(2026-07-24 GA) / Claude Opus 5 tests"""
201
+
202
+ def test_specific_model_config(self):
203
+ """验证 claude-opus-5 配置 / Validate claude-opus-5 config"""
204
+ config = get_specific_model_config("claude-opus-5")
205
+ assert config is not None
206
+ version, variant, capabilities = config
207
+ assert version == "5.0"
208
+ assert variant == "opus"
209
+ assert capabilities is not None
210
+ assert capabilities.supports_vision is True
211
+ assert capabilities.supports_thinking is True
212
+ assert capabilities.supports_function_calling is True
213
+ assert capabilities.supports_streaming is True
214
+ assert capabilities.supports_structured_outputs is True
215
+ assert capabilities.supports_computer_use is True
216
+ assert capabilities.max_tokens == 128000
217
+ assert capabilities.context_window == 1000000
218
+
219
+ def test_pattern_match(self):
220
+ """验证 claude-opus-5 模式匹配 / Validate claude-opus-5 pattern match"""
221
+ matched = match_model_pattern("claude-opus-5")
222
+ assert matched is not None
223
+ assert matched["family"] == ModelFamily.CLAUDE
224
+ assert matched["variant"] == "opus"
225
+ assert matched["provider"] == Provider.ANTHROPIC
226
+
227
+ @pytest.mark.parametrize("model_name", ["claude-opus-5-20260724", "claude-opus-5@20260724"])
228
+ def test_pattern_with_snapshot(self, model_name: str):
229
+ """验证带 snapshot 的解析(- 与 @ 两种格式,版本号不被吞) / Validate snapshot forms keep version 5.0"""
230
+ meta = LLMeta(model_name)
231
+ assert meta.family == ModelFamily.CLAUDE
232
+ assert meta.version == "5.0"
233
+ assert meta.variant == "opus"
234
+
235
+
236
+ class TestClaudeSonnet5:
237
+ """Claude Sonnet 5 测试(2026-06-30 GA) / Claude Sonnet 5 tests"""
238
+
239
+ def test_specific_model_config(self):
240
+ """验证 claude-sonnet-5 配置 / Validate claude-sonnet-5 config"""
241
+ config = get_specific_model_config("claude-sonnet-5")
242
+ assert config is not None
243
+ version, variant, capabilities = config
244
+ assert version == "5.0"
245
+ assert variant == "sonnet"
246
+ assert capabilities is not None
247
+ assert capabilities.supports_vision is True
248
+ assert capabilities.supports_thinking is True
249
+ assert capabilities.supports_function_calling is True
250
+ assert capabilities.supports_streaming is True
251
+ assert capabilities.supports_structured_outputs is True
252
+ assert capabilities.supports_computer_use is True
253
+ assert capabilities.max_tokens == 128000
254
+ assert capabilities.context_window == 1000000
255
+
256
+ def test_pattern_match(self):
257
+ """验证 claude-sonnet-5 模式匹配 / Validate claude-sonnet-5 pattern match"""
258
+ matched = match_model_pattern("claude-sonnet-5")
259
+ assert matched is not None
260
+ assert matched["family"] == ModelFamily.CLAUDE
261
+ assert matched["variant"] == "sonnet"
262
+ assert matched["provider"] == Provider.ANTHROPIC
263
+
264
+ @pytest.mark.parametrize("model_name", ["claude-sonnet-5-20260630", "claude-sonnet-5@20260630"])
265
+ def test_pattern_with_snapshot(self, model_name: str):
266
+ """验证带 snapshot 的解析(- 与 @ 两种格式,版本号不被吞) / Validate snapshot forms keep version 5.0"""
267
+ meta = LLMeta(model_name)
268
+ assert meta.family == ModelFamily.CLAUDE
269
+ assert meta.version == "5.0"
270
+ assert meta.variant == "sonnet"
271
+
272
+
273
+ class TestClaude5Ordering:
274
+ """Claude 5 代版本比较:5.0 > 4.8 > 4.6;同版本 fable > opus > sonnet / Claude 5 generation ordering"""
275
+
276
+ def test_opus5_outranks_opus48(self):
277
+ """opus-5 (v5.0) 高于 opus-4-8 (v4.8) / opus-5 outranks opus-4-8 by version"""
278
+ assert LLMeta("claude-opus-5") > LLMeta("claude-opus-4-8")
279
+
280
+ def test_sonnet5_outranks_sonnet46(self):
281
+ """sonnet-5 (v5.0) 高于 sonnet-4-6 (v4.6) / sonnet-5 outranks sonnet-4-6 by version"""
282
+ assert LLMeta("claude-sonnet-5") > LLMeta("claude-sonnet-4-6")
283
+
284
+ def test_opus5_outranks_sonnet5(self):
285
+ """同版本 5.0 下 opus 变体优先级高于 sonnet / opus outranks sonnet on variant priority"""
286
+ assert LLMeta("claude-opus-5") > LLMeta("claude-sonnet-5")
287
+
288
+ def test_fable5_outranks_opus5(self):
289
+ """同版本 5.0 下 fable(Mythos-class)仍高于 opus / fable still outranks opus on variant priority"""
290
+ assert LLMeta("claude-fable-5") > LLMeta("claude-opus-5")
291
+
292
+ def test_mythos5_is_top(self):
293
+ """mythos-5 仍为当前最高 / mythos-5 remains the highest among current Claude models"""
294
+ models = [
295
+ LLMeta("claude-mythos-5"),
296
+ LLMeta("claude-fable-5"),
297
+ LLMeta("claude-opus-5"),
298
+ LLMeta("claude-sonnet-5"),
299
+ LLMeta("claude-opus-4-8"),
300
+ ]
301
+ assert max(models).variant == "mythos"
302
+
303
+
199
304
  class TestClaudeExistingModels:
200
305
  """验证现有模型未受影响 / Validate existing models are not affected"""
201
306
 
@@ -130,20 +130,58 @@ class TestGemini3x:
130
130
  assert capabilities.context_window == 65_536
131
131
 
132
132
  def test_gemini_3_1_pro_preview(self):
133
- config = get_specific_model_config("gemini-3-1-pro-preview")
133
+ config = get_specific_model_config("gemini-3.1-pro-preview")
134
134
  assert config is not None
135
- version, variant, capabilities = config
135
+ version, variant, _ = config
136
136
  assert version == "3.1"
137
137
  assert variant == "pro"
138
138
 
139
139
  def test_gemini_3_1_flash_lite_preview(self):
140
- config = get_specific_model_config("gemini-3-1-flash-lite-preview")
140
+ config = get_specific_model_config("gemini-3.1-flash-lite-preview")
141
141
  assert config is not None
142
- version, variant, capabilities = config
142
+ version, variant, _ = config
143
143
  assert version == "3.1"
144
144
  assert variant == "flash-lite"
145
145
 
146
146
 
147
+ class TestGemini35to37Flash:
148
+ """Gemini 3.5/3.6/3.7 Flash 系列(GA)测试 / Gemini 3.5/3.6/3.7 Flash (GA) tests"""
149
+
150
+ @pytest.mark.parametrize(
151
+ "model_name,expected_version,expected_variant",
152
+ [
153
+ ("gemini-3.5-flash", "3.5", "flash"),
154
+ ("gemini-3.6-flash", "3.6", "flash"),
155
+ ("gemini-3.7-flash", "3.7", "flash"),
156
+ ("gemini-3.5-flash-lite", "3.5", "flash-lite"),
157
+ ],
158
+ )
159
+ def test_specific_model_config(self, model_name: str, expected_version: str, expected_variant: str):
160
+ config = get_specific_model_config(model_name)
161
+ assert config is not None
162
+ version, variant, capabilities = config
163
+ assert version == expected_version
164
+ assert variant == expected_variant
165
+ assert capabilities is not None
166
+ assert capabilities.supports_thinking is True
167
+ assert capabilities.supports_vision is True
168
+ assert capabilities.supports_audio is True
169
+ assert capabilities.supports_video is True
170
+ assert capabilities.supports_pdf is True
171
+ assert capabilities.supports_structured_outputs is True
172
+ assert capabilities.supports_code_interpreter is True
173
+ assert capabilities.supports_file_search is True
174
+ assert capabilities.supports_web_search is True
175
+ assert capabilities.max_tokens == 65_536
176
+ assert capabilities.context_window == 1_048_576
177
+
178
+ def test_ga_flash_ordering(self):
179
+ """验证 3.1 < 3.5 < 3.6 < 3.7 / Validate 3.1 < 3.5 < 3.6 < 3.7"""
180
+ assert LLMeta("gemini-3.1-flash-lite") < LLMeta("gemini-3.5-flash")
181
+ assert LLMeta("gemini-3.5-flash") < LLMeta("gemini-3.6-flash")
182
+ assert LLMeta("gemini-3.6-flash") < LLMeta("gemini-3.7-flash")
183
+
184
+
147
185
  class TestGemini20:
148
186
  """Gemini 2.0 系列测试 / Gemini 2.0 series tests"""
149
187
 
@@ -191,14 +229,15 @@ class TestGeminiVersionComparison:
191
229
  """Gemini 版本比较测试 / Gemini version comparison tests"""
192
230
 
193
231
  def test_version_ordering(self):
194
- """验证 2.5 < 3.0 < 3.1 / Validate 2.5 < 3.0 < 3.1"""
232
+ """验证 2.5 < 3.0 < 3.1 < 3.7 / Validate 2.5 < 3.0 < 3.1 < 3.7"""
195
233
  gemini_25 = LLMeta("gemini-2.5-flash")
196
234
  gemini_30 = LLMeta("gemini-3-pro-preview")
197
- gemini_31 = LLMeta("gemini-3-1-pro-preview")
235
+ gemini_31 = LLMeta("gemini-3.1-pro-preview")
198
236
 
199
237
  assert gemini_25 < gemini_30
200
238
  assert gemini_30 < gemini_31
201
239
  assert gemini_25 < gemini_31
240
+ assert gemini_31 < LLMeta("gemini-3.7-flash")
202
241
 
203
242
 
204
243
  class TestGeminiLLMeta:
@@ -219,7 +258,7 @@ class TestGeminiLLMeta:
219
258
  assert meta.variant == "flash"
220
259
 
221
260
  def test_gemini_3_1_pro_preview_resolution(self):
222
- meta = LLMeta("gemini-3-1-pro-preview")
261
+ meta = LLMeta("gemini-3.1-pro-preview")
223
262
  assert meta.provider == Provider.GOOGLE
224
263
  assert meta.family == ModelFamily.GEMINI
225
264
  assert meta.version == "3.1"
@@ -236,8 +275,21 @@ class TestGeminiParametrized:
236
275
  ("gemini-2.5-flash", "2.5", "flash"),
237
276
  ("gemini-2.5-flash-lite", "2.5", "flash-lite"),
238
277
  ("gemini-3-pro-preview", "3.0", "pro"),
239
- ("gemini-3-1-pro-preview", "3.1", "pro"),
240
- ("gemini-3-1-flash-lite-preview", "3.1", "flash-lite"),
278
+ ("gemini-3.1-pro-preview", "3.1", "pro"),
279
+ ("gemini-3.1-flash-lite-preview", "3.1", "flash-lite"),
280
+ ("gemini-3.5-flash", "3.5", "flash"),
281
+ ("gemini-3.6-flash", "3.6", "flash"),
282
+ ("gemini-3.7-flash", "3.7", "flash"),
283
+ ("gemini-3.5-flash-lite", "3.5", "flash-lite"),
284
+ ("gemini-3.1-flash-lite", "3.1", "flash-lite"),
285
+ ("gemini-3.1-flash-image", "3.1", "flash-image"),
286
+ ("gemini-3.1-flash-lite-image", "3.1", "flash-lite-image"),
287
+ ("gemini-3-pro-image", "3.0", "pro-image"),
288
+ ("gemini-3.1-flash-live-preview", "3.1", "flash-live"),
289
+ ("gemini-3.1-flash-tts-preview", "3.1", "flash-tts"),
290
+ ("gemini-3.5-live-translate-preview", "3.5", "live-translate"),
291
+ ("gemini-omni-flash", "3.0", "omni-flash"),
292
+ ("gemini-omni-flash-preview", "3.0", "omni-flash"),
241
293
  ],
242
294
  )
243
295
  def test_all_specific_models(self, model_name: str, expected_version: str, expected_variant: str):
@@ -252,6 +304,18 @@ class TestGeminiParametrized:
252
304
  [
253
305
  ("gemini-3-pro-preview", 65_536, 1_048_576),
254
306
  ("gemini-3-pro-image-preview", 32_768, 65_536),
307
+ ("gemini-3-pro-image", 32_768, 65_536),
308
+ ("gemini-3.5-flash", 65_536, 1_048_576),
309
+ ("gemini-3.6-flash", 65_536, 1_048_576),
310
+ ("gemini-3.7-flash", 65_536, 1_048_576),
311
+ ("gemini-3.5-flash-lite", 65_536, 1_048_576),
312
+ ("gemini-3.1-flash-lite", 65_536, 1_048_576),
313
+ ("gemini-3.1-flash-image", 32_768, 131_072),
314
+ ("gemini-3.1-flash-lite-image", 4_096, 65_536),
315
+ ("gemini-2.5-flash-native-audio-preview-12-2025", 8_192, 131_072),
316
+ ("gemini-3.1-flash-live-preview", 8_192, 131_072),
317
+ ("gemini-3.1-flash-tts-preview", 16_384, 8_192),
318
+ ("gemini-3.5-live-translate-preview", 65_536, 131_072),
255
319
  ("gemini-2.5-flash", 65_536, 1_048_576),
256
320
  ("gemini-2.5-flash-lite", 65_536, 1_048_576),
257
321
  ("gemini-2.5-pro", 65_536, 1_048_576),
@@ -263,5 +327,7 @@ class TestGeminiParametrized:
263
327
  """参数化测试 Gemini 各型号的 max_tokens 和 context_window"""
264
328
  config = get_specific_model_config(model_name)
265
329
  assert config is not None
266
- assert config[2].max_tokens == expected_tokens
267
- assert config[2].context_window == expected_context
330
+ _, _, capabilities = config
331
+ assert capabilities is not None
332
+ assert capabilities.max_tokens == expected_tokens
333
+ assert capabilities.context_window == expected_context