anthropic 0.72.0__py3-none-any.whl → 0.73.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.
Files changed (43) hide show
  1. anthropic/__init__.py +2 -0
  2. anthropic/_compat.py +6 -0
  3. anthropic/_models.py +50 -16
  4. anthropic/_streaming.py +4 -6
  5. anthropic/_utils/_sync.py +3 -31
  6. anthropic/_utils/_transform.py +1 -1
  7. anthropic/_utils/_utils.py +1 -1
  8. anthropic/_version.py +1 -1
  9. anthropic/lib/_parse/_response.py +44 -0
  10. anthropic/lib/_parse/_transform.py +167 -0
  11. anthropic/lib/streaming/__init__.py +14 -4
  12. anthropic/lib/streaming/_beta_messages.py +82 -43
  13. anthropic/lib/streaming/_beta_types.py +21 -13
  14. anthropic/lib/tools/_beta_runner.py +102 -101
  15. anthropic/resources/beta/messages/batches.py +12 -12
  16. anthropic/resources/beta/messages/messages.py +365 -29
  17. anthropic/resources/messages/batches.py +12 -12
  18. anthropic/resources/messages/messages.py +14 -8
  19. anthropic/types/beta/__init__.py +1 -0
  20. anthropic/types/beta/beta_code_execution_tool_20250522_param.py +2 -0
  21. anthropic/types/beta/beta_code_execution_tool_20250825_param.py +2 -0
  22. anthropic/types/beta/beta_json_output_format_param.py +15 -0
  23. anthropic/types/beta/beta_memory_tool_20250818_param.py +2 -0
  24. anthropic/types/beta/beta_tool_bash_20241022_param.py +2 -0
  25. anthropic/types/beta/beta_tool_bash_20250124_param.py +2 -0
  26. anthropic/types/beta/beta_tool_computer_use_20241022_param.py +2 -0
  27. anthropic/types/beta/beta_tool_computer_use_20250124_param.py +2 -0
  28. anthropic/types/beta/beta_tool_param.py +2 -0
  29. anthropic/types/beta/beta_tool_text_editor_20241022_param.py +2 -0
  30. anthropic/types/beta/beta_tool_text_editor_20250124_param.py +2 -0
  31. anthropic/types/beta/beta_tool_text_editor_20250429_param.py +2 -0
  32. anthropic/types/beta/beta_tool_text_editor_20250728_param.py +2 -0
  33. anthropic/types/beta/beta_web_fetch_tool_20250910_param.py +2 -0
  34. anthropic/types/beta/beta_web_search_tool_20250305_param.py +2 -0
  35. anthropic/types/beta/message_count_tokens_params.py +4 -0
  36. anthropic/types/beta/message_create_params.py +24 -2
  37. anthropic/types/beta/messages/batch_create_params.py +8 -2
  38. anthropic/types/beta/parsed_beta_message.py +68 -0
  39. anthropic/types/messages/batch_create_params.py +0 -1
  40. {anthropic-0.72.0.dist-info → anthropic-0.73.0.dist-info}/METADATA +4 -5
  41. {anthropic-0.72.0.dist-info → anthropic-0.73.0.dist-info}/RECORD +43 -39
  42. {anthropic-0.72.0.dist-info → anthropic-0.73.0.dist-info}/WHEEL +0 -0
  43. {anthropic-0.72.0.dist-info → anthropic-0.73.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import builtins
3
4
  from types import TracebackType
4
- from typing import TYPE_CHECKING, Any, Type, Callable, cast
5
+ from typing import TYPE_CHECKING, Any, Type, Generic, Callable, cast
5
6
  from typing_extensions import Self, Iterator, Awaitable, AsyncIterator, assert_never
6
7
 
7
8
  import httpx
@@ -11,23 +12,27 @@ from anthropic.types.beta.beta_tool_use_block import BetaToolUseBlock
11
12
  from anthropic.types.beta.beta_mcp_tool_use_block import BetaMCPToolUseBlock
12
13
  from anthropic.types.beta.beta_server_tool_use_block import BetaServerToolUseBlock
13
14
 
15
+ from ..._types import NOT_GIVEN, NotGiven
14
16
  from ..._utils import consume_sync_iterator, consume_async_iterator
15
17
  from ..._models import build, construct_type, construct_type_unchecked
16
18
  from ._beta_types import (
17
- BetaTextEvent,
18
19
  BetaCitationEvent,
19
20
  BetaThinkingEvent,
20
21
  BetaInputJsonEvent,
21
22
  BetaSignatureEvent,
22
- BetaMessageStopEvent,
23
- BetaMessageStreamEvent,
24
- BetaContentBlockStopEvent,
23
+ ParsedBetaTextEvent,
24
+ ParsedBetaMessageStopEvent,
25
+ ParsedBetaMessageStreamEvent,
26
+ ParsedBetaContentBlockStopEvent,
25
27
  )
26
28
  from ..._streaming import Stream, AsyncStream
27
- from ...types.beta import BetaMessage, BetaContentBlock, BetaRawMessageStreamEvent
29
+ from ...types.beta import BetaRawMessageStreamEvent
30
+ from ..._utils._utils import is_given
31
+ from .._parse._response import ResponseFormatT, parse_text
32
+ from ...types.beta.parsed_beta_message import ParsedBetaMessage, ParsedBetaContentBlock
28
33
 
29
34
 
30
- class BetaMessageStream:
35
+ class BetaMessageStream(Generic[ResponseFormatT]):
31
36
  text_stream: Iterator[str]
32
37
  """Iterator over just the text deltas in the stream.
33
38
 
@@ -38,11 +43,16 @@ class BetaMessageStream:
38
43
  ```
39
44
  """
40
45
 
41
- def __init__(self, raw_stream: Stream[BetaRawMessageStreamEvent]) -> None:
46
+ def __init__(
47
+ self,
48
+ raw_stream: Stream[BetaRawMessageStreamEvent],
49
+ output_format: ResponseFormatT | NotGiven,
50
+ ) -> None:
42
51
  self._raw_stream = raw_stream
43
52
  self.text_stream = self.__stream_text__()
44
53
  self._iterator = self.__stream__()
45
- self.__final_message_snapshot: BetaMessage | None = None
54
+ self.__final_message_snapshot: ParsedBetaMessage[ResponseFormatT] | None = None
55
+ self.__output_format = output_format
46
56
 
47
57
  @property
48
58
  def response(self) -> httpx.Response:
@@ -52,10 +62,10 @@ class BetaMessageStream:
52
62
  def request_id(self) -> str | None:
53
63
  return self.response.headers.get("request-id") # type: ignore[no-any-return]
54
64
 
55
- def __next__(self) -> BetaMessageStreamEvent:
65
+ def __next__(self) -> ParsedBetaMessageStreamEvent[ResponseFormatT]:
56
66
  return self._iterator.__next__()
57
67
 
58
- def __iter__(self) -> Iterator[BetaMessageStreamEvent]:
68
+ def __iter__(self) -> Iterator[ParsedBetaMessageStreamEvent[ResponseFormatT]]:
59
69
  for item in self._iterator:
60
70
  yield item
61
71
 
@@ -78,7 +88,7 @@ class BetaMessageStream:
78
88
  """
79
89
  self._raw_stream.close()
80
90
 
81
- def get_final_message(self) -> BetaMessage:
91
+ def get_final_message(self) -> ParsedBetaMessage[ResponseFormatT]:
82
92
  """Waits until the stream has been read to completion and returns
83
93
  the accumulated `Message` object.
84
94
  """
@@ -113,16 +123,17 @@ class BetaMessageStream:
113
123
 
114
124
  # properties
115
125
  @property
116
- def current_message_snapshot(self) -> BetaMessage:
126
+ def current_message_snapshot(self) -> ParsedBetaMessage[ResponseFormatT]:
117
127
  assert self.__final_message_snapshot is not None
118
128
  return self.__final_message_snapshot
119
129
 
120
- def __stream__(self) -> Iterator[BetaMessageStreamEvent]:
130
+ def __stream__(self) -> Iterator[ParsedBetaMessageStreamEvent[ResponseFormatT]]:
121
131
  for sse_event in self._raw_stream:
122
132
  self.__final_message_snapshot = accumulate_event(
123
133
  event=sse_event,
124
134
  current_snapshot=self.__final_message_snapshot,
125
135
  request_headers=self.response.request.headers,
136
+ output_format=self.__output_format,
126
137
  )
127
138
 
128
139
  events_to_fire = build_events(event=sse_event, message_snapshot=self.current_message_snapshot)
@@ -135,7 +146,7 @@ class BetaMessageStream:
135
146
  yield chunk.delta.text
136
147
 
137
148
 
138
- class BetaMessageStreamManager:
149
+ class BetaMessageStreamManager(Generic[ResponseFormatT]):
139
150
  """Wrapper over MessageStream that is returned by `.stream()`.
140
151
 
141
152
  ```py
@@ -148,13 +159,16 @@ class BetaMessageStreamManager:
148
159
  def __init__(
149
160
  self,
150
161
  api_request: Callable[[], Stream[BetaRawMessageStreamEvent]],
162
+ *,
163
+ output_format: ResponseFormatT | NotGiven,
151
164
  ) -> None:
152
- self.__stream: BetaMessageStream | None = None
165
+ self.__stream: BetaMessageStream[ResponseFormatT] | None = None
153
166
  self.__api_request = api_request
167
+ self.__output_format = output_format
154
168
 
155
- def __enter__(self) -> BetaMessageStream:
169
+ def __enter__(self) -> BetaMessageStream[ResponseFormatT]:
156
170
  raw_stream = self.__api_request()
157
- self.__stream = BetaMessageStream(raw_stream)
171
+ self.__stream = BetaMessageStream(raw_stream, output_format=self.__output_format)
158
172
  return self.__stream
159
173
 
160
174
  def __exit__(
@@ -167,7 +181,7 @@ class BetaMessageStreamManager:
167
181
  self.__stream.close()
168
182
 
169
183
 
170
- class BetaAsyncMessageStream:
184
+ class BetaAsyncMessageStream(Generic[ResponseFormatT]):
171
185
  text_stream: AsyncIterator[str]
172
186
  """Async iterator over just the text deltas in the stream.
173
187
 
@@ -178,11 +192,16 @@ class BetaAsyncMessageStream:
178
192
  ```
179
193
  """
180
194
 
181
- def __init__(self, raw_stream: AsyncStream[BetaRawMessageStreamEvent]) -> None:
195
+ def __init__(
196
+ self,
197
+ raw_stream: AsyncStream[BetaRawMessageStreamEvent],
198
+ output_format: ResponseFormatT | NotGiven,
199
+ ) -> None:
182
200
  self._raw_stream = raw_stream
183
201
  self.text_stream = self.__stream_text__()
184
202
  self._iterator = self.__stream__()
185
- self.__final_message_snapshot: BetaMessage | None = None
203
+ self.__final_message_snapshot: ParsedBetaMessage[ResponseFormatT] | None = None
204
+ self.__output_format = output_format
186
205
 
187
206
  @property
188
207
  def response(self) -> httpx.Response:
@@ -192,10 +211,10 @@ class BetaAsyncMessageStream:
192
211
  def request_id(self) -> str | None:
193
212
  return self.response.headers.get("request-id") # type: ignore[no-any-return]
194
213
 
195
- async def __anext__(self) -> BetaMessageStreamEvent:
214
+ async def __anext__(self) -> ParsedBetaMessageStreamEvent[ResponseFormatT]:
196
215
  return await self._iterator.__anext__()
197
216
 
198
- async def __aiter__(self) -> AsyncIterator[BetaMessageStreamEvent]:
217
+ async def __aiter__(self) -> AsyncIterator[ParsedBetaMessageStreamEvent[ResponseFormatT]]:
199
218
  async for item in self._iterator:
200
219
  yield item
201
220
 
@@ -218,7 +237,7 @@ class BetaAsyncMessageStream:
218
237
  """
219
238
  await self._raw_stream.close()
220
239
 
221
- async def get_final_message(self) -> BetaMessage:
240
+ async def get_final_message(self) -> ParsedBetaMessage[ResponseFormatT]:
222
241
  """Waits until the stream has been read to completion and returns
223
242
  the accumulated `Message` object.
224
243
  """
@@ -253,16 +272,17 @@ class BetaAsyncMessageStream:
253
272
 
254
273
  # properties
255
274
  @property
256
- def current_message_snapshot(self) -> BetaMessage:
275
+ def current_message_snapshot(self) -> ParsedBetaMessage[ResponseFormatT]:
257
276
  assert self.__final_message_snapshot is not None
258
277
  return self.__final_message_snapshot
259
278
 
260
- async def __stream__(self) -> AsyncIterator[BetaMessageStreamEvent]:
279
+ async def __stream__(self) -> AsyncIterator[ParsedBetaMessageStreamEvent[ResponseFormatT]]:
261
280
  async for sse_event in self._raw_stream:
262
281
  self.__final_message_snapshot = accumulate_event(
263
282
  event=sse_event,
264
283
  current_snapshot=self.__final_message_snapshot,
265
284
  request_headers=self.response.request.headers,
285
+ output_format=self.__output_format,
266
286
  )
267
287
 
268
288
  events_to_fire = build_events(event=sse_event, message_snapshot=self.current_message_snapshot)
@@ -275,7 +295,7 @@ class BetaAsyncMessageStream:
275
295
  yield chunk.delta.text
276
296
 
277
297
 
278
- class BetaAsyncMessageStreamManager:
298
+ class BetaAsyncMessageStreamManager(Generic[ResponseFormatT]):
279
299
  """Wrapper over BetaAsyncMessageStream that is returned by `.stream()`
280
300
  so that an async context manager can be used without `await`ing the
281
301
  original client call.
@@ -290,13 +310,16 @@ class BetaAsyncMessageStreamManager:
290
310
  def __init__(
291
311
  self,
292
312
  api_request: Awaitable[AsyncStream[BetaRawMessageStreamEvent]],
313
+ *,
314
+ output_format: ResponseFormatT | NotGiven = NOT_GIVEN,
293
315
  ) -> None:
294
- self.__stream: BetaAsyncMessageStream | None = None
316
+ self.__stream: BetaAsyncMessageStream[ResponseFormatT] | None = None
295
317
  self.__api_request = api_request
318
+ self.__output_format = output_format
296
319
 
297
- async def __aenter__(self) -> BetaAsyncMessageStream:
320
+ async def __aenter__(self) -> BetaAsyncMessageStream[ResponseFormatT]:
298
321
  raw_stream = await self.__api_request
299
- self.__stream = BetaAsyncMessageStream(raw_stream)
322
+ self.__stream = BetaAsyncMessageStream(raw_stream, output_format=self.__output_format)
300
323
  return self.__stream
301
324
 
302
325
  async def __aexit__(
@@ -312,16 +335,18 @@ class BetaAsyncMessageStreamManager:
312
335
  def build_events(
313
336
  *,
314
337
  event: BetaRawMessageStreamEvent,
315
- message_snapshot: BetaMessage,
316
- ) -> list[BetaMessageStreamEvent]:
317
- events_to_fire: list[BetaMessageStreamEvent] = []
338
+ message_snapshot: ParsedBetaMessage[ResponseFormatT],
339
+ ) -> list[ParsedBetaMessageStreamEvent[ResponseFormatT]]:
340
+ events_to_fire: list[ParsedBetaMessageStreamEvent[ResponseFormatT]] = []
318
341
 
319
342
  if event.type == "message_start":
320
343
  events_to_fire.append(event)
321
344
  elif event.type == "message_delta":
322
345
  events_to_fire.append(event)
323
346
  elif event.type == "message_stop":
324
- events_to_fire.append(build(BetaMessageStopEvent, type="message_stop", message=message_snapshot))
347
+ events_to_fire.append(
348
+ build(ParsedBetaMessageStopEvent[ResponseFormatT], type="message_stop", message=message_snapshot)
349
+ )
325
350
  elif event.type == "content_block_start":
326
351
  events_to_fire.append(event)
327
352
  elif event.type == "content_block_delta":
@@ -332,7 +357,7 @@ def build_events(
332
357
  if content_block.type == "text":
333
358
  events_to_fire.append(
334
359
  build(
335
- BetaTextEvent,
360
+ ParsedBetaTextEvent,
336
361
  type="text",
337
362
  text=event.delta.text,
338
363
  snapshot=content_block.text,
@@ -385,9 +410,14 @@ def build_events(
385
410
  elif event.type == "content_block_stop":
386
411
  content_block = message_snapshot.content[event.index]
387
412
 
388
- events_to_fire.append(
389
- build(BetaContentBlockStopEvent, type="content_block_stop", index=event.index, content_block=content_block),
413
+ event_to_fire = build(
414
+ ParsedBetaContentBlockStopEvent,
415
+ type="content_block_stop",
416
+ index=event.index,
417
+ content_block=content_block,
390
418
  )
419
+
420
+ events_to_fire.append(event_to_fire)
391
421
  else:
392
422
  # we only want exhaustive checking for linters, not at runtime
393
423
  if TYPE_CHECKING: # type: ignore[unreachable]
@@ -408,9 +438,10 @@ TRACKS_TOOL_INPUT = (
408
438
  def accumulate_event(
409
439
  *,
410
440
  event: BetaRawMessageStreamEvent,
411
- current_snapshot: BetaMessage | None,
441
+ current_snapshot: ParsedBetaMessage[ResponseFormatT] | None,
412
442
  request_headers: httpx.Headers,
413
- ) -> BetaMessage:
443
+ output_format: ResponseFormatT | NotGiven = NOT_GIVEN,
444
+ ) -> ParsedBetaMessage[ResponseFormatT]:
414
445
  if not isinstance(cast(Any, event), BaseModel):
415
446
  event = cast( # pyright: ignore[reportUnnecessaryCast]
416
447
  BetaRawMessageStreamEvent,
@@ -420,11 +451,15 @@ def accumulate_event(
420
451
  ),
421
452
  )
422
453
  if not isinstance(cast(Any, event), BaseModel):
423
- raise TypeError(f"Unexpected event runtime type, after deserialising twice - {event} - {type(event)}")
454
+ raise TypeError(
455
+ f"Unexpected event runtime type, after deserialising twice - {event} - {builtins.type(event)}"
456
+ )
424
457
 
425
458
  if current_snapshot is None:
426
459
  if event.type == "message_start":
427
- return BetaMessage.construct(**cast(Any, event.message.to_dict()))
460
+ return cast(
461
+ ParsedBetaMessage[ResponseFormatT], ParsedBetaMessage.construct(**cast(Any, event.message.to_dict()))
462
+ )
428
463
 
429
464
  raise RuntimeError(f'Unexpected event order, got {event.type} before "message_start"')
430
465
 
@@ -432,8 +467,8 @@ def accumulate_event(
432
467
  # TODO: check index
433
468
  current_snapshot.content.append(
434
469
  cast(
435
- BetaContentBlock,
436
- construct_type(type_=BetaContentBlock, value=event.content_block.model_dump()),
470
+ Any, # Pydantic does not support generic unions at runtime
471
+ construct_type(type_=ParsedBetaContentBlock, value=event.content_block.model_dump()),
437
472
  ),
438
473
  )
439
474
  elif event.type == "content_block_delta":
@@ -481,6 +516,10 @@ def accumulate_event(
481
516
  # we only want exhaustive checking for linters, not at runtime
482
517
  if TYPE_CHECKING: # type: ignore[unreachable]
483
518
  assert_never(event.delta)
519
+ elif event.type == "content_block_stop":
520
+ content_block = current_snapshot.content[event.index]
521
+ if content_block.type == "text" and is_given(output_format):
522
+ content_block.parsed_output = parse_text(content_block.text, output_format)
484
523
  elif event.type == "message_delta":
485
524
  current_snapshot.container = event.delta.container
486
525
  current_snapshot.stop_reason = event.delta.stop_reason
@@ -1,10 +1,10 @@
1
- from typing import Union
1
+ from typing import TYPE_CHECKING, Any, Dict, Union, Generic, cast
2
2
  from typing_extensions import List, Literal, Annotated
3
3
 
4
- from ..._models import BaseModel
4
+ import jiter
5
+
6
+ from ..._models import BaseModel, GenericModel
5
7
  from ...types.beta import (
6
- BetaMessage,
7
- BetaContentBlock,
8
8
  BetaRawMessageStopEvent,
9
9
  BetaRawMessageDeltaEvent,
10
10
  BetaRawMessageStartEvent,
@@ -12,11 +12,13 @@ from ...types.beta import (
12
12
  BetaRawContentBlockDeltaEvent,
13
13
  BetaRawContentBlockStartEvent,
14
14
  )
15
+ from .._parse._response import ResponseFormatT
15
16
  from ..._utils._transform import PropertyInfo
17
+ from ...types.beta.parsed_beta_message import ParsedBetaMessage, ParsedBetaContentBlock
16
18
  from ...types.beta.beta_citations_delta import Citation
17
19
 
18
20
 
19
- class BetaTextEvent(BaseModel):
21
+ class ParsedBetaTextEvent(BaseModel):
20
22
  type: Literal["text"]
21
23
 
22
24
  text: str
@@ -25,6 +27,9 @@ class BetaTextEvent(BaseModel):
25
27
  snapshot: str
26
28
  """The entire accumulated text"""
27
29
 
30
+ def parsed_snapshot(self) -> Dict[str, Any]:
31
+ return cast(Dict[str, Any], jiter.from_json(self.snapshot.encode("utf-8"), partial_mode="trailing-strings"))
32
+
28
33
 
29
34
  class BetaCitationEvent(BaseModel):
30
35
  type: Literal["citation"]
@@ -70,31 +75,34 @@ class BetaInputJsonEvent(BaseModel):
70
75
  """
71
76
 
72
77
 
73
- class BetaMessageStopEvent(BetaRawMessageStopEvent):
78
+ class ParsedBetaMessageStopEvent(BetaRawMessageStopEvent, GenericModel, Generic[ResponseFormatT]):
74
79
  type: Literal["message_stop"]
75
80
 
76
- message: BetaMessage
81
+ message: ParsedBetaMessage[ResponseFormatT]
77
82
 
78
83
 
79
- class BetaContentBlockStopEvent(BetaRawContentBlockStopEvent):
84
+ class ParsedBetaContentBlockStopEvent(BetaRawContentBlockStopEvent, GenericModel, Generic[ResponseFormatT]):
80
85
  type: Literal["content_block_stop"]
81
86
 
82
- content_block: BetaContentBlock
87
+ if TYPE_CHECKING:
88
+ content_block: ParsedBetaContentBlock[ResponseFormatT]
89
+ else:
90
+ content_block: ParsedBetaContentBlock
83
91
 
84
92
 
85
- BetaMessageStreamEvent = Annotated[
93
+ ParsedBetaMessageStreamEvent = Annotated[
86
94
  Union[
87
- BetaTextEvent,
95
+ ParsedBetaTextEvent,
88
96
  BetaCitationEvent,
89
97
  BetaThinkingEvent,
90
98
  BetaSignatureEvent,
91
99
  BetaInputJsonEvent,
92
100
  BetaRawMessageStartEvent,
93
101
  BetaRawMessageDeltaEvent,
94
- BetaMessageStopEvent,
102
+ ParsedBetaMessageStopEvent[ResponseFormatT],
95
103
  BetaRawContentBlockStartEvent,
96
104
  BetaRawContentBlockDeltaEvent,
97
- BetaContentBlockStopEvent,
105
+ ParsedBetaContentBlockStopEvent[ResponseFormatT],
98
106
  ],
99
107
  PropertyInfo(discriminator="type"),
100
108
  ]