mojentic 1.0.0__py3-none-any.whl → 1.1.0__py3-none-any.whl

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.
@@ -35,6 +35,9 @@ class ModelCapabilities:
35
35
  max_context_tokens: Optional[int] = None
36
36
  max_output_tokens: Optional[int] = None
37
37
  supported_temperatures: Optional[List[float]] = None # None means all temperatures supported
38
+ supports_chat_api: bool = True
39
+ supports_completions_api: bool = False
40
+ supports_responses_api: bool = False
38
41
 
39
42
  def get_token_limit_param(self) -> str:
40
43
  """Get the correct parameter name for token limits based on model type."""
@@ -67,30 +70,34 @@ class OpenAIModelRegistry:
67
70
  def _initialize_default_models(self):
68
71
  """Initialize the registry with known OpenAI models and their capabilities."""
69
72
 
70
- # Reasoning Models (o1, o3, o4, gpt-5 series) - Updated 2025-09-28
73
+ # Reasoning Models (o1, o3, o4, gpt-5 series) - Updated 2026-02-04
71
74
  reasoning_models = [
72
- "o1", "o1-2024-12-17", "o1-mini", "o1-mini-2024-09-12",
75
+ "o1", "o1-2024-12-17",
73
76
  "o1-pro", "o1-pro-2025-03-19",
74
77
  "o3", "o3-2025-04-16", "o3-deep-research", "o3-deep-research-2025-06-26",
75
78
  "o3-mini", "o3-mini-2025-01-31", "o3-pro", "o3-pro-2025-06-10",
76
79
  "o4-mini", "o4-mini-2025-04-16", "o4-mini-deep-research",
77
80
  "o4-mini-deep-research-2025-06-26",
78
- "gpt-5", "gpt-5-2025-08-07", "gpt-5-chat-latest", "gpt-5-codex",
79
- "gpt-5-mini", "gpt-5-mini-2025-08-07", "gpt-5-nano", "gpt-5-nano-2025-08-07"
81
+ "gpt-5", "gpt-5-2025-08-07", "gpt-5-codex",
82
+ "gpt-5-mini", "gpt-5-mini-2025-08-07", "gpt-5-nano", "gpt-5-nano-2025-08-07",
83
+ "gpt-5-pro", "gpt-5-pro-2025-10-06",
84
+ "gpt-5.1", "gpt-5.1-2025-11-13", "gpt-5.1-chat-latest",
85
+ "gpt-5.2", "gpt-5.2-2025-12-11", "gpt-5.2-chat-latest"
80
86
  ]
81
87
 
82
88
  for model in reasoning_models:
83
89
  # Deep research models and GPT-5 might have different capabilities
84
90
  is_deep_research = "deep-research" in model
85
91
  is_gpt5 = "gpt-5" in model
86
- is_o1_series = model.startswith("o1")
87
- is_o3_series = model.startswith("o3")
88
- is_o4_series = model.startswith("o4")
92
+ is_gpt5_1 = "gpt-5.1" in model
93
+ is_gpt5_2 = "gpt-5.2" in model
94
+ is_gpt5_pro = "gpt-5-pro" in model and not is_gpt5_2
89
95
  is_mini_or_nano = ("mini" in model or "nano" in model)
96
+ is_chat_latest = "chat-latest" in model
90
97
 
91
- # GPT-5 models may support more features than o1/o3/o4
92
- supports_tools = is_gpt5 # GPT-5 might support tools
93
- supports_streaming = is_gpt5 # GPT-5 might support streaming
98
+ # ALL reasoning models now support tools and streaming (except gpt-5-pro which is responses-only)
99
+ supports_tools = not is_gpt5_pro
100
+ supports_streaming = not is_gpt5_pro
94
101
 
95
102
  # Set context and output tokens based on model tier
96
103
  if is_gpt5:
@@ -104,15 +111,20 @@ class OpenAIModelRegistry:
104
111
  output_tokens = 32768
105
112
 
106
113
  # Temperature restrictions based on model series
