anthropic 0.75.0__py3-none-any.whl → 0.77.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 (81) hide show
  1. anthropic/_base_client.py +145 -13
  2. anthropic/_client.py +4 -12
  3. anthropic/_compat.py +3 -3
  4. anthropic/_models.py +16 -1
  5. anthropic/_streaming.py +78 -76
  6. anthropic/_types.py +12 -2
  7. anthropic/_utils/_json.py +35 -0
  8. anthropic/_version.py +1 -1
  9. anthropic/lib/_parse/_response.py +29 -1
  10. anthropic/lib/streaming/__init__.py +3 -0
  11. anthropic/lib/streaming/_messages.py +74 -40
  12. anthropic/lib/streaming/_types.py +42 -2
  13. anthropic/lib/tools/_beta_compaction_control.py +2 -2
  14. anthropic/lib/tools/_beta_runner.py +17 -0
  15. anthropic/resources/beta/messages/messages.py +229 -83
  16. anthropic/resources/messages/messages.py +409 -5
  17. anthropic/types/__init__.py +7 -0
  18. anthropic/types/beta/beta_code_execution_tool_20250522_param.py +1 -0
  19. anthropic/types/beta/beta_code_execution_tool_20250825_param.py +1 -0
  20. anthropic/types/beta/beta_container.py +4 -0
  21. anthropic/types/beta/beta_container_params.py +2 -0
  22. anthropic/types/beta/beta_container_upload_block.py +2 -0
  23. anthropic/types/beta/beta_container_upload_block_param.py +5 -0
  24. anthropic/types/beta/beta_direct_caller.py +2 -0
  25. anthropic/types/beta/beta_direct_caller_param.py +2 -0
  26. anthropic/types/beta/beta_mcp_tool_config_param.py +2 -0
  27. anthropic/types/beta/beta_mcp_tool_default_config_param.py +2 -0
  28. anthropic/types/beta/beta_mcp_toolset_param.py +6 -0
  29. anthropic/types/beta/beta_memory_tool_20250818_param.py +1 -0
  30. anthropic/types/beta/beta_output_config_param.py +15 -1
  31. anthropic/types/beta/beta_server_tool_caller.py +2 -0
  32. anthropic/types/beta/beta_server_tool_caller_param.py +2 -0
  33. anthropic/types/beta/beta_server_tool_use_block.py +4 -4
  34. anthropic/types/beta/beta_skill.py +2 -0
  35. anthropic/types/beta/beta_skill_params.py +2 -0
  36. anthropic/types/beta/beta_tool_bash_20241022_param.py +1 -0
  37. anthropic/types/beta/beta_tool_bash_20250124_param.py +1 -0
  38. anthropic/types/beta/beta_tool_choice_any_param.py +2 -0
  39. anthropic/types/beta/beta_tool_choice_auto_param.py +2 -0
  40. anthropic/types/beta/beta_tool_choice_none_param.py +2 -0
  41. anthropic/types/beta/beta_tool_choice_tool_param.py +2 -0
  42. anthropic/types/beta/beta_tool_computer_use_20241022_param.py +1 -0
  43. anthropic/types/beta/beta_tool_computer_use_20250124_param.py +1 -0
  44. anthropic/types/beta/beta_tool_computer_use_20251124_param.py +1 -0
  45. anthropic/types/beta/beta_tool_param.py +6 -0
  46. anthropic/types/beta/beta_tool_reference_block_param.py +2 -0
  47. anthropic/types/beta/beta_tool_search_tool_bm25_20251119_param.py +1 -0
  48. anthropic/types/beta/beta_tool_search_tool_regex_20251119_param.py +1 -0
  49. anthropic/types/beta/beta_tool_text_editor_20241022_param.py +1 -0
  50. anthropic/types/beta/beta_tool_text_editor_20250124_param.py +1 -0
  51. anthropic/types/beta/beta_tool_text_editor_20250429_param.py +1 -0
  52. anthropic/types/beta/beta_tool_text_editor_20250728_param.py +1 -0
  53. anthropic/types/beta/beta_web_fetch_tool_20250910_param.py +1 -0
  54. anthropic/types/beta/beta_web_search_tool_20250305_param.py +6 -0
  55. anthropic/types/beta/beta_web_search_tool_result_error_code.py +1 -1
  56. anthropic/types/beta/message_count_tokens_params.py +9 -5
  57. anthropic/types/beta/message_create_params.py +9 -5
  58. anthropic/types/beta/messages/batch_create_params.py +2 -9
  59. anthropic/types/beta/messages/beta_message_batch_individual_response.py +4 -0
  60. anthropic/types/json_output_format_param.py +15 -0
  61. anthropic/types/message_count_tokens_params.py +4 -0
  62. anthropic/types/message_create_params.py +4 -0
  63. anthropic/types/messages/message_batch_individual_response.py +4 -0
  64. anthropic/types/output_config_param.py +19 -0
  65. anthropic/types/parsed_message.py +56 -0
  66. anthropic/types/tool_bash_20250124_param.py +3 -0
  67. anthropic/types/tool_choice_any_param.py +2 -0
  68. anthropic/types/tool_choice_auto_param.py +2 -0
  69. anthropic/types/tool_choice_none_param.py +2 -0
  70. anthropic/types/tool_choice_tool_param.py +2 -0
  71. anthropic/types/tool_param.py +8 -0
  72. anthropic/types/tool_text_editor_20250124_param.py +3 -0
  73. anthropic/types/tool_text_editor_20250429_param.py +3 -0
  74. anthropic/types/tool_text_editor_20250728_param.py +3 -0
  75. anthropic/types/web_search_tool_20250305_param.py +8 -0
  76. anthropic/types/web_search_tool_request_error_param.py +8 -1
  77. anthropic/types/web_search_tool_result_error.py +8 -1
  78. {anthropic-0.75.0.dist-info → anthropic-0.77.0.dist-info}/METADATA +4 -2
  79. {anthropic-0.75.0.dist-info → anthropic-0.77.0.dist-info}/RECORD +81 -77
  80. {anthropic-0.75.0.dist-info → anthropic-0.77.0.dist-info}/WHEEL +0 -0
  81. {anthropic-0.75.0.dist-info → anthropic-0.77.0.dist-info}/licenses/LICENSE +0 -0
