pydantic-ai-slim 0.4.2__py3-none-any.whl → 0.4.4__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.

Potentially problematic release.


This version of pydantic-ai-slim might be problematic. Click here for more details.

Files changed (55) hide show
  1. pydantic_ai/_agent_graph.py +219 -315
  2. pydantic_ai/_cli.py +9 -7
  3. pydantic_ai/_output.py +296 -226
  4. pydantic_ai/_parts_manager.py +2 -2
  5. pydantic_ai/_run_context.py +8 -14
  6. pydantic_ai/_tool_manager.py +190 -0
  7. pydantic_ai/_utils.py +18 -1
  8. pydantic_ai/ag_ui.py +675 -0
  9. pydantic_ai/agent.py +369 -155
  10. pydantic_ai/common_tools/duckduckgo.py +5 -2
  11. pydantic_ai/exceptions.py +14 -2
  12. pydantic_ai/ext/aci.py +12 -3
  13. pydantic_ai/ext/langchain.py +9 -1
  14. pydantic_ai/mcp.py +147 -84
  15. pydantic_ai/messages.py +19 -9
  16. pydantic_ai/models/__init__.py +43 -19
  17. pydantic_ai/models/anthropic.py +2 -2
  18. pydantic_ai/models/bedrock.py +1 -1
  19. pydantic_ai/models/cohere.py +1 -1
  20. pydantic_ai/models/function.py +50 -24
  21. pydantic_ai/models/gemini.py +3 -11
  22. pydantic_ai/models/google.py +3 -12
  23. pydantic_ai/models/groq.py +2 -1
  24. pydantic_ai/models/huggingface.py +463 -0
  25. pydantic_ai/models/instrumented.py +1 -1
  26. pydantic_ai/models/mistral.py +3 -3
  27. pydantic_ai/models/openai.py +5 -5
  28. pydantic_ai/output.py +21 -7
  29. pydantic_ai/profiles/google.py +1 -1
  30. pydantic_ai/profiles/moonshotai.py +8 -0
  31. pydantic_ai/providers/__init__.py +4 -0
  32. pydantic_ai/providers/google.py +2 -2
  33. pydantic_ai/providers/google_vertex.py +10 -5
  34. pydantic_ai/providers/grok.py +13 -1
  35. pydantic_ai/providers/groq.py +2 -0
  36. pydantic_ai/providers/huggingface.py +88 -0
  37. pydantic_ai/result.py +57 -33
  38. pydantic_ai/tools.py +26 -119
  39. pydantic_ai/toolsets/__init__.py +22 -0
  40. pydantic_ai/toolsets/abstract.py +155 -0
  41. pydantic_ai/toolsets/combined.py +88 -0
  42. pydantic_ai/toolsets/deferred.py +38 -0
  43. pydantic_ai/toolsets/filtered.py +24 -0
  44. pydantic_ai/toolsets/function.py +238 -0
  45. pydantic_ai/toolsets/prefixed.py +37 -0
  46. pydantic_ai/toolsets/prepared.py +36 -0
  47. pydantic_ai/toolsets/renamed.py +42 -0
  48. pydantic_ai/toolsets/wrapper.py +37 -0
  49. pydantic_ai/usage.py +14 -8
  50. {pydantic_ai_slim-0.4.2.dist-info → pydantic_ai_slim-0.4.4.dist-info}/METADATA +13 -8
  51. pydantic_ai_slim-0.4.4.dist-info/RECORD +98 -0
  52. pydantic_ai_slim-0.4.2.dist-info/RECORD +0 -83
  53. {pydantic_ai_slim-0.4.2.dist-info → pydantic_ai_slim-0.4.4.dist-info}/WHEEL +0 -0
  54. {pydantic_ai_slim-0.4.2.dist-info → pydantic_ai_slim-0.4.4.dist-info}/entry_points.txt +0 -0
  55. {pydantic_ai_slim-0.4.2.dist-info → pydantic_ai_slim-0.4.4.dist-info}/licenses/LICENSE +0 -0