107
- if is_gpt5 or is_o1_series or is_o4_series:
108
- # GPT-5, o1, and o4 series only support temperature=1.0
109
- supported_temps = [1.0]
110
- elif is_o3_series:
111
- # o3 series doesn't support temperature parameter at all
112
- supported_temps = []
113
- else:
114
- # Other reasoning models support all temperatures
114
+ # All reasoning models now support only temperature=1.0 (o3 now supports it too)
115
+ if is_gpt5_1 and not is_chat_latest:
116
+ # gpt-5.1 and gpt-5.1-2025-11-13 support all temperatures
117
+ supported_temps = None
118
+ elif is_gpt5_2 and not is_chat_latest:
119
+ # gpt-5.2 and gpt-5.2-2025-12-11 support all temperatures
115
120
  supported_temps = None
121
+ else:
122
+ # All other reasoning models (including o1, o3, o4, gpt-5, and *-chat-latest) support only temp=1.0
123
+ supported_temps = [1.0]
124
+
125
+ # API endpoint support flags
126
+ is_responses_only = "pro" in model or "deep-research" in model or model == "gpt-5-codex"
127
+ is_both_endpoint = model in ("gpt-5.1", "gpt-5.1-2025-11-13")
116
128
 
117
129
  self._models[model] = ModelCapabilities(
118
130
  model_type=ModelType.REASONING,
@@ -121,11 +133,14 @@ class OpenAIModelRegistry:
121
133
  supports_vision=False, # Vision support would need to be confirmed for GPT-5
122
134
  max_context_tokens=context_tokens,
123
135
  max_output_tokens=output_tokens,
124
- supported_temperatures=supported_temps
136
+ supported_temperatures=supported_temps,
137
+ supports_chat_api=not is_responses_only,
138
+ supports_completions_api=is_both_endpoint,
139
+ supports_responses_api=is_responses_only
125
140
  )
126
141
 
127
- # Chat Models (GPT-4 and GPT-4.1 series) - Updated 2025-09-28
128
- # Note: GPT-5 series moved to reasoning models
142
+ # Chat Models (GPT-4 and GPT-4.1 series) - Updated 2026-02-04
143
+ # Note: Most GPT-5 series moved to reasoning models; gpt-5-chat-latest is chat
129
144
  gpt4_and_newer_models = [
130
145
  "chatgpt-4o-latest",
131
146
  "gpt-4", "gpt-4-0125-preview", "gpt-4-0613", "gpt-4-1106-preview",
@@ -133,7 +148,7 @@ class OpenAIModelRegistry:
133
148
  "gpt-4.1", "gpt-4.1-2025-04-14", "gpt-4.1-mini", "gpt-4.1-mini-2025-04-14",
134
149
  "gpt-4.1-nano", "gpt-4.1-nano-2025-04-14",
135
150
  "gpt-4o", "gpt-4o-2024-05-13", "gpt-4o-2024-08-06", "gpt-4o-2024-11-20",
136
- "gpt-4o-audio-preview", "gpt-4o-audio-preview-2024-10-01",
151
+ "gpt-4o-audio-preview",
137
152
  "gpt-4o-audio-preview-2024-12-17", "gpt-4o-audio-preview-2025-06-03",
138
153
  "gpt-4o-mini", "gpt-4o-mini-2024-07-18",
139
154
  "gpt-4o-mini-audio-preview", "gpt-4o-mini-audio-preview-2024-12-17",
@@ -143,18 +158,37 @@ class OpenAIModelRegistry:
143
158
  "gpt-4o-realtime-preview", "gpt-4o-realtime-preview-2024-10-01",
144
159
  "gpt-4o-realtime-preview-2024-12-17", "gpt-4o-realtime-preview-2025-06-03",
145
160
  "gpt-4o-search-preview", "gpt-4o-search-preview-2025-03-11",
146
- "gpt-4o-transcribe"
161
+ "gpt-4o-transcribe",
162
+ "gpt-5-chat-latest",
163
+ "gpt-5-search-api", "gpt-5-search-api-2025-10-14"
147
164
  ]
148
165
 
149
166
  for model in gpt4_and_newer_models:
150
167
  # Determine capabilities based on model features
151
- vision_support = ("gpt-4o" in model or "audio-preview" in model or "realtime" in model)
168
+ is_chatgpt_latest = model == "chatgpt-4o-latest"
152
169
  is_mini_or_nano = ("mini" in model or "nano" in model)