@@ -5,6 +5,8 @@ from typing_extensions import TypeVar
5
5
  from ..._types import NotGiven
6
6
  from ..._models import TypeAdapter, construct_type_unchecked
7
7
  from ..._utils._utils import is_given
8
+ from ...types.message import Message
9
+ from ...types.parsed_message import ParsedMessage, ParsedTextBlock, ParsedContentBlock
8
10
  from ...types.beta.beta_message import BetaMessage
9
11
  from ...types.beta.parsed_beta_message import ParsedBetaMessage, ParsedBetaTextBlock, ParsedBetaContentBlock
10
12
 
@@ -18,7 +20,7 @@ def parse_text(text: str, output_format: ResponseFormatT | NotGiven) -> Response
18
20
  return None
19
21
 
20
22
 
21
- def parse_response(
23
+ def parse_beta_response(
22
24
  *,
23
25
  output_format: ResponseFormatT | NotGiven,
24
26
  response: BetaMessage,
@@ -42,3 +44,29 @@ def parse_response(
42
44
  "content": content_list,
43
45
  },
44
46
  )
47
+
48
+
49
+ def parse_response(
50
+ *,
51
+ output_format: ResponseFormatT | NotGiven,
52
+ response: Message,
53
+ ) -> ParsedMessage[ResponseFormatT]:
54
+ content_list: list[ParsedContentBlock[ResponseFormatT]] = []
55
+ for content in response.content:
56
+ if content.type == "text":
57
+ content_list.append(
58
+ construct_type_unchecked(
59
+ type_=ParsedTextBlock[ResponseFormatT],
60
+ value={**content.to_dict(), "parsed_output": parse_text(content.text, output_format)},
61
+ )
62
+ )
63
+ else:
64
+ content_list.append(content) # type: ignore
65
+
66
+ return construct_type_unchecked(
67
+ type_=ParsedMessage[ResponseFormatT],
68
+ value={
69
+ **response.to_dict(),
70
+ "content": content_list,
71
+ },
72
+ )
@@ -6,6 +6,9 @@ from ._types import (
6
6
  MessageStopEvent as MessageStopEvent,
7
7
  MessageStreamEvent as MessageStreamEvent,
8
8
  ContentBlockStopEvent as ContentBlockStopEvent,
9
+ ParsedMessageStopEvent as ParsedMessageStopEvent,
10
+ ParsedMessageStreamEvent as ParsedMessageStreamEvent,
11
+ ParsedContentBlockStopEvent as ParsedContentBlockStopEvent,
9
12
  )
10
13
  from ._messages import (
11
14
  MessageStream as MessageStream,
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from types import TracebackType
4
- from typing import TYPE_CHECKING, Any, Type, Callable, cast
4
+ from typing import TYPE_CHECKING, Any, Type, Generic, Callable, cast
5
5
  from typing_extensions import Self, Iterator, Awaitable, AsyncIterator, assert_never
6
6
 
7
7
  import httpx
@@ -16,17 +16,21 @@ from ._types import (
16
16
  ThinkingEvent,
17
17
  InputJsonEvent,
18
18
  SignatureEvent,
19
- MessageStopEvent,
20
- MessageStreamEvent,
21
- ContentBlockStopEvent,
19
+ ParsedMessageStopEvent,
20
+ ParsedMessageStreamEvent,
21
+ ParsedContentBlockStopEvent,
22
22
  )
23
- from ...types import Message, ContentBlock, RawMessageStreamEvent
23
+ from ...types import RawMessageStreamEvent
24
+ from ..._types import NOT_GIVEN, NotGiven
24
25
  from ..._utils import consume_sync_iterator, consume_async_iterator
25
26
  from ..._models import build, construct_type, construct_type_unchecked
26
27
  from ..._streaming import Stream, AsyncStream
28
+ from ..._utils._utils import is_given
29
+ from .._parse._response import ResponseFormatT, parse_text
30
+ from ...types.parsed_message import ParsedMessage, ParsedContentBlock
27
31
 
28
32
 
29
- class MessageStream:
33
+ class MessageStream(Generic[ResponseFormatT]):
30
34
  text_stream: Iterator[str]
31
35
  """Iterator over just the text deltas in the stream.
32
36
 
@@ -37,11 +41,16 @@ class MessageStream:
37
41
  ```
38
42
  """
39
43
 
40
- def __init__(self, raw_stream: Stream[RawMessageStreamEvent]) -> None:
44
+ def __init__(
45
+ self,
46
+ raw_stream: Stream[RawMessageStreamEvent],
47
+ output_format: ResponseFormatT | NotGiven,
48
+ ) -> None:
41
49
  self._raw_stream = raw_stream
42
50
  self.text_stream = self.__stream_text__()
43
51
  self._iterator = self.__stream__()
44
- self.__final_message_snapshot: Message | None = None
52
+ self.__final_message_snapshot: ParsedMessage[ResponseFormatT] | None = None
53
+ self.__output_format = output_format
45
54
 
46
55
  @property
47
56
  def response(self) -> httpx.Response:
@@ -51,10 +60,10 @@ class MessageStream:
51
60
  def request_id(self) -> str | None:
52
61
  return self.response.headers.get("request-id") # type: ignore[no-any-return]
53
62
 
54
- def __next__(self) -> MessageStreamEvent:
63
+ def __next__(self) -> ParsedMessageStreamEvent[ResponseFormatT]:
55
64
  return self._iterator.__next__()
56
65
 
57
- def __iter__(self) -> Iterator[MessageStreamEvent]:
66
+ def __iter__(self) -> Iterator[ParsedMessageStreamEvent[ResponseFormatT]]:
58
67
  for item in self._iterator:
59
68
  yield item
60
69
 
@@ -77,7 +86,7 @@ class MessageStream:
77
86
  """
78
87
  self._raw_stream.close()
79
88
 
80
- def get_final_message(self) -> Message:
89
+ def get_final_message(self) -> ParsedMessage[ResponseFormatT]:
81
90
  """Waits until the stream has been read to completion and returns
82
91
  the accumulated `Message` object.
83
92
  """
@@ -112,15 +121,16 @@ class MessageStream:
112
121
 
113
122
  # properties
114
123
  @property
115
- def current_message_snapshot(self) -> Message:
124
+ def current_message_snapshot(self) -> ParsedMessage[ResponseFormatT]:
116
125
  assert self.__final_message_snapshot is not None
117
126
  return self.__final_message_snapshot
118
127
 
119
- def __stream__(self) -> Iterator[MessageStreamEvent]:
128
+ def __stream__(self) -> Iterator[ParsedMessageStreamEvent[ResponseFormatT]]:
120
129
  for sse_event in self._raw_stream:
121
130
  self.__final_message_snapshot = accumulate_event(
122
131
  event=sse_event,
123
132
  current_snapshot=self.__final_message_snapshot,
133
+ output_format=self.__output_format,
124
134
  )
125
135
 
126
136
  events_to_fire = build_events(event=sse_event, message_snapshot=self.current_message_snapshot)
@@ -133,7 +143,7 @@ class MessageStream:
133
143
  yield chunk.delta.text
134
144
 
135
145
 
136
- class MessageStreamManager:
146
+ class MessageStreamManager(Generic[ResponseFormatT]):
137
147
  """Wrapper over MessageStream that is returned by `.stream()`.
138
148
 
139
149
  ```py
@@ -146,13 +156,16 @@ class MessageStreamManager:
146
156
  def __init__(
147
157
  self,
148
158
  api_request: Callable[[], Stream[RawMessageStreamEvent]],
159
+ *,
160
+ output_format: ResponseFormatT | NotGiven,
149
161
  ) -> None:
150
- self.__stream: MessageStream | None = None
162
+ self.__stream: MessageStream[ResponseFormatT] | None = None
151
163
  self.__api_request = api_request
164
+ self.__output_format = output_format
152
165
 
153
- def __enter__(self) -> MessageStream:
166
+ def __enter__(self) -> MessageStream[ResponseFormatT]:
154
167
  raw_stream = self.__api_request()
155
- self.__stream = MessageStream(raw_stream)
168
+ self.__stream = MessageStream(raw_stream, output_format=self.__output_format)
156
169
  return self.__stream
157
170
 
158
171
  def __exit__(
@@ -165,7 +178,7 @@ class MessageStreamManager:
165
178
  self.__stream.close()
166
179
 
167
180
 
168
- class AsyncMessageStream:
181
+ class AsyncMessageStream(Generic[ResponseFormatT]):
169
182
  text_stream: AsyncIterator[str]
170
183
  """Async iterator over just the text deltas in the stream.
171
184
 
@@ -176,11 +189,16 @@ class AsyncMessageStream:
176
189
  ```
177
190
  """
178
191
 
179
- def __init__(self, raw_stream: AsyncStream[RawMessageStreamEvent]) -> None:
192
+ def __init__(
193
+ self,
194
+ raw_stream: AsyncStream[RawMessageStreamEvent],
195
+ output_format: ResponseFormatT | NotGiven,
196
+ ) -> None:
180
197
  self._raw_stream = raw_stream
181
198
  self.text_stream = self.__stream_text__()
182
199
  self._iterator = self.__stream__()
183
- self.__final_message_snapshot: Message | None = None
200
+ self.__final_message_snapshot: ParsedMessage[ResponseFormatT] | None = None
201
+ self.__output_format = output_format
184
202
 
185
203
  @property
186
204
  def response(self) -> httpx.Response:
@@ -190,10 +208,10 @@ class AsyncMessageStream:
190
208
  def request_id(self) -> str | None:
191
209
  return self.response.headers.get("request-id") # type: ignore[no-any-return]
192
210
 
193
- async def __anext__(self) -> MessageStreamEvent:
211
+ async def __anext__(self) -> ParsedMessageStreamEvent[ResponseFormatT]:
194
212
  return await self._iterator.__anext__()
195
213
 
196
- async def __aiter__(self) -> AsyncIterator[MessageStreamEvent]:
214
+ async def __aiter__(self) -> AsyncIterator[ParsedMessageStreamEvent[ResponseFormatT]]:
197
215
  async for item in self._iterator:
198
216
  yield item
199
217
 
@@ -216,7 +234,7 @@ class AsyncMessageStream:
216
234
  """
217
235
  await self._raw_stream.close()
218
236
 
219
- async def get_final_message(self) -> Message:
237
+ async def get_final_message(self) -> ParsedMessage[ResponseFormatT]:
220
238
  """Waits until the stream has been read to completion and returns
221
239
  the accumulated `Message` object.
222
240
  """
@@ -251,15 +269,16 @@ class AsyncMessageStream:
251
269
 
252
270
  # properties
253
271
  @property
254
- def current_message_snapshot(self) -> Message:
272
+ def current_message_snapshot(self) -> ParsedMessage[ResponseFormatT]:
255
273
  assert self.__final_message_snapshot is not None
256
274
  return self.__final_message_snapshot
257
275
 
258
- async def __stream__(self) -> AsyncIterator[MessageStreamEvent]:
276
+ async def __stream__(self) -> AsyncIterator[ParsedMessageStreamEvent[ResponseFormatT]]:
259
277
  async for sse_event in self._raw_stream:
260
278
  self.__final_message_snapshot = accumulate_event(
261
279
  event=sse_event,
262
280
  current_snapshot=self.__final_message_snapshot,
281
+ output_format=self.__output_format,
263
282
  )
264
283
 
265
284
  events_to_fire = build_events(event=sse_event, message_snapshot=self.current_message_snapshot)
@@ -272,7 +291,7 @@ class AsyncMessageStream:
272
291
  yield chunk.delta.text
273
292
 
274
293
 
275
- class AsyncMessageStreamManager:
294
+ class AsyncMessageStreamManager(Generic[ResponseFormatT]):
276
295
  """Wrapper over AsyncMessageStream that is returned by `.stream()`
277
296
  so that an async context manager can be used without `await`ing the
278
297
  original client call.
@@ -287,13 +306,16 @@ class AsyncMessageStreamManager:
287
306
  def __init__(
288
307
  self,
289
308
  api_request: Awaitable[AsyncStream[RawMessageStreamEvent]],
309
+ *,
310
+ output_format: ResponseFormatT | NotGiven = NOT_GIVEN,
290
311
  ) -> None:
291
- self.__stream: AsyncMessageStream | None = None
312
+ self.__stream: AsyncMessageStream[ResponseFormatT] | None = None
292
313
  self.__api_request = api_request
314
+ self.__output_format = output_format
293
315
 
294
- async def __aenter__(self) -> AsyncMessageStream:
316
+ async def __aenter__(self) -> AsyncMessageStream[ResponseFormatT]:
295
317
  raw_stream = await self.__api_request
296
- self.__stream = AsyncMessageStream(raw_stream)
318
+ self.__stream = AsyncMessageStream(raw_stream, output_format=self.__output_format)
297
319
  return self.__stream
298
320
 
299
321
  async def __aexit__(
@@ -309,16 +331,18 @@ class AsyncMessageStreamManager:
309
331
  def build_events(
310
332
  *,
311
333
  event: RawMessageStreamEvent,
312
- message_snapshot: Message,
313
- ) -> list[MessageStreamEvent]:
314
- events_to_fire: list[MessageStreamEvent] = []
334
+ message_snapshot: ParsedMessage[ResponseFormatT],
335
+ ) -> list[ParsedMessageStreamEvent[ResponseFormatT]]:
336
+ events_to_fire: list[ParsedMessageStreamEvent[ResponseFormatT]] = []
315
337
 
316
338
  if event.type == "message_start":
317
339
  events_to_fire.append(event)
318
340
  elif event.type == "message_delta":
319
341
  events_to_fire.append(event)
320
342
  elif event.type == "message_stop":
321
- events_to_fire.append(build(MessageStopEvent, type="message_stop", message=message_snapshot))
343
+ events_to_fire.append(
344
+ build(ParsedMessageStopEvent[ResponseFormatT], type="message_stop", message=message_snapshot)
345
+ )
322
346
  elif event.type == "content_block_start":
323
347
  events_to_fire.append(event)
324
348
  elif event.type == "content_block_delta":
@@ -382,9 +406,14 @@ def build_events(
382
406
  elif event.type == "content_block_stop":
383
407
  content_block = message_snapshot.content[event.index]
384
408
 
385
- events_to_fire.append(
386
- build(ContentBlockStopEvent, type="content_block_stop", index=event.index, content_block=content_block),
409
+ event_to_fire = build(
410
+ ParsedContentBlockStopEvent,
411
+ type="content_block_stop",
412
+ index=event.index,
413
+ content_block=content_block,
387
414
  )
415
+
416
+ events_to_fire.append(event_to_fire)
388
417
  else:
389
418
  # we only want exhaustive checking for linters, not at runtime
390
419
  if TYPE_CHECKING: # type: ignore[unreachable]
@@ -404,8 +433,9 @@ TRACKS_TOOL_INPUT = (
404
433
  def accumulate_event(
405
434
  *,
406
435
  event: RawMessageStreamEvent,
407
- current_snapshot: Message | None,
408
- ) -> Message:
436
+ current_snapshot: ParsedMessage[ResponseFormatT] | None,
437
+ output_format: ResponseFormatT | NotGiven = NOT_GIVEN,
438
+ ) -> ParsedMessage[ResponseFormatT]:
409
439
  if not isinstance(cast(Any, event), BaseModel):
410
440
  event = cast( # pyright: ignore[reportUnnecessaryCast]
411
441
  RawMessageStreamEvent,
@@ -419,7 +449,7 @@ def accumulate_event(
419
449
 
420
450
  if current_snapshot is None:
421
451
  if event.type == "message_start":
422
- return Message.construct(**cast(Any, event.message.to_dict()))
452
+ return cast(ParsedMessage[ResponseFormatT], ParsedMessage.construct(**cast(Any, event.message.to_dict())))
423
453
 
424
454
  raise RuntimeError(f'Unexpected event order, got {event.type} before "message_start"')
425
455
 
@@ -427,8 +457,8 @@ def accumulate_event(
427
457
  # TODO: check index
428
458
  current_snapshot.content.append(
429
459
  cast(
430
- ContentBlock,
431
- construct_type(type_=ContentBlock, value=event.content_block.model_dump()),
460
+ Any, # Pydantic does not support generic unions at runtime
461
+ construct_type(type_=ParsedContentBlock, value=event.content_block.model_dump()),
432
462
  ),
433
463
  )
434
464
  elif event.type == "content_block_delta":
@@ -466,6 +496,10 @@ def accumulate_event(
466
496
  # we only want exhaustive checking for linters, not at runtime
467
497
  if TYPE_CHECKING: # type: ignore[unreachable]
468
498
  assert_never(event.delta)
499
+ elif event.type == "content_block_stop":
500
+ content_block = current_snapshot.content[event.index]
501
+ if content_block.type == "text" and is_given(output_format):
502
+ content_block.parsed_output = parse_text(content_block.text, output_format)
469
503
  elif event.type == "message_delta":
470
504
  current_snapshot.stop_reason = event.delta.stop_reason
471
505
  current_snapshot.stop_sequence = event.delta.stop_sequence
@@ -1,6 +1,8 @@
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
+ import jiter
5
+
4
6
  from ...types import (
5
7
  Message,
6
8
  ContentBlock,
@@ -11,8 +13,10 @@ from ...types import (
11
13
  ContentBlockStartEvent as RawContentBlockStartEvent,
12
14
  RawContentBlockStopEvent,
13
15
  )
14
- from ..._models import BaseModel
16
+ from ..._models import BaseModel, GenericModel
17
+ from .._parse._response import ResponseFormatT
15
18
  from ..._utils._transform import PropertyInfo
19
+ from ...types.parsed_message import ParsedMessage, ParsedContentBlock
16
20
  from ...types.citations_delta import Citation
17
21
 
18
22
 
@@ -25,6 +29,9 @@ class TextEvent(BaseModel):
25
29
  snapshot: str
26
30
  """The entire accumulated text"""
27
31
 
32
+ def parsed_snapshot(self) -> Dict[str, Any]:
33
+ return cast(Dict[str, Any], jiter.from_json(self.snapshot.encode("utf-8"), partial_mode="trailing-strings"))
34
+
28
35
 
29
36
  class CitationEvent(BaseModel):
30
37
  type: Literal["citation"]
@@ -98,3 +105,36 @@ MessageStreamEvent = Annotated[
98
105
  ],
99
106
  PropertyInfo(discriminator="type"),
100
107
  ]
108
+
109
+
110
+ class ParsedMessageStopEvent(RawMessageStopEvent, GenericModel, Generic[ResponseFormatT]):
111
+ type: Literal["message_stop"]
112
+
113
+ message: ParsedMessage[ResponseFormatT]
114
+
115
+
116
+ class ParsedContentBlockStopEvent(RawContentBlockStopEvent, GenericModel, Generic[ResponseFormatT]):
117
+ type: Literal["content_block_stop"]
118
+
119
+ if TYPE_CHECKING:
120
+ content_block: ParsedContentBlock[ResponseFormatT]
121
+ else:
122
+ content_block: ParsedContentBlock
123
+
124
+
125
+ ParsedMessageStreamEvent = Annotated[
126
+ Union[
127
+ TextEvent,
128
+ CitationEvent,
129
+ ThinkingEvent,
130
+ SignatureEvent,
131
+ InputJsonEvent,
132
+ RawMessageStartEvent,
133
+ RawMessageDeltaEvent,
134
+ ParsedMessageStopEvent[ResponseFormatT],
135
+ RawContentBlockStartEvent,
136
+ RawContentBlockDeltaEvent,
137
+ ParsedContentBlockStopEvent[ResponseFormatT],
138
+ ],
139
+ PropertyInfo(discriminator="type"),
140
+ ]
@@ -31,9 +31,9 @@ DEFAULT_THRESHOLD = 100_000
31
31
  class CompactionControl(TypedDict, total=False):
32
32
  context_token_threshold: int
33
33
  """The context token threshold at which to trigger compaction.
34
-
34
+
35
35
  When the cumulative token count (input + output) across all messages exceeds this threshold,
36
- the message history will be automatically summarized and compressed. Defaults to 150,000 tokens.
36
+ the message history will be automatically summarized and compressed. Defaults to 100,000 tokens.
37
37
  """
38
38
 
39
39
  model: str
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
+ import warnings
4
5
  from abc import ABC, abstractmethod
5
6
  from typing import (
6
7
  TYPE_CHECKING,
@@ -298,6 +299,14 @@ class BaseSyncToolRunner(BaseToolRunner[BetaRunnableTool, ResponseFormatT], Gene
298
299
  for tool_use in tool_use_blocks:
299
300
  tool = self._tools_by_name.get(tool_use.name)
300
301
  if tool is None:
302
+ warnings.warn(
303
+ f"Tool '{tool_use.name}' not found in tool runner. "
304
+ f"Available tools: {list(self._tools_by_name.keys())}. "
305
+ f"If using a raw tool definition, handle the tool call manually and use `append_messages()` to add the result. "
306
+ f"Otherwise, pass the tool using `beta_tool(func)` or a `@beta_tool` decorated function.",
307
+ UserWarning,
308
+ stacklevel=3,
309
+ )
301
310
  results.append(
302
311
  {
303
312
  "type": "tool_result",
@@ -554,6 +563,14 @@ class BaseAsyncToolRunner(
554
563
  for tool_use in tool_use_blocks:
555
564
  tool = self._tools_by_name.get(tool_use.name)
556
565
  if tool is None:
566
+ warnings.warn(
567
+ f"Tool '{tool_use.name}' not found in tool runner. "
568
+ f"Available tools: {list(self._tools_by_name.keys())}. "
569
+ f"If using a raw tool definition, handle the tool call manually and use `append_messages()` to add the result. "
570
+ f"Otherwise, pass the tool using `beta_async_tool(func)` or a `@beta_async_tool` decorated function.",
571
+ UserWarning,
572
+ stacklevel=3,
573
+ )
557
574
  results.append(
558
575
  {
559
576
  "type": "tool_result",