@@ -134,31 +134,15 @@ KnownModelName = TypeAliasType(
134
134
  'cohere:command-r7b-12-2024',
135
135
  'deepseek:deepseek-chat',
136
136
  'deepseek:deepseek-reasoner',
137
- 'google-gla:gemini-1.5-flash',
138
- 'google-gla:gemini-1.5-flash-8b',
139
- 'google-gla:gemini-1.5-pro',
140
- 'google-gla:gemini-1.0-pro',
141
137
  'google-gla:gemini-2.0-flash',
142
- 'google-gla:gemini-2.0-flash-lite-preview-02-05',
143
- 'google-gla:gemini-2.0-pro-exp-02-05',
144
- 'google-gla:gemini-2.5-flash-preview-05-20',
138
+ 'google-gla:gemini-2.0-flash-lite',
145
139
  'google-gla:gemini-2.5-flash',
146
140
  'google-gla:gemini-2.5-flash-lite-preview-06-17',
147
- 'google-gla:gemini-2.5-pro-exp-03-25',
148
- 'google-gla:gemini-2.5-pro-preview-05-06',
149
141
  'google-gla:gemini-2.5-pro',
150
- 'google-vertex:gemini-1.5-flash',
151
- 'google-vertex:gemini-1.5-flash-8b',
152
- 'google-vertex:gemini-1.5-pro',
153
- 'google-vertex:gemini-1.0-pro',
154
142
  'google-vertex:gemini-2.0-flash',
155
- 'google-vertex:gemini-2.0-flash-lite-preview-02-05',
156
- 'google-vertex:gemini-2.0-pro-exp-02-05',
157
- 'google-vertex:gemini-2.5-flash-preview-05-20',
143
+ 'google-vertex:gemini-2.0-flash-lite',
158
144
  'google-vertex:gemini-2.5-flash',
159
145
  'google-vertex:gemini-2.5-flash-lite-preview-06-17',
160
- 'google-vertex:gemini-2.5-pro-exp-03-25',
161
- 'google-vertex:gemini-2.5-pro-preview-05-06',
162
146
  'google-vertex:gemini-2.5-pro',
163
147
  'gpt-3.5-turbo',
164
148
  'gpt-3.5-turbo-0125',
@@ -192,6 +176,7 @@ KnownModelName = TypeAliasType(
192
176
  'gpt-4o-audio-preview',
193
177
  'gpt-4o-audio-preview-2024-10-01',
194
178
  'gpt-4o-audio-preview-2024-12-17',
179
+ 'gpt-4o-audio-preview-2025-06-03',
195
180
  'gpt-4o-mini',
196
181
  'gpt-4o-mini-2024-07-18',
197
182
  'gpt-4o-mini-audio-preview',
@@ -200,6 +185,14 @@ KnownModelName = TypeAliasType(
200
185
  'gpt-4o-mini-search-preview-2025-03-11',
201
186
  'gpt-4o-search-preview',
202
187
  'gpt-4o-search-preview-2025-03-11',
188
+ 'grok:grok-4',
189
+ 'grok:grok-4-0709',
190
+ 'grok:grok-3',
191
+ 'grok:grok-3-mini',
192
+ 'grok:grok-3-fast',
193
+ 'grok:grok-3-mini-fast',
194
+ 'grok:grok-2-vision-1212',
195
+ 'grok:grok-2-image-1212',
203
196
  'groq:distil-whisper-large-v3-en',
204
197
  'groq:gemma2-9b-it',
205
198
  'groq:llama-3.3-70b-versatile',
@@ -207,6 +200,7 @@ KnownModelName = TypeAliasType(
207
200
  'groq:llama-guard-3-8b',
208
201
  'groq:llama3-70b-8192',
209
202
  'groq:llama3-8b-8192',
203
+ 'groq:moonshotai/kimi-k2-instruct',
210
204
  'groq:whisper-large-v3',
211
205
  'groq:whisper-large-v3-turbo',
212
206
  'groq:playai-tts',
@@ -227,6 +221,14 @@ KnownModelName = TypeAliasType(
227
221
  'heroku:claude-3-7-sonnet',
228
222
  'heroku:claude-4-sonnet',
229
223
  'heroku:claude-3-haiku',
224
+ 'huggingface:Qwen/QwQ-32B',
225
+ 'huggingface:Qwen/Qwen2.5-72B-Instruct',
226
+ 'huggingface:Qwen/Qwen3-235B-A22B',
227
+ 'huggingface:Qwen/Qwen3-32B',
228
+ 'huggingface:deepseek-ai/DeepSeek-R1',
229
+ 'huggingface:meta-llama/Llama-3.3-70B-Instruct',
230
+ 'huggingface:meta-llama/Llama-4-Maverick-17B-128E-Instruct',
231
+ 'huggingface:meta-llama/Llama-4-Scout-17B-16E-Instruct',
230
232
  'mistral:codestral-latest',
231
233
  'mistral:mistral-large-latest',
232
234
  'mistral:mistral-moderation-latest',
@@ -237,11 +239,18 @@ KnownModelName = TypeAliasType(
237
239
  'o1-mini-2024-09-12',
238
240
  'o1-preview',
239
241
  'o1-preview-2024-09-12',
242
+ 'o1-pro',
243
+ 'o1-pro-2025-03-19',
240
244
  'o3',
241
245
  'o3-2025-04-16',
246
+ 'o3-deep-research',
247
+ 'o3-deep-research-2025-06-26',
242
248
  'o3-mini',
243
249
  'o3-mini-2025-01-31',
250
+ 'o3-pro',
251
+ 'o3-pro-2025-06-10',
244
252
  'openai:chatgpt-4o-latest',
253
+ 'openai:codex-mini-latest',
245
254
  'openai:gpt-3.5-turbo',
246
255
  'openai:gpt-3.5-turbo-0125',
247
256
  'openai:gpt-3.5-turbo-0301',
@@ -274,6 +283,7 @@ KnownModelName = TypeAliasType(
274
283
  'openai:gpt-4o-audio-preview',
275
284
  'openai:gpt-4o-audio-preview-2024-10-01',
276
285
  'openai:gpt-4o-audio-preview-2024-12-17',
286
+ 'openai:gpt-4o-audio-preview-2025-06-03',
277
287
  'openai:gpt-4o-mini',
278
288
  'openai:gpt-4o-mini-2024-07-18',
279
289
  'openai:gpt-4o-mini-audio-preview',
@@ -288,12 +298,22 @@ KnownModelName = TypeAliasType(
288
298
  'openai:o1-mini-2024-09-12',
289
299
  'openai:o1-preview',
290
300
  'openai:o1-preview-2024-09-12',
301
+ 'openai:o1-pro',
302
+ 'openai:o1-pro-2025-03-19',
291
303
  'openai:o3',
292
304
  'openai:o3-2025-04-16',
305
+ 'openai:o3-deep-research',
306
+ 'openai:o3-deep-research-2025-06-26',
293
307
  'openai:o3-mini',
294
308
  'openai:o3-mini-2025-01-31',
295
309
  'openai:o4-mini',
296
310
  'openai:o4-mini-2025-04-16',
311
+ 'openai:o4-mini-deep-research',
312
+ 'openai:o4-mini-deep-research-2025-06-26',
313
+ 'openai:o3-pro',
314
+ 'openai:o3-pro-2025-06-10',
315
+ 'openai:computer-use-preview',
316
+ 'openai:computer-use-preview-2025-03-11',
297
317
  'test',
298
318
  ],
299
319
  )
@@ -560,7 +580,7 @@ def override_allow_model_requests(allow_model_requests: bool) -> Iterator[None]:
560
580
  ALLOW_MODEL_REQUESTS = old_value # pyright: ignore[reportConstantRedefinition]
561
581
 
562
582
 
563
- def infer_model(model: Model | KnownModelName | str) -> Model:
583
+ def infer_model(model: Model | KnownModelName | str) -> Model: # noqa: C901
564
584
  """Infer the model from the name."""
565
585
  if isinstance(model, Model):
566
586
  return model
@@ -624,6 +644,10 @@ def infer_model(model: Model | KnownModelName | str) -> Model:
624
644
  from .bedrock import BedrockConverseModel
625
645
 
626
646
  return BedrockConverseModel(model_name, provider=provider)
647
+ elif provider == 'huggingface':
648
+ from .huggingface import HuggingFaceModel
649
+
650
+ return HuggingFaceModel(model_name, provider=provider)
627
651
  else:
628
652
  raise UserError(f'Unknown model: {model}') # pragma: no cover
629
653
 
@@ -256,7 +256,7 @@ class AnthropicModel(Model):
256
256
  except APIStatusError as e:
257
257
  if (status_code := e.status_code) >= 400:
258
258
  raise ModelHTTPError(status_code=status_code, model_name=self.model_name, body=e.body) from e
259
- raise # pragma: lax no cover
259
+ raise # pragma: no cover
260
260
 
261
261
  def _process_response(self, response: BetaMessage) -> ModelResponse:
262
262
  """Process a non-streamed response, and prepare a message to return."""
@@ -266,7 +266,7 @@ class AnthropicModel(Model):
266
266
  items.append(TextPart(content=item.text))
267
267
  elif isinstance(item, BetaRedactedThinkingBlock): # pragma: no cover
268
268
  warnings.warn(
269
- 'PydanticAI currently does not handle redacted thinking blocks. '
269
+ 'Pydantic AI currently does not handle redacted thinking blocks. '
270
270
  'If you have a suggestion on how we should handle them, please open an issue.',
271
271
  UserWarning,
272
272
  )
@@ -663,4 +663,4 @@ class _AsyncIteratorWrapper(Generic[T]):
663
663
  if type(e.__cause__) is StopIteration:
664
664
  raise StopAsyncIteration
665
665
  else:
666
- raise e # pragma: lax no cover
666
+ raise e # pragma: no cover
@@ -183,7 +183,7 @@ class CohereModel(Model):
183
183
  except ApiError as e:
184
184
  if (status_code := e.status_code) and status_code >= 400:
185
185
  raise ModelHTTPError(status_code=status_code, model_name=self.model_name, body=e.body) from e
186
- raise # pragma: lax no cover
186
+ raise # pragma: no cover
187
187
 
188
188
  def _process_response(self, response: ChatResponse) -> ModelResponse:
189
189
  """Process a non-streamed response, and prepare a message to return."""
@@ -214,21 +214,39 @@ class DeltaToolCall:
214
214
  """Incremental change to the tool call ID."""
215
215
 
216
216
 
217
+ @dataclass
218
+ class DeltaThinkingPart:
219
+ """Incremental change to a thinking part.
220
+
221
+ Used to describe a chunk when streaming thinking responses.
222
+ """
223
+
224
+ content: str | None = None
225
+ """Incremental change to the thinking content."""
226
+ signature: str | None = None
227
+ """Incremental change to the thinking signature."""
228
+
229
+
217
230
  DeltaToolCalls: TypeAlias = dict[int, DeltaToolCall]
218
231
  """A mapping of tool call IDs to incremental changes."""
219
232
 
233
+ DeltaThinkingCalls: TypeAlias = dict[int, DeltaThinkingPart]
234
+ """A mapping of thinking call IDs to incremental changes."""
235
+
220
236
  # TODO: Change the signature to Callable[[list[ModelMessage], ModelSettings, ModelRequestParameters], ...]
221
237
  FunctionDef: TypeAlias = Callable[[list[ModelMessage], AgentInfo], Union[ModelResponse, Awaitable[ModelResponse]]]
222
238
  """A function used to generate a non-streamed response."""
223
239
 
224
240
  # TODO: Change signature as indicated above
225
- StreamFunctionDef: TypeAlias = Callable[[list[ModelMessage], AgentInfo], AsyncIterator[Union[str, DeltaToolCalls]]]
241
+ StreamFunctionDef: TypeAlias = Callable[
242
+ [list[ModelMessage], AgentInfo], AsyncIterator[Union[str, DeltaToolCalls, DeltaThinkingCalls]]
243
+ ]
226
244
  """A function used to generate a streamed response.
227
245
 
228
- While this is defined as having return type of `AsyncIterator[Union[str, DeltaToolCalls]]`, it should
229
- really be considered as `Union[AsyncIterator[str], AsyncIterator[DeltaToolCalls]`,
246
+ While this is defined as having return type of `AsyncIterator[Union[str, DeltaToolCalls, DeltaThinkingCalls]]`, it should
247
+ really be considered as `Union[AsyncIterator[str], AsyncIterator[DeltaToolCalls], AsyncIterator[DeltaThinkingCalls]]`,
230
248
 
231
- E.g. you need to yield all text or all `DeltaToolCalls`, not mix them.
249
+ E.g. you need to yield all text, all `DeltaToolCalls`, or all `DeltaThinkingCalls`, not mix them.
232
250
  """
233
251
 
234
252
 
@@ -237,7 +255,7 @@ class FunctionStreamedResponse(StreamedResponse):
237
255
  """Implementation of `StreamedResponse` for [FunctionModel][pydantic_ai.models.function.FunctionModel]."""
238
256
 
239
257
  _model_name: str
240
- _iter: AsyncIterator[str | DeltaToolCalls]
258
+ _iter: AsyncIterator[str | DeltaToolCalls | DeltaThinkingCalls]
241
259
  _timestamp: datetime = field(default_factory=_utils.now_utc)
242
260
 
243
261
  def __post_init__(self):
@@ -249,20 +267,31 @@ class FunctionStreamedResponse(StreamedResponse):
249
267
  response_tokens = _estimate_string_tokens(item)
250
268
  self._usage += usage.Usage(response_tokens=response_tokens, total_tokens=response_tokens)
251
269
  yield self._parts_manager.handle_text_delta(vendor_part_id='content', content=item)
252
- else:
253
- delta_tool_calls = item
254
- for dtc_index, delta_tool_call in delta_tool_calls.items():
255
- if delta_tool_call.json_args:
256
- response_tokens = _estimate_string_tokens(delta_tool_call.json_args)
257
- self._usage += usage.Usage(response_tokens=response_tokens, total_tokens=response_tokens)
258
- maybe_event = self._parts_manager.handle_tool_call_delta(
259
- vendor_part_id=dtc_index,
260
- tool_name=delta_tool_call.name,
261
- args=delta_tool_call.json_args,
262
- tool_call_id=delta_tool_call.tool_call_id,
263
- )
264
- if maybe_event is not None:
265
- yield maybe_event
270
+ elif isinstance(item, dict) and item:
271
+ for dtc_index, delta in item.items():
272
+ if isinstance(delta, DeltaThinkingPart):
273
+ if delta.content: # pragma: no branch
274
+ response_tokens = _estimate_string_tokens(delta.content)
275
+ self._usage += usage.Usage(response_tokens=response_tokens, total_tokens=response_tokens)
276
+ yield self._parts_manager.handle_thinking_delta(
277
+ vendor_part_id=dtc_index,
278
+ content=delta.content,
279
+ signature=delta.signature,
280
+ )
281
+ elif isinstance(delta, DeltaToolCall):
282
+ if delta.json_args:
283
+ response_tokens = _estimate_string_tokens(delta.json_args)
284
+ self._usage += usage.Usage(response_tokens=response_tokens, total_tokens=response_tokens)
285
+ maybe_event = self._parts_manager.handle_tool_call_delta(
286
+ vendor_part_id=dtc_index,
287
+ tool_name=delta.name,
288
+ args=delta.json_args,
289
+ tool_call_id=delta.tool_call_id,
290
+ )
291
+ if maybe_event is not None:
292
+ yield maybe_event
293
+ else:
294
+ assert_never(delta)
266
295
 
267
296
  @property
268
297
  def model_name(self) -> str:
@@ -299,12 +328,9 @@ def _estimate_usage(messages: Iterable[ModelMessage]) -> usage.Usage:
299
328
  if isinstance(part, TextPart):
300
329
  response_tokens += _estimate_string_tokens(part.content)
301
330
  elif isinstance(part, ThinkingPart):
302
- # NOTE: We don't send ThinkingPart to the providers yet.
303
- # If you are unsatisfied with this, please open an issue.
304
- pass
331
+ response_tokens += _estimate_string_tokens(part.content)
305
332
  elif isinstance(part, ToolCallPart):
306
- call = part
307
- response_tokens += 1 + _estimate_string_tokens(call.args_as_json_str())
333
+ response_tokens += 1 + _estimate_string_tokens(part.args_as_json_str())
308
334
  else:
309
335
  assert_never(part)
310
336
  else:
@@ -48,18 +48,10 @@ from . import (
48
48
  )
49
49
 
50
50
  LatestGeminiModelNames = Literal[
51
- 'gemini-1.5-flash',
52
- 'gemini-1.5-flash-8b',
53
- 'gemini-1.5-pro',
54
- 'gemini-1.0-pro',
55
51
  'gemini-2.0-flash',
56
- 'gemini-2.0-flash-lite-preview-02-05',
57
- 'gemini-2.0-pro-exp-02-05',
58
- 'gemini-2.5-flash-preview-05-20',
52
+ 'gemini-2.0-flash-lite',
59
53
  'gemini-2.5-flash',
60
54
  'gemini-2.5-flash-lite-preview-06-17',
61
- 'gemini-2.5-pro-exp-03-25',
62
- 'gemini-2.5-pro-preview-05-06',
63
55
  'gemini-2.5-pro',
64
56
  ]
65
57
  """Latest Gemini models."""
@@ -253,7 +245,7 @@ class GeminiModel(Model):
253
245
 
254
246
  if gemini_labels := model_settings.get('gemini_labels'):
255
247
  if self._system == 'google-vertex':
256
- request_data['labels'] = gemini_labels # pragma: lax no cover
248
+ request_data['labels'] = gemini_labels
257
249
 
258
250
  headers = {'Content-Type': 'application/json', 'User-Agent': get_user_agent()}
259
251
  url = f'/{self._model_name}:{"streamGenerateContent" if streamed else "generateContent"}'
@@ -415,7 +407,7 @@ def _settings_to_generation_config(model_settings: GeminiModelSettings) -> _Gemi
415
407
  if (frequency_penalty := model_settings.get('frequency_penalty')) is not None:
416
408
  config['frequency_penalty'] = frequency_penalty
417
409
  if (thinkingConfig := model_settings.get('gemini_thinking_config')) is not None:
418
- config['thinking_config'] = thinkingConfig # pragma: lax no cover
410
+ config['thinking_config'] = thinkingConfig
419
411
  return config
420
412
 
421
413
 
@@ -73,18 +73,10 @@ except ImportError as _import_error:
73
73
  ) from _import_error
74
74
 
75
75
  LatestGoogleModelNames = Literal[
76
- 'gemini-1.5-flash',
77
- 'gemini-1.5-flash-8b',
78
- 'gemini-1.5-pro',
79
- 'gemini-1.0-pro',
80
76
  'gemini-2.0-flash',
81
- 'gemini-2.0-flash-lite-preview-02-05',
82
- 'gemini-2.0-pro-exp-02-05',
83
- 'gemini-2.5-flash-preview-05-20',
77
+ 'gemini-2.0-flash-lite',
84
78
  'gemini-2.5-flash',
85
79
  'gemini-2.5-flash-lite-preview-06-17',
86
- 'gemini-2.5-pro-exp-03-25',
87
- 'gemini-2.5-pro-preview-05-06',
88
80
  'gemini-2.5-pro',
89
81
  ]
90
82
  """Latest Gemini models."""
@@ -166,7 +158,7 @@ class GoogleModel(Model):
166
158
  self._model_name = model_name
167
159
 
168
160
  if isinstance(provider, str):
169
- provider = GoogleProvider(vertexai=provider == 'google-vertex') # pragma: lax no cover
161
+ provider = GoogleProvider(vertexai=provider == 'google-vertex')
170
162
 
171
163
  self._provider = provider
172
164
  self._system = provider.name
@@ -492,8 +484,7 @@ def _content_model_response(m: ModelResponse) -> ContentDict:
492
484
  function_call = FunctionCallDict(name=item.tool_name, args=item.args_as_dict(), id=item.tool_call_id)
493
485
  parts.append({'function_call': function_call})
494
486
  elif isinstance(item, TextPart):
495
- if item.content: # pragma: no branch
496
- parts.append({'text': item.content})
487
+ parts.append({'text': item.content})
497
488
  elif isinstance(item, ThinkingPart): # pragma: no cover
498
489
  # NOTE: We don't send ThinkingPart to the providers yet. If you are unsatisfied with this,
499
490
  # please open an issue. The below code is the code to send thinking to the provider.
@@ -79,6 +79,7 @@ PreviewGroqModelNames = Literal[
79
79
  'llama-3.2-3b-preview',
80
80
  'llama-3.2-11b-vision-preview',
81
81
  'llama-3.2-90b-vision-preview',
82
+ 'moonshotai/kimi-k2-instruct',
82
83
  ]
83
84
  """Preview Groq models from <https://console.groq.com/docs/models#preview-models>."""
84
85
 
@@ -248,7 +249,7 @@ class GroqModel(Model):
248
249
  except APIStatusError as e:
249
250
  if (status_code := e.status_code) >= 400:
250
251
  raise ModelHTTPError(status_code=status_code, model_name=self.model_name, body=e.body) from e
251
- raise # pragma: lax no cover
252
+ raise # pragma: no cover
252
253
 
253
254
  def _process_response(self, response: chat.ChatCompletion) -> ModelResponse:
254
255
  """Process a non-streamed response, and prepare a message to return."""