153
- is_audio = "audio" in model or "realtime" in model or "transcribe" in model
170
+ is_audio = "audio" in model or "realtime" in model or "transcribe" in model or "tts" in model
171
+ is_search = "search" in model
154
172
  is_gpt41 = "gpt-4.1" in model
173
+ is_gpt5_chat = model == "gpt-5-chat-latest"
174
+ is_gpt5_search = "gpt-5-search-api" in model
175
+ is_nano_base = model == "gpt-4.1-nano"
176
+ # Note: Keep vision=True for gpt-4o models (audit probe limitation with 1x1 PNG)
177
+ # Exclude chatgpt-4o-latest, audio/search/transcribe/tts/realtime variants
178
+ vision_support = ("gpt-4o" in model and not is_chatgpt_latest and not is_audio and not is_search)
179
+
180
+ # Tool support: disabled for audio models, search models, chatgpt-4o-latest, and gpt-4.1-nano
181
+ supports_tools = not (is_audio or is_search or is_chatgpt_latest or is_nano_base)
182
+ # Streaming: disabled for audio models only
183
+ supports_streaming = not is_audio
184
+ # Temperature restrictions for search models
185
+ supported_temps = [] if is_search else None
155
186
 
156
187
  # Set context and output tokens based on model tier
157
- if is_gpt41:
188
+ if is_gpt5_chat or is_gpt5_search:
189
+ context_tokens = 300000
190
+ output_tokens = 50000
191
+ elif is_gpt41:
158
192
  context_tokens = 200000 if not is_mini_or_nano else 128000
159
193
  output_tokens = 32768 if not is_mini_or_nano else 16384
160
194
  elif "gpt-4o" in model:
@@ -164,33 +198,42 @@ class OpenAIModelRegistry:
164
198
  context_tokens = 32000
165
199
  output_tokens = 8192
166
200
 
201
+ # API endpoint support flags
202
+ is_both_endpoint = model in ("gpt-4.1-nano", "gpt-4.1-nano-2025-04-14",
203
+ "gpt-4o-mini", "gpt-4o-mini-2024-07-18")
204
+
167
205
  self._models[model] = ModelCapabilities(
168
206
  model_type=ModelType.CHAT,
169
- supports_tools=True,
170
- supports_streaming=not is_audio, # Audio models may not support streaming
207
+ supports_tools=supports_tools,
208
+ supports_streaming=supports_streaming,
171
209
  supports_vision=vision_support,
172
210
  max_context_tokens=context_tokens,
173
- max_output_tokens=output_tokens
211
+ max_output_tokens=output_tokens,
212
+ supported_temperatures=supported_temps,
213
+ supports_completions_api=is_both_endpoint
174
214
  )
175
215
 
176
- # Chat Models (GPT-3.5 series) - Updated 2025-09-28
216
+ # Chat Models (GPT-3.5 series) - Updated 2026-02-04
177
217
  gpt35_models = [
178
218
  "gpt-3.5-turbo", "gpt-3.5-turbo-0125", "gpt-3.5-turbo-1106",
179
219
  "gpt-3.5-turbo-16k", "gpt-3.5-turbo-instruct", "gpt-3.5-turbo-instruct-0914"
180
220
  ]
181
221
 
182
222
  for model in gpt35_models:
223
+ is_instruct = "instruct" in model
183
224
  context_tokens = 16385 if "16k" not in model else 16385
184
225
  self._models[model] = ModelCapabilities(
185
226
  model_type=ModelType.CHAT,
186
- supports_tools="instruct" not in model, # Instruct models don't support tools
187
- supports_streaming="instruct" not in model, # Instruct models don't support streaming
227
+ supports_tools=not is_instruct, # Instruct models don't support tools
228
+ supports_streaming=not is_instruct, # Instruct models don't support streaming
188
229
  supports_vision=False,
189
230
  max_context_tokens=context_tokens,
190
- max_output_tokens=4096
231
+ max_output_tokens=4096,
232
+ supports_chat_api=not is_instruct,
233
+ supports_completions_api=is_instruct
191
234
  )
192
235
 
193
- # Embedding Models - Updated 2025-09-28
236
+ # Embedding Models - Updated 2026-02-04
194
237
  embedding_models = [
195
238
  "text-embedding-3-large", "text-embedding-3-small", "text-embedding-ada-002"
196
239
  ]
@@ -200,15 +243,61 @@ class OpenAIModelRegistry:
200
243
  model_type=ModelType.EMBEDDING,
201
244
  supports_tools=False,
202
245
  supports_streaming=False,
203
- supports_vision=False
246
+ supports_vision=False,
247
+ supports_chat_api=False
204
248
  )
205
249
 
206
- # Pattern mappings for unknown models - Updated 2025-09-28
250
+ # Legacy & Codex Models - Updated 2026-02-05
251
+ self._models["babbage-002"] = ModelCapabilities(
252
+ model_type=ModelType.CHAT,
253
+ supports_tools=False,
254
+ supports_streaming=False,
255
+ supports_vision=False,
256
+ supports_chat_api=False,
257
+ supports_completions_api=True
258
+ )
259
+
260
+ self._models["davinci-002"] = ModelCapabilities(
261
+ model_type=ModelType.CHAT,
262
+ supports_tools=False,
263
+ supports_streaming=False,
264
+ supports_vision=False,
265
+ supports_chat_api=False,
266
+ supports_completions_api=True
267
+ )
268
+
269
+ self._models["gpt-5.1-codex-mini"] = ModelCapabilities(
270
+ model_type=ModelType.REASONING,
271
+ supports_tools=False,
272
+ supports_streaming=False,
273
+ supports_vision=False,
274
+ max_context_tokens=128000,
275
+ max_output_tokens=32768,
276
+ supported_temperatures=[1.0],
277
+ supports_chat_api=False,
278
+ supports_completions_api=True
279
+ )
280
+
281
+ self._models["codex-mini-latest"] = ModelCapabilities(
282
+ model_type=ModelType.REASONING,
283
+ supports_tools=False,
284
+ supports_streaming=False,
285
+ supports_vision=False,
286
+ max_context_tokens=128000,
287
+ max_output_tokens=32768,
288
+ supported_temperatures=[1.0],
289
+ supports_chat_api=False,
290
+ supports_responses_api=True
291
+ )
292
+
293
+ # Pattern mappings for unknown models - Updated 2026-02-04
207
294
  self._pattern_mappings = {
208
295
  "o1": ModelType.REASONING,
209
296
  "o3": ModelType.REASONING,
210
297
  "o4": ModelType.REASONING,
211
298
  "gpt-5": ModelType.REASONING, # GPT-5 is a reasoning model
299
+ "gpt-5.1": ModelType.REASONING,
300
+ "gpt-5.2": ModelType.REASONING,
212
301
  "gpt-4": ModelType.CHAT,
213
302
  "gpt-4.1": ModelType.CHAT,
214
303
  "gpt-3.5": ModelType.CHAT,
@@ -262,28 +351,40 @@ class OpenAIModelRegistry:
262
351
  model_type=ModelType.REASONING,
263
352
  supports_tools=False,
264
353
  supports_streaming=False,
265
- supports_vision=False
354
+ supports_vision=False,
355
+ supports_chat_api=True,
356
+ supports_completions_api=False,
357
+ supports_responses_api=False
266
358
  )
267
359
  elif model_type == ModelType.CHAT:
268
360
  return ModelCapabilities(
269
361
  model_type=ModelType.CHAT,
270
362
  supports_tools=True,
271
363
  supports_streaming=True,
272
- supports_vision=False
364
+ supports_vision=False,
365
+ supports_chat_api=True,
366
+ supports_completions_api=False,
367
+ supports_responses_api=False
273
368
  )
274
369
  elif model_type == ModelType.EMBEDDING:
275
370
  return ModelCapabilities(
276
371
  model_type=ModelType.EMBEDDING,
277
372
  supports_tools=False,
278
373
  supports_streaming=False,
279
- supports_vision=False
374
+ supports_vision=False,
375
+ supports_chat_api=False,
376
+ supports_completions_api=False,
377
+ supports_responses_api=False
280
378
  )
281
379
  else: # MODERATION
282
380
  return ModelCapabilities(
283
381
  model_type=ModelType.MODERATION,
284
382
  supports_tools=False,
285
383
  supports_streaming=False,
286
- supports_vision=False
384
+ supports_vision=False,
385
+ supports_chat_api=False,
386
+ supports_completions_api=False,
387
+ supports_responses_api=False
287
388
  )
288
389
 
289
390
  def is_reasoning_model(self, model_name: str) -> bool:
@@ -22,9 +22,10 @@ class DescribeOpenAIModelRegistry:
22
22
  registry = OpenAIModelRegistry()
23
23
  registered_models = registry.get_registered_models()
24
24
 
25
- # Check that we have reasoning models
25
+ # Check that we have reasoning models (o1-mini removed in 2026-02-04 audit)
26
26
  assert "o1" in registered_models
27
- assert "o1-mini" in registered_models
27
+ assert "o3" in registered_models
28
+ assert "gpt-5" in registered_models
28
29
 
29
30
  # Check that we have chat models
30
31
  assert "gpt-4o" in registered_models
@@ -43,15 +44,17 @@ class DescribeOpenAIModelRegistry:
43
44
  """
44
45
  registry = OpenAIModelRegistry()
45
46
 
46
- # Test known reasoning models
47
- assert registry.is_reasoning_model("o1-preview") is True
48
- assert registry.is_reasoning_model("o1-mini") is True
47
+ # Test known reasoning models (o1-mini removed, o1-preview uses pattern matching)
48
+ assert registry.is_reasoning_model("o1") is True
49
49
  assert registry.is_reasoning_model("o3-mini") is True
50
+ assert registry.is_reasoning_model("gpt-5") is True
51
+ assert registry.is_reasoning_model("gpt-5.1") is True
50
52
 
51
53
  # Test chat models
52
54
  assert registry.is_reasoning_model("gpt-4o") is False
53
55
  assert registry.is_reasoning_model("gpt-4o-mini") is False
54
56
  assert registry.is_reasoning_model("gpt-3.5-turbo") is False
57
+ assert registry.is_reasoning_model("gpt-5-chat-latest") is False
55
58
 
56
59
  def should_use_pattern_matching_for_unknown_models(self):
57
60
  """
@@ -80,7 +83,7 @@ class DescribeOpenAIModelRegistry:
80
83
  registry = OpenAIModelRegistry()
81
84
 
82
85
  # Reasoning models should use max_completion_tokens
83
- o1_capabilities = registry.get_model_capabilities("o1-mini")
86
+ o1_capabilities = registry.get_model_capabilities("o1")
84
87
  assert o1_capabilities.get_token_limit_param() == "max_completion_tokens"
85
88
 
86
89
  # Chat models should use max_tokens
@@ -178,3 +181,167 @@ class DescribeOpenAIModelRegistry:
178
181
  assert ModelType.CHAT.value == "chat"
179
182
  assert ModelType.EMBEDDING.value == "embedding"
180
183
  assert ModelType.MODERATION.value == "moderation"
184
+
185
+ def should_support_tools_and_streaming_for_all_reasoning_models(self):
186
+ """
187
+ Given reasoning models as of 2026-02-04 audit
188
+ When checking their capabilities
189
+ Then all should support tools and streaming except gpt-5-pro
190
+ """
191
+ registry = OpenAIModelRegistry()
192
+
193
+ # All o1/o3/o4 models now support tools and streaming
194
+ o1_caps = registry.get_model_capabilities("o1")
195
+ assert o1_caps.supports_tools is True
196
+ assert o1_caps.supports_streaming is True
197
+
198
+ o3_caps = registry.get_model_capabilities("o3")
199
+ assert o3_caps.supports_tools is True
200
+ assert o3_caps.supports_streaming is True
201
+
202
+ o3_mini_caps = registry.get_model_capabilities("o3-mini")
203
+ assert o3_mini_caps.supports_tools is True
204
+ assert o3_mini_caps.supports_streaming is True
205
+
206
+ # GPT-5 family (except gpt-5-pro) supports tools and streaming
207
+ gpt5_caps = registry.get_model_capabilities("gpt-5")
208
+ assert gpt5_caps.supports_tools is True
209
+ assert gpt5_caps.supports_streaming is True
210
+
211
+ # gpt-5-pro is responses-only, no tools/streaming
212
+ gpt5_pro_caps = registry.get_model_capabilities("gpt-5-pro")
213
+ assert gpt5_pro_caps.supports_tools is False
214
+ assert gpt5_pro_caps.supports_streaming is False
215
+
216
+ def should_support_temperature_1_0_only_for_most_reasoning_models(self):
217
+ """
218
+ Given reasoning models as of 2026-02-04 audit
219
+ When checking temperature support
220
+ Then most should support only temperature=1.0, except gpt-5.1/5.2 base models
221
+ """
222
+ registry = OpenAIModelRegistry()
223
+
224
+ # o1/o3/o4 series support only temperature=1.0
225
+ o1_caps = registry.get_model_capabilities("o1")
226
+ assert o1_caps.supported_temperatures == [1.0]
227
+ assert o1_caps.supports_temperature(1.0) is True
228
+ assert o1_caps.supports_temperature(0.7) is False
229
+
230
+ o3_caps = registry.get_model_capabilities("o3")
231
+ assert o3_caps.supported_temperatures == [1.0]
232
+
233
+ # gpt-5.1 and gpt-5.1-2025-11-13 support all temperatures
234
+ gpt5_1_caps = registry.get_model_capabilities("gpt-5.1")
235
+ assert gpt5_1_caps.supported_temperatures is None
236
+ assert gpt5_1_caps.supports_temperature(0.7) is True
237
+ assert gpt5_1_caps.supports_temperature(1.0) is True
238
+
239
+ # gpt-5.1-chat-latest supports only temperature=1.0
240
+ gpt5_1_chat_caps = registry.get_model_capabilities("gpt-5.1-chat-latest")
241
+ assert gpt5_1_chat_caps.supported_temperatures == [1.0]
242
+
243
+ # gpt-5.2 and gpt-5.2-2025-12-11 support all temperatures
244
+ gpt5_2_caps = registry.get_model_capabilities("gpt-5.2")
245
+ assert gpt5_2_caps.supported_temperatures is None
246
+
247
+ # gpt-5.2-chat-latest supports only temperature=1.0
248
+ gpt5_2_chat_caps = registry.get_model_capabilities("gpt-5.2-chat-latest")
249
+ assert gpt5_2_chat_caps.supported_temperatures == [1.0]
250
+
251
+ def should_disable_tools_for_specific_chat_models(self):
252
+ """
253
+ Given chat models as of 2026-02-04 audit
254
+ When checking tool support
255
+ Then specific models should have tools disabled
256
+ """
257
+ registry = OpenAIModelRegistry()
258
+
259
+ # chatgpt-4o-latest does not support tools
260
+ chatgpt_caps = registry.get_model_capabilities("chatgpt-4o-latest")
261
+ assert chatgpt_caps.supports_tools is False
262
+ assert chatgpt_caps.supports_vision is False
263
+
264
+ # gpt-4.1-nano does not support tools
265
+ nano_caps = registry.get_model_capabilities("gpt-4.1-nano")
266
+ assert nano_caps.supports_tools is False
267
+
268
+ # Search models do not support tools and have no temperature support
269
+ search_caps = registry.get_model_capabilities("gpt-4o-search-preview")
270
+ assert search_caps.supports_tools is False
271
+ assert search_caps.supported_temperatures == []
272
+ assert search_caps.supports_temperature(1.0) is False
273
+
274
+ gpt5_search_caps = registry.get_model_capabilities("gpt-5-search-api")
275
+ assert gpt5_search_caps.supports_tools is False
276
+ assert gpt5_search_caps.supported_temperatures == []
277
+
278
+ # Audio models do not support tools or streaming
279
+ audio_caps = registry.get_model_capabilities("gpt-4o-audio-preview")
280
+ assert audio_caps.supports_tools is False
281
+ assert audio_caps.supports_streaming is False
282
+
283
+
284
+ class DescribeAPIEndpointSupport:
285
+
286
+ def should_flag_chat_only_model(self):
287
+ registry = OpenAIModelRegistry()
288
+ caps = registry.get_model_capabilities("gpt-4")
289
+ assert caps.supports_chat_api is True
290
+ assert caps.supports_completions_api is False
291
+ assert caps.supports_responses_api is False
292
+
293
+ def should_flag_both_endpoint_model(self):
294
+ registry = OpenAIModelRegistry()
295
+ caps = registry.get_model_capabilities("gpt-4o-mini")
296
+ assert caps.supports_chat_api is True
297
+ assert caps.supports_completions_api is True
298
+ assert caps.supports_responses_api is False
299
+
300
+ def should_flag_completions_only_model(self):
301
+ registry = OpenAIModelRegistry()
302
+ caps = registry.get_model_capabilities("gpt-3.5-turbo-instruct")
303
+ assert caps.supports_chat_api is False
304
+ assert caps.supports_completions_api is True
305
+ assert caps.supports_responses_api is False
306
+
307
+ def should_flag_responses_only_model(self):
308
+ registry = OpenAIModelRegistry()
309
+ caps = registry.get_model_capabilities("gpt-5-pro")
310
+ assert caps.supports_chat_api is False
311
+ assert caps.supports_completions_api is False
312
+ assert caps.supports_responses_api is True
313
+
314
+ def should_flag_legacy_completions_model(self):
315
+ registry = OpenAIModelRegistry()
316
+ caps = registry.get_model_capabilities("babbage-002")
317
+ assert caps.supports_chat_api is False
318
+ assert caps.supports_completions_api is True
319
+ assert caps.supports_responses_api is False
320
+
321
+ def should_flag_embedding_model_with_no_endpoints(self):
322
+ registry = OpenAIModelRegistry()
323
+ caps = registry.get_model_capabilities("text-embedding-3-large")
324
+ assert caps.supports_chat_api is False
325
+ assert caps.supports_completions_api is False
326
+ assert caps.supports_responses_api is False
327
+
328
+ def should_flag_codex_mini_latest_as_responses_only(self):
329
+ registry = OpenAIModelRegistry()
330
+ caps = registry.get_model_capabilities("codex-mini-latest")
331
+ assert caps.supports_chat_api is False
332
+ assert caps.supports_completions_api is False
333
+ assert caps.supports_responses_api is True
334
+
335
+ def should_flag_gpt51_as_both_chat_and_completions(self):
336
+ registry = OpenAIModelRegistry()
337
+ caps = registry.get_model_capabilities("gpt-5.1")
338
+ assert caps.supports_chat_api is True
339
+ assert caps.supports_completions_api is True
340
+ assert caps.supports_responses_api is False
341
+
342
+ def should_include_endpoint_flags_in_default_capabilities(self):
343
+ registry = OpenAIModelRegistry()
344
+ caps = registry.get_model_capabilities("completely-unknown-model-xyz")
345
+ assert caps.supports_chat_api is True
346
+ assert caps.supports_completions_api is False
347
+ assert caps.supports_responses_api is False
@@ -88,16 +88,16 @@ class DescribeOpenAIGatewayTemperatureHandling:
88
88
  call_args = mock_openai_client.chat.completions.create.call_args
89
89
  assert call_args[1]['temperature'] == 0.1
90
90
 
91
- def should_automatically_adjust_unsupported_temperature_for_o1_mini(self, openai_gateway, mock_openai_client):
91
+ def should_automatically_adjust_unsupported_temperature_for_o1(self, openai_gateway, mock_openai_client):
92
92
  """
93
- Given an o1-mini model that only supports temperature=1.0
93
+ Given an o1 model that only supports temperature=1.0
94
94
  When calling complete with temperature=0.1 (unsupported)
95
95
  Then it should automatically adjust to temperature=1.0
96
96
  """
97
97
  messages = [LLMMessage(role=MessageRole.User, content="Test message")]
98
98
 
99
99
  openai_gateway.complete(
100
- model="o1-mini",
100
+ model="o1",
101
101
  messages=messages,
102
102
  temperature=0.1
103
103
  )
@@ -124,11 +124,11 @@ class DescribeOpenAIGatewayTemperatureHandling:
124
124
  call_args = mock_openai_client.chat.completions.create.call_args
125
125
  assert call_args[1]['temperature'] == 1.0
126
126
 
127
- def should_remove_temperature_parameter_for_o3_mini(self, openai_gateway, mock_openai_client):
127
+ def should_automatically_adjust_unsupported_temperature_for_o3_mini(self, openai_gateway, mock_openai_client):
128
128
  """
129
- Given an o3-mini model that doesn't support temperature parameter at all
130
- When calling complete with temperature=0.1
131
- Then it should remove the temperature parameter entirely
129
+ Given an o3-mini model that only supports temperature=1.0
130
+ When calling complete with temperature=0.1 (unsupported)
131
+ Then it should automatically adjust to temperature=1.0
132
132
  """
133
133
  messages = [LLMMessage(role=MessageRole.User, content="Test message")]
134
134
 
@@ -138,9 +138,9 @@ class DescribeOpenAIGatewayTemperatureHandling:
138
138
  temperature=0.1
139
139
  )
140
140
 
141
- # Verify the API was called without temperature parameter
141
+ # Verify the API was called with temperature=1.0, not 0.1
142
142
  call_args = mock_openai_client.chat.completions.create.call_args
143
- assert 'temperature' not in call_args[1]
143
+ assert call_args[1]['temperature'] == 1.0
144
144
 
145
145
 
146
146
  class DescribeModelCapabilitiesTemperatureRestrictions:
@@ -178,14 +178,14 @@ class DescribeModelCapabilitiesTemperatureRestrictions:
178
178
  def should_identify_all_gpt5_variants_temperature_restrictions(self):
179
179
  """
180
180
  Given the model registry
181
- When checking all GPT-5 variant models
182
- Then they should all have temperature restrictions to 1.0 only
181
+ When checking GPT-5 reasoning variant models
182
+ Then they should have temperature restrictions to 1.0 only
183
+ Note: gpt-5-chat-latest is a CHAT model and supports all temperatures
183
184
  """
184
185
  registry = get_model_registry()
185
- gpt5_models = [
186
+ gpt5_reasoning_models = [
186
187
  "gpt-5",
187
188
  "gpt-5-2025-08-07",
188
- "gpt-5-chat-latest",
189
189
  "gpt-5-codex",
190
190
  "gpt-5-mini",
191
191
  "gpt-5-mini-2025-08-07",
@@ -193,7 +193,7 @@ class DescribeModelCapabilitiesTemperatureRestrictions:
193
193
  "gpt-5-nano-2025-08-07"
194
194
  ]
195
195
 
196
- for model in gpt5_models:
196
+ for model in gpt5_reasoning_models:
197
197
  capabilities = registry.get_model_capabilities(model)
198
198
  assert capabilities.supports_temperature(1.0) is True
199
199
  assert capabilities.supports_temperature(0.1) is False
@@ -204,9 +204,10 @@ class DescribeModelCapabilitiesTemperatureRestrictions:
204
204
  Given the model registry
205
205
  When checking o1 series models
206
206
  Then they should have temperature restrictions to 1.0 only
207
+ Note: o1-mini removed from API as of 2026-02-04 audit
207
208
  """
208
209
  registry = get_model_registry()
209
- o1_models = ["o1", "o1-mini", "o1-pro", "o1-2024-12-17"]
210
+ o1_models = ["o1", "o1-pro", "o1-2024-12-17", "o1-pro-2025-03-19"]
210
211
 
211
212
  for model in o1_models:
212
213
  capabilities = registry.get_model_capabilities(model)
@@ -214,20 +215,21 @@ class DescribeModelCapabilitiesTemperatureRestrictions:
214
215
  assert capabilities.supports_temperature(0.1) is False
215
216
  assert capabilities.supported_temperatures == [1.0]
216
217
 
217
- def should_identify_o3_series_no_temperature_support(self):
218
+ def should_identify_o3_series_temperature_restrictions(self):
218
219
  """
219
220
  Given the model registry
220
221
  When checking o3 series models
221
- Then they should not support temperature parameter at all
222
+ Then they should now support temperature=1.0 only (as of 2026-02-04 audit)
222
223
  """
223
224
  registry = get_model_registry()
224
- o3_models = ["o3", "o3-mini", "o3-pro", "o3-deep-research"]
225
+ o3_models = ["o3", "o3-mini", "o3-pro", "o3-deep-research", "o3-2025-04-16",
226
+ "o3-mini-2025-01-31", "o3-pro-2025-06-10", "o3-deep-research-2025-06-26"]
225
227
 
226
228
  for model in o3_models:
227
229
  capabilities = registry.get_model_capabilities(model)
228
- assert capabilities.supports_temperature(1.0) is False
230
+ assert capabilities.supports_temperature(1.0) is True
229
231
  assert capabilities.supports_temperature(0.1) is False
230
- assert capabilities.supported_temperatures == []
232
+ assert capabilities.supported_temperatures == [1.0]
231
233
 
232
234
  def should_identify_o4_series_temperature_restrictions(self):
233
235
  """